From a748eaade7328e3ee2dbb59107b3f7cf46d19ad3 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Thu, 12 Dec 2024 16:37:14 -0600 Subject: [PATCH 001/787] =?UTF-8?q?=F0=9F=94=A8=20Add=20offset=5Faddress?= =?UTF-8?q?=20for=20convenience?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ini/stm32f1.ini | 4 ++++ ini/stm32f4.ini | 14 ++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/ini/stm32f1.ini b/ini/stm32f1.ini index 0978b19476..ef117eb269 100644 --- a/ini/stm32f1.ini +++ b/ini/stm32f1.ini @@ -95,6 +95,7 @@ board = genericSTM32F103ZE board_build.variant = MARLIN_F103Zx board_build.encrypt_mks = Robin.bin board_build.offset = 0x7000 +board_build.offset_address = 0x08007000 build_flags = ${stm32_variant.build_flags} -DENABLE_HWSERIAL3 -DTIMER_SERIAL=TIM5 build_unflags = ${stm32_variant.build_unflags} @@ -239,6 +240,7 @@ extends = stm32_variant board = genericSTM32F103ZE board_build.variant = MARLIN_F103Zx board_build.offset = 0x10000 +board_build.offset_address = 0x08010000 build_flags = ${stm32_variant.build_flags} -DENABLE_HWSERIAL3 -DTIMER_SERIAL=TIM5 build_unflags = ${stm32_variant.build_unflags} @@ -417,6 +419,7 @@ board = genericSTM32F103ZE board_build.crypt_chitu = update.zw board_build.variant = MARLIN_F103Zx board_build.offset = 0x8800 +board_build.offset_address = 0x08008800 build_flags = ${stm32_variant.build_flags} -DENABLE_HWSERIAL3 -DTIMER_SERIAL=TIM5 build_unflags = ${stm32_variant.build_unflags} @@ -434,6 +437,7 @@ board = genericSTM32F103ZE board_build.crypt_chitu = update.cbd board_build.variant = MARLIN_F103Zx board_build.offset = 0x8800 +board_build.offset_address = 0x08008800 build_flags = ${stm32_variant.build_flags} -DSTM32F1xx build_unflags = ${stm32_variant.build_unflags} diff --git a/ini/stm32f4.ini b/ini/stm32f4.ini index 7fdbc69804..1b67be582b 100644 --- a/ini/stm32f4.ini +++ b/ini/stm32f4.ini @@ -36,6 +36,7 @@ extends = stm32_variant platform_packages = platformio/tool-dfuutil@~1.11.0 board = marlin_FYSETC_CHEETAH_V20 board_build.offset = 0x8000 +board_build.offset_address = 0x08008000 build_flags = ${stm32_variant.build_flags} -DSTM32F401xC upload_command = dfu-util -a 0 -s 0x08008000:leave -D "$SOURCE" @@ -60,6 +61,7 @@ platform_packages = platformio/tool-dfuutil@~1.11.0 board = marlin_STM32F407ZGT6 board_build.variant = MARLIN_FLY_F407ZG board_build.offset = 0x8000 +board_build.offset_address = 0x08008000 upload_protocol = dfu # @@ -95,6 +97,7 @@ platform_packages = platformio/tool-dfuutil@~1.11.0 board = marlin_STM32F407ZGT6 board_build.variant = MARLIN_FYSETC_SPIDER_KING407 board_build.offset = 0x8000 +board_build.offset_address = 0x08008000 upload_protocol = dfu # @@ -168,6 +171,7 @@ extra_scripts = ${Anet_ET4.extra_scripts} extends = stm32_variant board = marlin_BTT_SKR_Pro board_build.offset = 0x8000 +board_build.offset_address = 0x08008000 build_flags = ${stm32_variant.build_flags} -DSTM32F407_5ZX debug_tool = stlink upload_protocol = stlink @@ -189,6 +193,7 @@ extends = stm32_variant board = marlin_STM32F407VGT6_CCM board_build.variant = MARLIN_BTT_E3_RRF board_build.offset = 0x8000 +board_build.offset_address = 0x08008000 build_flags = ${stm32_variant.build_flags} -DSTM32F407_5VX -DMF_RX_BUFFER_SIZE=255 @@ -202,6 +207,7 @@ extends = stm32_variant board = marlin_STM32F407VGT6_CCM #board_build.variant = MARLIN_BTT_E3_RRF board_build.offset = 0x8000 +board_build.offset_address = 0x08008000 build_flags = ${stm32_variant.build_flags} -DSTM32F407_5VX -DMF_RX_BUFFER_SIZE=255 @@ -214,6 +220,7 @@ build_flags = ${stm32_variant.build_flags} extends = stm32_variant board = marlin_BTT_GTR_v1 board_build.offset = 0x8000 +board_build.offset_address = 0x08008000 build_flags = ${stm32_variant.build_flags} -DSTM32F407IX # @@ -232,6 +239,7 @@ build_unflags = ${env:BTT_GTR_V1_0.build_unflags} -DUSBCON -DUSBD_USE_CDC extends = stm32_variant board = marlin_BTT_BTT002 board_build.offset = 0x8000 +board_build.offset_address = 0x08008000 build_flags = ${stm32_variant.build_flags} -DSTM32F407_5VX -DHAVE_HWSERIAL2 @@ -354,6 +362,7 @@ build_flags = ${stm_flash_drive.build_flags} extends = stm32_variant board = marlin_STM32F407ZE board_build.offset = 0x8000 +board_build.offset_address = 0x08008000 build_flags = ${stm32_variant.build_flags} -DUSE_USB_HS_IN_FS @@ -378,6 +387,7 @@ board = marlin_STM32F407ZGT6 board_build.variant = MARLIN_LERDGE board_build.crypt_lerdge = firmware.bin board_build.offset = 0x10000 +board_build.offset_address = 0x08010000 build_flags = ${stm32_variant.build_flags} -DSTM32F4 -DSTM32F4xx -DTARGET_STM32F4 -DDISABLE_GENERIC_SERIALUSB -DARDUINO_ARCH_STM32 -DLERDGE_TFT35 @@ -440,6 +450,7 @@ platform_packages = platformio/tool-dfuutil@~1.11.0 board = rumba32_f446ve board_build.variant = MARLIN_F446VE board_build.offset = 0x0000 +board_build.offset_address = 0x08000000 build_flags = ${stm32_variant.build_flags} -Os -DHAL_PCD_MODULE_ENABLED -DDISABLE_GENERIC_SERIALUSB @@ -840,6 +851,7 @@ extends = stm32_variant board = marlin_STM32F446ZET_tronxy board_build.ldscript = buildroot/share/PlatformIO/variants/MARLIN_F446Zx_TRONXY/ldscript.ld board_build.offset = 0x10000 +board_build.offset_address = 0x08010000 build_flags = ${stm32_variant.build_flags} -DSTM32F4xx -DUSE_USB_HS -DUSE_USB_HS_IN_FS @@ -873,6 +885,7 @@ monitor_speed = 115200 extends = stm32_variant board = marlin_I3DBEEZ9 board_build.offset = 0x8000 +board_build.offset_address = 0x08008000 build_flags = ${stm32_variant.build_flags} -DSTM32F407_5ZX debug_tool = stlink upload_protocol = stlink @@ -886,6 +899,7 @@ platform_packages = platformio/tool-dfuutil@~1.11.0 extends = common_stm32 board = blackpill_f401cc board_build.offset = 0x0000 +board_build.offset_address = 0x08000000 build_flags = ${common_stm32.build_flags} -Os -DHAL_PCD_MODULE_ENABLED -DHAL_UART_MODULE_ENABLED From a23212bd95e268fe29682e53cd5b7719811c5519 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Thu, 12 Dec 2024 16:26:13 -0600 Subject: [PATCH 002/787] =?UTF-8?q?=F0=9F=94=A8=20Versioned=20ststm32=20fo?= =?UTF-8?q?r=20BLACKBEEZMINI=5FV1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ini/stm32f4.ini | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ini/stm32f4.ini b/ini/stm32f4.ini index 1b67be582b..3f7b5b6346 100644 --- a/ini/stm32f4.ini +++ b/ini/stm32f4.ini @@ -894,9 +894,8 @@ upload_protocol = stlink # BlackBeezMini (blackpill_f401cc) # [env:BLACKBEEZMINI_V1] -platform = ststm32 -platform_packages = platformio/tool-dfuutil@~1.11.0 extends = common_stm32 +platform_packages = platformio/tool-dfuutil@~1.11.0 board = blackpill_f401cc board_build.offset = 0x0000 board_build.offset_address = 0x08000000 From 94ca5487ab18647f1078847e9e1b460bb894a412 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Mon, 16 Dec 2024 00:31:26 +0000 Subject: [PATCH 003/787] [cron] Bump distribution date (2024-12-16) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 042bc34f24..69ec210a65 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2024-12-13" +//#define STRING_DISTRIBUTION_DATE "2024-12-16" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index a4d9a75819..ca04b24869 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2024-12-13" + #define STRING_DISTRIBUTION_DATE "2024-12-16" #endif /** From 4c388d711880d64b33be5d0d8a0366f4cf5fe498 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sun, 15 Dec 2024 18:41:42 -0600 Subject: [PATCH 004/787] =?UTF-8?q?=F0=9F=9A=B8=20Limited=20number=20of=20?= =?UTF-8?q?DGUS=20fans?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/lcd/extui/dgus/fysetc/DGUSDisplayDef.cpp | 9 ++++++++- .../src/lcd/extui/dgus/hiprecy/DGUSDisplayDef.cpp | 9 ++++++++- Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp | 15 +++++++++++---- .../src/lcd/extui/dgus/origin/DGUSDisplayDef.cpp | 9 ++++++++- 4 files changed, 35 insertions(+), 7 deletions(-) diff --git a/Marlin/src/lcd/extui/dgus/fysetc/DGUSDisplayDef.cpp b/Marlin/src/lcd/extui/dgus/fysetc/DGUSDisplayDef.cpp index 243dbfbab6..575e56103e 100644 --- a/Marlin/src/lcd/extui/dgus/fysetc/DGUSDisplayDef.cpp +++ b/Marlin/src/lcd/extui/dgus/fysetc/DGUSDisplayDef.cpp @@ -406,11 +406,18 @@ const struct DGUS_VP_Variable ListOfVP[] PROGMEM = { // Fan Data #if HAS_FAN + #if HOTENDS <= 4 + #define FAN_CONTROL HOTENDS + #elif FAN_COUNT <= 4 + #define FAN_CONTROL FAN_COUNT + #else + #define FAN_CONTROL 4 + #endif #define FAN_VPHELPER(N) \ VPHELPER(VP_Fan##N##_Percentage, &thermalManager.fan_speed[N], screen.percentageToUint8, screen.sendPercentageToDisplay), \ VPHELPER(VP_FAN##N##_CONTROL, &thermalManager.fan_speed[N], screen.handleFanControl, nullptr), \ VPHELPER(VP_FAN##N##_STATUS, &thermalManager.fan_speed[N], nullptr, screen.sendFanStatusToDisplay), - REPEAT(FAN_COUNT, FAN_VPHELPER) + REPEAT(FAN_CONTROL, FAN_VPHELPER) #endif // Feedrate diff --git a/Marlin/src/lcd/extui/dgus/hiprecy/DGUSDisplayDef.cpp b/Marlin/src/lcd/extui/dgus/hiprecy/DGUSDisplayDef.cpp index 56d58a19b0..338f6a319c 100644 --- a/Marlin/src/lcd/extui/dgus/hiprecy/DGUSDisplayDef.cpp +++ b/Marlin/src/lcd/extui/dgus/hiprecy/DGUSDisplayDef.cpp @@ -399,11 +399,18 @@ const struct DGUS_VP_Variable ListOfVP[] PROGMEM = { // Fan Data #if HAS_FAN + #if HOTENDS <= 2 + #define FAN_CONTROL HOTENDS + #elif FAN_COUNT <= 2 + #define FAN_CONTROL FAN_COUNT + #else + #define FAN_CONTROL 2 + #endif #define FAN_VPHELPER(N) \ VPHELPER(VP_Fan##N##_Percentage, &thermalManager.fan_speed[N], screen.percentageToUint8, screen.sendPercentageToDisplay), \ VPHELPER(VP_FAN##N##_CONTROL, &thermalManager.fan_speed[N], screen.handleFanControl, nullptr), \ VPHELPER(VP_FAN##N##_STATUS, &thermalManager.fan_speed[N], nullptr, screen.sendFanStatusToDisplay), - REPEAT(FAN_COUNT, FAN_VPHELPER) + REPEAT(FAN_CONTROL, FAN_VPHELPER) #endif // Feedrate diff --git a/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp b/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp index 6429ac07e5..4182c3f2ca 100644 --- a/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp +++ b/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp @@ -602,11 +602,18 @@ const struct DGUS_VP_Variable ListOfVP[] PROGMEM = { // Fan Data #if HAS_FAN - #define FAN_VPHELPER(N) \ - VPHELPER(VP_Fan##N##_Percentage, &thermalManager.fan_speed[N], screen.setUint8, screen.sendFanToDisplay), \ - VPHELPER(VP_FAN##N##_CONTROL, &thermalManager.fan_speed[N], screen.handleFanControl, nullptr), \ + #if HOTENDS <= 4 + #define FAN_CONTROL HOTENDS + #elif FAN_COUNT <= 4 + #define FAN_CONTROL FAN_COUNT + #else + #define FAN_CONTROL 4 + #endif + #define FAN_VPHELPER(N) \ + VPHELPER(VP_Fan##N##_Percentage, &thermalManager.fan_speed[N], screen.percentageToUint8, screen.sendFanToDisplay), \ + VPHELPER(VP_FAN##N##_CONTROL, &thermalManager.fan_speed[N], screen.handleFanControl, nullptr), \ VPHELPER(VP_FAN##N##_STATUS, &thermalManager.fan_speed[N], nullptr, screen.sendFanStatusToDisplay), - REPEAT(FAN_COUNT, FAN_VPHELPER) + REPEAT(FAN_CONTROL, FAN_VPHELPER) #endif // Feedrate diff --git a/Marlin/src/lcd/extui/dgus/origin/DGUSDisplayDef.cpp b/Marlin/src/lcd/extui/dgus/origin/DGUSDisplayDef.cpp index 8c82b63f3a..4875020f55 100644 --- a/Marlin/src/lcd/extui/dgus/origin/DGUSDisplayDef.cpp +++ b/Marlin/src/lcd/extui/dgus/origin/DGUSDisplayDef.cpp @@ -207,11 +207,18 @@ const struct DGUS_VP_Variable ListOfVP[] PROGMEM = { // Fan Data #if HAS_FAN + #if HOTENDS <= 2 + #define FAN_CONTROL HOTENDS + #elif FAN_COUNT <= 2 + #define FAN_CONTROL FAN_COUNT + #else + #define FAN_CONTROL 2 + #endif #define FAN_VPHELPER(N) \ VPHELPER(VP_Fan##N##_Percentage, &thermalManager.fan_speed[N], screen.percentageToUint8, screen.sendPercentageToDisplay), \ VPHELPER(VP_FAN##N##_CONTROL, &thermalManager.fan_speed[N], screen.handleFanControl, nullptr), \ VPHELPER(VP_FAN##N##_STATUS, &thermalManager.fan_speed[N], nullptr, screen.sendFanStatusToDisplay), - REPEAT(FAN_COUNT, FAN_VPHELPER) + REPEAT(FAN_CONTROL, FAN_VPHELPER) #endif // Feedrate From dcc10565f8865d6400008a280fbcdff4ac8ae074 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sun, 15 Dec 2024 20:34:18 -0600 Subject: [PATCH 005/787] =?UTF-8?q?=F0=9F=93=9D=20@section=20calibration?= =?UTF-8?q?=20=3D>=20calibrate?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/Configuration_adv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 564f44df60..806bafa2d0 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -1020,7 +1020,7 @@ #endif // BLTOUCH -// @section calibration +// @section calibrate /** * Z Steppers Auto-Alignment From d5dfd18c24d8d79e55893cf90b1cb5c28bc369ed Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sun, 15 Dec 2024 16:04:23 -0600 Subject: [PATCH 006/787] =?UTF-8?q?=F0=9F=94=A8=20Scripted=20build/archive?= =?UTF-8?q?=20multiple=20envs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- buildroot/bin/build_all_examples | 9 +- buildroot/bin/build_example | 168 +++++++++++++++++++------------ buildroot/bin/mfenvs | 33 ++++++ buildroot/bin/mftest | 2 +- buildroot/share/git/mfhelp | 1 + 5 files changed, 149 insertions(+), 64 deletions(-) create mode 100755 buildroot/bin/mfenvs diff --git a/buildroot/bin/build_all_examples b/buildroot/bin/build_all_examples index c2b0007b0c..595cfad839 100755 --- a/buildroot/bin/build_all_examples +++ b/buildroot/bin/build_all_examples @@ -11,6 +11,7 @@ # [-f|--nofail] - Don't stop on a failed build # [-h|--help] - Print usage and exit # [-l|--limit=#] - Limit the number of builds in this run +# [-m|--many] - Build all the environments for each example # [-n|--nobuild] - Don't actually build anything # [-o|--output] - Redirect export / archiving to another location # (By default export to origin config folders) @@ -38,6 +39,7 @@ build_all_examples [-a|--archive] - Copy the binary to the export locati [-f|--nofail] - Don't stop on a failed build [-h|--help] - Print usage and exit [-l|--limit=#] - Limit the number of builds in this run + [-m|--many] - Build all the environments for each example [-n|--nobuild] - Don't actually build anything [-o|--output] - Redirect export / archiving to another location (By default export to origin config folders) @@ -53,7 +55,7 @@ unset FIRST_CONF EXIT_USAGE= LIMIT=1000 -while getopts 'aB:b:cde:fhl:no:pr:sv-:' OFLAG; do +while getopts 'aB:b:cde:fhl:mno:pr:sv-:' OFLAG; do case "${OFLAG}" in a) ARCHIVE=1 ; bugout "Archiving" ;; B) CBASE=${OPTARG%/} ; bugout "Base: $CBASE" ;; @@ -64,6 +66,7 @@ while getopts 'aB:b:cde:fhl:no:pr:sv-:' OFLAG; do f) NOFAIL=1 ; bugout "Continue on Fail" ;; h) EXIT_USAGE=1 ; break ;; l) LIMIT=$OPTARG ; bugout "Limit to $LIMIT build(s)" ;; + m) MANY=1 ; bugout "Many Envs" ;; n) DRYRUN=1 ; bugout "Dry Run" ;; o) OUTBASE="${OPTARG%/}" ; bugout "Archive to $OUTBASE" ;; p) PURGE=1 ; bugout "Purge stat file" ;; @@ -74,6 +77,7 @@ while getopts 'aB:b:cde:fhl:no:pr:sv-:' OFLAG; do archive) ARCHIVE=1 ; bugout "Archiving" ;; base) CBASE=${OVAL%/} ; bugout "Base: $CBASE" ;; branch) BRANCH=$OVAL ; bugout "Branch: $BRANCH" ;; + many) MANY=1 ; bugout "Many Envs" ;; nofail) NOFAIL=1 ; bugout "Continue on Fail" ;; resume) ISRES=1 ; FIRST_CONF=$OVAL ; bugout "Resume: $FIRST_CONF" ;; continue) CONTINUE=1 ; bugout "Continue" ;; @@ -179,6 +183,9 @@ find -ds "$CBASE"/config/examples -type d -name 'Configuration.h' -o -name 'Conf # Exporting? Add -e argument ((CEXPORT)) && CARGS+=("-e" "$CEXPORT") + # Build many environments? Add -m argument + ((NOFAIL)) && CARGS+=("-m") + # Continue on fail? Add -f argument ((NOFAIL)) && CARGS+=("-f") diff --git a/buildroot/bin/build_example b/buildroot/bin/build_example index 566919abd6..623da8ac84 100755 --- a/buildroot/bin/build_example +++ b/buildroot/bin/build_example @@ -5,6 +5,7 @@ # build_example -b|--base= - Configurations root folder (e.g., ./.pio/build-BRANCH) # -c|--config= - Sub-path of the configs to build (within config/examples) # [-n|--index=N] - Which environment to build, by index (Based on pins.h comments) +# [-m|--many] - Build all the board's environments listed in pins.h # [-e|--export=N] - Use CONFIG_EXPORT N to export the config to the export location # [-a|--archive] - Archive the build (to the export location) # [-o|--output] - Redirect export / archiving to another location @@ -21,6 +22,7 @@ usage() { echo "Usage: build_example -b|--base= - Configurations root folder (e.g., ./.pio/build-BRANCH) -c|--config= - Sub-path of the configs to build (within config/examples) [-n|--index=N] - Which environment to build, by index (Based on pins.h comments) + [-m|--many] - Build all the board's environments listed in pins.h [-e|--export=N] - Use CONFIG_EXPORT N to export the config to the export location [-a|--archive] - Archive the build (to the export location) [-o|--output] - Redirect export / archiving to another location @@ -53,8 +55,9 @@ EXPNUM= NOFAIL= OUTBASE= BUILDINDEX=1 +MANY= -while getopts 'ab:c:e:fhn:o:r-:' OFLAG; do +while getopts 'ab:c:e:fhmn:o:r-:' OFLAG; do case "${OFLAG}" in a) ARCHIVE=1 ;; b) BASE="${OPTARG%/}" ;; @@ -62,6 +65,7 @@ while getopts 'ab:c:e:fhn:o:r-:' OFLAG; do e) EXPNUM="$OPTARG" ;; f) NOFAIL=1 ;; h) EXIT_USAGE=1 ; break ;; + m) MANY=1 ;; n) BUILDINDEX="$OPTARG" ;; o) OUTBASE="${OPTARG%/}" ;; r) REVEAL=1 ;; @@ -71,6 +75,7 @@ while getopts 'ab:c:e:fhn:o:r-:' OFLAG; do allow) ALLOW=1 ;; base) BASE="${OVAL%/}" ;; config) CONFIG="${OVAL%/}" ;; + many) MANY=1 ;; index) BUILDINDEX="$OVAL" ;; export) EXPNUM="$OVAL" ;; output) OUTBASE="${OVAL%/}" ;; @@ -178,68 +183,107 @@ fi ((ARCHIVE)) && find "$BUILD" -type f \( "${BNAME[@]}" \) -exec rm "{}" \; -set +e - -echo "Building example $CONFIG ..." -mftest -s -a -n$BUILDINDEX ; ERR=$? - -((ERR)) && alrt "Failed ($ERR)" || annc "Success" - -set -e - -if [[ $ERR -gt 0 ]]; then - - # Error? For --nofail simply log. Otherwise return the error. - if [[ -n $NOFAIL ]]; then - date +"%F %T [FAIL] $CONFIG" >>./.pio/error-log.txt - else - exit $ERR - fi - -else - - # Copy exports back to the configs - if [[ -n $EXPNUM ]]; then - annc "Exporting $EXPNUM" - [[ -f Marlin/Config-export.h ]] && { cp Marlin/Config-export.h "$ARCSUB"/Config.h ; } - find "$BUILD" -type f \( "${ENAME[@]}" \) -exec cp "{}" "$ARCSUB" \; - fi - - # Copy potential firmware files into the config folder - # TODO: Consider firmware that needs an STM32F4_UPDATE folder. - # Currently only BOARD_CREALITY_F401RE env:STM32F401RE_creality - if ((ARCHIVE)); then - annc "Archiving" - find "$BUILD" -type f \( "${BNAME[@]}" \) -exec sh -c ' - ARCSUB="$1" ; CONFIG="$2" ; FILE="$3" ; shift 3 - NAME=${FILE##*/} ; SHRT=${NAME%.*} ; DIR=${FILE%/*} - ZIPX= - if [[ $CONFIG == *Simulator* ]]; then - case $(uname | tr '[:upper:]' '[:lower:]') in - darwin) SUB="macOS" ; ZIPX="-X" ;; - *linux) SUB="Linux" ;; - win*) SUB="Windows" ;; - msys*) SUB="Windows" ;; - cygwin*) SUB="Windows" ;; - mingw*) SUB="Windows" ;; - *) SUB='Unix' ;; - esac - ARCH=$(uname -m | tr '[:lower:]' '[:upper:]') - ARCSUB="$ARCSUB/$SUB-$ARCH" - fi - mkdir -p "$ARCSUB" - rm -f "$ARCSUB"/*.zip "$ARCSUB"/*.sha256.txt - cd "$DIR" - SHASUM=$(sha256sum "$NAME" | cut -d" " -f1) - echo "$CONFIG\n$SHASUM" > "$ARCSUB/$NAME.sha256.txt" - zip $ZIPX "$ARCSUB/$SHRT.zip" "$NAME" && rm "$NAME" - cd - >/dev/null - ' sh "$ARCSUB" "$CONFIG" {} + - fi - - # Reveal the configs after the build, if requested - ((REVEAL)) && { annc "Revealing $ARCSUB" ; open "$ARCSUB" ; } +echo "Building example $CONFIG..." +# If doing many builds get a list of all environment names, +# which also gives us the number of environments. +if ((MANY)); then + ENVLIST=$(mfenvs) # BOARD_NAME_STRING (1234): [ env1 env2 env3 ... ] + ENVLIST=${ENVLIST##*: [ } + ENVARRAY=(${ENVLIST% ]}) + ENVCOUNT=${#ENVARRAY[*]} + ((ENVCOUNT)) || { alrt "mfenvs failed for this board." ; exit 1 ; } + echo "Found $ENVCOUNT environment(s): ${ENVARRAY[*]}" fi +# Run one or more builds based on --many +# Build all from BUILDINDEX onward (usually 1) meaning ALL. +# MANY with a BUILDINDEX may be useful for continuing an interrupted build. + +while ((1)); do + set +e + + echo "Building example $CONFIG ($BUILDINDEX)..." + + # Run a build and record the error number + mftest -s -a -n$BUILDINDEX ; ERR=$? + + # "Index out of range" can fail without an error + ((MANY)) && ((ERR == 66)) && ERR=0 && break # "index out of range" + + # Short message reporting Error or Success + ((ERR)) && alrt "Failed ($ERR)" || annc "Success" + + set -e + + if [[ $ERR -gt 0 ]]; then + + # Error? For --nofail simply log. Otherwise return the error. + if [[ -n $NOFAIL ]]; then + date +"%F %T [FAIL] $CONFIG" >>./.pio/error-log.txt + else + exit $ERR + fi + + else + + # Copy exports back to the configs + if [[ -n $EXPNUM ]]; then + annc "Exporting $EXPNUM" + [[ -f Marlin/Config-export.h ]] && { cp Marlin/Config-export.h "$ARCSUB"/Config.h ; } + find "$BUILD" -type f \( "${ENAME[@]}" \) -exec cp "{}" "$ARCSUB" \; + fi + + # When building many, create sub-folders for each build env name + if [[ -n $MANY && $ENVCOUNT -gt 1 ]]; then + ENV=${ENVARRAY[BUILDINDEX-1]} + ARCENVSUB="$ARCSUB/$ENV" + else + ARCENVSUB="$ARCSUB" + fi + + # Copy potential firmware files into the config folder + # TODO: Consider firmware that needs an STM32F4_UPDATE folder. + # Currently only BOARD_CREALITY_F401RE env:STM32F401RE_creality + if ((ARCHIVE)); then + annc "Archiving" + find "$BUILD" -type f \( "${BNAME[@]}" \) -exec sh -c ' + ARCDIR="$1" ; CONFIG="$2" ; FILE="$3" ; shift 3 + NAME=${FILE##*/} ; SHRT=${NAME%.*} ; DIR=${FILE%/*} + ZIPX= + if [[ $CONFIG == *Simulator* ]]; then + case $(uname | tr '[:upper:]' '[:lower:]') in + darwin) SUB="macOS" ; ZIPX="-X" ;; + *linux) SUB="Linux" ;; + win*) SUB="Windows" ;; + msys*) SUB="Windows" ;; + cygwin*) SUB="Windows" ;; + mingw*) SUB="Windows" ;; + *) SUB='Unix' ;; + esac + ARCH=$(uname -m | tr '[:lower:]' '[:upper:]') + ARCDIR="$ARCDIR/$SUB-$ARCH" + fi + mkdir -p "$ARCDIR" + rm -f "$ARCDIR"/*.zip "$ARCDIR"/*.sha256.txt + cd "$DIR" + SHASUM=$(sha256sum "$NAME" | cut -d" " -f1) + echo "$CONFIG\n$SHASUM" > "$ARCDIR/$NAME.sha256.txt" + zip $ZIPX "$ARCDIR/$SHRT.zip" "$NAME" && rm "$NAME" + cd - >/dev/null + ' sh "$ARCENVSUB" "$CONFIG" {} + + fi + + # Reveal the configs after the build, if requested + ((REVEAL)) && { annc "Revealing $ARCENVSUB" ; open "$ARCENVSUB" ; } + + fi + + ((MANY)) || break # Only one build if not --many + + # Set up for the next build, if there is one + ((++BUILDINDEX > ENVCOUNT)) && break + +done + exit 0 diff --git a/buildroot/bin/mfenvs b/buildroot/bin/mfenvs new file mode 100755 index 0000000000..3c726af53c --- /dev/null +++ b/buildroot/bin/mfenvs @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +# +# mfenvs Print the current board and environment information +# Output -> "SHORT_NAME (###): [ env1 env2 env3 ... ]" +# + +[[ -d Marlin/src ]] || { echo "Please 'cd' to the Marlin repo root." ; exit 1 ; } +which pio >/dev/null || { echo "Make sure 'pio' is in your execution PATH." ; exit 1 ; } + +errout() { echo -e "\033[0;31m$1\033[0m" ; } + +case $(uname | tr '[:upper:]' '[:lower:]') in + darwin) SYS='mac' ;; + *linux) SYS='lin' ;; + win*) SYS='win' ;; + msys*) SYS='win' ;; + cygwin*) SYS='win' ;; + mingw*) SYS='win' ;; + *) SYS='uni' ;; +esac + +ACODE='/^[[:space:]]*#define[[:space:]]MOTHERBOARD[[:space:]]/ { sub(/^BOARD_/, "", $3); print $3 }' +MB=$(awk "$ACODE" Marlin/Configuration.h 2>/dev/null) +[[ -z $MB ]] && MB=$(awk "$ACODE" Marlin/Config.h 2>/dev/null) +[[ -z $MB ]] && { echo "Error - Can't read MOTHERBOARD setting." ; exit 1 ; } +BLINE=$( grep -E "define\s+BOARD_$MB\b" Marlin/src/core/boards.h ) +BNUM=$( sed -E 's/^.+BOARD_[^ ]+ +([0-9]+).+$/\1/' <<<"$BLINE" ) +[[ -z $BNUM ]] && { echo "Error - Can't find BOARD_$MB in core/boards.h." ; exit 1 ; } +ENVS=( $( grep -EA1 "MB\(.*\b$MB\b.*\)" Marlin/src/pins/pins.h | grep -E "#include.+//.+(env|$SYS):[^ ]+" | grep -oE "(env|$SYS):[^ ]+" | sed -E "s/(env|$SYS)://" ) ) +[[ -z $ENVS ]] && { errout "Error - Can't find target(s) for $MB ($BNUM)." ; exit 1 ; } +ECOUNT=${#ENVS[*]} +[[ $ECOUNT == 1 ]] && EOUT=$ENVS || EOUT="${ENVS[@]}" +echo "$MB ($BNUM): [ $EOUT ]" diff --git a/buildroot/bin/mftest b/buildroot/bin/mftest index 57aa95400c..07601654aa 100755 --- a/buildroot/bin/mftest +++ b/buildroot/bin/mftest @@ -196,7 +196,7 @@ if ((AUTO_BUILD)); then fi else echo "Detected \"$BDESC\" | $MB ($BNUM)." - [[ $CHOICE > $ECOUNT ]] && { echo "Environment selection out of range." ; exit 1 ; } + [[ $CHOICE > $ECOUNT ]] && { echo "Environment selection out of range." ; exit 66 ; } fi TARGET="${ENVS[$CHOICE-1]}" if [[ $MB == 'SIMULATED' && $TARGET == 'linux_native' ]]; then diff --git a/buildroot/share/git/mfhelp b/buildroot/share/git/mfhelp index cbdd6ec4ef..bbf713a926 100755 --- a/buildroot/share/git/mfhelp +++ b/buildroot/share/git/mfhelp @@ -12,6 +12,7 @@ Marlin Firmware Commands: mfadd ....... Fetch a remote branch from any Marlin fork mfclean ..... Attempt to clean up merged and deleted branches mfdoc ....... Build the website, serve locally, and browse + mfenvs ...... Get current board SHORT_NAME (###): [ env1 env2 ... ] mffp ........ Push new commits directly to MarlinFirmware mfinfo ...... Provide branch information (for the other scripts) mfinit ...... Create an 'upstream' remote for 'MarlinFirmare' From c0becd6ce1bb3729663811b174ca93f901601238 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sun, 15 Dec 2024 23:25:10 -0600 Subject: [PATCH 007/787] =?UTF-8?q?=F0=9F=94=A8=20Scripted=20build/archive?= =?UTF-8?q?=20multiple=20envs=20(2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- buildroot/bin/build_all_examples | 2 +- buildroot/bin/build_example | 9 +++++---- buildroot/share/PlatformIO/scripts/signature.py | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/buildroot/bin/build_all_examples b/buildroot/bin/build_all_examples index 595cfad839..d50937a732 100755 --- a/buildroot/bin/build_all_examples +++ b/buildroot/bin/build_all_examples @@ -184,7 +184,7 @@ find -ds "$CBASE"/config/examples -type d -name 'Configuration.h' -o -name 'Conf ((CEXPORT)) && CARGS+=("-e" "$CEXPORT") # Build many environments? Add -m argument - ((NOFAIL)) && CARGS+=("-m") + ((MANY)) && CARGS+=("-m") # Continue on fail? Add -f argument ((NOFAIL)) && CARGS+=("-f") diff --git a/buildroot/bin/build_example b/buildroot/bin/build_example index 623da8ac84..133f3c4cc9 100755 --- a/buildroot/bin/build_example +++ b/buildroot/bin/build_example @@ -211,22 +211,23 @@ while ((1)); do # "Index out of range" can fail without an error ((MANY)) && ((ERR == 66)) && ERR=0 && break # "index out of range" - # Short message reporting Error or Success - ((ERR)) && alrt "Failed ($ERR)" || annc "Success" - set -e if [[ $ERR -gt 0 ]]; then + alrt "Failed ($ERR)" + # Error? For --nofail simply log. Otherwise return the error. if [[ -n $NOFAIL ]]; then - date +"%F %T [FAIL] $CONFIG" >>./.pio/error-log.txt + date +"%F %T [FAIL] $CONFIG ($BUILDINDEX)" >>./.pio/error-log.txt else exit $ERR fi else + annc "Success" + # Copy exports back to the configs if [[ -n $EXPNUM ]]; then annc "Exporting $EXPNUM" diff --git a/buildroot/share/PlatformIO/scripts/signature.py b/buildroot/share/PlatformIO/scripts/signature.py index 6ae3793910..efb8527869 100755 --- a/buildroot/share/PlatformIO/scripts/signature.py +++ b/buildroot/share/PlatformIO/scripts/signature.py @@ -364,7 +364,7 @@ f'''# with config_h.open('w') as outfile: filegrp = { 'Configuration.h':'config:basic', 'Configuration_adv.h':'config:advanced' } vers = build_defines["CONFIGURATION_H_VERSION"] - dt_string = datetime.now().strftime("%Y-%m-%d at %H:%M:%S") + dt_string = datetime.utcnow().strftime("%Y-%m-%d at %H:%M:%S") out_text = f'''/** * Config.h - Marlin Firmware distilled configuration From 2a137d67444e5de32589720930ebeba9db3b47cc Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Mon, 16 Dec 2024 14:58:03 -0600 Subject: [PATCH 008/787] =?UTF-8?q?=F0=9F=A9=B9=20Fix=20build=20with=20Col?= =?UTF-8?q?or=20UI=20touch=20items?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/lcd/menu/menu_probe_level.cpp | 6 ++---- Marlin/src/lcd/menu/menu_x_twist.cpp | 5 +++++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Marlin/src/lcd/menu/menu_probe_level.cpp b/Marlin/src/lcd/menu/menu_probe_level.cpp index 588a5b257b..ba806d665f 100644 --- a/Marlin/src/lcd/menu/menu_probe_level.cpp +++ b/Marlin/src/lcd/menu/menu_probe_level.cpp @@ -44,11 +44,9 @@ #include "../../feature/babystep.h" #endif -#if HAS_GRAPHICAL_TFT +#if ALL(TOUCH_SCREEN, HAS_GRAPHICAL_TFT) #include "../tft/tft.h" - #if ENABLED(TOUCH_SCREEN) - #include "../tft/touch.h" - #endif + #include "../tft/touch.h" #endif #if ENABLED(LCD_BED_LEVELING) && ANY(PROBE_MANUALLY, MESH_BED_LEVELING) diff --git a/Marlin/src/lcd/menu/menu_x_twist.cpp b/Marlin/src/lcd/menu/menu_x_twist.cpp index 6c2ab70dbc..a9998e3e44 100644 --- a/Marlin/src/lcd/menu/menu_x_twist.cpp +++ b/Marlin/src/lcd/menu/menu_x_twist.cpp @@ -36,6 +36,11 @@ #define XATC_Y_POSITION ((probe.max_y() - probe.min_y())/2) #endif +#if ALL(TOUCH_SCREEN, HAS_GRAPHICAL_TFT) + #include "../tft/tft.h" + #include "../tft/touch.h" +#endif + void _goto_manual_move_z(const_float_t); float measured_z, z_offset; From c4ef2d63e1c4651f652873b16e9e47339b66d851 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Mon, 16 Dec 2024 15:30:01 -0600 Subject: [PATCH 009/787] =?UTF-8?q?=F0=9F=94=A5=20Remove=20obsolete=20supp?= =?UTF-8?q?ort=20files?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Followup to #15347 Originally from #10849 --- buildroot/share/vscode/avrdude.conf | 15478 -------------------- buildroot/share/vscode/avrdude_5.10_linux | Bin 1159576 -> 0 bytes buildroot/share/vscode/avrdude_5.10_macOS | Bin 346784 -> 0 bytes buildroot/share/vscode/avrdude_linux.conf | 15478 -------------------- buildroot/share/vscode/avrdude_macOS.conf | 15272 ------------------- 5 files changed, 46228 deletions(-) delete mode 100644 buildroot/share/vscode/avrdude.conf delete mode 100644 buildroot/share/vscode/avrdude_5.10_linux delete mode 100644 buildroot/share/vscode/avrdude_5.10_macOS delete mode 100644 buildroot/share/vscode/avrdude_linux.conf delete mode 100644 buildroot/share/vscode/avrdude_macOS.conf diff --git a/buildroot/share/vscode/avrdude.conf b/buildroot/share/vscode/avrdude.conf deleted file mode 100644 index c6056b4c0f..0000000000 --- a/buildroot/share/vscode/avrdude.conf +++ /dev/null @@ -1,15478 +0,0 @@ -# $Id: avrdude.conf.in 916 2010-01-15 16:36:13Z joerg_wunsch $ -# -# AVRDUDE Configuration File -# -# This file contains configuration data used by AVRDUDE which describes -# the programming hardware pinouts and also provides part definitions. -# AVRDUDE's "-C" command line option specifies the location of the -# configuration file. The "-c" option names the programmer configuration -# which must match one of the entry's "id" parameter. The "-p" option -# identifies which part AVRDUDE is going to be programming and must match -# one of the parts' "id" parameter. -# -# Possible entry formats are: -# -# programmer -# id = [, [, ] ...] ; # are quoted strings -# desc = ; # quoted string -# type = par | stk500 | stk500v2 | stk500pp | stk500hvsp | stk500generic | -# stk600 | stk600pp | stk600hvsp | -# avr910 | butterfly | usbasp | -# jtagmki | jtagmkii | jtagmkii_isp | jtagmkii_dw | -# jtagmkII_avr32 | jtagmkii_pdi | -# dragon_dw | dragon_jtag | dragon_isp | dragon_pp | -# dragon_hvsp | dragon_pdi | arduino; # programmer type -# baudrate = ; # baudrate for avr910-programmer -# vcc = [, ... ] ; # pin number(s) -# reset = ; # pin number -# sck = ; # pin number -# mosi = ; # pin number -# miso = ; # pin number -# errled = ; # pin number -# rdyled = ; # pin number -# pgmled = ; # pin number -# vfyled = ; # pin number -# ; -# -# part -# id = ; # quoted string -# desc = ; # quoted string -# has_jtag = ; # part has JTAG i/f -# has_debugwire = ; # part has debugWire i/f -# has_pdi = ; # part has PDI i/f -# has_tpi = ; # part has TPI i/f -# devicecode = ; # deprecated, use stk500_devcode -# stk500_devcode = ; # numeric -# avr910_devcode = ; # numeric -# signature = ; # signature bytes -# chip_erase_delay = ; # micro-seconds -# reset = dedicated | io; -# retry_pulse = reset | sck; -# pgm_enable = ; -# chip_erase = ; -# chip_erase_delay = ; # chip erase delay (us) -# # STK500 parameters (parallel programming IO lines) -# pagel = ; # pin name in hex, i.e., 0xD7 -# bs2 = ; # pin name in hex, i.e., 0xA0 -# serial = ; # can use serial downloading -# parallel = ; # can use par. programming -# # STK500v2 parameters, to be taken from Atmel's XML files -# timeout = ; -# stabdelay = ; -# cmdexedelay = ; -# synchloops = ; -# bytedelay = ; -# pollvalue = ; -# pollindex = ; -# predelay = ; -# postdelay = ; -# pollmethod = ; -# mode = ; -# delay = ; -# blocksize = ; -# readsize = ; -# hvspcmdexedelay = ; -# # STK500v2 HV programming parameters, from XML -# pp_controlstack = , , ...; # PP only -# hvsp_controlstack = , , ...; # HVSP only -# hventerstabdelay = ; -# progmodedelay = ; # PP only -# latchcycles = ; -# togglevtg = ; -# poweroffdelay = ; -# resetdelayms = ; -# resetdelayus = ; -# hvleavestabdelay = ; -# resetdelay = ; -# synchcycles = ; # HVSP only -# chiperasepulsewidth = ; # PP only -# chiperasepolltimeout = ; -# chiperasetime = ; # HVSP only -# programfusepulsewidth = ; # PP only -# programfusepolltimeout = ; -# programlockpulsewidth = ; # PP only -# programlockpolltimeout = ; -# # JTAG ICE mkII parameters, also from XML files -# allowfullpagebitstream = ; -# enablepageprogramming = ; -# idr = ; # IO addr of IDR (OCD) reg. -# rampz = ; # IO addr of RAMPZ reg. -# spmcr = ; # mem addr of SPMC[S]R reg. -# eecr = ; # mem addr of EECR reg. -# # (only when != 0x3c) -# is_avr32 = ; # AVR32 part -# -# memory -# paged = ; # yes / no -# size = ; # bytes -# page_size = ; # bytes -# num_pages = ; # numeric -# min_write_delay = ; # micro-seconds -# max_write_delay = ; # micro-seconds -# readback_p1 = ; # byte value -# readback_p2 = ; # byte value -# pwroff_after_write = ; # yes / no -# read = ; -# write = ; -# read_lo = ; -# read_hi = ; -# write_lo = ; -# write_hi = ; -# loadpage_lo = ; -# loadpage_hi = ; -# writepage = ; -# ; -# ; -# -# If any of the above parameters are not specified, the default value -# of 0 is used for numerics or the empty string ("") for string -# values. If a required parameter is left empty, AVRDUDE will -# complain. -# -# NOTES: -# * 'devicecode' is the device code used by the STK500 (see codes -# listed below) -# * Not all memory types will implement all instructions. -# * AVR Fuse bits and Lock bits are implemented as a type of memory. -# * Example memory types are: -# "flash", "eeprom", "fuse", "lfuse" (low fuse), "hfuse" (high -# fuse), "signature", "calibration", "lock" -# * The memory type specified on the avrdude command line must match -# one of the memory types defined for the specified chip. -# * The pwroff_after_write flag causes avrdude to attempt to -# power the device off and back on after an unsuccessful write to -# the affected memory area if VCC programmer pins are defined. If -# VCC pins are not defined for the programmer, a message -# indicating that the device needs a power-cycle is printed out. -# This flag was added to work around a problem with the -# at90s4433/2333's; see the at90s4433 errata page 2 at: -# -# https://ww1.microchip.com/downloads/en/AppNotes/doc2574.pdf -# -# INSTRUCTION FORMATS -# -# Instruction formats are specified as a comma separated list of -# string values containing information (bit specifiers) about each -# of the 32 bits of the instruction. Bit specifiers may be one of -# the following formats: -# -# '1' = the bit is always set on input as well as output -# -# '0' = the bit is always clear on input as well as output -# -# 'x' = the bit is ignored on input and output -# -# 'a' = the bit is an address bit, the bit-number matches this bit -# specifier's position within the current instruction byte -# -# 'aN' = the bit is the Nth address bit, bit-number = N, i.e., a12 -# is address bit 12 on input, a0 is address bit 0. -# -# 'i' = the bit is an input data bit -# -# 'o' = the bit is an output data bit -# -# Each instruction must be composed of 32 bit specifiers. The -# instruction specification closely follows the instruction data -# provided in Atmel's data sheets for their parts. -# -# See below for some examples. -# -# -# The following are STK500 part device codes to use for the -# "devicecode" field of the part. These came from Atmel's software -# section avr061.zip which accompanies the application note -# AVR061 available from: -# -# https://www.microchip.com/en-us/application-notes/an2525 -# - -#define ATTINY10 0x10 /* the _old_ one that never existed! */ -#define ATTINY11 0x11 -#define ATTINY12 0x12 -#define ATTINY15 0x13 -#define ATTINY13 0x14 - -#define ATTINY22 0x20 -#define ATTINY26 0x21 -#define ATTINY28 0x22 -#define ATTINY2313 0x23 - -#define AT90S1200 0x33 - -#define AT90S2313 0x40 -#define AT90S2323 0x41 -#define AT90S2333 0x42 -#define AT90S2343 0x43 - -#define AT90S4414 0x50 -#define AT90S4433 0x51 -#define AT90S4434 0x52 -#define ATMEGA48 0x59 - -#define AT90S8515 0x60 -#define AT90S8535 0x61 -#define AT90C8534 0x62 -#define ATMEGA8515 0x63 -#define ATMEGA8535 0x64 - -#define ATMEGA8 0x70 -#define ATMEGA88 0x73 -#define ATMEGA168 0x86 - -#define ATMEGA161 0x80 -#define ATMEGA163 0x81 -#define ATMEGA16 0x82 -#define ATMEGA162 0x83 -#define ATMEGA169 0x84 - -#define ATMEGA323 0x90 -#define ATMEGA32 0x91 - -#define ATMEGA64 0xA0 - -#define ATMEGA103 0xB1 -#define ATMEGA128 0xB2 -#define AT90CAN128 0xB3 -#define AT90CAN64 0xB3 -#define AT90CAN32 0xB3 - -#define AT86RF401 0xD0 - -#define AT89START 0xE0 -#define AT89S51 0xE0 -#define AT89S52 0xE1 - -# The following table lists the devices in the original AVR910 -# appnote: -# |Device |Signature | Code | -# +-------+----------+------+ -# |tiny12 | 1E 90 05 | 0x55 | -# |tiny15 | 1E 90 06 | 0x56 | -# | | | | -# | S1200 | 1E 90 01 | 0x13 | -# | | | | -# | S2313 | 1E 91 01 | 0x20 | -# | S2323 | 1E 91 02 | 0x48 | -# | S2333 | 1E 91 05 | 0x34 | -# | S2343 | 1E 91 03 | 0x4C | -# | | | | -# | S4414 | 1E 92 01 | 0x28 | -# | S4433 | 1E 92 03 | 0x30 | -# | S4434 | 1E 92 02 | 0x6C | -# | | | | -# | S8515 | 1E 93 01 | 0x38 | -# | S8535 | 1E 93 03 | 0x68 | -# | | | | -# |mega32 | 1E 95 01 | 0x72 | -# |mega83 | 1E 93 05 | 0x65 | -# |mega103| 1E 97 01 | 0x41 | -# |mega161| 1E 94 01 | 0x60 | -# |mega163| 1E 94 02 | 0x64 | - -# Appnote AVR109 also has a table of AVR910 device codes, which -# lists: -# dev avr910 signature -# ATmega8 0x77 0x1E 0x93 0x07 -# ATmega8515 0x3B 0x1E 0x93 0x06 -# ATmega8535 0x6A 0x1E 0x93 0x08 -# ATmega16 0x75 0x1E 0x94 0x03 -# ATmega162 0x63 0x1E 0x94 0x04 -# ATmega163 0x66 0x1E 0x94 0x02 -# ATmega169 0x79 0x1E 0x94 0x05 -# ATmega32 0x7F 0x1E 0x95 0x02 -# ATmega323 0x73 0x1E 0x95 0x01 -# ATmega64 0x46 0x1E 0x96 0x02 -# ATmega128 0x44 0x1E 0x97 0x02 -# -# These codes refer to "BOOT" device codes which are apparently -# different than standard device codes, for whatever reasons -# (often one above the standard code). - -# There are several extended versions of AVR910 implementations around -# in the Internet. These add the following codes (only devices that -# actually exist are listed): - -# ATmega8515 0x3A -# ATmega128 0x43 -# ATmega64 0x45 -# ATtiny26 0x5E -# ATmega8535 0x69 -# ATmega32 0x72 -# ATmega16 0x74 -# ATmega8 0x76 -# ATmega169 0x78 - -# -# Overall avrdude defaults -# -default_parallel = "lpt1"; -default_serial = "com1"; - - -# -# PROGRAMMER DEFINITIONS -# - -programmer - id = "arduino"; - desc = "Arduino"; - type = arduino; -; - -programmer - id = "avrisp"; - desc = "Atmel AVR ISP"; - type = stk500; -; - -programmer - id = "avrispv2"; - desc = "Atmel AVR ISP V2"; - type = stk500v2; -; - -programmer - id = "avrispmkII"; - desc = "Atmel AVR ISP mkII"; - type = stk500v2; -; - -programmer - id = "avrisp2"; - desc = "Atmel AVR ISP mkII"; - type = stk500v2; -; - -programmer - id = "buspirate"; - desc = "The Bus Pirate"; - type = buspirate; -; - -# This is supposed to be the "default" STK500 entry. -# Attempts to select the correct firmware version -# by probing for it. Better use one of the entries -# below instead. -programmer - id = "stk500"; - desc = "Atmel STK500"; - type = stk500generic; -; - -programmer - id = "stk500v1"; - desc = "Atmel STK500 Version 1.x firmware"; - type = stk500; -; - -programmer - id = "mib510"; - desc = "Crossbow MIB510 programming board"; - type = stk500; -; - -programmer - id = "stk500v2"; - desc = "Atmel STK500 Version 2.x firmware"; - type = stk500v2; -; - -programmer - id = "stk500pp"; - desc = "Atmel STK500 V2 in parallel programming mode"; - type = stk500pp; -; - -programmer - id = "stk500hvsp"; - desc = "Atmel STK500 V2 in high-voltage serial programming mode"; - type = stk500hvsp; -; - -programmer - id = "stk600"; - desc = "Atmel STK600"; - type = stk600; -; - -programmer - id = "stk600pp"; - desc = "Atmel STK600 in parallel programming mode"; - type = stk600pp; -; - -programmer - id = "stk600hvsp"; - desc = "Atmel STK600 in high-voltage serial programming mode"; - type = stk600hvsp; -; - -programmer - id = "avr910"; - desc = "Atmel Low Cost Serial Programmer"; - type = avr910; -; - -programmer - id = "usbasp"; - desc = "USBasp, https://www.fischl.de/usbasp/"; - type = usbasp; -; - -programmer - id = "usbtiny"; - desc = "USBtiny simple USB programmer, https://learn.adafruit.com/usbtinyisp"; - type = usbtiny; -; - -programmer - id = "butterfly"; - desc = "Atmel Butterfly Development Board"; - type = butterfly; -; - -programmer - id = "avr109"; - desc = "Atmel AppNote AVR109 Boot Loader"; - type = butterfly; -; - -programmer - id = "avr911"; - desc = "Atmel AppNote AVR911 AVROSP"; - type = butterfly; -; - -programmer - id = "jtagmkI"; - desc = "Atmel JTAG ICE (mkI)"; - baudrate = 115200; # default is 115200 - type = jtagmki; -; - -# easier to type -programmer - id = "jtag1"; - desc = "Atmel JTAG ICE (mkI)"; - baudrate = 115200; # default is 115200 - type = jtagmki; -; - -# easier to type -programmer - id = "jtag1slow"; - desc = "Atmel JTAG ICE (mkI)"; - baudrate = 19200; - type = jtagmki; -; - -programmer - id = "jtagmkII"; - desc = "Atmel JTAG ICE mkII"; - baudrate = 19200; # default is 19200 - type = jtagmkii; -; - -# easier to type -programmer - id = "jtag2slow"; - desc = "Atmel JTAG ICE mkII"; - baudrate = 19200; # default is 19200 - type = jtagmkii; -; - -# JTAG ICE mkII @ 115200 Bd -programmer - id = "jtag2fast"; - desc = "Atmel JTAG ICE mkII"; - baudrate = 115200; - type = jtagmkii; -; - -# make the fast one the default, people will love that -programmer - id = "jtag2"; - desc = "Atmel JTAG ICE mkII"; - baudrate = 115200; - type = jtagmkii; -; - -# JTAG ICE mkII in ISP mode -programmer - id = "jtag2isp"; - desc = "Atmel JTAG ICE mkII in ISP mode"; - baudrate = 115200; - type = jtagmkii_isp; -; - -# JTAG ICE mkII in debugWire mode -programmer - id = "jtag2dw"; - desc = "Atmel JTAG ICE mkII in debugWire mode"; - baudrate = 115200; - type = jtagmkii_dw; -; - -# JTAG ICE mkII in AVR32 mode -programmer - id = "jtagmkII_avr32"; - desc = "Atmel JTAG ICE mkII im AVR32 mode"; - baudrate = 115200; - type = jtagmkii_avr32; -; - -# JTAG ICE mkII in AVR32 mode -programmer - id = "jtag2avr32"; - desc = "Atmel JTAG ICE mkII im AVR32 mode"; - baudrate = 115200; - type = jtagmkii_avr32; -; - -# JTAG ICE mkII in PDI mode -programmer - id = "jtag2pdi"; - desc = "Atmel JTAG ICE mkII PDI mode"; - baudrate = 115200; - type = jtagmkii_pdi; -; - -# AVR Dragon in JTAG mode -programmer - id = "dragon_jtag"; - desc = "Atmel AVR Dragon in JTAG mode"; - baudrate = 115200; - type = dragon_jtag; -; - -# AVR Dragon in ISP mode -programmer - id = "dragon_isp"; - desc = "Atmel AVR Dragon in ISP mode"; - baudrate = 115200; - type = dragon_isp; -; - -# AVR Dragon in PP mode -programmer - id = "dragon_pp"; - desc = "Atmel AVR Dragon in PP mode"; - baudrate = 115200; - type = dragon_pp; -; - -# AVR Dragon in HVSP mode -programmer - id = "dragon_hvsp"; - desc = "Atmel AVR Dragon in HVSP mode"; - baudrate = 115200; - type = dragon_hvsp; -; - -# AVR Dragon in debugWire mode -programmer - id = "dragon_dw"; - desc = "Atmel AVR Dragon in debugWire mode"; - baudrate = 115200; - type = dragon_dw; -; - -# AVR Dragon in PDI mode -programmer - id = "dragon_pdi"; - desc = "Atmel AVR Dragon in PDI mode"; - baudrate = 115200; - type = dragon_pdi; -; - -programmer - id = "pavr"; - desc = "Jason Kyle's pAVR Serial Programmer"; - type = avr910; -; - -# Parallel port programmers. - -programmer - id = "bsd"; - desc = "Brian Dean's Programmer, https://savannah.nongnu.org/projects/avrdude"; - type = par; - vcc = 2, 3, 4, 5; - reset = 7; - sck = 8; - mosi = 9; - miso = 10; -; - -programmer - id = "stk200"; - desc = "STK200"; - type = par; - buff = 4, 5; - sck = 6; - mosi = 7; - reset = 9; - miso = 10; -; - -# The programming dongle used by the popular Ponyprog -# utility. It is almost similar to the STK200 one, -# except that there is a LED indicating that the -# programming is currently in progress. - -programmer - id = "pony-stk200"; - desc = "Pony Prog STK200"; - type = par; - buff = 4, 5; - sck = 6; - mosi = 7; - reset = 9; - miso = 10; - pgmled = 8; -; - -programmer - id = "dt006"; - desc = "Dontronics DT006"; - type = par; - reset = 4; - sck = 5; - mosi = 2; - miso = 11; -; - -programmer - id = "bascom"; - desc = "Bascom SAMPLE programming cable"; - type = par; - reset = 4; - sck = 5; - mosi = 2; - miso = 11; -; - -programmer - id = "alf"; - desc = "Nightshade ALF-PgmAVR, http://nightshade.homeip.net/"; - type = par; - vcc = 2, 3, 4, 5; - buff = 6; - reset = 7; - sck = 8; - mosi = 9; - miso = 10; - errled = 1; - rdyled = 14; - pgmled = 16; - vfyled = 17; -; - -programmer - id = "sp12"; - desc = "Steve Bolt's Programmer"; - type = par; - vcc = 4,5,6,7,8; - reset = 3; - sck = 2; - mosi = 9; - miso = 11; -; - -programmer - id = "picoweb"; - desc = "Picoweb Programming Cable, http://www.picoweb.net/"; - type = par; - reset = 2; - sck = 3; - mosi = 4; - miso = 13; -; - -programmer - id = "abcmini"; - desc = "ABCmini Board, aka Dick Smith HOTCHIP"; - type = par; - reset = 4; - sck = 3; - mosi = 2; - miso = 10; -; - -programmer - id = "futurlec"; - desc = "Futurlec.com programming cable."; - type = par; - reset = 3; - sck = 2; - mosi = 1; - miso = 10; -; - - -# From the contributor of the "xil" jtag cable: -# The "vcc" definition isn't really vcc (the cable gets its power from -# the programming circuit) but is necessary to switch one of the -# buffer lines (trying to add it to the "buff" lines doesn't work). -# With this, TMS connects to RESET, TDI to MOSI, TDO to MISO and TCK -# to SCK (plus vcc/gnd of course) -programmer - id = "xil"; - desc = "Xilinx JTAG cable"; - type = par; - mosi = 2; - sck = 3; - reset = 4; - buff = 5; - miso = 13; - vcc = 6; -; - - -programmer - id = "dapa"; - desc = "Direct AVR Parallel Access cable"; - type = par; - vcc = 3; - reset = 16; - sck = 1; - mosi = 2; - miso = 11; -; - -programmer - id = "atisp"; - desc = "AT-ISP V1.1 programming cable for AVR-SDK1 from micro-research.co.th"; - type = par; - reset = ~6; - sck = ~8; - mosi = ~7; - miso = ~10; -; - -programmer - id = "ere-isp-avr"; - desc = "ERE ISP-AVR "; - type = par; - reset = ~4; - sck = 3; - mosi = 2; - miso = 10; -; - -programmer - id = "blaster"; - desc = "Altera ByteBlaster"; - type = par; - sck = 2; - miso = 11; - reset = 3; - mosi = 8; - buff = 14; -; - -# It is almost same as pony-stk200, except vcc on pin 5 to auto -# disconnect port download on http://www.electropol.fr -programmer - id = "frank-stk200"; - desc = "Frank STK200"; - type = par; - vcc = 5; - sck = 6; - mosi = 7; - reset = 9; - miso = 10; - pgmled = 8; -; - -# The AT98ISP Cable is a simple parallel dongle for AT89 family. -# https://www.microchip.com/wwwAppNotes/AppNotes.aspx?appnote=en592141 -programmer -id = "89isp"; -desc = "Atmel at89isp cable"; -type = par; -reset = 17; -sck = 1; -mosi = 2; -miso = 10; -; - - -# -# some ultra cheap programmers use bitbanging on the -# serialport. -# -# PC - DB9 - Pins for RS232: -# -# GND 5 -- |O -# | O| <- 9 RI -# DTR 4 <- |O | -# | O| <- 8 CTS -# TXD 3 <- |O | -# | O| -> 7 RTS -# RXD 2 -> |O | -# | O| <- 6 DSR -# DCD 1 -> |O -# -# Using RXD is currently not supported. -# Using RI is not supported under Win32 but is supported under Posix. - -# serial ponyprog design (dasa2 in uisp) -# reset=!txd sck=rts mosi=dtr miso=cts - -programmer - id = "ponyser"; - desc = "design ponyprog serial, reset=!txd sck=rts mosi=dtr miso=cts"; - type = serbb; - reset = ~3; - sck = 7; - mosi = 4; - miso = 8; -; - -# Same as above, different name -# reset=!txd sck=rts mosi=dtr miso=cts - -programmer - id = "siprog"; - desc = "Lancos SI-Prog "; - type = serbb; - reset = ~3; - sck = 7; - mosi = 4; - miso = 8; -; - -# unknown (dasa in uisp) -# reset=rts sck=dtr mosi=txd miso=cts - -programmer - id = "dasa"; - desc = "serial port banging, reset=rts sck=dtr mosi=txd miso=cts"; - type = serbb; - reset = 7; - sck = 4; - mosi = 3; - miso = 8; -; - -# unknown (dasa3 in uisp) -# reset=!dtr sck=rts mosi=txd miso=cts - -programmer - id = "dasa3"; - desc = "serial port banging, reset=!dtr sck=rts mosi=txd miso=cts"; - type = serbb; - reset = ~4; - sck = 7; - mosi = 3; - miso = 8; -; - -# C2N232i (jumper configuration "auto") -# reset=dtr sck=!rts mosi=!txd miso=!cts - -programmer - id = "c2n232i"; - desc = "serial port banging, reset=dtr sck=!rts mosi=!txd miso=!cts"; - type = serbb; - reset = 4; - sck = ~7; - mosi = ~3; - miso = ~8; -; - -# -# PART DEFINITIONS -# - -#------------------------------------------------------------ -# ATtiny11 -#------------------------------------------------------------ - -# This is an HVSP-only device. - -part - id = "t11"; - desc = "ATtiny11"; - stk500_devcode = 0x11; - signature = 0x1e 0x90 0x04; - chip_erase_delay = 20000; - - timeout = 200; - hvsp_controlstack = - 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x00, - 0x68, 0x78, 0x68, 0x68, 0x00, 0x00, 0x68, 0x78, - 0x78, 0x00, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, - 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - hvspcmdexedelay = 0; - synchcycles = 6; - latchcycles = 1; - togglevtg = 1; - poweroffdelay = 25; - resetdelayms = 0; - resetdelayus = 50; - hvleavestabdelay = 100; - resetdelay = 25; - chiperasepolltimeout = 40; - chiperasetime = 0; - programfusepolltimeout = 25; - programlockpolltimeout = 25; - - memory "eeprom" - size = 64; - blocksize = 64; - readsize = 256; - delay = 5; - ; - - memory "flash" - size = 1024; - blocksize = 128; - readsize = 256; - delay = 3; - ; - - memory "signature" - size = 3; - ; - - memory "lock" - size = 1; - ; - - memory "calibration" - size = 1; - ; - - memory "fuse" - size = 1; - ; -; - -#------------------------------------------------------------ -# ATtiny12 -#------------------------------------------------------------ - -part - id = "t12"; - desc = "ATtiny12"; - stk500_devcode = 0x12; - avr910_devcode = 0x55; - signature = 0x1e 0x90 0x05; - chip_erase_delay = 20000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - hvsp_controlstack = - 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x00, - 0x68, 0x78, 0x68, 0x68, 0x00, 0x00, 0x68, 0x78, - 0x78, 0x00, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, - 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00; - hventerstabdelay = 100; - hvspcmdexedelay = 0; - synchcycles = 6; - latchcycles = 1; - togglevtg = 1; - poweroffdelay = 25; - resetdelayms = 0; - resetdelayus = 50; - hvleavestabdelay = 100; - resetdelay = 25; - chiperasepolltimeout = 40; - chiperasetime = 0; - programfusepolltimeout = 25; - programlockpolltimeout = 25; - - memory "eeprom" - size = 64; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 x x x x x x x x", - "x x a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 x x x x x x x x", - "x x a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - mode = 0x04; - delay = 8; - blocksize = 64; - readsize = 256; - ; - - memory "flash" - size = 1024; - min_write_delay = 4500; - max_write_delay = 20000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - write_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 5; - blocksize = 128; - readsize = 256; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x x x x x x o o x"; - - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "fuse" - size = 1; - read = "0 1 0 1 0 0 0 0 x x x x x x x x", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 x x x x x", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; -; - -#------------------------------------------------------------ -# ATtiny13 -#------------------------------------------------------------ - -part - id = "t13"; - desc = "ATtiny13"; - has_debugwire = yes; - flash_instr = 0xB4, 0x0E, 0x1E; - eeprom_instr = 0xBB, 0xFE, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, - 0xBC, 0x0E, 0xB4, 0x0E, 0xBA, 0x0D, 0xBB, 0xBC, - 0x99, 0xE1, 0xBB, 0xAC; - stk500_devcode = 0x14; - signature = 0x1e 0x90 0x07; - chip_erase_delay = 4000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - hvsp_controlstack = - 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x66, - 0x68, 0x78, 0x68, 0x68, 0x7A, 0x6A, 0x68, 0x78, - 0x78, 0x7D, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, - 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - hvspcmdexedelay = 0; - synchcycles = 6; - latchcycles = 1; - togglevtg = 1; - poweroffdelay = 25; - resetdelayms = 0; - resetdelayus = 90; - hvleavestabdelay = 100; - resetdelay = 25; - chiperasepolltimeout = 40; - chiperasetime = 0; - programfusepolltimeout = 25; - programlockpolltimeout = 25; - - memory "eeprom" - size = 64; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x x", - "x x a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x x", - "x x a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " x x a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 5; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 1024; - page_size = 32; - num_pages = 32; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 0 0 0 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 0 0 0 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 0 0 0 a8", - " a7 a6 a5 a4 x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 32; - readsize = 256; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "calibration" - size = 2; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 a0 o o o o o o o o"; - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - ; - -; - - -#------------------------------------------------------------ -# ATtiny15 -#------------------------------------------------------------ - -part - id = "t15"; - desc = "ATtiny15"; - stk500_devcode = 0x13; - avr910_devcode = 0x56; - signature = 0x1e 0x90 0x06; - chip_erase_delay = 8200; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - hvsp_controlstack = - 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x00, - 0x68, 0x78, 0x68, 0x68, 0x00, 0x00, 0x68, 0x78, - 0x78, 0x00, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, - 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00; - hventerstabdelay = 100; - hvspcmdexedelay = 5; - synchcycles = 6; - latchcycles = 16; - togglevtg = 1; - poweroffdelay = 25; - resetdelayms = 0; - resetdelayus = 50; - hvleavestabdelay = 100; - resetdelay = 25; - chiperasepolltimeout = 40; - chiperasetime = 0; - programfusepolltimeout = 25; - programlockpolltimeout = 25; - - memory "eeprom" - size = 64; - min_write_delay = 8200; - max_write_delay = 8200; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 x x x x x x x x", - "x x a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 x x x x x x x x", - "x x a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - mode = 0x04; - delay = 10; - blocksize = 64; - readsize = 256; - ; - - memory "flash" - size = 1024; - min_write_delay = 4100; - max_write_delay = 4100; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - write_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 5; - blocksize = 128; - readsize = 256; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x x x x x x o o x"; - - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "fuse" - size = 1; - read = "0 1 0 1 0 0 0 0 x x x x x x x x", - "x x x x x x x x o o o o x x o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 x x x x x", - "x x x x x x x x i i i i 1 1 i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; -; - -#------------------------------------------------------------ -# AT90s1200 -#------------------------------------------------------------ - -part - id = "1200"; - desc = "AT90S1200"; - stk500_devcode = 0x33; - avr910_devcode = 0x13; - signature = 0x1e 0x90 0x01; - pagel = 0xd7; - bs2 = 0xa0; - chip_erase_delay = 20000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 1; - bytedelay = 0; - pollindex = 0; - pollvalue = 0xFF; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 0; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 15; - chiperasepolltimeout = 0; - programfusepulsewidth = 2; - programfusepolltimeout = 0; - programlockpulsewidth = 0; - programlockpolltimeout = 1; - - memory "eeprom" - size = 64; - min_write_delay = 4000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 x x x x x x x x", - "x x a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 x x x x x x x x", - "x x a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - mode = 0x04; - delay = 20; - blocksize = 32; - readsize = 256; - ; - memory "flash" - size = 1024; - min_write_delay = 4000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - write_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x02; - delay = 15; - blocksize = 128; - readsize = 256; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "fuse" - size = 1; - ; - memory "lock" - size = 1; - min_write_delay = 9000; - max_write_delay = 20000; - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", - "x x x x x x x x x x x x x x x x"; - ; - ; - -#------------------------------------------------------------ -# AT90s4414 -#------------------------------------------------------------ - -part - id = "4414"; - desc = "AT90S4414"; - stk500_devcode = 0x50; - avr910_devcode = 0x28; - signature = 0x1e 0x92 0x01; - chip_erase_delay = 20000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 0; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 15; - chiperasepolltimeout = 0; - programfusepulsewidth = 2; - programfusepolltimeout = 0; - programlockpulsewidth = 0; - programlockpolltimeout = 1; - - memory "eeprom" - size = 256; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0x80; - readback_p2 = 0x7f; - read = " 1 0 1 0 0 0 0 0 x x x x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0 x x x x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 64; - readsize = 256; - ; - memory "flash" - size = 4096; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0x7f; - readback_p2 = 0x7f; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write_lo = " 0 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - write_hi = " 0 1 0 0 1 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 64; - readsize = 256; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "fuse" - size = 1; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - ; - -#------------------------------------------------------------ -# AT90s2313 -#------------------------------------------------------------ - -part - id = "2313"; - desc = "AT90S2313"; - stk500_devcode = 0x40; - avr910_devcode = 0x20; - signature = 0x1e 0x91 0x01; - chip_erase_delay = 20000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 0; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 15; - chiperasepolltimeout = 0; - programfusepulsewidth = 2; - programfusepolltimeout = 0; - programlockpulsewidth = 0; - programlockpolltimeout = 1; - - memory "eeprom" - size = 128; - min_write_delay = 4000; - max_write_delay = 9000; - readback_p1 = 0x80; - readback_p2 = 0x7f; - read = "1 0 1 0 0 0 0 0 x x x x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 x x x x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 64; - readsize = 256; - ; - memory "flash" - size = 2048; - min_write_delay = 4000; - max_write_delay = 9000; - readback_p1 = 0x7f; - readback_p2 = 0x7f; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - write_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 128; - readsize = 256; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "fuse" - size = 1; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x i i x", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - ; - -#------------------------------------------------------------ -# AT90s2333 -#------------------------------------------------------------ - -part - id = "2333"; -##### WARNING: No XML file for device 'AT90S2333'! ##### - desc = "AT90S2333"; - stk500_devcode = 0x42; - avr910_devcode = 0x34; - signature = 0x1e 0x91 0x05; - chip_erase_delay = 20000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 0; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 15; - chiperasepolltimeout = 0; - programfusepulsewidth = 2; - programfusepolltimeout = 0; - programlockpulsewidth = 0; - programlockpolltimeout = 1; - - memory "eeprom" - size = 128; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0x00; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 x x x x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 x x x x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 128; - readsize = 256; - ; - - memory "flash" - size = 2048; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - write_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 128; - readsize = 256; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "fuse" - size = 1; - min_write_delay = 9000; - max_write_delay = 20000; - pwroff_after_write = yes; - read = "0 1 0 1 0 0 0 0 x x x x x x x x", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 i i i i i", - "x x x x x x x x x x x x x x x x"; - ; - memory "lock" - size = 1; - min_write_delay = 9000; - max_write_delay = 20000; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x x x x x x o o x"; - - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", - "x x x x x x x x x x x x x x x x"; - ; - ; - - -#------------------------------------------------------------ -# AT90s2343 (also AT90s2323 and ATtiny22) -#------------------------------------------------------------ - -part - id = "2343"; - desc = "AT90S2343"; - stk500_devcode = 0x43; - avr910_devcode = 0x4c; - signature = 0x1e 0x91 0x03; - chip_erase_delay = 18000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - hvsp_controlstack = - 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x00, - 0x68, 0x78, 0x68, 0x68, 0x00, 0x00, 0x68, 0x78, - 0x78, 0x00, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, - 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00; - hventerstabdelay = 100; - hvspcmdexedelay = 0; - synchcycles = 6; - latchcycles = 1; - togglevtg = 0; - poweroffdelay = 25; - resetdelayms = 0; - resetdelayus = 50; - hvleavestabdelay = 100; - resetdelay = 25; - chiperasepolltimeout = 40; - chiperasetime = 0; - programfusepolltimeout = 25; - programlockpolltimeout = 25; - - memory "eeprom" - size = 128; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0x00; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0", - "x a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0", - "x a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 64; - readsize = 256; - ; - memory "flash" - size = 2048; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - write_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 128; - readsize = 128; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "fuse" - size = 1; - min_write_delay = 9000; - max_write_delay = 20000; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x o o o x x x x o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 1 1 1 1 i", - "x x x x x x x x x x x x x x x x"; - ; - memory "lock" - size = 1; - min_write_delay = 9000; - max_write_delay = 20000; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x o o o x x x x o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", - "x x x x x x x x x x x x x x x x"; - ; - ; - - -#------------------------------------------------------------ -# AT90s4433 -#------------------------------------------------------------ - -part - id = "4433"; - desc = "AT90S4433"; - stk500_devcode = 0x51; - avr910_devcode = 0x30; - signature = 0x1e 0x92 0x03; - chip_erase_delay = 20000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 0; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 15; - chiperasepolltimeout = 0; - programfusepulsewidth = 2; - programfusepolltimeout = 0; - programlockpulsewidth = 0; - programlockpolltimeout = 1; - - memory "eeprom" - size = 256; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0x00; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0 x x x x x x x x", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0 x x x x x x x x", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 128; - readsize = 256; - ; - memory "flash" - size = 4096; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write_lo = " 0 1 0 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - write_hi = " 0 1 0 0 1 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 128; - readsize = 256; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "fuse" - size = 1; - min_write_delay = 9000; - max_write_delay = 20000; - pwroff_after_write = yes; - read = "0 1 0 1 0 0 0 0 x x x x x x x x", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 i i i i i", - "x x x x x x x x x x x x x x x x"; - ; - memory "lock" - size = 1; - min_write_delay = 9000; - max_write_delay = 20000; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x x x x x x o o x"; - - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", - "x x x x x x x x x x x x x x x x"; - ; - ; - -#------------------------------------------------------------ -# AT90s4434 -#------------------------------------------------------------ - -part - id = "4434"; -##### WARNING: No XML file for device 'AT90S4434'! ##### - desc = "AT90S4434"; - stk500_devcode = 0x52; - avr910_devcode = 0x6c; - signature = 0x1e 0x92 0x02; - chip_erase_delay = 20000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - memory "eeprom" - size = 256; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0x00; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0 x x x x x x x x", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0 x x x x x x x x", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - ; - memory "flash" - size = 4096; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write_lo = " 0 1 0 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - write_hi = " 0 1 0 0 1 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "fuse" - size = 1; - min_write_delay = 9000; - max_write_delay = 20000; - read = "0 1 0 1 0 0 0 0 x x x x x x x x", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 i i i i i", - "x x x x x x x x x x x x x x x x"; - ; - memory "lock" - size = 1; - min_write_delay = 9000; - max_write_delay = 20000; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x x x x x x o o x"; - - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", - "x x x x x x x x x x x x x x x x"; - ; - ; - -#------------------------------------------------------------ -# AT90s8515 -#------------------------------------------------------------ - -part - id = "8515"; - desc = "AT90S8515"; - stk500_devcode = 0x60; - avr910_devcode = 0x38; - signature = 0x1e 0x93 0x01; - chip_erase_delay = 20000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 0; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - resetdelay = 15; - chiperasepulsewidth = 15; - chiperasepolltimeout = 0; - programfusepulsewidth = 2; - programfusepolltimeout = 0; - programlockpulsewidth = 0; - programlockpolltimeout = 1; - - memory "eeprom" - size = 512; - min_write_delay = 4000; - max_write_delay = 9000; - readback_p1 = 0x80; - readback_p2 = 0x7f; - read = " 1 0 1 0 0 0 0 0 x x x x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0 x x x x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 128; - readsize = 256; - ; - memory "flash" - size = 8192; - min_write_delay = 4000; - max_write_delay = 9000; - readback_p1 = 0x7f; - readback_p2 = 0x7f; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write_lo = " 0 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - write_hi = " 0 1 0 0 1 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 128; - readsize = 256; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "fuse" - size = 1; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - ; - -#------------------------------------------------------------ -# AT90s8535 -#------------------------------------------------------------ - -part - id = "8535"; - desc = "AT90S8535"; - stk500_devcode = 0x61; - avr910_devcode = 0x68; - signature = 0x1e 0x93 0x03; - chip_erase_delay = 20000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 0; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 15; - chiperasepolltimeout = 0; - programfusepulsewidth = 2; - programfusepolltimeout = 0; - programlockpulsewidth = 0; - programlockpolltimeout = 1; - - memory "eeprom" - size = 512; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0x00; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0 x x x x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0 x x x x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 128; - readsize = 256; - ; - memory "flash" - size = 8192; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write_lo = " 0 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - write_hi = " 0 1 0 0 1 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 128; - readsize = 256; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "fuse" - size = 1; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x x x x x x x x o"; - write = "1 0 1 0 1 1 0 0 1 0 1 1 1 1 1 i", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x o o x x x x x x"; - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - ; - -#------------------------------------------------------------ -# ATmega103 -#------------------------------------------------------------ - -part - id = "m103"; - desc = "ATMEGA103"; - stk500_devcode = 0xB1; - avr910_devcode = 0x41; - signature = 0x1e 0x97 0x01; - chip_erase_delay = 112000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x8E, 0x9E, 0x2E, 0x3E, 0xAE, 0xBE, - 0x4E, 0x5E, 0xCE, 0xDE, 0x6E, 0x7E, 0xEE, 0xDE, - 0x66, 0x76, 0xE6, 0xF6, 0x6A, 0x7A, 0xEA, 0x7A, - 0x7F, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 0; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 15; - chiperasepolltimeout = 0; - programfusepulsewidth = 2; - programfusepolltimeout = 0; - programlockpulsewidth = 0; - programlockpolltimeout = 10; - - memory "eeprom" - size = 4096; - min_write_delay = 4000; - max_write_delay = 9000; - readback_p1 = 0x80; - readback_p2 = 0x7f; - read = " 1 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 64; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 131072; - page_size = 256; - num_pages = 512; - min_write_delay = 22000; - max_write_delay = 56000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x11; - delay = 70; - blocksize = 256; - readsize = 256; - ; - - memory "fuse" - size = 1; - read = "0 1 0 1 0 0 0 0 x x x x x x x x", - "x x x x x x x x x x o x o 1 o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 1 i 1 i i", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x x x x x x o o x"; - - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - - -#------------------------------------------------------------ -# ATmega64 -#------------------------------------------------------------ - -part - id = "m64"; - desc = "ATMEGA64"; - has_jtag = yes; - stk500_devcode = 0xA0; - avr910_devcode = 0x45; - signature = 0x1e 0x96 0x02; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x22; - spmcr = 0x68; - allowfullpagebitstream = yes; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 2048; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 20; - blocksize = 64; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 65536; - page_size = 256; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 6; - blocksize = 128; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 4; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - - - - -#------------------------------------------------------------ -# ATmega128 -#------------------------------------------------------------ - -part - id = "m128"; - desc = "ATMEGA128"; - has_jtag = yes; - stk500_devcode = 0xB2; - avr910_devcode = 0x43; - signature = 0x1e 0x97 0x02; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x22; - spmcr = 0x68; - rampz = 0x3b; - allowfullpagebitstream = yes; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 4096; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 64; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 131072; - page_size = 256; - num_pages = 512; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 6; - blocksize = 128; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 4; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# AT90CAN128 -#------------------------------------------------------------ - -part - id = "c128"; - desc = "AT90CAN128"; - has_jtag = yes; - stk500_devcode = 0xB3; -# avr910_devcode = 0x43; - signature = 0x1e 0x97 0x81; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - eecr = 0x3f; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 4096; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - - mode = 0x41; - delay = 20; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 131072; - page_size = 256; - num_pages = 512; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# AT90CAN64 -#------------------------------------------------------------ - -part - id = "c64"; - desc = "AT90CAN64"; - has_jtag = yes; - stk500_devcode = 0xB3; -# avr910_devcode = 0x43; - signature = 0x1e 0x96 0x81; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - eecr = 0x3f; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 2048; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - - mode = 0x41; - delay = 20; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 65536; - page_size = 256; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# AT90CAN32 -#------------------------------------------------------------ - -part - id = "c32"; - desc = "AT90CAN32"; - has_jtag = yes; - stk500_devcode = 0xB3; -# avr910_devcode = 0x43; - signature = 0x1e 0x95 0x81; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - eecr = 0x3f; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 1024; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - - mode = 0x41; - delay = 20; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 32768; - page_size = 256; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - - -#------------------------------------------------------------ -# ATmega16 -#------------------------------------------------------------ - -part - id = "m16"; - desc = "ATMEGA16"; - has_jtag = yes; - stk500_devcode = 0x82; - avr910_devcode = 0x74; - signature = 0x1e 0x94 0x03; - pagel = 0xd7; - bs2 = 0xa0; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 100; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - resetdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - allowfullpagebitstream = yes; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 512; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x04; - delay = 10; - blocksize = 128; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 16384; - page_size = 128; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 6; - blocksize = 128; - readsize = 256; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "calibration" - size = 4; - - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - ; - - -#------------------------------------------------------------ -# ATmega164P -#------------------------------------------------------------ - -# close to ATmega16 - -part - id = "m164p"; - desc = "ATMEGA164P"; - has_jtag = yes; - stk500_devcode = 0x82; # no STK500v1 support, use the ATmega16 one - avr910_devcode = 0x74; - signature = 0x1e 0x94 0x0a; - pagel = 0xd7; - bs2 = 0xa0; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 512; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 128; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 16384; - page_size = 128; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 6; - blocksize = 128; - readsize = 256; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x 1 1 1 1 1 i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - - -#------------------------------------------------------------ -# ATmega324P -#------------------------------------------------------------ - -# similar to ATmega164P - -part - id = "m324p"; - desc = "ATMEGA324P"; - has_jtag = yes; - stk500_devcode = 0x82; # no STK500v1 support, use the ATmega16 one - avr910_devcode = 0x74; - signature = 0x1e 0x95 0x08; - pagel = 0xd7; - bs2 = 0xa0; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 1024; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 128; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 32768; - page_size = 128; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x 1 1 1 1 1 i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - - -#------------------------------------------------------------ -# ATmega644 -#------------------------------------------------------------ - -# similar to ATmega164 - -part - id = "m644"; - desc = "ATMEGA644"; - has_jtag = yes; - stk500_devcode = 0x82; # no STK500v1 support, use the ATmega16 one - avr910_devcode = 0x74; - signature = 0x1e 0x96 0x09; - pagel = 0xd7; - bs2 = 0xa0; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 2048; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 128; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 65536; - page_size = 256; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x 1 1 1 1 1 i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega644P -#------------------------------------------------------------ - -# similar to ATmega164p - -part - id = "m644p"; - desc = "ATMEGA644P"; - has_jtag = yes; - stk500_devcode = 0x82; # no STK500v1 support, use the ATmega16 one - avr910_devcode = 0x74; - signature = 0x1e 0x96 0x0a; - pagel = 0xd7; - bs2 = 0xa0; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 2048; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 128; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 65536; - page_size = 256; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x 1 1 1 1 1 i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - - - -#------------------------------------------------------------ -# ATmega1284P -#------------------------------------------------------------ - -# similar to ATmega164p - -part - id = "m1284p"; - desc = "ATMEGA1284P"; - has_jtag = yes; - stk500_devcode = 0x82; # no STK500v1 support, use the ATmega16 one - avr910_devcode = 0x74; - signature = 0x1e 0x97 0x05; - pagel = 0xd7; - bs2 = 0xa0; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 4096; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 128; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 131072; - page_size = 256; - num_pages = 512; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 256; - readsize = 256; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x 1 1 1 1 1 i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - - - -#------------------------------------------------------------ -# ATmega162 -#------------------------------------------------------------ - -part - id = "m162"; - desc = "ATMEGA162"; - has_jtag = yes; - stk500_devcode = 0x83; - avr910_devcode = 0x63; - signature = 0x1e 0x94 0x04; - chip_erase_delay = 9000; - pagel = 0xd7; - bs2 = 0xa0; - - idr = 0x04; - spmcr = 0x57; - allowfullpagebitstream = yes; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - memory "flash" - paged = yes; - size = 16384; - page_size = 128; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - mode = 0x41; - delay = 10; - blocksize = 128; - readsize = 256; - - ; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 512; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - - read = " 1 0 1 0 0 0 0 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 4; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 16000; - max_write_delay = 16000; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 16000; - max_write_delay = 16000; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - min_write_delay = 16000; - max_write_delay = 16000; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x 1 1 1 1 1 i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 16000; - max_write_delay = 16000; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "signature" - size = 3; - - read = "0 0 1 1 0 0 0 0 0 0 x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - - read = "0 0 1 1 1 0 0 0 0 0 x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; -; - - - -#------------------------------------------------------------ -# ATmega163 -#------------------------------------------------------------ - -part - id = "m163"; - desc = "ATMEGA163"; - stk500_devcode = 0x81; - avr910_devcode = 0x64; - signature = 0x1e 0x94 0x02; - chip_erase_delay = 32000; - pagel = 0xd7; - bs2 = 0xa0; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 0; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 30; - programfusepulsewidth = 0; - programfusepolltimeout = 2; - programlockpulsewidth = 0; - programlockpolltimeout = 2; - - - memory "eeprom" - size = 512; - min_write_delay = 4000; - max_write_delay = 4000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - mode = 0x41; - delay = 20; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 16384; - page_size = 128; - num_pages = 128; - min_write_delay = 16000; - max_write_delay = 16000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x11; - delay = 20; - blocksize = 128; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o x x o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i 1 1 i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x x x x x 1 o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x 1 1 1 1 1 i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x 0 x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega169 -#------------------------------------------------------------ - -part - id = "m169"; - desc = "ATMEGA169"; - has_jtag = yes; - stk500_devcode = 0x85; - avr910_devcode = 0x78; - signature = 0x1e 0x94 0x05; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 512; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 16384; - page_size = 128; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 128; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - ; - - memory "lock" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega329 -#------------------------------------------------------------ - -part - id = "m329"; - desc = "ATMEGA329"; - has_jtag = yes; -# stk500_devcode = 0x85; # no STK500 support, only STK500v2 -# avr910_devcode = 0x?; # try the ATmega169 one: - avr910_devcode = 0x75; - signature = 0x1e 0x95 0x03; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 1024; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 32768; - page_size = 128; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega329P -#------------------------------------------------------------ -# Identical to ATmega329 except of the signature - -part - id = "m329p"; - desc = "ATMEGA329P"; - has_jtag = yes; -# stk500_devcode = 0x85; # no STK500 support, only STK500v2 -# avr910_devcode = 0x?; # try the ATmega169 one: - avr910_devcode = 0x75; - signature = 0x1e 0x95 0x0b; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 1024; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 32768; - page_size = 128; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega3290 -#------------------------------------------------------------ - -# identical to ATmega329 - -part - id = "m3290"; - desc = "ATMEGA3290"; - has_jtag = yes; -# stk500_devcode = 0x85; # no STK500 support, only STK500v2 -# avr910_devcode = 0x?; # try the ATmega169 one: - avr910_devcode = 0x75; - signature = 0x1e 0x95 0x04; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 1024; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a3 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 32768; - page_size = 128; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega3290P -#------------------------------------------------------------ - -# identical to ATmega3290 except of the signature - -part - id = "m3290p"; - desc = "ATMEGA3290P"; - has_jtag = yes; -# stk500_devcode = 0x85; # no STK500 support, only STK500v2 -# avr910_devcode = 0x?; # try the ATmega169 one: - avr910_devcode = 0x75; - signature = 0x1e 0x95 0x0c; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 1024; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a3 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 32768; - page_size = 128; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega649 -#------------------------------------------------------------ - -part - id = "m649"; - desc = "ATMEGA649"; - has_jtag = yes; -# stk500_devcode = 0x85; # no STK500 support, only STK500v2 -# avr910_devcode = 0x?; # try the ATmega169 one: - avr910_devcode = 0x75; - signature = 0x1e 0x96 0x03; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 2048; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 65536; - page_size = 256; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega6490 -#------------------------------------------------------------ - -# identical to ATmega649 - -part - id = "m6490"; - desc = "ATMEGA6490"; - has_jtag = yes; -# stk500_devcode = 0x85; # no STK500 support, only STK500v2 -# avr910_devcode = 0x?; # try the ATmega169 one: - avr910_devcode = 0x75; - signature = 0x1e 0x96 0x04; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 2048; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 65536; - page_size = 256; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega32 -#------------------------------------------------------------ - -part - id = "m32"; - desc = "ATMEGA32"; - has_jtag = yes; - stk500_devcode = 0x91; - avr910_devcode = 0x72; - signature = 0x1e 0x95 0x02; - chip_erase_delay = 9000; - pagel = 0xd7; - bs2 = 0xa0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - allowfullpagebitstream = yes; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 1024; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x04; - delay = 10; - blocksize = 64; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 32768; - page_size = 128; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 6; - blocksize = 64; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 4; - read = "0 0 1 1 1 0 0 0 0 0 x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega161 -#------------------------------------------------------------ - -part - id = "m161"; - desc = "ATMEGA161"; - stk500_devcode = 0x80; - avr910_devcode = 0x60; - signature = 0x1e 0x94 0x01; - chip_erase_delay = 28000; - pagel = 0xd7; - bs2 = 0xa0; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 0; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 30; - programfusepulsewidth = 0; - programfusepolltimeout = 2; - programlockpulsewidth = 0; - programlockpolltimeout = 2; - - memory "eeprom" - size = 512; - min_write_delay = 3400; - max_write_delay = 3400; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 5; - blocksize = 128; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 16384; - page_size = 128; - num_pages = 128; - min_write_delay = 14000; - max_write_delay = 14000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 16; - blocksize = 128; - readsize = 256; - ; - - memory "fuse" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 0 0 0 0 x x x x x x x x", - "x x x x x x x x x o x o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 x x x x x", - "x x x x x x x x 1 i 1 i i i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - - -#------------------------------------------------------------ -# ATmega8 -#------------------------------------------------------------ - -part - id = "m8"; - desc = "ATMEGA8"; - stk500_devcode = 0x70; - avr910_devcode = 0x76; - signature = 0x1e 0x93 0x07; - pagel = 0xd7; - bs2 = 0xc2; - chip_erase_delay = 10000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 2; - resetdelayus = 0; - hvleavestabdelay = 15; - resetdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - size = 512; - page_size = 4; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 20; - blocksize = 128; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 8192; - page_size = 64; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 0 x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 0 x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 10; - blocksize = 64; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "calibration" - size = 4; - read = "0 0 1 1 1 0 0 0 0 0 x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - - - -#------------------------------------------------------------ -# ATmega8515 -#------------------------------------------------------------ - -part - id = "m8515"; - desc = "ATMEGA8515"; - stk500_devcode = 0x63; - avr910_devcode = 0x3A; - signature = 0x1e 0x93 0x06; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - size = 512; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 10; - blocksize = 128; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 8192; - page_size = 64; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 0 x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 0 x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 6; - blocksize = 64; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "calibration" - size = 4; - read = "0 0 1 1 1 0 0 0 0 0 x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - - - - -#------------------------------------------------------------ -# ATmega8535 -#------------------------------------------------------------ - -part - id = "m8535"; - desc = "ATMEGA8535"; - stk500_devcode = 0x64; - avr910_devcode = 0x69; - signature = 0x1e 0x93 0x08; - pagel = 0xd7; - bs2 = 0xa0; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - size = 512; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 10; - blocksize = 128; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 8192; - page_size = 64; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 0 x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 0 x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 6; - blocksize = 64; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "calibration" - size = 4; - read = "0 0 1 1 1 0 0 0 0 0 x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - - -#------------------------------------------------------------ -# ATtiny26 -#------------------------------------------------------------ - -part - id = "t26"; - desc = "ATTINY26"; - stk500_devcode = 0x21; - avr910_devcode = 0x5e; - signature = 0x1e 0x91 0x09; - pagel = 0xb3; - bs2 = 0xb2; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0xC4, 0xE4, 0xC4, 0xE4, 0xCC, 0xEC, 0xCC, 0xEC, - 0xD4, 0xF4, 0xD4, 0xF4, 0xDC, 0xFC, 0xDC, 0xFC, - 0xC8, 0xE8, 0xD8, 0xF8, 0x4C, 0x6C, 0x5C, 0x7C, - 0xEC, 0xBC, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 2; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - size = 128; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 x x x x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 x x x x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - mode = 0x04; - delay = 10; - blocksize = 64; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 2048; - page_size = 32; - num_pages = 64; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 6; - blocksize = 16; - readsize = 256; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x x x x x x x o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 1 i i", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x x x x i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x x x x o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 4; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - -; - - -#------------------------------------------------------------ -# ATtiny261 -#------------------------------------------------------------ -# Close to ATtiny26 - -part - id = "t261"; - desc = "ATTINY261"; - has_debugwire = yes; - flash_instr = 0xB4, 0x00, 0x10; - eeprom_instr = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, - 0xBC, 0x00, 0xB4, 0x00, 0xBA, 0x0D, 0xBB, 0xBC, - 0x99, 0xE1, 0xBB, 0xAC; -# stk500_devcode = 0x21; -# avr910_devcode = 0x5e; - signature = 0x1e 0x91 0x0c; - pagel = 0xb3; - bs2 = 0xb2; - chip_erase_delay = 4000; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0xC4, 0xE4, 0xC4, 0xE4, 0xCC, 0xEC, 0xCC, 0xEC, - 0xD4, 0xF4, 0xD4, 0xF4, 0xDC, 0xFC, 0xDC, 0xFC, - 0xC8, 0xE8, 0xD8, 0xF8, 0x4C, 0x6C, 0x5C, 0x7C, - 0xEC, 0xBC, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 2; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - paged = no; - size = 128; - page_size = 4; - num_pages = 32; - min_write_delay = 4000; - max_write_delay = 4000; - readback_p1 = 0xff; - readback_p2 = 0xff; - - read = "1 0 1 0 0 0 0 0 x x x x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 x x x x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 2048; - page_size = 32; - num_pages = 64; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 32; - readsize = 256; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x x x x x x x o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 1 i i", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x x x x x x x x o"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - -; - - -#------------------------------------------------------------ -# ATtiny461 -#------------------------------------------------------------ -# Close to ATtiny261 - -part - id = "t461"; - desc = "ATTINY461"; - has_debugwire = yes; - flash_instr = 0xB4, 0x00, 0x10; - eeprom_instr = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, - 0xBC, 0x00, 0xB4, 0x00, 0xBA, 0x0D, 0xBB, 0xBC, - 0x99, 0xE1, 0xBB, 0xAC; -# stk500_devcode = 0x21; -# avr910_devcode = 0x5e; - signature = 0x1e 0x92 0x08; - pagel = 0xb3; - bs2 = 0xb2; - chip_erase_delay = 4000; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0xC4, 0xE4, 0xC4, 0xE4, 0xCC, 0xEC, 0xCC, 0xEC, - 0xD4, 0xF4, 0xD4, 0xF4, 0xDC, 0xFC, 0xDC, 0xFC, - 0xC8, 0xE8, 0xD8, 0xF8, 0x4C, 0x6C, 0x5C, 0x7C, - 0xEC, 0xBC, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 2; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - paged = no; - size = 256; - page_size = 4; - num_pages = 64; - min_write_delay = 4000; - max_write_delay = 4000; - readback_p1 = 0xff; - readback_p2 = 0xff; - - read = " 1 0 1 0 0 0 0 0 x x x x x x x x", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0 x x x x x x x x", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 4096; - page_size = 64; - num_pages = 64; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 64; - readsize = 256; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x x x x x x x o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 1 i i", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x x x x x x x x o"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - -; - - -#------------------------------------------------------------ -# ATtiny861 -#------------------------------------------------------------ -# Close to ATtiny461 - -part - id = "t861"; - desc = "ATTINY861"; - has_debugwire = yes; - flash_instr = 0xB4, 0x00, 0x10; - eeprom_instr = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, - 0xBC, 0x00, 0xB4, 0x00, 0xBA, 0x0D, 0xBB, 0xBC, - 0x99, 0xE1, 0xBB, 0xAC; -# stk500_devcode = 0x21; -# avr910_devcode = 0x5e; - signature = 0x1e 0x93 0x0d; - pagel = 0xb3; - bs2 = 0xb2; - chip_erase_delay = 4000; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0xC4, 0xE4, 0xC4, 0xE4, 0xCC, 0xEC, 0xCC, 0xEC, - 0xD4, 0xF4, 0xD4, 0xF4, 0xDC, 0xFC, 0xDC, 0xFC, - 0xC8, 0xE8, 0xD8, 0xF8, 0x4C, 0x6C, 0x5C, 0x7C, - 0xEC, 0xBC, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 2; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - paged = no; - size = 512; - num_pages = 128; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4000; - readback_p1 = 0xff; - readback_p2 = 0xff; - - read = " 1 0 1 0 0 0 0 0 x x x x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0 x x x x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 8192; - page_size = 64; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 64; - readsize = 256; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x x x x x x x o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 1 i i", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x x x x x x x x o"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - -; - - -#------------------------------------------------------------ -# ATmega48 -#------------------------------------------------------------ - -part - id = "m48"; - desc = "ATMEGA48"; - has_debugwire = yes; - flash_instr = 0xB6, 0x01, 0x11; - eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00, - 0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF, - 0x99, 0xF9, 0xBB, 0xAF; - stk500_devcode = 0x59; -# avr910_devcode = 0x; - signature = 0x1e 0x92 0x05; - pagel = 0xd7; - bs2 = 0xc2; - chip_erase_delay = 45000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - resetdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - paged = no; - page_size = 4; - size = 256; - min_write_delay = 3600; - max_write_delay = 3600; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 x x x x x", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 5; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 4096; - page_size = 64; - num_pages = 64; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 64; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x x x x x x x x o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - - -#------------------------------------------------------------ -# ATmega88 -#------------------------------------------------------------ - -part - id = "m88"; - desc = "ATMEGA88"; - has_debugwire = yes; - flash_instr = 0xB6, 0x01, 0x11; - eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00, - 0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF, - 0x99, 0xF9, 0xBB, 0xAF; - stk500_devcode = 0x73; -# avr910_devcode = 0x; - signature = 0x1e 0x93 0x0a; - pagel = 0xd7; - bs2 = 0xc2; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - resetdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - paged = no; - page_size = 4; - size = 512; - min_write_delay = 3600; - max_write_delay = 3600; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 5; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 8192; - page_size = 64; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 64; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x x x x x x o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega168 -#------------------------------------------------------------ - -part - id = "m168"; - desc = "ATMEGA168"; - has_debugwire = yes; - flash_instr = 0xB6, 0x01, 0x11; - eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00, - 0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF, - 0x99, 0xF9, 0xBB, 0xAF; - stk500_devcode = 0x86; - # avr910_devcode = 0x; - signature = 0x1e 0x94 0x06; - pagel = 0xd7; - bs2 = 0xc2; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - resetdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - paged = no; - page_size = 4; - size = 512; - min_write_delay = 3600; - max_write_delay = 3600; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 5; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 16384; - page_size = 128; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 128; - readsize = 256; - - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x x x x x x o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; -; - -#------------------------------------------------------------ -# ATtiny88 -#------------------------------------------------------------ - -part - id = "t88"; - desc = "attiny88"; - has_debugwire = yes; - flash_instr = 0xB6, 0x01, 0x11; - eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00, - 0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF, - 0x99, 0xF9, 0xBB, 0xAF; - stk500_devcode = 0x73; -# avr910_devcode = 0x; - signature = 0x1e 0x93 0x11; - pagel = 0xd7; - bs2 = 0xc2; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - resetdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - paged = no; - page_size = 4; - size = 64; - min_write_delay = 3600; - max_write_delay = 3600; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 5; - blocksize = 4; - readsize = 64; - ; - memory "flash" - paged = yes; - size = 8192; - page_size = 64; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 64; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x x x x x x o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega328P -#------------------------------------------------------------ - -part - id = "m328p"; - desc = "ATMEGA328P"; - has_debugwire = yes; - flash_instr = 0xB6, 0x01, 0x11; - eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00, - 0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF, - 0x99, 0xF9, 0xBB, 0xAF; - stk500_devcode = 0x86; - # avr910_devcode = 0x; - signature = 0x1e 0x95 0x0F; - pagel = 0xd7; - bs2 = 0xc2; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - resetdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - paged = no; - page_size = 4; - size = 1024; - min_write_delay = 3600; - max_write_delay = 3600; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 5; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 32768; - page_size = 128; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 128; - readsize = 256; - - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x x x x x x o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; -; - -#------------------------------------------------------------ -# ATtiny2313 -#------------------------------------------------------------ - -part - id = "t2313"; - desc = "ATtiny2313"; - has_debugwire = yes; - flash_instr = 0xB2, 0x0F, 0x1F; - eeprom_instr = 0xBB, 0xFE, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, - 0xBA, 0x0F, 0xB2, 0x0F, 0xBA, 0x0D, 0xBB, 0xBC, - 0x99, 0xE1, 0xBB, 0xAC; - stk500_devcode = 0x23; -## Use the ATtiny26 devcode: - avr910_devcode = 0x5e; - signature = 0x1e 0x91 0x0a; - pagel = 0xD4; - bs2 = 0xD6; - reset = io; - chip_erase_delay = 9000; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0E, 0x1E, 0x2E, 0x3E, 0x2E, 0x3E, - 0x4E, 0x5E, 0x4E, 0x5E, 0x6E, 0x7E, 0x6E, 0x7E, - 0x26, 0x36, 0x66, 0x76, 0x2A, 0x3A, 0x6A, 0x7A, - 0x2E, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - size = 128; - paged = no; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 2048; - page_size = 32; - num_pages = 64; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - -# The information in the data sheet of April/2004 is wrong, this works: - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - -# The information in the data sheet of April/2004 is wrong, this works: - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - -# The information in the data sheet of April/2004 is wrong, this works: - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 32; - readsize = 256; - ; -# ATtiny2313 has Signature Bytes: 0x1E 0x91 0x0A. - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; -# The Tiny2313 has calibration data for both 4 MHz and 8 MHz. -# The information in the data sheet of April/2004 is wrong, this works: - - memory "calibration" - size = 2; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# AT90PWM2 -#------------------------------------------------------------ - -part - id = "pwm2"; - desc = "AT90PWM2"; - has_debugwire = yes; - flash_instr = 0xB6, 0x01, 0x11; - eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00, - 0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF, - 0x99, 0xF9, 0xBB, 0xAF; - stk500_devcode = 0x65; -## avr910_devcode = ?; - signature = 0x1e 0x93 0x81; - pagel = 0xD8; - bs2 = 0xE2; - reset = io; - chip_erase_delay = 9000; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - size = 512; - paged = no; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 8192; - page_size = 64; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 64; - readsize = 256; - ; -# AT90PWM2 has Signature Bytes: 0x1E 0x93 0x81. - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# AT90PWM3 -#------------------------------------------------------------ - -# Completely identical to AT90PWM2 (including the signature!) - -part - id = "pwm3"; - desc = "AT90PWM3"; - has_debugwire = yes; - flash_instr = 0xB6, 0x01, 0x11; - eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00, - 0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF, - 0x99, 0xF9, 0xBB, 0xAF; - stk500_devcode = 0x65; -## avr910_devcode = ?; - signature = 0x1e 0x93 0x81; - pagel = 0xD8; - bs2 = 0xE2; - reset = io; - chip_erase_delay = 9000; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - size = 512; - paged = no; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 8192; - page_size = 64; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 64; - readsize = 256; - ; -# AT90PWM2 has Signature Bytes: 0x1E 0x93 0x81. - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# AT90PWM2B -#------------------------------------------------------------ -# Same as AT90PWM2 but different signature. - -part - id = "pwm2b"; - desc = "AT90PWM2B"; - has_debugwire = yes; - flash_instr = 0xB6, 0x01, 0x11; - eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00, - 0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF, - 0x99, 0xF9, 0xBB, 0xAF; - stk500_devcode = 0x65; -## avr910_devcode = ?; - signature = 0x1e 0x93 0x83; - pagel = 0xD8; - bs2 = 0xE2; - reset = io; - chip_erase_delay = 9000; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - size = 512; - paged = no; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 8192; - page_size = 64; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 64; - readsize = 256; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# AT90PWM3B -#------------------------------------------------------------ - -# Completely identical to AT90PWM2B (including the signature!) - -part - id = "pwm3b"; - desc = "AT90PWM3B"; - has_debugwire = yes; - flash_instr = 0xB6, 0x01, 0x11; - eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00, - 0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF, - 0x99, 0xF9, 0xBB, 0xAF; - stk500_devcode = 0x65; -## avr910_devcode = ?; - signature = 0x1e 0x93 0x83; - pagel = 0xD8; - bs2 = 0xE2; - reset = io; - chip_erase_delay = 9000; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - size = 512; - paged = no; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 8192; - page_size = 64; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 64; - readsize = 256; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATtiny25 -#------------------------------------------------------------ - -part - id = "t25"; - desc = "ATtiny25"; - has_debugwire = yes; - flash_instr = 0xB4, 0x02, 0x12; - eeprom_instr = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, - 0xBC, 0x02, 0xB4, 0x02, 0xBA, 0x0D, 0xBB, 0xBC, - 0x99, 0xE1, 0xBB, 0xAC; -## no STK500 devcode in XML file, use the ATtiny45 one - stk500_devcode = 0x14; -## avr910_devcode = ?; -## Try the AT90S2313 devcode: - avr910_devcode = 0x20; - signature = 0x1e 0x91 0x08; - reset = io; - chip_erase_delay = 4500; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - hvsp_controlstack = - 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x66, - 0x68, 0x78, 0x68, 0x68, 0x7A, 0x6A, 0x68, 0x78, - 0x78, 0x7D, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, - 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00; - hventerstabdelay = 100; - hvspcmdexedelay = 0; - synchcycles = 6; - latchcycles = 1; - togglevtg = 1; - poweroffdelay = 25; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 100; - resetdelay = 25; - chiperasepolltimeout = 40; - chiperasetime = 0; - programfusepolltimeout = 25; - programlockpolltimeout = 25; - - memory "eeprom" - size = 128; - paged = no; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 2048; - page_size = 32; - num_pages = 64; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 32; - readsize = 256; - ; -# ATtiny25 has Signature Bytes: 0x1E 0x91 0x08. - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 2; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATtiny45 -#------------------------------------------------------------ - -part - id = "t45"; - desc = "ATtiny45"; - has_debugwire = yes; - flash_instr = 0xB4, 0x02, 0x12; - eeprom_instr = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, - 0xBC, 0x02, 0xB4, 0x02, 0xBA, 0x0D, 0xBB, 0xBC, - 0x99, 0xE1, 0xBB, 0xAC; - stk500_devcode = 0x14; -## avr910_devcode = ?; -## Try the AT90S2313 devcode: - avr910_devcode = 0x20; - signature = 0x1e 0x92 0x06; - reset = io; - chip_erase_delay = 4500; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - hvsp_controlstack = - 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x66, - 0x68, 0x78, 0x68, 0x68, 0x7A, 0x6A, 0x68, 0x78, - 0x78, 0x7D, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, - 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - hvspcmdexedelay = 0; - synchcycles = 6; - latchcycles = 1; - togglevtg = 1; - poweroffdelay = 25; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 100; - resetdelay = 25; - chiperasepolltimeout = 40; - chiperasetime = 0; - programfusepolltimeout = 25; - programlockpolltimeout = 25; - - memory "eeprom" - size = 256; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x x", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x x", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 4096; - page_size = 64; - num_pages = 64; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 32; - readsize = 256; - ; -# ATtiny45 has Signature Bytes: 0x1E 0x92 0x08. (Data sheet 2586C-AVR-06/05 (doc2586.pdf) indicates otherwise!) - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 2; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATtiny85 -#------------------------------------------------------------ - -part - id = "t85"; - desc = "ATtiny85"; - has_debugwire = yes; - flash_instr = 0xB4, 0x02, 0x12; - eeprom_instr = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, - 0xBC, 0x02, 0xB4, 0x02, 0xBA, 0x0D, 0xBB, 0xBC, - 0x99, 0xE1, 0xBB, 0xAC; -## no STK500 devcode in XML file, use the ATtiny45 one - stk500_devcode = 0x14; -## avr910_devcode = ?; -## Try the AT90S2313 devcode: - avr910_devcode = 0x20; - signature = 0x1e 0x93 0x0b; - reset = io; - chip_erase_delay = 4500; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - hvsp_controlstack = - 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x66, - 0x68, 0x78, 0x68, 0x68, 0x7A, 0x6A, 0x68, 0x78, - 0x78, 0x7D, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, - 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00; - hventerstabdelay = 100; - hvspcmdexedelay = 0; - synchcycles = 6; - latchcycles = 1; - togglevtg = 1; - poweroffdelay = 25; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 100; - resetdelay = 25; - chiperasepolltimeout = 40; - chiperasetime = 0; - programfusepolltimeout = 25; - programlockpolltimeout = 25; - - memory "eeprom" - size = 512; - paged = no; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x a8", - "a8 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 8192; - page_size = 64; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 32; - readsize = 256; - ; -# ATtiny85 has Signature Bytes: 0x1E 0x93 0x08. - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 2; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega640 -#------------------------------------------------------------ -# Almost same as ATmega1280, except for different memory sizes - -part - id = "m640"; - desc = "ATMEGA640"; - signature = 0x1e 0x96 0x08; - has_jtag = yes; -# stk500_devcode = 0xB2; -# avr910_devcode = 0x43; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 4096; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 65536; - page_size = 256; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega1280 -#------------------------------------------------------------ - -part - id = "m1280"; - desc = "ATMEGA1280"; - signature = 0x1e 0x97 0x03; - has_jtag = yes; -# stk500_devcode = 0xB2; -# avr910_devcode = 0x43; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 4096; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 131072; - page_size = 256; - num_pages = 512; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega1281 -#------------------------------------------------------------ -# Identical to ATmega1280 - -part - id = "m1281"; - desc = "ATMEGA1281"; - signature = 0x1e 0x97 0x04; - has_jtag = yes; -# stk500_devcode = 0xB2; -# avr910_devcode = 0x43; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 4096; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 131072; - page_size = 256; - num_pages = 512; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega2560 -#------------------------------------------------------------ - -part - id = "m2560"; - desc = "ATMEGA2560"; - signature = 0x1e 0x98 0x01; - has_jtag = yes; -# stk500_devcode = 0xB2; -# avr910_devcode = 0x43; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 4096; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 262144; - page_size = 256; - num_pages = 1024; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - load_ext_addr = " 0 1 0 0 1 1 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 0 a16", - " 0 0 0 0 0 0 0 0"; - - mode = 0x41; - delay = 10; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega2561 -#------------------------------------------------------------ - -part - id = "m2561"; - desc = "ATMEGA2561"; - signature = 0x1e 0x98 0x02; - has_jtag = yes; -# stk500_devcode = 0xB2; -# avr910_devcode = 0x43; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 4096; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 262144; - page_size = 256; - num_pages = 1024; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - load_ext_addr = " 0 1 0 0 1 1 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 0 a16", - " 0 0 0 0 0 0 0 0"; - - mode = 0x41; - delay = 10; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega128RFA1 -#------------------------------------------------------------ -# Identical to ATmega2561 but half the ROM - -part - id = "m128rfa1"; - desc = "ATMEGA128RFA1"; - signature = 0x1e 0xa7 0x01; - has_jtag = yes; -# stk500_devcode = 0xB2; -# avr910_devcode = 0x43; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xE2; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 4096; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 131072; - page_size = 256; - num_pages = 512; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATtiny24 -#------------------------------------------------------------ - -part - id = "t24"; - desc = "ATtiny24"; - has_debugwire = yes; - flash_instr = 0xB4, 0x07, 0x17; - eeprom_instr = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, - 0xBC, 0x07, 0xB4, 0x07, 0xBA, 0x0D, 0xBB, 0xBC, - 0x99, 0xE1, 0xBB, 0xAC; -## no STK500 devcode in XML file, use the ATtiny45 one - stk500_devcode = 0x14; -## avr910_devcode = ?; -## Try the AT90S2313 devcode: - avr910_devcode = 0x20; - signature = 0x1e 0x91 0x0b; - reset = io; - chip_erase_delay = 4500; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - hvsp_controlstack = - 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x66, - 0x68, 0x78, 0x68, 0x68, 0x7A, 0x6A, 0x68, 0x78, - 0x78, 0x7D, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, - 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x0F; - hventerstabdelay = 100; - hvspcmdexedelay = 0; - synchcycles = 6; - latchcycles = 1; - togglevtg = 1; - poweroffdelay = 25; - resetdelayms = 0; - resetdelayus = 70; - hvleavestabdelay = 100; - resetdelay = 25; - chiperasepolltimeout = 40; - chiperasetime = 0; - programfusepolltimeout = 25; - programlockpolltimeout = 25; - - memory "eeprom" - size = 128; - paged = no; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 2048; - page_size = 32; - num_pages = 64; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 32; - readsize = 256; - ; -# ATtiny24 has Signature Bytes: 0x1E 0x91 0x0B. - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x x x x x x x i i"; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATtiny44 -#------------------------------------------------------------ - -part - id = "t44"; - desc = "ATtiny44"; - has_debugwire = yes; - flash_instr = 0xB4, 0x07, 0x17; - eeprom_instr = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, - 0xBC, 0x07, 0xB4, 0x07, 0xBA, 0x0D, 0xBB, 0xBC, - 0x99, 0xE1, 0xBB, 0xAC; -## no STK500 devcode in XML file, use the ATtiny45 one - stk500_devcode = 0x14; -## avr910_devcode = ?; -## Try the AT90S2313 devcode: - avr910_devcode = 0x20; - signature = 0x1e 0x92 0x07; - reset = io; - chip_erase_delay = 4500; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - hvsp_controlstack = - 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x66, - 0x68, 0x78, 0x68, 0x68, 0x7A, 0x6A, 0x68, 0x78, - 0x78, 0x7D, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, - 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x0F; - hventerstabdelay = 100; - hvspcmdexedelay = 0; - synchcycles = 6; - latchcycles = 1; - togglevtg = 1; - poweroffdelay = 25; - resetdelayms = 0; - resetdelayus = 70; - hvleavestabdelay = 100; - resetdelay = 25; - chiperasepolltimeout = 40; - chiperasetime = 0; - programfusepolltimeout = 25; - programlockpolltimeout = 25; - - memory "eeprom" - size = 256; - paged = no; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x x", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x x", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 4096; - page_size = 64; - num_pages = 64; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 32; - readsize = 256; - ; -# ATtiny44 has Signature Bytes: 0x1E 0x92 0x07. - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x x x x x x x i i"; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATtiny84 -#------------------------------------------------------------ - -part - id = "t84"; - desc = "ATtiny84"; - has_debugwire = yes; - flash_instr = 0xB4, 0x07, 0x17; - eeprom_instr = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, - 0xBC, 0x07, 0xB4, 0x07, 0xBA, 0x0D, 0xBB, 0xBC, - 0x99, 0xE1, 0xBB, 0xAC; -## no STK500 devcode in XML file, use the ATtiny45 one - stk500_devcode = 0x14; -## avr910_devcode = ?; -## Try the AT90S2313 devcode: - avr910_devcode = 0x20; - signature = 0x1e 0x93 0x0c; - reset = io; - chip_erase_delay = 4500; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - hvsp_controlstack = - 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x66, - 0x68, 0x78, 0x68, 0x68, 0x7A, 0x6A, 0x68, 0x78, - 0x78, 0x7D, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, - 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x0F; - hventerstabdelay = 100; - hvspcmdexedelay = 0; - synchcycles = 6; - latchcycles = 1; - togglevtg = 1; - poweroffdelay = 25; - resetdelayms = 0; - resetdelayus = 70; - hvleavestabdelay = 100; - resetdelay = 25; - chiperasepolltimeout = 40; - chiperasetime = 0; - programfusepolltimeout = 25; - programlockpolltimeout = 25; - - memory "eeprom" - size = 512; - paged = no; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x a8", - "a8 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 8192; - page_size = 64; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 32; - readsize = 256; - ; -# ATtiny84 has Signature Bytes: 0x1E 0x93 0x0C. - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x x x x x x x i i"; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega32u4 -#------------------------------------------------------------ - -part - id = "m32u4"; - desc = "ATmega32U4"; - signature = 0x1e 0x95 0x87; - has_jtag = yes; -# stk500_devcode = 0xB2; -# avr910_devcode = 0x43; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 1024; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 32768; - page_size = 128; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 128; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# AT90USB646 -#------------------------------------------------------------ - -part - id = "usb646"; - desc = "AT90USB646"; - signature = 0x1e 0x96 0x82; - has_jtag = yes; -# stk500_devcode = 0xB2; -# avr910_devcode = 0x43; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 2048; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 65536; - page_size = 256; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# AT90USB647 -#------------------------------------------------------------ -# identical to AT90USB646 - -part - id = "usb647"; - desc = "AT90USB647"; - signature = 0x1e 0x96 0x82; - has_jtag = yes; -# stk500_devcode = 0xB2; -# avr910_devcode = 0x43; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 2048; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 65536; - page_size = 256; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# AT90USB1286 -#------------------------------------------------------------ - -part - id = "usb1286"; - desc = "AT90USB1286"; - signature = 0x1e 0x97 0x82; - has_jtag = yes; -# stk500_devcode = 0xB2; -# avr910_devcode = 0x43; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 4096; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 131072; - page_size = 256; - num_pages = 512; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# AT90USB1287 -#------------------------------------------------------------ -# identical to AT90USB1286 - -part - id = "usb1287"; - desc = "AT90USB1287"; - signature = 0x1e 0x97 0x82; - has_jtag = yes; -# stk500_devcode = 0xB2; -# avr910_devcode = 0x43; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 4096; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 131072; - page_size = 256; - num_pages = 512; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - - -#------------------------------------------------------------ -# AT90USB162 -#------------------------------------------------------------ - -part - id = "usb162"; - desc = "AT90USB162"; - has_jtag = no; - has_debugwire = yes; - signature = 0x1e 0x94 0x82; - chip_erase_delay = 9000; - reset = io; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - pagel = 0xD7; - bs2 = 0xC6; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 512; - num_pages = 128; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 16384; - page_size = 128; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 128; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# AT90USB82 -#------------------------------------------------------------ -# Changes against AT90USB162 (beside IDs) -# memory "flash" -# size = 8192; -# num_pages = 64; - -part - id = "usb82"; - desc = "AT90USB82"; - has_jtag = no; - has_debugwire = yes; - signature = 0x1e 0x93 0x82; - chip_erase_delay = 9000; - reset = io; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - pagel = 0xD7; - bs2 = 0xC6; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 512; - num_pages = 128; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 8192; - page_size = 128; - num_pages = 64; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 128; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega325 -#------------------------------------------------------------ - -part - id = "m325"; - desc = "ATMEGA325"; - signature = 0x1e 0x95 0x05; - has_jtag = yes; -# stk500_devcode = 0x??; # No STK500v1 support? -# avr910_devcode = 0x??; # Try the ATmega16 one - avr910_devcode = 0x74; - pagel = 0xd7; - bs2 = 0xa0; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 1024; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 32768; - page_size = 128; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 0 0 0 0 0", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 0 0 0 0 0", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 128; - readsize = 256; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 0 0 0 0 0", - "0 0 0 0 0 0 0 0 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "0 0 0 0 0 0 0 0 i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "0 0 0 0 0 0 0 0 i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "0 0 0 0 0 0 0 0 1 1 1 1 1 i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - - read = "0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega645 -#------------------------------------------------------------ - -part - id = "m645"; - desc = "ATMEGA645"; - signature = 0x1E 0x96 0x05; - has_jtag = yes; -# stk500_devcode = 0x??; # No STK500v1 support? -# avr910_devcode = 0x??; # Try the ATmega16 one - avr910_devcode = 0x74; - pagel = 0xd7; - bs2 = 0xa0; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 2048; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 65536; - page_size = 256; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 0 0 0 0 0", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 0 0 0 0 0", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " 0 0 0 0 0 0 0 0"; - - mode = 0x41; - delay = 10; - blocksize = 128; - readsize = 256; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 0 0 0 0 0", - "0 0 0 0 0 0 0 0 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "0 0 0 0 0 0 0 0 i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "0 0 0 0 0 0 0 0 i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "0 0 0 0 0 0 0 0 1 1 1 1 1 i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - - read = "0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega3250 -#------------------------------------------------------------ - -part - id = "m3250"; - desc = "ATMEGA3250"; - signature = 0x1E 0x95 0x06; - has_jtag = yes; -# stk500_devcode = 0x??; # No STK500v1 support? -# avr910_devcode = 0x??; # Try the ATmega16 one - avr910_devcode = 0x74; - pagel = 0xd7; - bs2 = 0xa0; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 1024; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 32768; - page_size = 128; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 0 0 0 0 0", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 0 0 0 0 0", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 128; - readsize = 256; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 0 0 0 0 0", - "0 0 0 0 0 0 0 0 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "0 0 0 0 0 0 0 0 i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "0 0 0 0 0 0 0 0 i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "0 0 0 0 0 0 0 0 1 1 1 1 1 i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - - read = "0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega6450 -#------------------------------------------------------------ - -part - id = "m6450"; - desc = "ATMEGA6450"; - signature = 0x1E 0x96 0x06; - has_jtag = yes; -# stk500_devcode = 0x??; # No STK500v1 support? -# avr910_devcode = 0x??; # Try the ATmega16 one - avr910_devcode = 0x74; - pagel = 0xd7; - bs2 = 0xa0; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 2048; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 65536; - page_size = 256; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 0 0 0 0 0", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 0 0 0 0 0", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " 0 0 0 0 0 0 0 0"; - - mode = 0x41; - delay = 10; - blocksize = 128; - readsize = 256; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 0 0 0 0 0", - "0 0 0 0 0 0 0 0 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "0 0 0 0 0 0 0 0 i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "0 0 0 0 0 0 0 0 i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "0 0 0 0 0 0 0 0 1 1 1 1 1 i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - - read = "0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATXMEGA64A1 -#------------------------------------------------------------ - -part - id = "x64a1"; - desc = "ATXMEGA64A1"; - signature = 0x1e 0x96 0x4e; - has_jtag = yes; - has_pdi = yes; - nvm_base = 0x01c0; - - memory "eeprom" - size = 0x0800; - offset = 0x08c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x00010000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x00001000; - offset = 0x0080f000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x00001000; - offset = 0x00810000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x00011000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "prodsig" - size = 0x200; - offset = 0x8e0200; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; - - memory "signature" - size = 3; - offset = 0x1000090; - ; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; - - memory "fuse1" - size = 1; - offset = 0x8f0021; - ; - - memory "fuse2" - size = 1; - offset = 0x8f0022; - ; - - memory "fuse4" - size = 1; - offset = 0x8f0024; - ; - - memory "fuse5" - size = 1; - offset = 0x8f0025; - ; - - memory "lock" - size = 1; - offset = 0x8f0027; - ; -; - -#------------------------------------------------------------ -# ATXMEGA128A1 -#------------------------------------------------------------ - -part - id = "x128a1"; - desc = "ATXMEGA128A1"; - signature = 0x1e 0x97 0x4c; - has_jtag = yes; - has_pdi = yes; - nvm_base = 0x01c0; - - memory "eeprom" - size = 0x0800; - offset = 0x08c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x00020000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x00002000; - offset = 0x0081e000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x00002000; - offset = 0x00820000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x00022000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "prodsig" - size = 0x200; - offset = 0x8e0200; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; - - memory "signature" - size = 3; - offset = 0x1000090; - ; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; - - memory "fuse1" - size = 1; - offset = 0x8f0021; - ; - - memory "fuse2" - size = 1; - offset = 0x8f0022; - ; - - memory "fuse4" - size = 1; - offset = 0x8f0024; - ; - - memory "fuse5" - size = 1; - offset = 0x8f0025; - ; - - memory "lock" - size = 1; - offset = 0x8f0027; - ; -; - -#------------------------------------------------------------ -# ATXMEGA128A1REVD -#------------------------------------------------------------ - -part - id = "x128a1d"; - desc = "ATXMEGA128A1REVD"; - signature = 0x1e 0x97 0x41; - has_jtag = yes; - has_pdi = yes; - nvm_base = 0x01c0; - - memory "eeprom" - size = 0x0800; - offset = 0x08c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x00020000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x00002000; - offset = 0x0081e000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x00002000; - offset = 0x00820000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x00022000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "prodsig" - size = 0x200; - offset = 0x8e0200; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; - - memory "signature" - size = 3; - offset = 0x1000090; - ; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; - - memory "fuse1" - size = 1; - offset = 0x8f0021; - ; - - memory "fuse2" - size = 1; - offset = 0x8f0022; - ; - - memory "fuse4" - size = 1; - offset = 0x8f0024; - ; - - memory "fuse5" - size = 1; - offset = 0x8f0025; - ; - - memory "lock" - size = 1; - offset = 0x8f0027; - ; -; - -#------------------------------------------------------------ -# ATXMEGA192A1 -#------------------------------------------------------------ - -part - id = "x192a1"; - desc = "ATXMEGA192A1"; - signature = 0x1e 0x97 0x4e; - has_jtag = yes; - has_pdi = yes; - nvm_base = 0x01c0; - - memory "eeprom" - size = 0x0800; - offset = 0x08c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x00030000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x00002000; - offset = 0x0082e000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x00002000; - offset = 0x00830000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x00032000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "prodsig" - size = 0x200; - offset = 0x8e0200; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; - - memory "signature" - size = 3; - offset = 0x1000090; - ; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; - - memory "fuse1" - size = 1; - offset = 0x8f0021; - ; - - memory "fuse2" - size = 1; - offset = 0x8f0022; - ; - - memory "fuse4" - size = 1; - offset = 0x8f0024; - ; - - memory "fuse5" - size = 1; - offset = 0x8f0025; - ; - - memory "lock" - size = 1; - offset = 0x8f0027; - ; -; - -#------------------------------------------------------------ -# ATXMEGA256A1 -#------------------------------------------------------------ - -part - id = "x256a1"; - desc = "ATXMEGA256A1"; - signature = 0x1e 0x98 0x46; - has_jtag = yes; - has_pdi = yes; - nvm_base = 0x01c0; - - memory "eeprom" - size = 0x1000; - offset = 0x08c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x00040000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x00002000; - offset = 0x0083e000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x00002000; - offset = 0x00840000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x00042000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "prodsig" - size = 0x200; - offset = 0x8e0200; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; - - memory "signature" - size = 3; - offset = 0x1000090; - ; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; - - memory "fuse1" - size = 1; - offset = 0x8f0021; - ; - - memory "fuse2" - size = 1; - offset = 0x8f0022; - ; - - memory "fuse4" - size = 1; - offset = 0x8f0024; - ; - - memory "fuse5" - size = 1; - offset = 0x8f0025; - ; - - memory "lock" - size = 1; - offset = 0x8f0027; - ; -; - -#------------------------------------------------------------ -# ATXMEGA64A3 -#------------------------------------------------------------ - -part - id = "x64a3"; - desc = "ATXMEGA64A3"; - signature = 0x1e 0x96 0x42; - has_jtag = yes; - has_pdi = yes; - nvm_base = 0x01c0; - - memory "eeprom" - size = 0x0800; - offset = 0x08c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x00010000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x00001000; - offset = 0x0080f000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x00001000; - offset = 0x00810000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x00011000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "prodsig" - size = 0x200; - offset = 0x8e0200; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; - - memory "signature" - size = 3; - offset = 0x1000090; - ; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; - - memory "fuse1" - size = 1; - offset = 0x8f0021; - ; - - memory "fuse2" - size = 1; - offset = 0x8f0022; - ; - - memory "fuse4" - size = 1; - offset = 0x8f0024; - ; - - memory "fuse5" - size = 1; - offset = 0x8f0025; - ; - - memory "lock" - size = 1; - offset = 0x8f0027; - ; -; - -#------------------------------------------------------------ -# ATXMEGA128A3 -#------------------------------------------------------------ - -part - id = "x128a3"; - desc = "ATXMEGA128A3"; - signature = 0x1e 0x97 0x42; - has_jtag = yes; - has_pdi = yes; - nvm_base = 0x01c0; - - memory "eeprom" - size = 0x0800; - offset = 0x08c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x00020000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x00002000; - offset = 0x0081e000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x00002000; - offset = 0x00820000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x00022000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "prodsig" - size = 0x200; - offset = 0x8e0200; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; - - memory "signature" - size = 3; - offset = 0x1000090; - ; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; - - memory "fuse1" - size = 1; - offset = 0x8f0021; - ; - - memory "fuse2" - size = 1; - offset = 0x8f0022; - ; - - memory "fuse4" - size = 1; - offset = 0x8f0024; - ; - - memory "fuse5" - size = 1; - offset = 0x8f0025; - ; - - memory "lock" - size = 1; - offset = 0x8f0027; - ; -; - -#------------------------------------------------------------ -# ATXMEGA192A3 -#------------------------------------------------------------ - -part - id = "x192a3"; - desc = "ATXMEGA192A3"; - signature = 0x1e 0x97 0x44; - has_jtag = yes; - has_pdi = yes; - nvm_base = 0x01c0; - - memory "eeprom" - size = 0x0800; - offset = 0x08c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x00030000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x00002000; - offset = 0x0082e000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x00002000; - offset = 0x00830000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x00032000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "prodsig" - size = 0x200; - offset = 0x8e0200; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; - - memory "signature" - size = 3; - offset = 0x1000090; - ; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; - - memory "fuse1" - size = 1; - offset = 0x8f0021; - ; - - memory "fuse2" - size = 1; - offset = 0x8f0022; - ; - - memory "fuse4" - size = 1; - offset = 0x8f0024; - ; - - memory "fuse5" - size = 1; - offset = 0x8f0025; - ; - - memory "lock" - size = 1; - offset = 0x8f0027; - ; -; - -#------------------------------------------------------------ -# ATXMEGA256A3 -#------------------------------------------------------------ - -part - id = "x256a3"; - desc = "ATXMEGA256A3"; - signature = 0x1e 0x98 0x42; - has_jtag = yes; - has_pdi = yes; - nvm_base = 0x01c0; - - memory "eeprom" - size = 0x1000; - offset = 0x08c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x00040000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x00002000; - offset = 0x0083e000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x00002000; - offset = 0x00840000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x00042000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "prodsig" - size = 0x200; - offset = 0x8e0200; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; - - memory "signature" - size = 3; - offset = 0x1000090; - ; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; - - memory "fuse1" - size = 1; - offset = 0x8f0021; - ; - - memory "fuse2" - size = 1; - offset = 0x8f0022; - ; - - memory "fuse4" - size = 1; - offset = 0x8f0024; - ; - - memory "fuse5" - size = 1; - offset = 0x8f0025; - ; - - memory "lock" - size = 1; - offset = 0x8f0027; - ; -; - -#------------------------------------------------------------ -# ATXMEGA256A3B -#------------------------------------------------------------ - -part - id = "x256a3b"; - desc = "ATXMEGA256A3B"; - signature = 0x1e 0x98 0x43; - has_jtag = yes; - has_pdi = yes; - nvm_base = 0x01c0; - - memory "eeprom" - size = 0x1000; - offset = 0x08c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x00040000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x00002000; - offset = 0x0083e000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x00002000; - offset = 0x00840000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x00042000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "prodsig" - size = 0x200; - offset = 0x8e0200; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; - - memory "signature" - size = 3; - offset = 0x1000090; - ; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; - - memory "fuse1" - size = 1; - offset = 0x8f0021; - ; - - memory "fuse2" - size = 1; - offset = 0x8f0022; - ; - - memory "fuse4" - size = 1; - offset = 0x8f0024; - ; - - memory "fuse5" - size = 1; - offset = 0x8f0025; - ; - - memory "lock" - size = 1; - offset = 0x8f0027; - ; -; - -#------------------------------------------------------------ -# ATXMEGA16A4 -#------------------------------------------------------------ - -part - id = "x16a4"; - desc = "ATXMEGA16A4"; - signature = 0x1e 0x94 0x41; - has_jtag = yes; - has_pdi = yes; - nvm_base = 0x01c0; - - memory "eeprom" - size = 0x0400; - offset = 0x08c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x00004000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x00001000; - offset = 0x00803000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x00001000; - offset = 0x00804000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x00005000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "prodsig" - size = 0x200; - offset = 0x8e0200; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; - - memory "signature" - size = 3; - offset = 0x1000090; - ; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; - - memory "fuse1" - size = 1; - offset = 0x8f0021; - ; - - memory "fuse2" - size = 1; - offset = 0x8f0022; - ; - - memory "fuse4" - size = 1; - offset = 0x8f0024; - ; - - memory "fuse5" - size = 1; - offset = 0x8f0025; - ; - - memory "lock" - size = 1; - offset = 0x8f0027; - ; -; - -#------------------------------------------------------------ -# ATXMEGA32A4 -#------------------------------------------------------------ - -part - id = "x32a4"; - desc = "ATXMEGA32A4"; - signature = 0x1e 0x95 0x41; - has_jtag = yes; - has_pdi = yes; - nvm_base = 0x01c0; - - memory "eeprom" - size = 0x0400; - offset = 0x08c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x00008000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x00001000; - offset = 0x00807000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x00001000; - offset = 0x00808000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x00009000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "prodsig" - size = 0x200; - offset = 0x8e0200; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; - - memory "signature" - size = 3; - offset = 0x1000090; - ; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; - - memory "fuse1" - size = 1; - offset = 0x8f0021; - ; - - memory "fuse2" - size = 1; - offset = 0x8f0022; - ; - - memory "fuse4" - size = 1; - offset = 0x8f0024; - ; - - memory "fuse5" - size = 1; - offset = 0x8f0025; - ; - - memory "lock" - size = 1; - offset = 0x8f0027; - ; -; - -#------------------------------------------------------------ -# ATXMEGA64A4 -#------------------------------------------------------------ - -part - id = "x64a4"; - desc = "ATXMEGA64A4"; - signature = 0x1e 0x96 0x46; - has_jtag = yes; - has_pdi = yes; - nvm_base = 0x01c0; - - memory "eeprom" - size = 0x0800; - offset = 0x08c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x00010000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x00001000; - offset = 0x0080f000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x00001000; - offset = 0x00810000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x00011000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "prodsig" - size = 0x200; - offset = 0x8e0200; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; - - memory "signature" - size = 3; - offset = 0x1000090; - ; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; - - memory "fuse1" - size = 1; - offset = 0x8f0021; - ; - - memory "fuse2" - size = 1; - offset = 0x8f0022; - ; - - memory "fuse4" - size = 1; - offset = 0x8f0024; - ; - - memory "fuse5" - size = 1; - offset = 0x8f0025; - ; - - memory "lock" - size = 1; - offset = 0x8f0027; - ; -; - -#------------------------------------------------------------ -# ATXMEGA128A4 -#------------------------------------------------------------ - -part - id = "x128a4"; - desc = "ATXMEGA128A4"; - signature = 0x1e 0x97 0x46; - has_jtag = yes; - has_pdi = yes; - nvm_base = 0x01c0; - - memory "eeprom" - size = 0x0800; - offset = 0x08c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x00020000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x00002000; - offset = 0x0081e000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x00002000; - offset = 0x00820000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x00022000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "prodsig" - size = 0x200; - offset = 0x8e0200; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; - - memory "signature" - size = 3; - offset = 0x1000090; - ; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; - - memory "fuse1" - size = 1; - offset = 0x8f0021; - ; - - memory "fuse2" - size = 1; - offset = 0x8f0022; - ; - - memory "fuse4" - size = 1; - offset = 0x8f0024; - ; - - memory "fuse5" - size = 1; - offset = 0x8f0025; - ; - - memory "lock" - size = 1; - offset = 0x8f0027; - ; -; - - -#------------------------------------------------------------ -# AVR32UC3A0512 -#------------------------------------------------------------ - -part - id = "ucr2"; - desc = "32UC3A0512"; - signature = 0xED 0xC0 0x3F; - has_jtag = yes; - is_avr32 = yes; - - memory "flash" - paged = yes; - page_size = 512; # bytes - readsize = 512; # bytes - num_pages = 1024; # could be set dynamicly - size = 0x00080000; # could be set dynamicly - offset = 0x80000000; - ; -; - -#------------------------------------------------------------ -# ATtiny4 -#------------------------------------------------------------ - -part - id = "t4"; - desc = "ATtiny4"; - signature = 0x1e 0x8f 0x0a; - has_tpi = yes; - - memory "flash" - size = 512; - offset = 0x4000; - page_size = 16; - blocksize = 128; - ; - - memory "signature" - size = 3; - offset = 0x3fc0; - ; - - memory "fuse" - size = 1; - offset = 0x3f40; - blocksize = 4; - ; - - memory "calibration" - size = 1; - offset = 0x3f80; - ; - - memory "lockbits" - size = 1; - offset = 0x3f00; - ; -; - - -#------------------------------------------------------------ -# ATtiny5 -#------------------------------------------------------------ - -part - id = "t5"; - desc = "ATtiny5"; - signature = 0x1e 0x8f 0x09; - has_tpi = yes; - - memory "flash" - size = 512; - offset = 0x4000; - page_size = 16; - blocksize = 128; - ; - - memory "signature" - size = 3; - offset = 0x3fc0; - ; - - memory "fuse" - size = 1; - offset = 0x3f40; - blocksize = 4; - ; - - memory "calibration" - size = 1; - offset = 0x3f80; - ; - - memory "lockbits" - size = 1; - offset = 0x3f00; - ; -; - - -#------------------------------------------------------------ -# ATtiny9 -#------------------------------------------------------------ - -part - id = "t8"; - desc = "ATtiny9"; - signature = 0x1e 0x90 0x08; - has_tpi = yes; - - memory "flash" - size = 1024; - offset = 0x4000; - page_size = 16; - blocksize = 128; - ; - - memory "signature" - size = 3; - offset = 0x3fc0; - ; - - memory "fuse" - size = 1; - offset = 0x3f40; - blocksize = 4; - ; - - memory "calibration" - size = 1; - offset = 0x3f80; - ; - - memory "lockbits" - size = 1; - offset = 0x3f00; - ; -; - - -#------------------------------------------------------------ -# ATtiny10 -#------------------------------------------------------------ - -part - id = "t10"; - desc = "ATtiny10"; - signature = 0x1e 0x90 0x03; - has_tpi = yes; - - memory "flash" - size = 1024; - offset = 0x4000; - page_size = 16; - blocksize = 128; - ; - - memory "signature" - size = 3; - offset = 0x3fc0; - ; - - memory "fuse" - size = 1; - offset = 0x3f40; - blocksize = 4; - ; - - memory "calibration" - size = 1; - offset = 0x3f80; - ; - - memory "lockbits" - size = 1; - offset = 0x3f00; - ; -; - - diff --git a/buildroot/share/vscode/avrdude_5.10_linux b/buildroot/share/vscode/avrdude_5.10_linux deleted file mode 100644 index 0b7f3fda43501321935378999e219175e706ef87..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1159576 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

+%f7Fmmh#`gxTtf6PxF{iJ$m@tFd~qw= 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%0D_66Ac*SxR_akZ1XwWrQ~bd6wTc2P0 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 ?KPCcS?c4#OLd zdUO`k;9C?z@82c>K~vJZG?&i2pUI`e@2ed}hhMSGjvPeNJyg*wFvly9F4tsw|H~wK zQWR^+^7@YYQ*cAnb%+FxpaP~*n zJ9{}de~gsxJ`v?*hHK()GA^$@IyQnf;i?(dN$q)&A=^#MjBnIt!q3act&05pMD6=C zP{^3#0!0P;egj`#jSm+i_%?>A=IDHXI>*zsL=`rU+-Z^WY2f5^>^5)?VB()U$9+#2 z`K)uqrCL4S7?r$+q$?wHNXp^*9!O=lj-3RF#E(u?=w3osMb=p8A|M31i%?O)l?rXc zdhl^ChP$)-_1Dp&`Qk3hk$2yUQZ)TEZnBVH@p&poDws`#T%gU%s8g+_%Uo z%3Lj@_kfOjSEL)}MdBoH1hcH7{LBDXQF60^a>q>s>Ky3c1MxqkBO zRJ^6R;*Fi1ria9b_881N=ofRKS*J#4&Cli-J9FzsFRpe~U>!Yprd`0p*9AmwwiFY{`Pg}`)!R{PRonJrBK40~! z#KW~Xu~K~kRz6IPQThu1C-ORD;c0?c>{s+YZb0jFcsmjVtJw3a!3Bb*I+lexP8}7E`F-T zdLHS=2eo(`W4(^sKJq}%p<&|LBf3v5w3pONa$S>@+03^!sQ;}y^0D-SX57# zUHhC~62#|nUFZ!hQ^QXCTTZjN+P@pYD*gLC0>%`w)J}I0`bExg3+*yPq3aPamxb!x zM&5mdRzzwEWykCU!gNfHB7(B|FAKOeG?#_-3N6OIusb~R3duNg{uX2dm?)Qpelu}d zX!fe9*LPX?R7&^ zRP@nNedkV$%D5WnPDHK)nOts6FX3|YMg8UGGX?T;v)usoawEqaanZpezKY@X=KTPM z*PBAMH(pDAFuAziq&I0YuNJxUMFOt6r;k+2;0kpgO_%39Wi|9L*}R&_1;+GjMY0XY zDAK&#(%*nH6vcW@@zwK#rgJ@eZJ?g0Y$>yb5;Z+ywgoZ0xbzK7#o5-4fR`V~rw+iER*=rs z%i`7*y|F!ZZq7i^-9H;=&3SX#<{?v04Xb@J=X(e#L*yF(1~5^E$b>lj2U446%`y{ zd#?Xinmiti6d^}B*f zEY+r*V=PtfT-(6nhmB@}4Xl3;kmzchg1jrumYlmRRX>kvPJ>jLuip{EvlQCd%64ha zeoHvrBfOzO!m6P1e^pRdOLb+==tZir8jq@(8bGj_e%WNj;{tU4Y=tKA+@lYsD6aSS}o-pGTo3f_g*Fj3pT6D5?fN%lE z(eZTd7Ydn8~0Md)Sx!Mt$-#noQsJvn1EwD|kyS=^uTCQ}8>u4w19J>XKD;s!txN z$>cm#k{epS`A$*d66L)f^MI9gc^uyOpeH);aB+IY`jEj>*7WMyFR^a&aB-6b^Kg41 zFEu(`e*bbY;^s9)lV!TEuPN%KM4khgk`p;aZFnP!7+*9=Q9&C{-f2gDf4-(@mV&CW zOXZ%NGl?{OP0?RLBd;mik3jhfMSTMOKxN@m&1;I}lI(j;(G?2Iw+&pHvzCN>P0=Cq zLCDt>%|&3;O^O7WnBOEk>}=K70J2rwr+`k>zmdGNG@^jl4?S*YA*MXGxb7HlqW9i-nLfncWJI!M1Y zTVVU`Ab-EztVCYFbbU`0YyyPo>Ek>-}c=R=(o2Nlw`jR&&h>A(r;&iM*3|X z0_EQ->c8|`IP>*VV{$4<$bS2pgzUG}LiAhXKYhJaC(ZHtZAi|Iz{q}42Y1kx`w*Ba}?FU5#`|Xe|fqsi;GN9^-`EO-df~D(L(9BD@e$GdkBG16^i`hc&pMJuisKRQ^~=8dj~~L zzb#kPf9W?X&>3K8u-_&qPq5#5px?%Gyge`dwlAL9Z{yCe{r0@{Th1ceZ_i7=%|P7r z+b(~_j`Y-)v1?mZg z2K#M=@&x;>5Blxieo#oA^joR+TfLvmT4wvLPWo*V1T*8UPWmme*!J5xf4>b=B5%Ci znEknJ+fWoSZJVyB;CO2q?6=btw37YyXm;6|+HdngBmGu`K>1~g`Y-)2n>{g-}wU146ot;sG$3#H%ABO&{3 zBLbs7R^%W1&B^Sy3$s^|gZ=g*ikg0F`M>KoE6`0~Xt3YDRXKwFMn8EJu1oGP>9@*t zF0WCJ&Ob2>U%?82nU@Tce%lYhdJP&PCAfW9dMcKq=PkfnXR;HB&Ox*+rvtJ_X7kL% zKbU5iZszT`ywXi@fP)F+G9OHQbdZo(O1U+!i^eYsoAS)9Ep zZAxTDot4>jxG@n0?m|tXKr;tC=?2rV;TC#i_U9J*ZwoEIMo~dK+IyL`qw;sP#%`DZ zP|IA)#uGJbHXDRInz3O8j#bDT;BliQuTADw654B4_`Xw$(li8~kzIuh5xCt_+vAZ; zDR6Uirj{Cvicd!oRE`bFNlrRn!K08-YcgaJs-31Ej`WSb^xZ!E6ZPp8@%2VQa?3H| zaJt~~Y)5M~gBeM6zoLlwZL4xI2Y0eFVgctz-Ls4JVZg(zitDagX>F&wfG41d{rMQ+ z(F#qDLCJyHX96dW0lo#m046r{7~t4NT1p=Sl&4B@+gGN^5A8%`oG;?^Xv90EXR|nS ztI-|tkG&_DHmci+_Z_Gfo&E3M7{fb7Jut7T)T4la9HFESp&fq zuKoA2z6){EXP1yWWu2+87qe*c&!J@h?=L}RuIDsZlJ|DdecC22$}C5DS?WouxXy8C*{|Wfmh4lHtW*&}GXDY+PC)$L+_F|YsWw3WlfFs2 zj6NqDR&A~~co&nV)91AGrSJ3Md;8K4RpoHS=WtCo3*~Ul>7zB5i#;d%b2&boit{y_ z!#@3dvC$w`Tdp!#F2cO2$y{yOCdrfVsFGQoHY+%|8!XRO#j-G(f`TwjdWU>14lg1f z_tUJ#=b?)qL0)nd9=**340JBU(`?Amm4}g;1fOLcO9C2e4PeGbW+^Jz7hl{(8h&I| zWwHuc$}Vk_y_z(fy=()G%sRhdwPH?}Dzu9!jx~qu*KMtdvu&++H)u|4gO<5fLEh5l z_gSsZ*9P?UsNQRks>&N}BGs{Kao)iFd)6FFHO-?st3kUg4pMDbPF zpEO9dS=CC*#thJCEUahqJeT!z)@PRRQA=osR!X5&?1xl#>kCvHpIcaYdqsHNsg;yy zdTT3n)9jOM=_cpcZW)zX8gmM~9`zP$4CyvH61k&u0m^gmnKdT7^sQBEGY;fh*xer) ztdTo+;wm}O7fGL~k@!V;LOno;71vAEHhFewpO@*R2WyveHrWWnp}q z#S~SdsNrOd$jqk8THIl}o8%(yCNNq{<(2K5vbZ*Lc+$N)>q`*jN#Z?{=uDCqcy5*= zQK!!X2ZP|=ES8Oh(~p>b;cpi{YNi6oXF$M7jx5(koGzU?2{}tLT|PZ#et+^TnRA%m zfm|t>-DUG?RTej|y2(!nuFB#A9^J8PwMuGtx;)0I)=kzUy5vS8IN59nHkd00&96?&O2;q{|?gG+{#8 zV-Anb#HFya#S~sNKw9&hc7e1G=bp;HR}9UH#?+r1p{H73Fh+AdKh+{Db+Hce zPf&&N*>e?jHii>9_#T5;c>NlyC%FtydBC(^_B6X^&9XH4=UJN56%nNIUxrV$mtk0i z*|J=tWhzHP(LJ+nB`c>b1Hn3gi85`eL#*Ne-F@**Ti(;sUh{fp?Xz6bpec?X!k*+AHf0=i4Tppr~LIcdMr8hS{?8nW|9E1*U_=%qgH+ac=Uy zk<|*}gy8G|q!uUD?$cbE5A;|0c}c&`Ksg^6smYuVyd=pDom5K?R*_lyQ?GQzGEEjo zGVWE5pB-U$IcDQ#Nbd;qHiGX9*b(L}gc;mVhG(FCW)r*cE~*>@=Zj~@Y%G7M8=B|>&$s|ffn@a;*qd)R;jweO@Wd&|fKX>{B^biX0Ozumk^WDgQa*z30t)P zutC=ArZF{Sy*+$ASvl^ff^`5BW!yi4SjBk?^^N;+n&kEG?cp!1TtydIRm@jZP!*-? zJXO$CwkXIO_t%8`*Ju-mdsMGBNVP|`YNuc6Eovwn_s4>ze%#kq&@ZF;=_eG!fxpa; zF=xEL)@+Xak&RTdH~Vq)?&%vfhokxtlS`j)wnQ&xpwY$fXwCZ2t@_$WaX{aPULq%A5qZmNvLLbXgF#3SmQrHBab!a z*CN2j8p{wcL#J^_9mZso$q8R(t3HmB$NzB~?NAX;2O3 zrOCA5noJ6vrLWg?@7`i(sOc5j{<~1ODg9JtX}SDw)%Mf4VR2^IzOB$Iit(?|B$9F1 zz74VgOq5|e;BpSzh-tiU*meq=q&(2^1BMk=oV6$;;uzKSQRsSBv^e~*g*|0q<)anh zsZEu>RMU5}w z@IJ3=&0G(!NHbbLTanHY(B12yL078o)_Yv*8y4%ffLIpfiS^geC6?+%kLs~ZvA(|F zu-GXme!|a)^`s(8Db|~z*Dcq6k85v(V)gUHk{Rr03aTQ_o>23vv~}$9&XwJPZikLHR7X)=_wRzbx_g65;p`Ig4PtlQ}N!3JsS zl_XvEn1U)v^GWC>OVib(+20_|R!`SL^P7U!ljieK!CGz96pyAPr=gzT@6kw?ZBUSR zIXO0byrnwVqk6tUs`MRph{*h>g?h)mlxT7IdeYF5ZU)T&CW<3XT?I$_VbqA`bEKDQ zY0s~J7y8BuvJhpAhVNBW&>I!&g(cwLo>8dRvH{`#*Qk=N^9Vn0kg#T>ZJ8*kSj8>2 z?rlQ&Tub$=N0nAoP_{ims*@Ge#8TZKy2n!e(^8qq@p%e8&_cU}-?7lvSF1*hH`!zb zoC4J^43}Q3?Hp@itCf_j>4Dg7~!hLd46hF9^~eV`P&Mi zfE)Y}S#iUAeVz2D3Za0{1RxNwB2TSVn)|CpSmD3?(E18f+AUlYY63=1-bEvP%XKr& z0`8~50l5`Ugy>X+xQl{&B5F5Q0pq>QrL3Ek7_rdu&@wdsl zjYP#GP{oCz^RL$-wgLc|_}+;?`7MglYnv)tUZUAkC$Rk#($uufanBFEWywAQhjDa= zDk^CIJMRliDZUpF_FyEl&`L^nai~4ym%G_U*IKfL4U)Z(K~~XGVJD&E4fVh7GL7C0 zy|}AF%Pn<(P)nm%AyD3?LHeyqk009OZ2!}H43*dHnvh6&iznreiU|D7Spr>qv>L-c z^s75Rbo0$VY1q!gVHn1>@MB`py68G!+W4ZIGq(mL$Q-j2X~xTzg@KLRh|MtR_4 z2+Um{cBVX!fHUx~`1>KE13yAw422Dm_&z(jIVo_(@VIoz-(5$JU zH*e5>+X}QXg7u0B8Ub%B%tvU}D`yR9Dnl*TE6t}K%`=J!(o}mi;_N?CP#fiTe{*MB zsw5`YMxxLrBXf{yJ#LlE$6PKIRBEZdbnmxRgFLFC4N{%&S&cOALGW=C)k!z9!+|Sj?5+S7)wwd z*BAaE7caTEJdaGM{a&eAE1qk^EM9@+Vt2IWv-tgi;<(_9JX0<5oj~avoV?0u7X^cK ztdriYFkTaXFwiVw@H#X#4d&$CEYfMtotm=}75DVzK)M{7OS?E;2%#7XS7|WXHeLzI{$?jG#owI7y{IsfxDtP( ziKh4)OSHt_c;d)DAaJ^!+6ENwx@nMhyBV_t{BBGosJqXzp>72Ly6=m`-D=@}+z(8+ z4bdM;Sf)CAO%RipkMO!HP{@wuM=qBmyFCNzKzeuFd32L`(#LKEFx@U7$tM!-ehTJG zpSie*I^CwR&cC_c2zecicRx4bHTB`c@)-Wvbs|wRb=itmxlf7=E~mIgu}_L(OV_5o zOlSPQLl9Xf$m9m&V+NUj*bvFWJ)>EOT_;69MBkei@~xAW9EJs>p0f3@&gJ`TcOu?f zTDo5HkH;OCIQhv+T?Ogfd)?u;!#wHa9|b_1{C5m+ee)pP$(CQC@H!Zdta8K2=&gfU zE#$LS$0?|WocFj3$;s!ejt7H0XLUAjisdP;nF@_VH~hGFyXy$&b5^$#&ZoFu5I84D zyA@ty&{%eMza^YYqTd2#%>M^PWte|0D#gd%0E>VBNufI^>IS#Z1|>TX$AJu4Yjxj2 zvVKaY!?KNnV5RbLA9Pn)szW@giUz5wJgW2nm4*)U8k9G;BKR2#O}`dS;UP`e_m)SU zkq>F^9+MMZX09OSU@&hio>l-y`#!I@Q$9}R;Y|#x;;Y5RjiO1XTsIB98{147+myFG zro?!;J@PX*Ke8q zip_pSvX6a-73^f#ove_Zwt}Y(q*pIwZWYK1EuM+8zeipFP&h&?p@UK%aS$4wQ_nUEOBgWx8 zof&SF!Pd~dGySN>2oGFK7%x`_Ch-~njxdW|G2_^L2HA(s^qFW)R!1qp7xS7D5;w#h zKgS?5B|4fC#T2Erl;8+9C0b)KLq%!*wO69GDX|qA2p!L=!}qWRHj5E|fWdnuNa1I~ zq23e1m4lG!@4}!$t)=9X47nw`T#L{ zT|REz>P_$nT%p?p?N^?Iz??@=vWWt#)98SoOa6+a{Q#7_fI$0AaFl%%aH|V*i}t5K4me|t`)!jpy9D!}I@%BN}C7Sp;=v{IUd9cKEC^_u&L zt+$Q~A0^|E^)BiynT)`+yKvuk90G44Ag=g6Eww(421MLPtf+19+?)~hKZ@{+%9Ru6 zB-Wa~krs-HmHb6t+B(OBK|t7%YcF(#13;4gKpGcD#pj!l{;A1B_3C#GZb9S-1t4p^_It#yvbCN}Aq0T~S_34i9Iv z1inV@1lMNrEp|V(e3LxBdo%gIM;1SxX5eOpZ$~EI0=I0lYGz>5tKweCPd{e3hAehqSCz>(!<}OJ7I=K8XYy^!l+W_5%;Y=P-C+5y_4uyIAe?Mzl)89JE#<@>o&IirmevSn8HMsBIlmH$IbZpgYO(6+USDXJ#f}D3hgvVyG*`5%C}9C-t(sY+~HeQ zf7f|@f6e6kERzquM7s81H6pJ+M!Rb)-?JXys7zDqm#IJ7-btB!W86&(~X5s4Z5xC6x7z5-9_%1mTIg=wKY?$$(h4$ zh^pAIOXjRE_17pp5#le^pfYV@g>jllGEEXnKv!xnPhoBoNpY$=C&{Q=FHsk{(3#} z-KWgvc?{=K<7<8mna*(Qc)+w|DY9;c>IR;RKxiwr;`oya;o1jROytih@bSxm8xXh_ zSp)g=3fmD78_80_>O){7GL(IEdDx+zTi)al6#>kU8u; zcAF8ijWwBhSsN|$3H8j1@-xT6ORwg&m!IA3tQ^4JxU3l!{WydaJT_+j{5Qddp`hBB&kzQz~-mQ3ushMSB`Q zCF{V)v@O?ooYyqS*#~nU^AWf9x`LW(qI*QvOiT5&NA-1sRJ*UTROw~fFI@e;5aoGS zZ4XT9p4SBm;R7DG2O!I_UvZ!2K7>J-K0vGEfY@cAd>o~{CUfE82T7iksI6PECd>as z%Bd*-oUeQWL&l8gieEKZ_C#j$B$R!VuAW@Og3RqZphy1j%Xet}z$05fN;BG{X`_fBjo(td=b4tFfih~!w9Ia@-jG#JR*sq_U>(3j88vSrR`GyBeGjND z(I{Li&X$IDm`Aau=6As+t@sZD zV=`ftZ|uMo<$e4K*KS)e@nZx+wdsMMOMd|XaF$P(eb%)EcEbqI_M_PZ9;@6Y)-q=ZGW$W{H*w){uh+yk0&-1sQ_P7|V zBIs5vu$Po~#&%di2Y^xporysCdl`b(rtNh^1-;x8v^=iZ;BT$)*TJYR)SJFo^-e?% z48}8Zw~wH;rYvG?3mdIV44*jkkO_w#UpaiVvoN(Tf6Szzhm0RPdi3!_kC@o2 zr?W73U0e~vk8~F1t;^LIan8d0b&b3N!T^AmzygVNF&lTP4-PpFzoE&CxHnOWZ!?FX zMchVcif=QAp_9kr55LV144qtA3?#nIdxffh2A1E#kte@Zg2iQgBlo$B_rT4{y{8{i!qLcTVm8IU#{ zimc7UzpTiml9;nh60>8CfX~XFv)~jI$j*g!LiYoZeaRe9gx*GzvoB>ZJDL-{0{kS!b?GfvXc6DOge>rzDPyAkx^a zM$Xa%PgCVIbw?tyGBJd0Da4Utc>TojthC5o0Jd`yD+p`ho`uNj#L*<^;GPLsO`;o{ z(9Jy`k+q33M!HL6ePSRZ2TNo_qJoi9iEK`cW~8S)eXuoA*dCEyBHNC{FBG&lp47w- zR5_uJ(0?Ry1E_O{QRUah#v-FAXFb~+Pc}u;jSM>RS!BG4Esw^JXp8V|Cn7ls-Sj|O zPLv#t*vV``9&L!Joe`1LH8!=0lm8(qO|GIGLtLgO7g7;v6UOYv$r&o)oanWPL>~hr z!au3a5HWfIWk}r#V90GD*bgCMZc9@P29VoIf}f&nZfgcZ zJ3^poe?EduB3a|{FRyJG$`pKoW;+EJ!@Avq?XcHS!7L!d1*@ znKy?OR>jxA{pFp+@bq|Bl+ByV@a%XBZO@xG1mSswCob;knfPjkm&RYj7|1)BieDDzGevo)FnwkGGbkeuFaE*{eB*o&DDPB;SI4Kp zrRSZ-@FnrH8D7e8P5e04bvnaq;tQxSzN)}k8}ArG_)MnP#V?`0mNC3OzJ)R@XZV&l z4`1f3V7G6GpGy47)4{MQ?xJ7vR#E;JvUTh+j+m z`3!#*zmM`shcYp zDRztE6mktC?cE~YQRiLBNGG@1oarY!c~?_~UEQL~30uoZH@E02%61JS-QA)ww2o^> zB2wxWwW5_>$F3}Mn=Pz%@~*!ImGyI*@mEgsZg>g&Yu%zolxF=s$XSo_tr5AAb*@jD z(M)ZNsSa@(u@d%##6u>|9#B)3d{!axCQhS`2=goP1Y8U4UVOw3q&BAm{XO3aoljNY z^gQxn10et2yjyQZiWva6O$8D!+@t<(r(Eecf3iGp1H;4Pr&ALf86FiULEaq;5Z7h8&!>1JTakIQf?g!7(LTda`s$-?m6jMbLE;K<^hE8DDZQBKi z`nvpP1rV^H7MX6r*Rae`!4_yFT+kLNSp~O*=;anb)|`Ti(b`DCjVK!}I2!4(f|<}! zykIO+5>Dzo4Bcd#IVg5uGTCtmSmRyM(aBEdBgrY8QSBs4D00+k@iE$%Otzg5Ov^bl zr#s2^%xGE7UPi>eom`zLEU;a!ma1< z52Mr_{^dj|K{0WxQ?dkvoL`XBinZGU2Oum^R&Ai{jMm*y8u*Sjn-Z98@*-yh5>h|I zOC`%sLNF&vC8fF}FF8bl|6*QRfHu*Hwxj>tf==ky zkQ3UC?n-s7L#~B(|D4cDfnF}qUNi*ET+!pHp3fq;>4U7GZK~`}RL_e;sy7F-88WFp zOpVGFE7g}5jVW=yM?BS!V|-~*4LUH@|50F;CX3dx`T-Q~mSoXGs53Q?)o(}^#n{q8 z)WfD^(a(?|HJFjj$)a1){!}?5TaraD<6mmXF0gG)7Cn!msWfwTB%8r}QbXBQ&n1gE zOj8xi*pn>kF&2?wU!lm}WYHar3}@tvWKkX?BN*A2EP8efA|n~u4>@6JsY7x>4fGW zGjb>+{Zh^N;*QjWiHM|A%@$YBaZ-n!ipZ!`5p6wncnu36dXYzJL zs!~NI%sG;g*{PzY_?Mdc4*piBipIA`!l=>u! z^F^v?Fe7sr*_V>*Mrs~yYJW#v1;QeiiP6i;gKpaimqHPpsAt%kzw#N6<^u!NN za2kzAI*mu-aVH$jIuS-FWA$%HZY_UEi?R1TtScw_8j>YH2ep`dhLFQ+3Q)*zMcXiW zoKqvUF%nu)a7jf%CxnHDeQluP68Hz%{cSdTKO6|KaOcu-_LZJB5{8QHCQ{cH_$A;(?|q)jyl)Rx7NFAb-?WdOm` z(`M6}Og8%mIfvOCTA;}pPXRQ0uFa<9nQVVcFS6M*GRX$zMw>`uGiAh&VWNP9P`@mg zPBptdbQ@%7-0B;o=0v%O&?<(75YeL4FV_gC5oZ7e$iUr47>=iLF;S@jz&CFD3I3{! zZPH>4(hFu|1ULo1;ICV71O8&h{~J`AbW1Nlc474#yu_x5*k0kuGjN_zZh^97GVk_c zdNkggh07SubsCZMYJA0(lTMo_LFV=)7oLQ~;xRvM?`wv{%iOBoA&FPQ8S{gu+f(@M zX?dRYGM8a@a{C&r1J6<*Y+F8Vt=r*Fq~E_I>~vU~iK*di0OJwsG!4fdPm}05h?X3q3n=4p^V6B{%k8_uGy@Oy zf5_GiclY%&4VmsWWC3nUOf|!$n%h_nc!#?ji`h?xovwxO3GPUjQ@e2OjX3vi(?QZ98-W@Ieg^sh1WHC|k*Ol?OXD7;ZdkCS03ZG-8nd)vM{59nD2dewC2$bwm z)Ka4_w};eRgN+b=I%73>G5&IWzO(*FrO1+_eGJo(k9(;54=c+Ikc%vrQkH|MnS&Hw za{{zB(H#kWi&i!hO0B%d0JVZwR5>MM6mGS$9F;eql~SwlnGmD2hZd5^B#oQ{Zl}vX z+3`(Xr_}V%an6{^Au-tvp!bbYm5FD5@M1^5gb%7ZqqVOF$#lT*CmX z*@i%`%py|dhph6GKd;g)1-aDNgG)mA^p(G;vCRF{)_54s)JTm>7+{TS5$Kg!L~48# zIVIDSETfTVur{)+o62+v`oM*vsS27Ae=Vgf?aOTK&*aK`**?v^8b$khxlY-EzDg%+ z`l+_clBK>}t9SkisMGre8o&=HqTMSM^NiI&-H%vJ>my$52RgCu(YU_yBQ`(q(m3nc zu+#5k9DMi}OFx5{46eOOgG-ov+#L6F$RmTR?Q=S~oP#+IzftJ=D#*~tZG-9rcBqAw zxIIn3cw-O)lqHKa9a9)n$*+rS;WNC#gE9-t0FHVC*lewpU8Pdo1dUz@7V3wZzERWf zLi+8RE}ewUUZ?B<&E1OJr!<%PmM(nJm-$g3vxieMQpMVdlBkP^Rt8L>&-`Gs=A3L> zRd;Wp?ST*21Gk}V135w-Ris0&@!blb25}4;JN+IgvC{*d#{eWmZ1YgWN*b$&x3+2g zhYUa&4P|dAGXZtrr8WqnwUm6InXeepWh-dFdzAg{|u7=a$l7P-$vtYoqlYCvvw2R;L8DaRX|yBj$sN+MF~c6f5U zK{>t#oyhU9B9m1>z3J0m|6MA_F$nZvw#cyov6An#Py=#^{+t1?b3naNshT>@6NApz z45k+-M)Mc7E2k=QH^q4IP@u$}&P2Xwx;Cy13?>FX@pQP!P`R?6=V z_E@$akM6yZ%G$zVT&fna-IMhF=5Q_50^po*GG=i@S+ zFg+c2Yg=5{Lba6xTf#(+Q0h`z>0@m{+o2zlJHCt-bwgkx0wotK=v^eR4RW2Ai>=!a z7ui@iTd(!J)-Fa}1Lwd2tkF_cq~5WZ)aN3338_y@#P?Ik-ZH&!P(ma}GU>N9@99{RQ!1 zJYp9<>$wnNJc$>cA~0Tg4Qxt1Y>I)IGjD8A_(Q^=1}Aj3d zwddhm=rAj@bjIS2BFp*ZFx647XWOKH-{WC-v)Wiw?Q8BZIH)& z8{{$H26@c4K_2&SkjMQS;`#UH^`5LgjI3fAfJZF?6`k} zJnr8hkNY>sZWxOu3RzSrghA>X&q}|)0%V#*iGxfDBRR+S~G~= zBi(p>RX@6E-3}=S*iGv%u#FTmo7N0EO=Z)%C3w>@-==lUw`m>oZCb~Co7PQzo7OS2 zX}uqm3t}U|rkmC=-==lUw`m>oZCb~Co7OSkrgdx@7Rz+gI_BH7j`=pNW4=x6m~YcM zb_p(ex@jHrZCc07rZrb-HpI-Pbrf^oO);}+P5EDpnN8~=q`wk72PUSQ)-m6vbq7sgb)kRLy3oIAUFhGmF7$6&7y37?3;mnch5k+J zLjR_9p?}l5(7$P2|9#B)3d{!axCQfcYg!z>?H?3*+!a4z| z&FIvyX>E3JWt%l$wpp7e^E<8tAjWOhe6!8k6x*!%y3Kl^Y_sOKy&ISo+-A*}ZPpgt zX3dvv))w4m&F@?VfD@H%*8FYHn$eGqhF+-A)$D}pwFq~Laho;2FTqGt1i8(cKU9L;X3ei)Q1^{wn;_YWBQYoXBmTCG1Ja7Mw0a*=X`_?N2XqcV zhHeuii;0qLf@IrI0V_5S2BlhzMS26<1e)*moXh-ym`6DUXX3A0a321KoHm^GxqsU{ z5F-|!De{+-{@yT+wlk+=G5l}T@jA@o+dYnH?>maDgrx2l{Jo6!ZzK6Pr7Ix*fa|-_1?q_V*&W*PCeWZ3rBRK!*(q>SLtAT`C*h6PqN| zSXXVuK2p5a3_F&hu}euojXg|?!xa?N*izM4M}1IU_~t3Jm_4wE53&m1dzLTy7Wl4c zkZ)}U-$C0{a`wY&FhQ4CaFX7*xY{{rk7i$kyQIyUy;vGoiXN4APQ=2{L0|fCdjdH2 zd_C@09}e44Qk~)J>Bp6HQ0b-Pt^U~YB~_X;f{_`1m{kj52VJWdxik z?IeB^IR_o-Z#;ORYrav0%EnzV+h04YBQ{B}hQ8~t?E4Bdn&thbEAtdb)A=MYKW-g2pG`YfvmLqb*mekh1f$XpiJpZh+i{U! z(HFBFFCgcjc0TcbG2%7Y^-%PrfPlO=c9)Q6Wxo*Ra#qM+3izrg;1UYxylVv%{PB#6 zfD(NiQ3`mPU(riR+~_?BxK-Jy=xezmO3Dt*9< z{}hOJEcdtL;Nk3#eyq+eMNIInGrU}wcJyOAo`F239fF_!0ix)D{+wn^!X0JjgW7_t zKikn|Z`diFL+XK?4dP0vYtTK8W8xsz_dGB?c{$nDCxj@RzWhb@=s8H0OTdheuye;t zN{4S16ug{N*1LbY9Qer&eGM7?|0;axg|G_U;Rav2ra5Jt+l6I{7^Wb-BPbg#*^0lt zkAR#etB+IWTP*t?;QEmEcYk>4RxcbNo*d()VD5_zg|&do8H=ZCuiilSY2y z)7`#rW5bf)CLQ|Cz=j*Y1(&$}>|)dbGei9;-+BsiAVUM}I+qh_#^t2cWXwa&a?;@g z&2mywXA!4E>HK`W4iX&K7CZm{@5@O!m&^g99JT}1qcE+YOz z7ZLxVi-`ZwMZ|yTBH}-E5%C|oi1-g(MEr*?BK|`c5&xl!i2u+<#DC}_;y-i|@gKT~ z_zzt~0*5Z5^@lDZdgvljf9N9OJ9H889lD5kYf9V_{l7bO5%C?mh@|TeT}1weLl?37 zLl?37Ll?37Ll^PpC!*&YJaiHNuZJ%5kVT?xs2me^-DfY8V5l`J8qeU57@CcmF&Jx(ySqV+TJR1&{uz^7ozGi?_}2`# zW;iSUFvG)ovcmyP`r3Al4qw?hbEcGd5&668VIRcXJ zKLV0$`y|Tz|2qPbO#hAie|7{UIhw~y6qhRqR>GTLl za>5`KmZ!#&l?+0Qq#K8?YEM?vl83cLiXH(;&iovjktg7jvlx`8e3P@eQf`ibBO} zUx{-yjdm|bKn_J};0Q?arX!JOj({X@?ST~xGXQRr0U$>}lD;D#$^XOJo5x30WN+j5 zraPgNPA8pC8WKPVfnZodLJ|@PTL}B60fK-V`zk01A}UMVMqE%(P}Hb#M{$XW3a+@~ zE^Z?-<5y-x#ZgDp8Nrp`^PD<$>5ln*-}jIAem?1(Q+4X8Q>RW<-KCZ-w2N5+626bL zSppKipR`#55{_8{5`KW;W(i36LDFUkNcbVrW(i1m8?!Y_K*HM@ZkB+AA0us+fP^0> zZI*z9pCE0PfP{CDHcLRlPYwc(ECC5WMRU}dB_IqHOT;Y!2|qmrB6j|N&K(f?f3*Z8 zqDw#`o!4mSnB_NUFTR@v7Ad#LAfi_D(BBgJEHcLPvWu(m#kVr4CH!w>;A{C^~5|BtAS`$k^ zRv}2H_nIXjWZ^|DO;Ugw@QsbbJll)pd~k@l90Bc^yM!X(PAkf+jVLR_E&o^`|8unI#hut4lyK%Q#b=OF%Mvu`!z_lUdGCvjilwf`f)x0+QLA zZQLvY$?U@=p1K4ivy#f`5|GTk%wCs(WXgk*E&<7uPw%<}By#{Qq)R|D2TlQ+E&<7` zVvJb=k~xS~rAt6EW0!zr4n7}AbO}i25Hh+1By%VkT>_FhjEpV;$sB$Y7{@FD$sExL zCSaC;WR83uOxP>|$s9!{+bjXe98D(IECIoHvjik_;#kB?GfO}+Cy|+FmVjhVnFnUESpt%I z@&+&~%o32yQ=bG=XO@6up8heIwPp!O=2SwjH%mY=r~QbS&1MNm=JW`jtsBe|kjxp3 z*ehXqJFv&gu!V9cBqg=4={qmstXmIfu-vW(i2V&0!%ylhDrNOg2Xj2l!{9z#2yDN zFsy4MDqRA95WU+*v-X=r%Y71-yA^kcYDK!7X($z058mv1{+?N%Z*DR2>f z+i|UhSW)tqF~SM)7UB*>=(nA$TuRBeovgeiAUkB@k;X0FfIczVw_jfgg{bByh!r19 zb~=opQ1x2~!3@A>A&V>TXln$vbEgfWKjBTe_mXN9-nN*f8|_@u?!-?2!aP_j2o$;8 zTsJ>4+i^DFjZ*$E5ZDQVrI`bX&JW`83cJeh8eq_?ZKC?ufN0iJWD5GHNLBEOiY)=& z9T4ckS;SrVLCBWL>H59OJSFjb$qNCz3Gep1Myy0)r~4w7bssGd9%%AzW&YuH=nHr` zR48-a_OW2K|HNc$`RcQeZvH6P4qPqk{+;&pZCJmih+pE}Ply)z3@_l$#vElb>%jDU z0c9@LJm4yFxd&F_eSH2Wi24dL`R{>9KY-VA)hf6aN_LT1iYTKmB?0)Q83?PXGFsLF z-u?Dff^UMA*=YHfDGVvLp0K(Ojmw2@f9W@ReY=^oY{|5sSO zsMkv>x}R8ncd7-u0$}-6>~WUvV6%WdR5`xigXGUD6rKsFpnJcC`q)Axeh#SP)F0!^ zS>r(!Sd-rY$QOV?YvQ|2!D(vY2NAwc!sT?Hf;TjrzIE7yi*NBIX2F*lxdV}z@D4g& zDgCM#ADC5N#&y-WGN)ju2ET~lY6<3?Q>S2cO!#yYp6qLF^)7fQCc4f>ce2st&uH{J zKrOdM-$&+$*cfX=i8)?P^##P7io5CfAM*WYZ*lPt>EcesQw-j7$P3-+)o0>)yd2PSs))&Cp9>2H)iwj7O}j!}9Pm99kI#%v=09@ri-(N@?=2W=U~m@*8Z(qn0k21FHX zR(L9%3Si^-?LQJyJ*-~yschP8;d$~lT+&=5| z1p{NEH`(a#tyu~t#zb$o(Z{SdOQXeV{rN&aL7o789IgiN(?dd+XYf0KpB_xqK&L;a z^ZLznUiL}@%)uI0!zKgF!5Xj9=KcAF!Z($s@^Kx<02mwmK$4FLNwI+#?%Lyj3yM^+ zHRWne5`&jpKNnGhG7;rYbgBclCQTSRzPj2OTnEqOUv$`zB~|7dMsSup)PA5ykPj4t z`N4yKzKMhFq}!HxgKtJU{zas`h1ak! z5aQ#8R7vZE97J-X3B~Z3bUjIIQ?-q9?<0NEV+?5#cpbk`;9`v7LMONI6TMwg8E$b> zQjpehQ_kjXOhU?ytX6-@zsUts_>~V2_=ou~H)ROps!|s4UtRD6{Bwh^ASxlq&sF{) zZ&U)v?_I-GS% zHjOiZ1NrU-h^HLaVBu!c9KqrGl2tl zu;hWzNvOcUJuG+_wfhgGXb~Vrn2yB~WK@G-=sv_r=nxy4=|ngaIFmDhajq7_GdUAD zP-SS&1P%-m+V>&6GG+Kqgk*7-tdz@`eHM4gN?9u;CjqBiE+i)b2V09yl^`F6WYh`V z#RQxL9Bji7v>(39Oq~xG52pscMo{Pi+?l4P)KlNkCWNO3@1+Wk&xd9g>d6+5gwSx`NQKpClXEg{wuNH=>gY@zW|?h$JJebPFeylaB*w zWoIHNw3F{!%c;8)>Wb2(Rgm_>eoT=>ne4lewP~guvtLF)a2o>L;MY(xA(#N#7aWRT ze{czY6N7#6n-uH;l~Qs#;Fl#zc?ZHQ*{}GY-j*JjnvS?|_~HLjjn`oA@FN6wLM<4+ zjll_~0u#{=q@*Focgu00vuhyd+k<>Ea%PZR0Mv}u%Sc8+M%uMOlGLvN>W{P^1v+#F zKqDPGgM`eTWX=tPX&sJyxCZ~*EM>Bfggl$Ed#_>W6(m2tjj6)af`MxDFq1Pz_!dr> zSw3uepOg9t5W|u8Uqw)8Cvo;o1PLQhDC+gvzk=o1Ei zXH4=r!Xt-Rkc7}dhJW7^v_JFPVQ35I+KD zbvhq(S%@D2v+_yz#+G*Y7lKA&?e*qvt!r3f?jP5xt;q7@VXNazGDNj%C*%R7ZPi{# zZhVy8L7HheyYn-U32{blb^$v~r|s;;PIeax2Atz$Ms9ZA*N|z)8M)b=7}1V1avrNz5Rk>~kFp2+8)S6_yR6FaJRd!pdZJH(5nlEQRl~8jtJc2qRV=?364mlYB~SHOeM}^d_vfB zz;=_>vO8omOW%fvS9dR>_{;7=)unKQ5@-~1-2k8N@fQlcARs-iJVrZ(x2ZHNCfDnb z?mBfUO7Nmfdv8USMO##8Z+nCkr{fXeDh;Wc3EYp}R%op~dm;R5i1+LYA{~QV&-Nfn zK$KJsF^2jK0Ht`yT#aA8U~o8Y?eH^FOYs@iLA0;*V4d&t9k zrYRn`edguiRVdzWm9&-PzVCJcUN06^is=;7B70SAG0poocL7AoDU#v~JZF$^Ge-GZ z1wEtSnP#8XO=>RQQT(DzD=@bKhSpyy)-Nu_oI?D_P6b6)u{0 zXmBNhi;gP8T#Ay0n)+pGC%-)%Y>qfvu14^tg_m3ZC~obgg+Kr;WFL&!SzLOK%MNGz zH)t_08UXe^TffBuTxl`$q{XEC8%O+{`DD7#PdssE^-8d7IJ43b&ofFfB4DA#q4Kt;;Z72=3 zYueCqX+w7dwkTbNqz(11nuRd~_m5rCwr`WR{5gcA?gPUO+G2>fce!T*Ox&%__h?aU z3By5@tWzm0h^u*ep3aIS^_t6IE+g}=z1Z{a`m;BCFc>pM-Gg?3NZ zsj>H??%b>0zX7HfyC>+I!b)U8!| zP4@!VX_<)}*m6y&2EFuuH@lnp^7~_N%v;+Lz|S#-Riz$p`P)ezEh~$Txu=HKT7IfHQejW z*1A6-b<@r)b%b%~2AXEQTa3)aG@pAJv{wnQPSK^jqTV3A*dVnXd$GAl@AYEh_k2Ik zery$zS)KAASZJ@56pdAeJ)G0$W{&h_(%{`fJm6JwU-FS>L=Zl(r2TgR|r%;bU(c%VL$15`bfh5{U9({dIG!# zJDnY12e(Gmxd__ua_if{-=z2KAZld%h;4HA!>&GrOE-7Ca#e#71X((b+lxUy9VNpa&XI%Ycle`-^oQbC z(T8Vl!*JH~2L#`Yl%p9o=67(1!Hs1{Ja3fgZHfWT%bg;fP5EIv;9aEx@m_vJn*;li zrIPRjqRkv>(7Y~g(O%>q)5D2WgF<>E*QHUYB>B$p@_oK(zUXg8EBuCBIMQ@wZUIw? z^z7u$Mfjr{z6IfvC7c`Cm@d$%ct&F%MeOoF#lEhwY_ZoFOy2X26X4G^@>xVSYGf%R zVStK1Vj_2IWEr|;Ek!EQ6#b7f;+-cp(j!K(+T3KA&NSXptn$H&ro*kqFcj{?XSSLv z3((T?c=PTXMB&$w7(4_9jTLem$!s`gLY_Q>*6>N%FAwCt`ApFQHRJEX1~7;pAxzXb zr-lb&B=%);-_4ZcM+n0Y;`GEsd6O`R$95<7HORRbv=ZA(3f8$v(SAD>;Ae}(_N9K1 zlA^syVZLBcTi<_~g5#%e>aQdp5pp2Z8i%s-{d5vV#`C^+zuIfD*HXT34L^AaQCGuH zdcH%PBOv|;Vl9XXUxJwMBY%$KXAIx4hky1tW3oVO22o4c#b^YQB=;8ud71=atA0fz zVf=)0d@GsI7e8aF@Uso!6NWPA1pLTQF_|xLaW$}+Rk;TcE*^XkqUKg{rAoxNoDc0M zCud?VwAzE@zhKG7m=0jFe#19*+H}1pg(J!34t06Nh-5GdLMDTIn#~~gUUU^wi?&uY zJcmx_Znj{{J+R%)g2mp45=^u^prYs-<#I>3-&nvq04PJ`+aOAQS4r>5akt*P*`d%a zLA$t6r3U8$PI7R@7~^{7uW@^`>iJOT|J{~9L#1MFw4|_k8eYZ1p6p(1Q+7v6(QPt_ zl3^+pUp;Ggp^eE^(N)!YE!T0L2L`*4<@g^Nh%)vlYgH+T3HS;|fa(f{j_LDl1;|_~#)--d)S&Bw8Pcfo=Dqp6-QZF_~CV&#W@j0M5ICG(d z-+i4Ga0%D+U4!7EK4f+Yi1{SW1F;T-Gw~6mT@29@2u|1r zX3R7Ad4+K@vVN&>omd=P?#{CaNhAISA!GjFpUp3c^E4cuBA2`MMw__6uZc}I8&uM3 zp1WSOlC|-YkE*11L-5*Hkc_z@7{%`HC6#KR6+Xyorz+Q3tdfsZAjV@vW#>d=KJQNA z?u9n-176||D&!?b6HfLu9&6}dX_X(y#Tgt(Pp4YycPbLpn%^OuJ5n-SUK}I@DxHdA zjr|3&uV^e^)YZ}fkOdBEtC*oOiBRx=JOrm=xrT=k{!>i&Wg6ZV;jQ3#>>f(IzOvY< z_^S#W4}rc$z^H^*qmpTrQ<160BKQPP#;G_?!`UDfC^#C#0~#z1!q%6xpnt?9xcOLu zFJcpXtBmw)-PF>tJzJ4=t4d_+Oj7T4rH zxH~DrUu!vwYm%M!(0!E%1 zq~1`5f9=aB<)JM6Yu{&*oeR<7x+&QM@y;H9(IxI=-ji|7r(dR2O!@?O9QW@>V-jhXdF-?=-yV zH&Z5hA~)_sR;;yhb7xcluE|?qbF&}3&z!%d(;fVrFyP-i7Bb%K2|2hHz#-Xg_z%*+(j}e(BfMB3k2@MZ;Ko8qmv;L8DNj^;wHL!d{-HQ?eSd{x5syp zw#Rpow#RpoHY-V!j*|9{?;_(J-$lkdzKe`^d>0w-_%1Tu@m*xR*9^Xa0Flv?$ z^ML>{LabAkAdUXR(7s?K^lls4=EFfAC8X^-wY z1xz47f6$}5gyg5!Uo!wcZw8|~m5Ho5y2~VM zfn@E3Jb<*R?MeD~p**2Ztlg{@evFYgx@(XhMU9NiU_qr0N-LAB)QZb+s?<>;;`UnQh^*nK%qJj$7&PIM)12JqU}?2jfn zSFK^Jtmur&p0yv2dtYDU56n^eT?9?V(=O-yZ7K2-+U%#kBTNFVglHDQQ=eNp*9~{%B;v zZVnz+aHtoVEH}sOk47fj%`y95_k+?*Q-u!&58+uH1pRtu)P zn`8DzBU9++nElbn^l)>`{%F&{6uUWQe>7HQncG_SN81H+^>$mE{n4;93RZOHnElZ> zU8Di&+au50nP&qI^|}lHX>D;;tmtGWtO?<k#7Xpg-^3xTV>4lFFk#}q9vhKpHz)Uax0>NelW_r)Vpv?-*^wO5_ zakBz5y^OS3ftlW`7_?b|nO;HKtiVj~Lk%z&}q;hwKbDn@r!hM<#De5U%jxr=h_9a1IaQ3J)Q3Fr33f zxWYrp917>~5U%hrGDn~%JS{x@?_e;;Z*vux5j<@vkdebfxWXfS%pfCY7-L3}$oanA2v>MoFT`xl$Y~_> z^ja_t89CF*%wWtGl$6X&GL0EIJcKJeYblr=895zT?AbKpu8bTW!WEuF=GBZG9>Nu# z%ku2W$XPfT%)GTovo|B>^&pt}cYxWSk#jM%UO;sYX5{b?uJ9RT4rNF`A6`hGI+7v% ze0UKn_(+GGvmp>ZQ#zWw93H|IKI<;T1aJr!|I_uP-@*#ax!~`xe2Qt$kAu&ZAL60W z(X9djib;F_s~1lSG3@*UffvBEr&E};yd_5HKN(7mB@_Wi5FjwDWFsnl0e=vkj8KVY zwKs{*RecJq46SEm*heAt7#nlB7bDsV%hVQPKXMBM=0K`F-NS%*qKMjLk?1f@qI1U* zsn%r4#ipV#ovB$tE!oFbkdD?w5E&*QRB-4=k*iWMb)862Dt z$NB?^(506dxs;Nnml=7Fg3N2(2De>hiH*zX6}VMEAIQtCACFHpW&vecB55q3+&KvC zNCmTuoa2@!=6`_jy?AGq{~8D<5m`c~EkN(Q7j4$-D%Kzf(BJal?tM|B2wbCoxrqJc+&tzSEFuyzD*I=zJW6cwzl%{#1mwYvFf#)Pg9= zRx`XeOjcm&B1s?S`{`9ooNkJ9Aias$;TkEZ?g{yps=oJKirHsrus9?%{!+{_5X2Kb#EY9n zj5I+MKr4E@mcsp){}Ky$fd_bhvw&Tj0G4!9F;?&vpu{*+ovq;hF*0w)%UmcjaHbPu zWDdp4TqH7ZCTj`im4%v)$!oJZO381E!``?gP6pjZY4%j(G2%w$Ls`4`_}L9sO)wEZ zc&@}1n8uav5m&kwmZ{*jQ%J$ixNQn}S?_81-Qde)*4Gw4(_-T3n(hyvQ+4l?92_j} z>Ae+sxm*1=YHr1sVd(Lg`H0)*&%o!Q{09-f9SQR90I`?E4Iq96(dT(h%fhdbR(mdf z$FXHg?T)B5C4r6PazFCVCgjv=^wz0BVsAYPMA3AWjCaDtFIp#@><&@P29@k!F?aYI zE#@LXnGxXmX7Q>NPoX|gAtX2Iz3cbGTB6>K9@N*(LhU%FTH;cy%4@BdKd7|l(9ip8 zE#}J}X3j)onE$o7B^%Vd6=>rN0YWpwb4uRT@X@G;YrJrFn#TM+osvIdM7A|A(or=f z%7@L16sns4MNjvQ5y4m7(h?08&y_bRYz1=PosQ#w=$8w`&l)G0VjgzY!1X*K$$0Vt z@#ODe6647W#FOWQtS2wKMN+)k@y4@tzN^^q0W_#Bs&~!1y2z z!<1sjSMs5kj87|6K!rSixzvA&g*wlJDry!g_vJq~k3LQDZuEa(@$UBUru|>zEmO%( zrUo7NI)6UuMT+{ahqt*|ym`m;!=Mhw#e6k^p+olvigoCI8ctW7=7q;O^!yl+i<=j@ zG)Cl}=0$92=+Ms?5jym}s=hdMAiyrQ{K+b~$~e;@tG|CF$|Jab8-`Qk#^c0|e}^TG zhg**G^Un2yFz#b#or8&)6D0lY48Kz;gL|#S2R?oJrWGfZZ5vRzXgcO9YG9sRB?IM# zZLMZGjUDlH|Kn}dz#!@OyCP!KJnIL$fo%Kf`{{@Gp_) zw0h;sv(Sqz#-YS*`~=4Q2fcMEoIeW=&`y-t2BAXEH8pIXsNdxsE_wX?iPd(l$}P7`uLPuwS{Ir>SLOLs31owXwVU8;3i1r3~I~dhIR(*W5gE* z>!64AgohxJvl#;Q4&8TBPT-Mr>y^19y$Y{si9K5#I01nPJK$BWJ!cxeFn? z&6kfMPe#s@+vv!-ngs6%ZwJw5qKczR{Tq&~PGTRt7V3}(^^azu>f)hNXBn+LsONpbJk_dgTdP&6 zO2unsp}M%o?ovmoWYCs!kFVU~jj(u5$#v6Bw(f9vJmO)t#0_<8Hu`C|zf&?>6LQ3TFIGTn3%8KB z#EASHBQh?CdG8zj<`_n&MD%}48PVUGiR1BDlbGZ2$!a|r zj|Y5Br=BZr>fQ{Ys(B`0E^J#REyzTgvsvf)C{sNj_n?vlFVaqdV0n;<4kWM>nWpfC ze9wlrX~&dpveD&yfoae5?F+xx!|SY{!8NbfFC4H^K0QvBmPF{_8m+k{#H^x zM-B!3w{RWvfK!b7H1|7^y%_vpdC2SK8!{FdeTjf#c2V!mPGGT}8n)?T-}e+k0( zb%dj@0Fl2CKfi+;N|9mf!R2+Lv5F(r*k@*rNnXd~RlZ*M-q52r!t)F9vl(*vc_5ww zQS^z5<_#Ce@Gsx823^89|MJail7PlX&VQ&#Bhd!?E+rZtIrI6rxu0n4TzvWHTz*wi zb}q{siKI_F{^bqClV{FxoP~i4mY2&t)%PJVrGM!R6w|+~P^tKq?BKv?Ua>8?Q6)P_ z40Ign%k8Xq<2}50o5kA`-^q-f*F?4PzQq=5wFk9KrT$mdN-otpWY2LuK-hCEXS<|P z_{_q+%Sx|SDQS7vDH>HMy*KrE9UhBG(1Ry{=ySWKrO{#^EYT~8^S0Dm3Jmjdxo;;d zA|waLtANUg{-HQ^Tc_ zeVe%xfLtX@v@GuQsK3=!~%GKSm)!Hi~RvV}ctrkY9na)@Z z6PrhCB)!8#;9dFiVB9Mc?3`GmGJ@*IBf0rhcBL2%d!%(9ScRA=3Au}m*x9a@tp15Y zYvCy(`~`|-?vzi_#@ncGJ5QB5I;E>^yr(D3Ry1k63zVr@gq&t49EB3ncn>2%K8K$+ z-L&xz0MX}S6=!i`d%O~DR}W}B`X#yCr3oi?*Ty>?0A}QQU!}ZODeY?B>wg}3j;JKs zromf~aFfMb=i%j?Y3vh^*IV&awFxSOcX$Ts(uA)p)J_(%wi+}2Kores7H)4m+!;;b z>JrLODbh^^y4#YjZWgN1gDRP>1*DIRL3$dNJ;-$$&K~3}FFdXXDOPNXT-&_JIu&6L za-R`l4|1&rOAk`Mflc{FzOZ&0G$Nd&Hmav%n_lEbmv@C_C>rkyZ*+NAcpo_9b~n2X zE%=gs{hC7DCDyyVOAO%V(%iY-BItQNAT8f}ZguA(10SA_%m*LK|F*iCPye@xc=t*w z)*$pgBsDj354+;G;})ALuUiC}NWv36)Ni{Kso#zz!9iy+h(2eiIL&JY9rI)XyU3t( zoyL29+cKd=k=EvQ05E?0q)Ns6S>TOhemfL+`;qBKD%sxH5u>s@ka$V(vFE7SuMj#w z;t+^HF>WkHkDHd5VrAKMxd{ub9^D`nGx$BEqK&jb*Mz&Q*d!}f^t?)V>f(0uo(jB8 zIoo8yCDZQMgnTsK9&aJM$BX=V0zX3;HS%LnK0JyI`y9l@fF1Tdh`v3sbm&(QQV+i= zR@IrnYUhqbM=JeCd5PA;91^UD%R%(XSZcC9RuA%o6x{F)9?A4^%2?t{mCUr37~yUv zIBx?UASRpZUJymUsH9g+=}kuHr&cv={xXwsM+?`{{mjDs3KUbp!&E9Bs`s0Az?V82 zuR{1LCKnc8_P|>N(d_tA3pKl0s6+8kb5+Rellr*lS*Qsf)cMUq?TUxGM1|0$8Lhgz zuUV)y9@N%mp%yEY-t(7qP>Zr>`34}zdVBjkTQXcl*l+paKt{wVdMqaCpOa~2Oi>}+ zW*A*d6P5!*EV$Lvb(KoRSH{6(txaC2OO;p`=wJa)OnBY`e&hkRX}0idJx3{dU%Nkk z%K5@86g%AjKa8@!a!Njr5ek;tl8X?(jQTeGhDBKaRw21#_(>VLW0-lCam1?O`0S_2 z<&GiQ*T<)RR^KZn`s20Q zaqRU(;_8@h&Mj5i8^D*juUgF0J3w1!r;-^~#|zy|RH#_*3J-5avv{-g z%LZKTd#z+TdpD$KW%2f|otl7te1aEFKQ@(!b}}YLWJ&WPR!KVaS|dV-K1;Pa_MU*F zzI;gtI0MeDf-j_sJGy?nJ2zhvQpKMK;^nxB8Yo^Jayh%PTHfTPyL>A!NZts9B{^R( zW(Z|&%`#nQ^qstCdk2lnnWj%aPr1f~Zv9i0xW|?67Vq#@@^P4P3~nXg;hki+3coW} z@_E<1d}v&Af@Jj`v1TFmM0t<*!F>u_!)Ei4GP%5y`PV>nB zcym1bssKfo?q*%g+nz3ik#z)SF3|Cvjhk>ICxp*Ej*)_Z`EX3!4^D5y|d=9vU z1fK(*2VrV_{y3vWN2|pno0*J#_W=kQ-?>VK;=OS33&wX)PrjvlkzQ)*I+ewzV!7O% z+}TzD!+kAaW3zw-ODv$7>p3EzVlGO|y0R}kO4@0}Xbj;w63MD^MigmypV$PZ5_u#* zX@$n0gmfbYD>E%l7@g*b6Ex<$*ciUzeNrQib$B;GL^?cdIPon<^b1+H>rXUR?dqx# z>gjT(ZZBlr_Jb+LNOfMwj_+o&QlA%*{ROP)qb@NIyA5lk7rIel_s>N}>jw6RUHSfV zNRl~;J>Tn@`Wesqc@s7;HBf6` zH%wTFM}Jq@MpGf5DNX}zGxdFBEEUqNzgEbJBv>J5gXq(7e1c@>xw76%Vptf*{B3-? zQOa?rwM1_ruN5~Dh_4lQ5~!pp5ML{f<2YqwyxY6!{C+1&{hbi>5@&!a)e%IW;Z3oc zC}rb4rDklkN)00rm0CcclbQliDREmHDGs>g-tJ-6!y{(W}v@`xfB)-NS2_z}nA`pF?2~8?a z>`i6D8sjN*_8zOudQX|2Dip8G5l@+tI@OlVhkrymSPbkG-AS^#GSf)vhe&Q?z`pdYk+eJ++I?!T1<-e8$ICmBhgox6zxq4 za~e98_bp@!-dQ9}J)7hsLQ<8J@j<&7|65Sx6xy*$JJu19;pNt!F&I8`3ZkB-&&&Z4 ztOBtF#1Ig}R)Sas;#4M|rpXITY79b}_)(@|;*V|OqaaReDu4QeP-H5L*fho+ES+~g zmdl$#`$Eks-s{4i*I|^Hs3LHtB&=TPC<6tLpy%s_AKh^%GyA1o+RM>IyxjWjRGTe- z9I}%J(*R=HyDIo6JOFWyQKL@%``F+Bs2J}t^A{oNV*;HAqIWfjOF=9FG3*);4}ciS zU0E=M%Otu^C!V)_TQIaP&hUF;(cb*To9 z=rWrGb-5D6X-(x%{}-%q`j7aL$^T8G-48;H`&RYv-PQ#g-ny@s@Ljq%<3-54wLcOvRj7V~8g z1BSrT?|^`%hy4xz&q07Oxi0xwPm}-0_bjW8CjS%y#@$X+iFlJw)=!w24Vk!M#82EV z{#0snflA{mkX&P}F2SLyOAipIH5EJkG-Q1GZ2XAHn?}3e`b4YoNNcpJZ&s^Z@53rg z{*fAnCSStahhru;D_&so-(pO@DPBfa&hVwrLd}ZRvNK-BtCp=QBh@lJ`PLQ_YDf1f zE_P-V!K3+?Fma~c5-3x)1e#?x`I(*LH#`4C<|NGc1sx>+GKS3v`!EXOFH|#w_hbAE z)y`yp*b;x44yl>kQg0CcG96Mga)N-uU)ozUa_|hwzqFTTa~T!?Qr>Z~#Vy{pI=g4! zlY!Y{XFl$jxy8=G#pWhmDKKr1Qfv;Tn ziIaGG9)9*t2APrvczczpj1b1LaO8Sj-ILNbsl71(h z9UOvolk^Aa+#t^eN;*oqAeCnWB{?pc;?xX+y2A8M<=H?<3BpvR-p%BGVMe6#Y@nn> zVQNx;M9QQjVJ4^YY@nooyBQizOXb->Nh$8FVCJQAnQKz26lrlP&jv~g3$rYhX9Fcg z+(p1yk@`NqxUBwN)oDrJ~!e zRGtl#)XRMm`Ml&Lntgaagjfh&j+1m#%4kGnCpECVL7okibUR5W$g_cx?qJCS!ISbp z-@}^XK0KVh5(p3@jWx~^q_c7v%4rM|`nnCxbi$va(vx{MP|`q`;mJH3D5=WO&mtZ6 z;bC|nunmm=N02S}Bm3|qUq&5dAD-m3LMFhb$(IYs*R?6FsaV?2kg7yR5yxMIf3gox zN*jjgK0GOMKu|ES96`YgaOV)}2+Ef|uS zoQ9lI^Ahd`69_aQnQYb*>LesL>j{-mBiXDcR3Ric>k0KGnNrAPX=T{4(g~U~f*9-s zyTZHDMA{G7j}YC0GHDHn#N1e;iR)z4qsZyEwLnP5QWzq=K{DtD(e&HdJTq>kz&#>x z4h0?(0cM;2un2Iwpl}XxrI=>{O1BFNx1L2@p41XpA{gH9-etejV%q1yXN<`+Zg7K?@pTX-R^M@jIT5uye{Kx{*vx41W zx5yc!=LItW7Fo#d+UyS$SwwnK@E`Dw$eCjSd1i1J&?0A1ep&Es$}c9pBFM96B0OWs zSsC2W8T2xS*9AXEs>nH{FA3hvw984a4bDUxh@4CMs^CSWSCC#GJe_%+M|xxMOd9Nb z>aaQ38C4y*fZ_GQt7xy4q#J_U6G5*ceOK^1=Cy{^z9qPv@^z;nHh@JK<^&8ob-`k zKAb*s1!=QCP~=L|j@ch5aupfB*&isfj*RXP6uFv=?hh2XhK%kH6j@J3_Xmn>Afx*O zMXn{I`vXO;Ba>_P2a0SY)5+`)6xl>Z_XmpHKojczK#|R4bbp}8jbwCxpvX-eHFSTV z$jz)uvp-PemQ^s9?hh2X?H;sB-5)5@z~g}$%>F=;+nHxWhH2Qewz%p*bSwyGO$eW0 zc-DZrvcxkB;WM#`5@`Mj&;5bu_tIVPprJPG?y)~mBKHT1-0>jdQYzuy`y+Q>1}8KP z;GX`7bb<+pjND7Ts)Br$h-@J}B*>Y}k^4xG2)>5$MD8a&CU`16ZYzsk6YNT_e1PG# z!E@-{50ai7+{qRr{o1L)yD77c*-i^)cLKegGP8melzEKwyx<^WK2CaJ@JHtR1nI@b z(|3?I`vXOuya70}KTzZ;nxoEGilJf&?hiy$CUSqE$kPu)MEknToFfp5Za}0P{T7~? z5Zw-o_@a3T@kcr4Cq{X=cT)69l(t3mcIXs{@@_OaIwuhZjE+V~(Cjyq)qy>A+i+Ir zj%Wx$o_&>7z@An18_McJmF<2*S$X3SE&B~+bz+34)awU@Ow49YJRYCz38Bog2IvMat^cA9O*G zXJ2JikS><~C#w%NzTCdT91|)B0zoA6#Hx%t&hgd7x;|+@bdB35=(^2EmlC6l<{f44t+}DQt4Mlsg zF`Fh6EoW#zMyzNB2aU-=PNj_YW*ayA4MqFh1{vLNC|XJ7bibi!UuLiS4MqFW4!Yk^ zv_Bc$Zzwu|jP5rS9oPko?l%;zVvN~uC_0E$rTYyh;vC_0Rc?l%-2{uLO<>^Br0aTH9z>^Br0$zy85X1}56C^Fe*zoF=8GP!2Iq39Sg z1!ljY=vbl^oBf8OCy>$ohN34HK}`1>ijJEAW`x;qC^}&gm>RR+P_&k4lg)lZ(TVk7 zrkVYQqLawXGy4rir#t~>vDt4Zdh&iSE6jdF(NmMd=p4*`L($U5O1m*v@G_8W@M+k`ZG&3;4C`45BHZ}uCCE}%LG&3;4CGsqk=`wc}G(x;A?{f458 zSi!pAQ1ndcXv}^?(X+N9CXi?Pe!8CYgC{y^?4cjFJoXzR!i(T@<%b*^-CyC6fdIuM z{xdJ06k<4-1Oo4XX-}sxX?g39(C-*ZjU^NTiJ%3Bm25<%FW?WNTiR$=dz0u~)rULs z2n4NXWEzkdsi)YO>%AD!R#>LC5Vs(=K!7{+w5NL*5Kk0Q+=xf=pu;qY&gHE z&sae^Q?r6vvM;P49j%EVaMBSf8PbhRG+Q-dde|7co{3?#up(Xl0+YoqC1 z5)H_|*g$%jNh2LtAaFAR67h-Ji7sZfCvv}`mhIj^Xdv(|e%pV+6p{h+&uzeulg4|8 z?-8N<4YkarlBT|KclY4AGflWeS2{mV-Wn)!IFnJQ(zHYFZrp19`bC=p4O+w~=1M zrd8#n{2LmD-L)vS3<9p)xjMn&D4KgE{U2MFQo}UTQAkOvOLX#{LqhlJM1&;!_AlrJ zGz{!xkj(FHK9OkhMe`={FuC1wZypDc1jpYMv1t^Ug+GDo?)Ym#=lM}5ZUcjpeYrRR zhF2O@yV^3yP)jX5CNbazbEgkioBvE6i+;W+JajuGt?cDMQt zBPexw2Sh*UqxJA8&HNwonPR8CkN6gNIuaEFPRC`m+ryF!>M2qhJ*d!1-RX2JqUHV( zI1WL{J_qNu@yg%b2BBr?HTz*jT*a>Z!%OcQAlF&G$CRa$b|)TRaW2LO6`Y1wY;Jja z!FYtN#+%H7;UMk-L0^6hUYTEz1BuM^+)oYi@gDN`9&%P+9{VDG zi--G;;))flphI2XHJA%6=0<}#jF=ClE&iLq?C$CMy@&ZwET$FQvl{6d4d#;;^PdKD zGHrTITFpL#ndM;)#kW*bTi3*5TEPZlZZMdE;ac`$5Gebl#5^mln4gkx<$9R6c$jC! z+O$FikxVXkiNQU|;;uHhw-NV*G-t2DJ?2^8d$=dW>S_fSQ`Z`Ud6&g}(_r37n--?+ z`K!S^=2JuQTF#WeFc#AaRuQwvVE$k+TaS?Pe?~o1(&|1mn1j9Y-{@hc#9~^(FfmgN zW)+~M1rD7Y&XoXc`L+TvTz0*HN^NrZiMUZ332%CAuHG34Gmz8$dl^vkkB5nsD|3~6y&Nc zrj)m{=(yba$uMcLsMu4ox*8=YMs__VyR$}ulZ<*wM(={}DJyJC1n;k-z;DV0kl|k( zjRk>Fu`I;lVCYyZvJ%yLiE6va^Xb(s7yi@}z{^6|ickf#d6WDo_I14leej9k`_nFc zLVTQ=NB)Mc;44EMVtyw-e+c-#lK%c0OgKHX98ce<)6zXvh`2~H>M#xmW~@IK!`l7o zjiB8dLNl^4Ha!md1qc*u1<`Iihz1b1fN*-94r<<3lco-|dueDl(_BJ&0z}UPF@waJ zAT9$@evyiQb|X$b!EtG;9qhG~l-Du2f*;6^R=DF*Qyh1d)7DP#@BIRjp80^ugigZC zT^0I)8GVAd{ebQB9tfv=mFnLiU%>qvuxysNtC1B}eNZX<^NDA_a+t}yT;+Rf!4dSsr9Nu z#WwYwHnkDGwW;Xr&?#2*op{klRJ5~E$#G8$J!D0HwW8%8sg$P^Y61iL|Cj-`!kz5L zGN2^9dH-13UMiG-2RLw!AdU&~R(e!^uL2DxJI;4Tz^hMrTBSPzlX&RVoT76Fp#nZlWmj}aOZS>_ zC3F~1A7?v^PgB{a9ed^XD6Eu9mWCSXONc;-^=s-2 zG#s}=a=9s?7j5cJr`ZN=yjMj#SjB*%#i>8)|QTtWkVyC9J?fsZo5aHC`4OA8QmJ zn*hG2c+DeH>)(@?&F>x&uXCsf;CTy4{Rv-09lj{92m8T7f)yt;Y>ODiH zyy_LJZ{BaLu62FB3V9XyO6p%N)HDz3)@GrmDHJNu%x0;a*?7#h{4#?YcGt?ov^&j#sAcw4&3jX!)y6GZJ^1_rMRfQU`*l6Q@y~s)KsCTb}_9jISIBvcta$rKPVN z2(rWf8eCtQh4)2}l5+A@2JyZO!b6;Y&qZywLv^_ag>RUL4qtrhs~`u67r~c4$UD@3 zN&ffE$D$yP>CZfBYSz0WIzH8(r!{-s0^5Q1qUatK&0PVQ5vc>L*mG8_{4HsbH zX&x7>BbVz-z1*h$+Dl!aQeJAQ)fNAU>jX+v2wrQT4h283P_53eo;a>qs6FxhNu3IL zMGvMPwNQgCl(EuvO+}AO?b=bTbXL6RJxxUq2Paz5o8v`yHWlrcT4zOfd!m)Us;~4$ z2Xr^$>7#N(lI-&q!BzI!W=#C_LdSVag*Zmo-mHX=SD zH8Rs!JZ%`2dt>B=HX~Q2c%9WXsNYJQ^n# zxC?j*frC!v6){+Ui<2=}rK;6qF>*fSd#sdka{b=bnmX3}silko=}z~LtI;4{kap!> zgmBXXydcfE8%9J>X#f594~5u^(meaW!4AXFJ$~WKtd~Wm5X(4T5s5-huH7w|PEp2S zNL(z;{*|Vl`?~7?_4gfbJC2Jb#~~f&BHXVGR;j^oYuKGTY|vfB@c2%M!J_w;C74>QV(7%=a_A zcPelSc7mt_F>sDbvJ&N93is)zY_DnzZlMgut-*9yP0DsBlA5x8u2SQTLdm{e_nTrt zEf?Mg*TO@w80#Aq^^EmU@MH`4jt3Z8-JG%Zdd8}923P~%()91kL8flysLz=-SU2e>Zt^SCG;Y#Q+~njlt(y#p zbCZGMChHL^C4W?by^>c4YYWtruRzF{@&lEMcav#e$;C~+R-yf8LG4q6w-bhL@&jPR zO`@0)RPIy1{6Dx!D;4wHWJd6F0@6)p0Y}_qEr@}gRr1envQ}d}H<=VHht6TyoUL^P>at}ekTNGpcA z0z$@6r79I)u7Fpr^06wg&@?!VFL2@{I`M%N^p(yujX&1cZR&0{Jdnbhq{oq&apD6h z4M-7PVx9Pll-R!R%M|u?qY*3mFKw#-zfy9#ss0y2$mqYZS^a-M7}wWrRiQ>Yu|GJ6 zFm&Pv0V7Vl2SoXcD)oPG;*V6!bK;cX{RE^Fw?A8*crb{8U#R4top^+{D$j|Jru=Hl zHU~*f*=DQM|AiATR8g<8(}TlM4N}?HdVuRxD!#G{yvnY!Wt)q%%{pQHabJhD8FOC~uP}GrZ={?S!24T{qi>3wGboee-b*Rrca7(#!Y6pS z^=%5RU%ey<&!Sw_ZB>ks$XA~ZV-NKhG=_kSQue=L06QmIz%$D%;35G$3_#w^FG~3l zqR%e%J00avkF!!LkR)Nlu#R%5hh>L%EUN;tWk+}zrlTC{VcD9FV@5!DF&`BH zHKOBW+QzbDN@h*R_BMtcybO;8XU$w@`8UCL`~dFeiPv_a z?;NDYIU!5A?U*wST&e7jyG#nTm%Q{A=SXW?yFaTbHt~hdR*h5HcP) zQKjM?$e#Iu`!$S?xWC|o$Qvr!a6Z5;PuXX|-txd&yk)YC2eYSY#DRrXbU(qaOgX+t zHT&5E>(?xpJwU{QNylPEy~cM{$_fjZf37X+lx6|#0U{Q#*J{*2gNo)}0PSu`d4pg# zB77Xc3a$aM0mNWR?%iXG%&OrfV!N%_cOdlMrL6;{W6&FXmU zC>N=SKUAoO+TEQp)4~k!V7k5CTt(dUmFYvhqOw+(tLS=yZB1#kU<*93JDUZ2qB*dq zRCEu)9!&Y&f?e-{9c&it{pP?D-Z6y;U>qajHl0;>a|=*-xx3R0&!3em5;{Ad=M}5qLuk2M&?Mo%r2|*2=xNy)fPsL zvElPp=d)GjTnyS=I$GgQ5B{eM#$CDazQMZEMG%-43&K}xsE1moUy_cq#~!ZPPUPX* z=X5XNa5Pm$9QPiCcf$Z=*#0v3Oif`ZrbBRG9rPCOZQG^fDkNS}%jMQjMIp?+Z95r| zOW{x)klV@FbuGBQvP)d94#;Er%E1Aa9ott<1+wf39pzLY%bwVAM>X=bY)!{QRWa7_4=fel#49j zQ4cWfJ=3$sYq(Z#vEu-bsHg|nJLP=~*lndPa)%a{Y-vrl((tRk| zhf+g|5jLC>lOWH_RF!6PoCHZ$f46$CgP^JVPn*?yR+G9Hz5k=4i;b(D>UXsoo3|z0ZO?FBvN;KQL9Z-(<6%+3+LZ-4HT5pQ;k^-mtQX z&SHdxDw=1FFfrvH7VupU@akp(H#P@&tBT?=RxWo^N=YBp@OKYzSF?Z*GzS>gnJ(UF zHX`L>3)p3iEpnks#TVHg0%jXP<*nNAI5gY~l$fq~y>z1|U>J&#c_UtCgYB+uGbhe> z@iNzn%vh(gmo_v$_Jk^9^TN1a`GUq0p=VrdV2dDN(EK1qW@5a|eIhf?sr({F=Dc{B z`$cBFQ)!z#^SUKoW~<0da4IiQ=cUZ^@iO;NW+im~E=K0_c$vGcjCCjucFFjQvGA)_ z#`*|l3gcy7voibCL#WTVc$u3hv*ARi-)gON8SuJ)!H2hy^!IK9QuI$ABLPAmt-R5Jve@*6VlKygL*{{jy zCY=8A$@bS|J}jCC<=>O}pzL(NiU?mBgsxEEAbb^r@Kp@LSILwy2wxk7K!Bj#Td+VM z863W(H#i@~;CvK=W9S}SV;f1pM%{~Eex-a3_`HDfKQ4QKFF=(&Epc&d|^{STZ z6P9bcK}hIt5w^!5Y>z=ec(N_m;|8JVTPk<2AXGhRda)}|QeJNTTtJ#Ti+crfA{uuw zM)Z4=IkH?0u4L)VGjIf)nEW;H)vqhaJ>np^C*6e?UtA35-XfXo(fCW411`6|8!T%w zxkWPRU1u`6MKZYooO!IjO)`0#ygc?B{(JD1-zez1oA9s!opGy{v0?I0fiCubt>5~p zHcn;qDN{h+(WN8TrgwDJwJKngx35JK0?(ri$MNOeaw)^1#|;h_OPewr9%#$3T*}br zLcF}&5|$KnoXy~AxaCr&!{9o$twQVyshxxklS<`une(KGB^T+fQ0)^YpH7ks#5W~> z4Kx{A>LFx?mK7=$-_I5t@JT98>p7~i5EX;pAnEV|^`*^+9dN7qe6@spRJJPdXl8+nqL1vOu`LN2cMqZAWksJP{ z=mU4h$b1zqBM%Oc=~t%8NWWC{DE)DOae9sTuUD5RSKGQAAa$90v8lTOQg>^>l}g=J zN!>jGzN1v$AgMeYVq3!Za@B%9=@QIL;2VH`JB=~c(_AMcKaR>5tFMEAsm7%$5pS;b zUNz20+OT5{Tw3jamx}Kp;MC+6gA{P52l%&U0mGkLzc>acw;jKzc$#&#;mIWy^m7Yp z+$f;U%^UwGCoi_58JF4uwNWXrK&YxK)Y|ODHzG;QP$X4_`=`pMVq|v2%Se?&rs_+T zdDDw`Du2?jVz?7`e~ZDE=VG*isthfpA9ZZvoyxTuMi(pa!sU6|d+t0GBQqvm#y)rU z>!sy2E>_1!oqTbEnoXweKeCpsA27taSiZPee;AG3L%z6J)?e7g@vOJw#l`LhKSCba z3MAe;>urRb^`?RLtT%DD&6;KIGHB5&c_4-fakmAR+1hzYCA`|f2%hXawAXrvIqQub zsCU*|1k`Q6I&?9EZwi3d7^xs*hKN znO9Q*P8{vt7M|b+rP;fu0;PWtuWL2HDf$LJ=pGKBtHB|trs&%}56DEY8T1YZcpGy) zDuy0#m<`+stc3?)H_)FY^-18w)C&~m5KZkSA4Zl^tAB@pvGF>Uh_`Wp_PM<0MrY_$ z-=SiEDjCMPBC7qMWL&HU;C2YS-1=^h9eE2Z7goG14F*!sS>dCWO>(m&>EB7CZr z%Y83!E>sZc_dMv~%|fs6pyeF9$~u*z{khSO>58Pwx!$S1IVLvN?{2^xJ>E<_j}-C> zDaq+R1+=?S4CRJ!hhlCaH%jI7mm83ca_8C&zO_jzsfP?!H%Nu_kb%t5PSIr}fpvjk z?NJpvdNqF`?tD$nUm)OrpvZLC3k3AEb#@e7CBVF+5p2V5M6`JD!p+9=jr8El15ZO^ zG2kB%Fm-d6O2m8cLC=6@gC#T)sgxI0x`VBhivqkw7tF3#Tg(H^Vm2x!hMXJ~kehI% zXMMD=Ng;e3{t%B$S9R_Lc=WZ|)j$SirF?z*%swf-}>k&k?k&Yrt>H1-jwKg0J4A zStMK++oN&TD7sGkn~Wa9?K%1o@r+CNH&@#q#FprU68bfcnR?V&3AzNhFJqUc|c z85KQ46n%~y6g@)}JwnA~0mwo@8?xRiYWP*)tDpJ**n1N=tBPZP{G2=6<<4^NVFoTR zECaF(+prHfY{NP%vMDHTI0CXLB8n2CAc#iMXaqM$s4ei?9c zV*cSGdY77uflC_=zJs{5)8KCqm$n-GDjd)@C*}=aekpKi^CLxk(0U4RbG-A>BFde& zb?5s1c#y|`O!D)#Hmx5bx_DgVyA||{o96T=syaR4G2+) z{}{8)`i~V#757P-e`V$iW%a%i!D{5=zfp9#Wp!-Gs{C40VVqUHvNA`w=fab$Rq3~5 zt9mEcU~ZtIa0f&)c)I=t$*_kPPY03Q-{`24@O*wgG!Ac;zxB;^JfI(}_O@+^`^s_OT}7nfuMOTQMG)>mgS-Jp(Kv3FqWhQy9OZVn(j}x1pFjMa*|l6~){sV)nS)h`Ce5TmZ~?#A}4xEyP7k zgMSQsyw$|tBj!Ly%zhWrk&G6`{`HXF_`}g675(98k%<0qv`Az6X^a#w{!rm|^oL`M zB7Zo}_zUqB3V(h99eB%U>!T82|Kp|@$ye_Z8AL{)xCW*WeSb0xnH9_?^HHkY*cvgYlCFsojBhElb-Cu1<1yAtl~~ zOyeZKS4ag!PV)PObfS@y{DDaN#x>SS-d{*3+3DNBzecBN@Fl>-X+Fl6;^4D~PP1Rp zh&k#szY79!n#pU`Y0d;td+zmy{91SyE`m-^(P?f_rzvg#Zv^m$an!%0v{(gVE-gBZ ztk)v_WO7^qU>ku(0N)2Nkz@^L0sA#D^_jD8Fx7?bcVN*IWW)XAwCk+3KK`eLzqhQ`SXO2cx?M>dDfqjEeX+ce8ozDHYH!W0QRTfy(?fUkdf~yg z^wYMqS()z5B`qjA!;*d)lGb_JKlJmLBcFQ!20^+x>32BkYn=2SIqBP-^fx4(H}NdD zqqM6yBeaFNxiiAL<}=u3LEnF5~QRyV&=$y5zwiHNDw1e6AhWx68QhdA%9ex68ObikRF9 zxm`x~cHrhh*LMo%gTqgW%YCEo6b=WTx&bcrWv%2@u!ct9Z0qvP9$ANOeDQdB)tc? zk@R|z^gZGt>GdLMuNxuhQ~!{pI9xLzkNd+4k@S@-&0zZ_haWzE(^*iBk+ec2ZA4v^ zv_d3(h?q!PA(CExla;iMNV@uFD`^{%^x|89%OugZkdwqyz|F$0oz(x#t-u#@f-rc& zZNT{sJ;k>WUz-Z?wYOWJ*go`$L#TeggVf*n9nc>&KybEX|L+2q2u!7T>+~+*;&2T< z{fLst9fe2A*+iD@3pL+3|XyFsyM4p;;b%I zqV86ia|(-K1R~YPA*;JuWVJEYN$|FZsqplVL%@YopFD}kY~8ZHaO-wmF`tfGUUkcO1j$fMp@a#4JMPw@do^!1GQKN%9e*ru?pL? zrXh#gfm$pBwc9;rpcczOJ)D>f)M6Q^mjE{|r9=kGE5zl|Xo(nlzkA_QuG2~$-;(3} zG!zhD_WlV1&@n>Lhd6>0BIqjRfx#{xzv)+@pa~IlEvlkNNr<3#5EDTYBIw(|ji7lV zXzhJg&^!@z6Y%k8{5J$0I6V@y-yxh%wiIxg=(A(Z!gosnSA|^oZYki3u&>CorGV?f z(X!UtTEGr5&yu$m$n_@iY8MsA(pR>smk8S$@n!}#%hyW_Wceyy>N4R|BOdCq0(z(# z@lM+cWScFXNn!Cy3X4bDF7-{c))SvP=16k+xIQCOW$_)&?7C6 z5yGRxZgimB&l*v%6GXd#50U#>bp@D>y!U|1{g@FK8di-M4)~SvharnxEok#S_$j^! zXas=T*-DjjwSXg2f2dflQ7u%maItWBLBSDV$g2hCkRh*8-3nmriAu@wEw^Rm8r6;y z@Je*eX#*+w@sBK6Ngm%t-qR>LGnb&@2gvz7awh!{z@+E-^)kL@{SIHXXDd5@qj4r^ zCfdY1Up6Pr6ny-n3huPR_Wr&KI|IPjOIs9{5$;zsr;}lUlT8JA=n3(Ct5DQ<&XiX5u zSj1=fJ5i$U2i77!&!k?70c5aW~10dCW-}|4Xi~AxJel|w}5%M z!u2n>+Y0xf74A0_ZgES($(+1Lb3zL!DJX#E#R3W*uom!ZrTXg@P`6Ke@lLGW`+!Sm z1+DTH>Je(M-l}w(OW>Hv8IG(_jyJA`yY!Fq_ozoPhJvJ~&ER0(wDhr<2!5D*+)JGO zexE=4UPFdOpnUwMpMuydQGYMQgV4C~hbdWyMtAO_(;e5D?&_`ldZj1|8Ijg7dP^7` zOGXVXGlF6ENpPCmoA1v@IWu$Ym2#uoVa0(A&IQKnKA9hR-5<-a@cKN*(s$(h=Y^&3 zkkY2aT~3L+O^E?_aZ7QVAglDsO{9f)Lg8-{HrGOUPOG=&a|-(vn{uiant8OV6Wz?n zrsWdKbe+`DsKk+aSWGu9QbU^uO%2yc4Ksm_U;0;TfX)W|h;3+;8lK&2dXn#+=Era9 zz1Y^!C^ej;H8e^MT^@p;5Y;w{YVQMX0wN3ZSrP$}4Q4a3NcfN6gMh~h{Ji4gd@SR= zwL}ruIVPX;_@}^RUEE4vID}DaK%4vz^l99b-*>s+js5=##^Bs+js+z((-ZaKF=n=t24T2j^dnDynZlUYker zVLo>On!U!b52@znKTfJW$eT&3*|U_QRorav-kiIm>^n@h&GH63fmz%i zAkC=yrpf%Sm8R+Juo(l)h(&E|#sF!?9$;pK4ia~U-)gM8M|sd1)}pjl#NDNN@y!0P z2EX1L^^6kA4rsvV^^l^2NU`xeBgLhm6eUZnGCPPAtsgT|bPy?~12a-|45j$9@}Lx- zwpZvI$;_*CA28pfp zJihTn-jiT9^9lN<)l2ct19|`EEyQ_5Y_HT+_(M1=uIef-HnnZRK=9wndj{y~IeghZ6lHZ<%FtW5}jn zDdG~%SBb*MS;B3S((WTSFaNui+w&o}<67jlD{Nm~<3&awMoWK)@?uy?uWp^Dv&Y|; z^q3d&N0|<1`&RDPE5Yx|@fJm1LUL-NGddG+sT9e0=}o7b~o6;sz$C1nr%r<;jV zd{ilKKf#-=`YGK@u$1}{ig=KdUA|fjXAN>DXij@K2b;oCn>EAqVAE8z{uq(=S@jw3 zg{?pRINSPTr1eLkJ=E_p()ynPGp$`JffIfN1qunuK( z*`ZYN@wV(gj0Z45M>H#?Wcy;xg8D{j1_w|Qa?1e9^XlekI@LN*(yf-vz!e!}qN7EvH$e#l<;}~$ zTOmG5T#nO^5xm1wR#6%tGZXT?QHRP@YihCl=*6eH)^eNGTJ+B0<`yb zLguS;jP_piO{4rK?qJQJe>=hXsz1aTC{NviLwolSm*2bmUE)a;8vQf|=>+zN!5;^H zAf~W)gugfBHUz`{cLka83@my>1Mv3*e+&3Q@?+v3CO%a`hVDEG&m51(@5RZ)S0oeP z{Acs!X@62Wq!;JBk2f2^p9Q(!E>Ak)G?1B2=%4X>TeCLf|GoRHu+uIHukk@-9 zI+UCB8^LR4E`e;^pF~cJ8~3-AoxjmK3-A@oIY@X(3;9Ek$h23@~>S@^x&U@6dn*%OJ2M@N$YEPV1y(%h{tY=;sS}&5V4_O`5qB@tw zSskfFp-p>vhgw!QhpbL-kyR#SRhLw;pF_xNJ<3OJSE6@(OK5FdrD?sYc|Lbf{eH`7 zZJQXGp8%2Bhi?;ut`UpeE}3RmeR+a3HS+t#mnV4dr$(&w3Za=R7J5x$Ud>ze;JPa@ zM$|56SSWxj>`~_(th1-7vkbzUI(tf;eZ`moV*rglHY0=_JO{r%JbZtCuf!H`YcqQs z(%TFf2AVefA=^ZowSe>5Y`}MZn>&W$HTi8W#dl$w&rxAfn?q{hki8mtXM3+i0~>Pf zU=*$vIcuI954g91<&jw*({LP%?VCX5Ud=hAR(KJZ`TY|Ek>3AgEHrBpb1-CTo(G{n zAkmxTmqhSf>cB^b_A8qT;4_~d#a|k>{WD)8=F)b+VcY*Azl0|*A^Aee)C{MTo~Wnh zChE~oTn=7dKmKNu|DIvYAgEF5dk$m3A>;QW#=n;`UcZHu%>2@!Pm?kX-Vz3*x7UZ6 z-hgTJijPaN%-4)_*=_z|DKzI4>lGiDqA$Rp&BIpUsQ=>UtXF(oWVqsaJE#26XW2YF z4&uUouki2oGYvB=(TY}K`1&vSJK)SD%&-{*5@xuS0K*Kg0jS-s7JE6`J2G4Wk7|E6oP@xNm5sADO;pAkG`{9<-X&3=UF$ z{HOdsQsykyPwoE`S}X=Iioh43J_UeG8r`*6g(-z!yYOFRF*fy95J^+Lu^p9+ONljm z5rc8;OO{~MF9$3F6rW5u8{KmSD)(nSIUom8u!v9 zKg{X%+cO2^XG?}p-S(Ab;@SRiG>yj#H%oD^-x$iW&d9=dff!lVIkEtT8!)o06Ir}| z1Hi^#ZMaWkDZKV@wUKQFPFG8YH*V~BP%ZJFRc(Z(*z{c#F)OhpQc>P7uzV8lxJ<+! z1-$M}E#_Z|{SgXK(+u7m@_WsYDAc$=vJ(6(n)XSF?YgGlg_RsFm7D~ohmjVh;$EHzJ1Lk9Nx^rkBv?fdfHL$eZ>65f3Nz9^Art&i{=j)ceysD*Bhv&qk9zZ~$heD? z;PTLv=mMoE<1QD&A(#?fObPzLc^*%UdURVbU{9dVxv5l%$;-8eRb~<7G^*uLEcTa8$vG zcucE}lS$4Z8^PZ{FTwYFi8Aka#VWJ&8AcbOGBN3L5S*pYP}oBM*u)36Dv_#!$Dom?atuU7>MV#fb=dDSLWIL3o3XSzo zNStBW3=7#j)*_qgkWJm0s-sF+_zsk(h0ENEXhHqWn)!fcn9IR@a6gB!pvRoDzsMe-{ zbIWeh%qLqed$m*cjoh-&Yi1#gpBm0-?@+ZL*1MmQgza6Xnd4h7`-oHasNAw2Yv$=K zmaQ#U>tMZZ$HPjw_4-8ncQ(yySmGqCr>choJ{sm#-50>K1iAn?@HZH_Bx{&}uZMvx zmq6`kB`re&KYrW9t(M^=%g{W}Y*2+|u*2}XCB7gT*WV|C zOg0)%65#qf@jBMu2P%2E{^rO@uGtX#-Izut3S$Qy5`Cy?dioyVVpfzgDf}vzG?|!Z zN#}&5wPo6%p4zQ+KDfQI6QtfS?khJcK|Px>B=G@xY(e^Z@;D1X^;&%01#BWo8k&H; z1x$qaQLYdl`MGNIw({=88iYI#|&9?k%g_YGqd-!cC%2@T%_ z85lpB4u%pgx&^=jp7h}quz;t1#JG6k=M`khsUH#VL}k{4U5StXlf>m4Rh{R(Va?+* zrHWfw{m-m>6;@9xQ8)*`nt08!x;JF?ev7R3hOCbK05YzE8ZSNrs{9bhZ%|e$_{G_# z#oS5HN0Non;89boZ zd1StlaEZ`6Mq*-B$trKucT{d;HGEfZW{XiCG%Fum*E|!ty8&5?A=!dE0pK}c!-M#L z6%ra*Xr30T)=e0)J$F;FL3^ijj zTc;!pHg|-;93QdY2H`WX1e?4`DNU32jKY(8O*ubo^60Z5|4)(C<8AcHuK_F|z$1XS z0a)-60REmsBa8n|i$f3cDX@i$f2U;z5g?bj0A}XWPilm`qKVub|Nd5@iLarU(L_d{ zgvT}UO7x(lV70sn0D{y#;izN)WNN08!B!<5m8($+pAJ@O3M7+{-!$tRP|1bJx|WT( z62Pwr+z6oeJ5b480ALr5EPaxewi?OWvTHyoMVbhZ$s+(}=F(4E4RJ*yxjFtbMkBAI zn9<0#7B$i?dQ|IZe?gHHUW7te-9#vvXeisb z7G+zevQdh<+qID#9oIr0Iw!L>rs?X#V*LMh^%5WVQ9k_g=tZNu-3;)uV@&BM) zx&xS*OF!uX2rH_}&GCP4EVTi}jB6OKb;UdI#qg~m^BvdlU)n6Xh9e+TGuIG0%L&TW zsDvl*XKTuZp-NVs2bJ7`tkrDH0|0IVu;51kaGt2)1^oX635_g$r zTmUn3$tG=sl#{N;muMq5+ds2Fe9EaPYqarvi`r-xUO$21Y*P{{p%G#;AEL#% zxsxt}NRzI>m$W!H+kYTmT09bEO^Z)d_VNC2r$0dG;ZrwMN!a28QG2r%%fSnr>{_dY zro~<1Z8vJlZZg8hZ@TgVw0JPGmO_N;F#w(*Fatktq+4US_#}kKD_&h~+N#3$W)P_jTc02O6o7jFMVQZfEuJ zD{`bhz92w-bo&zk>f>+#Gjj`0x*ANfiLOqTpItGV(ISF!N7EPtyUlJ?)h$a z-=wPIqmbE<4&B{tjknITuTQWI>Qn7|ZOixb^`#1RKi6_Jle0}Zy|X40T5^q2Vt6Fi z*;2KyYbge*QIm;d@<+&CxjT2TZ1@)Xcp$QFL30+20+86cq>;1(?=iFhHwtVLJYQfP_YtF1pvWy02$G zi)`86f7Y@G0GOFeHt9A9Iq7bE$zsc9TiyA;%AZL_Tx^|y^2TnewXV1xZVL5KJ6H*v zFt<1AJZ&F4chofwQumG`G?wd8o#}dxNptAPx|HF{*656{X=~IJtOn%cH}M)<^?k^? zlI?yJz|ROg1EA|?P~I;AKzWTUeXo}8r=>5jWe)?T6xm3COl|-$GnanSTM$-kCpX70 zFgvmzp_tLxFSV|?&fZj=Ve{-vtyd^5^>H6$a*W6*gzw>yRrec8X*9x1ca1+#hm~(N zlEA{F`dwsw#Kz=d0-gI80BHbk5vT+(;tK%10IUKqm3QX~Kjrt;4MUK4r&r)Lj0Ny# z01KuAK+I!(!yy2k_mQ;-z{UiC69Dwj18^FEKKTI70q_`sivcVsC@^NWLxsd3k&l06 z!NXhC%!U^hsLCEys<_JLhwm*!yaB3l0%*(ckB5xPA7^T&-Ll!1KqG7W`-UESjNJ9w#cF6GnYF8+^>5wmZ@y~}!6n4bH$$GY#9`8TE z#dJiQhfU4#j!5c{aYEr|C>y@^U=hkkE=(qVJjAGbTuInh7a0=0WG!#wv3HB{avymc z&pS%aE_^Ufu5aU^Ta^37qrR)+nV#e;XY32U(mFR`b-4|#`Vd)(QYa}k3&AJ?6#zz* z0jL7-eFFUev`?c;`HGvuPx*ay!w7s|hs1`70Q?Mq*#M3NaP$!XHZ&~5_p3}l8NeX{ zfQ%yjTBYa^o+I_o)EDd-byb)Xr6M`xEP1_pK}3 z;C0(iF2c)CtmF6veqr3cEJ|K@a+4O?$2!&*tzaE|;mK)a%@>~RAix)%JPcqW$>fD6 zuL0BXzxgrKoY3qpF1n9wXm)ejShKrXsp4igA~L%&m4r6+Unnn{iQe$E(Z1nHZR&U> zr%h$I#mMv7ax75PZ5hL=`<51n{)w$n{+9^cHm2!v0p3%m2R(z7WRyYs}5*#j*y+ZZyd`-^I51k`;S%A-5Yaj?0q@;*-JP_8@7R)*>G zXNF2UW$QvNG41d9{z&Oe5AbBj#vdEi%?W#;@p4G{39_z&lnwb1_cH<+0FCVmyt?gL zf(H+VftG&F9z3YKOEU){bB1Pu)!3hE`gAgu=UWR)cN8BqcY5u>fm04XXtuYoct_{ojT$EI7Dodt!lunyFu3^UXsZ)=V1jBh)oHJ0CHPrw) zc(AvKhfrqYFY6InRF%OiaPXJ)2rV7}&G0X8-Z9gG^RHcHV)3USlcYu|P0iW8Q4{Oho6ar<(l;IH*#iyjE@C=7pDkI>=|;qmxa zdGg{6EQ5c+?8VDb7yp6-7cWN&|AM*4OhpU$SMrR%cwYlV$6xzS$F#>9k$>%$BoK8`<%}W+-PT`-QJQZT*C5pC};a`5y1(I0E zhe>&ff>x!V&o5ZM@?;b!C`p3FT_7kpe>qqr{u6C2xPV|mvM_lu{ugZ~YrpVJ6qkfn z-2lB<_)!-KllpNh%xNDl1c{eA4oxroGs%;w-KeGTGs2nFQ-y&4LbzRuZ+0*IoN!g@ z8HiW-1>x%ARY|}&PzGdRaX_ZNAR~$oM#Bpeg47pZ&*J%lOevlPSqlpUnO*z=N){Fh zGQSuLD6cT-FNB1R#SgPg%3lU#S#dYkS>jXRRmC?`u#6xl7avjtq_w{aIctlbXPLG> z`or5;JeFUpNd^j2O@J|ETmg4?wLVy2kAlr+F z5~&enXYoiP0|dFLcs!ATg6t}uN@TF#A7yqIXS)L#BC_o%{xby~=AVUn9`h1Cq5q9{DLa`h zD5DKAwGR+UWq@2#%f0l=s5Em1d=J*zlUt8j${+yoRF95B;fn#lvHN{Uqe=^3&8}Jg2mn0Ipy17UPXMFqgPVD z1$-+0fOdHmH=sJd;uCx)yjGXOI7>>VK8)aw~(`BIV)^TT>^JfaxCG+seZ^UIgaqM6jqB~$%?Un zSF~NYdaze=JmKS0uR?7lEAIg1%G6|3SaJgCPfk5e`c;J2rk;ZBl$=DxtV{7^e96g7 z-T4b0ovFJi!+OHkrQT;<8&;r}n^J2?zwu$nd|S##zm%Lo`JYPtlr)=u3iz4S znWQ<3WnW9RBm51*Z>Fvw{n>=yN!>|#&LO-nHJUV=34fS64u(*2F5yp7Jz$b0=Mnxa z`x5zold$J!_cG&rBKdyy1aiHANYc;VK~;QjGiM8t3P0P6t=meZ zou56FWETcmvX8l2i!(=BDC>>0rmp5W{eH=k7sUhb9t9x(p|FNVwE zIFNCjgcjP<5q**N5@%EO-}dPQ>d>B7O0NGMvdw_FVJpgeDMU%Uk{c;!edIiE2R;prlst>L7Hm1)_okDBBo$&nB_rSU2JA{u&T~C@j zS#4vgU3b8DGktMtIBD)7yeu`2JntpEBJ~05y^ruJWBI!YpWK!=#7e&ZXHc$f%O3av z)v?iNim9RrADW;l6F7nNnYDyR(Ykp zSw+&T{0&%UO1m8cnvTntEcQyfGo#}wf;~vy@s!mIz0y8e5O}TbLLK#`{huSpAEVaN z0q-(Bb>nEj1B;-KWa`9vz=PTW&ZM%0hYSbYE;WzvP{LKIE4u+6HV1HZ>JdC>D;-XF zp!ko{{VBl+uhSb~-FY+M&dd2l6m4Z|3X_yT+%oHwEFnV92gvEf+HHYSz(UHZ4Jnn^ zxj)!}zO&7y1SXsHBWE-cf=}UPO2;e&SeT@ef*RzNjur4@=G6;07Fng^1Uv+^rQ-=! znK`1Y`femuG$F;ScnG%PS5(6?6JFw3c4EIvkZVb6UMA^mA-zaQhrq>vbOG$KZ16+K zZF4WaGTq9CUW*($_p)IejK;*vYMGjp8K-RcHR#;=DW3l*8^JNUHoFBKShoLNpjn&A zZfEs%6z;lA_CC~EHj>rfl*zWjzp_!(!)=-Dr=TtyO=MRldp+7;HipREne5Z}S2p%h z?k%>g!%w)@m zOd_%`ll|c|Ad`uF0y$x6Wexezwijf#*8`c-0Z1~)?i~YUYF{9kAUl~k(}=VSvJWF( zTsECZRgk@v$N@yEgX}HjHiO&-2HCTT%p@`*Xvd2RWwWLMsSnz%UbWmSo3j$glpsr6 zFFR;6kl8_&23|Io+~x<_*36lAACSf%+nYIu5Lp&v+p^h*J_lq~kevZHP5N_{NFc{9k4CUP8+eS!G>vK6$cPXh7#WyiCFKk1r12}R3R(sOv- zviDP*6S!DRb~C=3rYC-DmRC9h=`l~hAGRnBvMmI=tRLK6$w>sz2oKcwk7N|PWN(_^b6j={gPPChx?9QC;`0L!{@uDT9 zO|?jqK%L*dAPOcDO#}aJ@H|Yo9D- zt)@=*Xx=rUylk|Qx0;+U1n0i=`F=Gm@;#va7J}quEr_Pe$L~J@@sHs0IvDf;*8~Eq7lG`+809VA+p(!WRB|SopBq!qvR>_X<~X z^6B+c6_U}Fmr!2yJn+|={z;gIx*63P_=)C}h&=MRx|gTbu(!HL>4Qo%-EdV7-e6v! z%9~GR=L;wbh(-gzX$AMh;%?+}n=Lt$MEauktd zSY}5VLTreAHB6d0>A`~zlLS6hE_AH7n=mzSq0y!T*A72G>um=3U8OTA*v4{gPS#)L!i)*eY2E%2@ zx}l5Lsz2alYUm;Om--&2@Ko(W4v-Y5v(#|H`52WfQACMO;a+Mg@V>t3zbOu;6T({GE!0*R4R>vO80_GYfpkor5$bsB0;6njzY_zQfU-a zDwU}}cn!=;Wg3>CQdxJdmYkqcy1paIeQ8iBJ#_}MWr?4j#%fGZDLtLA2`Z%zAgn>9 z^bE4opi+9)NkAm1l%7oxqLAGt{HZ=AsFa>FA1NACN-ya|wKAxbUP@5*9qDBZ>YAWZ z+6gM9k7ea1sFXgAun8)qouE?M2`Z&m_6JK7R7yKRrL+@NN;^TNv=dZHJ3*zi6I4n& zL8Y`4R7yKRrL+@NN;^TN^g7CHf=X#8sFdFD3EFFdO6iTGA+rf8rO%-JCa9F&Gy|{+ zDy5yEQrZbBrJbNs+6gM9ouE?M2`Z(}qdX?4l>R1R4JxJ2C!#^6v>Q}PyFsP28&pcW zL8Y`CR7$%+rL-GVO1nX&v>Q}PyFsP28&pcWL8Y`CR7yKRrSw%tLR}hEN?-jh^s7Oo z^v>1D(V$ZL8tD-YDpA{Fst77^0nDBdT!TpL0X1dGXBC1Yh;%$){t3eGEopI)8}FkXb>sWe^PS$X$R<5Gga1un8h%hW!Mv2_j{N6E;Dlj13|!LXs0i zB8pyTYYLN;K-@6v>@1Yak&T=akkE;>ODYo11uUej+K^ItHi&eE&87qw%FpPuGn0QdjR1-uBhSSNLAW|@bW6}hXg8c`8MuSK}9fi{% zQZSO$YY-_IMLlQ`DR6^G!5HRf5Gfct7Th$56gWYoU>v(jgGj-67SSM5Frg7eG>8;T zB%(p2U=k4xA_bF)Xb>rA*a*ZkL8M^HWk8Z9h!jk{5lF@ak%DPN+L<6yFr7%12_gjt z5UDmnq+kZQ4KzWdU?vd_A_cRa0HQ&pV9wh>rkEg7a8N#$8naChDVR%c^Gy&bm^TDD zjV6c`971H72_glD&IGc`1d)Qnz6NBi2_gkY>;$sW1d)OT4*}V1f=IzpWWB`%k%Gqm zM9y{-L<)}n1jtSkL<$x%=Oz9>L>5q{EQhS-x~IE`ebdCMP3V#`39QJ|X0A4k%160n&-KVah&`ki4^* zO2H)+WKDpD4g1=Vic8=ZvTwK9?ERc<8v%OC(ol(pW-|(-^gf%@Kg7*u-UXGlg<7?&f_+R z7HD#2uqm4TvdyODnQXVEpWAF2nPh`yC&1D=8k;F2ehkZfBuEe`SjBEn+yEI`cV39p z!sIf1cUsR9QUU9iIl?RDl+XANR`hvr!L6%E71S}M+adVw`XJ&P{_Mm)-Hh)C`T6mi zK1QwyM$JwTMl|Xw#1$-Ig`x9sX1M!qq+gGiNcYEjlf6E|R;yjIU!r)ca=u`n;}G z2?QMaGLX}kv6yy$GLnZy3P{}(a0|zg0 z)E@}mAs|B~HE4Ag{4XNOfL1$-@TBSJ)vLUL42tkCF>jDP9aFv};e80Qd~e+GaM~s^ zG6~vZWTfi1AjW5geB%u#&!OysZlL}uGV)bqOKytH{V#kr9vE$7qL*eb`r#5m8APIQc3v!j+^%X8zvD zNE=2*x+Z4pX1tSb#@)zBR~s2Q8(Voxh_H@){QVN$uR;1&L@2sn2H<-D!pO)hMn>98 zWW;XwqsR!^naD_ciHy9Ak|r|JKEcRHyN(6kehjvBSK-3QNM)k?UZl?fLG=RwdQVac z#w7YMD$<8hk;X78;`MbxAY|Du3W4-_gaI_91L9 z`w$K<`w$5)`w$5)`w$5)`w$5)`w$5)`w$5)`4=$fM2c6Wgp7W+FbS#&|LNr&|LPRV5KjBsx2av zQbbqiZ5c-9366ygbm~EJZV^$ z@LLAL=Lf(4JVwBD)`ocfHZA)p=?q9RHT>9-yaFt zC#D0={uh${>_U9w4$@pCRh2E{+40nNB$XZ4ALYH&b4V{co^Zx%&GRhj_H3eb>B%52 z_gbF^x18><97trMnQ6^DLR}wAOY;xS(6>0*Ljd zkEHB35v=vI4&2kE?}|oL47Ux%LS~gT)@h@5usq}Qe?|nnP3_vG-qXk>4eQ$ncx7zdR8Ww zL3ZuU1*~A!`9M1G0#-1aAXG$lP54ujk+U+voRg5!-dw;6mJCNAT#gC^O9^@%_;_{M zq0qKDD-$edh2{cQa4cbSRwg)(usJIetiW+?Z$$@QzzU8hY%X90D;vPloRtYqAicSO z74R2v^#WFK5*1@EUL z%mu9AG^U#iSiw5N=B!Mxp0K%q6>MO)o3k>(#zP>pIV%&KLHW&DnP3x7H<+_B!C5S8 zE?@=UAZ#vR1!ogB7qEhJ2%8I7!Dhnd0#F8JT z0#;1Hw*`*IV%&~NV&{~tKcTW=E7BQGhuV#D!7HPIV%&~%BGtOSHW#e zH)myn+X-C!q+9TccVx1 zvfYr9pS=!#tRTA*b5ddUo9Mlw>@~2SWcF~Rx5_So0#n)PNGbMO^8#0S*JDwvbEdp! zC-kwLy(zDzXZ1SZ0#|u&ik$Si$OW$QZqq?i#S2{J-I-Cv3tZ(rNM6MYT;+ZK0@3vB zO?m&_`nQQPH2TWds9A?usM5EK5RH(bM~fu zIAL@4rhI=&Fv6?&30Sn@#M0(iei4Q4*qWjwCFn{z)+t#+gq;6GLIrEL1wOE(tlE&W zGure?bnLxD^NTu7r3%=fh+4=;Hv0%DsnAp&Eq7Mvo~3}z?F3_a8(Sx9=Yw!1+I#r z=fV+ia;O-_!EEM?idv?cvo{sPIcb=)Hx(l|#@ANz0$0WUmxE?)rji%9D(WcQb(zZh zkY6#9)!&q<cebA8?xGLt%1u`Y5q^(yR#IZL! zs63JN%q6$^K_xG6Rm{5zNMlghn>mLNSr%0C0$0VMyMe3hNtPLu8fve(( z6!vTzgGyfDs#wq)$mXDu7q}{pBI_+dB`jao!9nd4a3qI3oK3nKvp{(55~KWZtMao*n#2*GgXCs#qzG zrduU1a8;aeJ#vz`z{USGJ@JD$dovX{jYshC?2Qb@$B^7czQ`71?^(!Il;i~<$$u@( zCxjf%DWC#ULEA88xj#VaKBiJ|Nku{-U}3|)Hl*Sb_=Rj9AdzhLeonSon-?W(Ee(}u zXs$+Kls?SnYzuQlT0z+w%VHa9D@vXWstQ_(VG@!e>srf+c9WCchVy3|^eK5fXbEXk zEfQ+W-mrwUw;V$7$sko4PHQsR>>uO|usO6qlf&L?quEn!HZ9L&yDeR2vuR|K4VLHF zL>ikZBYq4E1tiGXn~GKJb~$^~rt?!sElNIz?}|5ALMmYWGDmo&Tte`O2zDPld()F{za-sDQzjXvS^2n_W&8o=F3TD1vexA-rEU(d6V zepsghuji=%zD-~yfL{RU^+zSYy^8C5EK+x)96`#)IrbzPMGNdS7) z<+8u8W%jko{yAm8i|lXrKeOx~Bv-bxuu9pF0nn=^m;IiW*$+bq?o=qyDzmF-5LN8* z8^E;ZrN}!E4Evr3pjSKPItyfSF-`84RVix_bW?)Egh0+S6(#S5VfDL{HgbjUUktAO zrT4Fp-tWI^`ATNceb05M+e zwqeNU0yJ$HN~N8v#gQf-f5~YTstH#Z`MBjYF64B9 z62&>a7{*P9J*!nMf%e}*d5j8w4Em{6UgkB`+^`~Law2Go(N@w7G}rXdnf^ep*K~)X zSuU)REk8xAao-tG+C~0JU?iq;d?@UdN)Z><3!7bgnO1YQ5dv@a@`mlyv~>{fYLlLq zs+#H5-k}-0Lt-Or?IW7;)0~W9PdTjKc3J&WGd>SXc*9G?YIX)@z=Ijyjo6rX;I=9ah^v~cjg(0FnPb;|Jirds5 z_dbnZ7$Vxs?{2g=M6~yHU`Bhx;@YdV+Ur5>^;fogXx;Vx=ys~P-=Vl@F5N>lHw1vu z+%_!}YHol3TP#P-9Ska?xjU6AJ}RnD3^gZjk*lp$vKzqxwrCWD!=b|t&~4FpzP|mhNl$W{wD}Tx5NHRDVos6cT59XoMeVwq8ZP3#-1+B^lI1a zzXrt(`Y_PiTePZUQ2~3CQ~R9Mdhc}pXiv{U9lY8HmEug70wcWkCz`P>%<$@7)3lHk ze1|vg>HSgXw+3p9`%9bHDlX|qow6EvRO2U*XZ+%0@RP+mxOGizJ=vRZ9+h10C#w(| zU(R2OU&!Zr6VcX1r12(oBtflRF2f1Q$8VZa<#}Vyl1%a*G@!tn+*bwQavK8rWAH41 zuUyR=c@;?VPDPO^a&kfNDf|WCypb$DJLaV?P%!S{=zQ2tbFi0To6Mxw8uiY>9QsKl;2lR=bpCkQ+{79o4uwQ zQzjf!SNS7Zm}`}LQP{Y)2b9WnN3HU1((OjIKi>?kUO!YiXU}&)bhKiIy+FJaKKhwT&_5k}r*x<2Q@i)wRfA$gS_ugBLc$vAQ@)xk- z9hKR-`RoD$em1=bP0j`|8h?4?@%4q5PirYKFJvt+Z(@}PyoCh^pyQLI#LH52{w?Y~ z1c?V^-ZfLpQOM*6hKBFt>$HXg2>SDqlTp$?fOTNIwTN5KnM6|OKo(oR{!HY~F1{T} zzk!yEzYSpCKmgkSd=o$kDN6aWTYSor@8Y|_yfikSaJpnD7>qd;`CGK9r;rjKzlo_v zq%mgzv?7f$B4s|LuoI_(R7A4nGZbmEi1aWep-4jqsYojUl#s%T6qwi3mL)#~pVse^ z3A3?El(Z?WGUM|`g#HuSq7lTRF3ZrZ&)4Vp+itR1B6@L6C(ZhADonq`GKwXU* zT;R3c4d7M)pbPvSW#z?rWtC;~vVot$&LGj`By@9IFR!ewcx3TZSbM&vBkWm_ z1_?$1|1qm*xW|9Vp7O6%xt~{7T+DJlQt>h?%VY!!6)RdWwVY^)tpbYi{i)?FQPvfF z1|TzCj-sQm`pgV9JWyzCdnN>$fa*;`>#k@`dA>iUm?GJ_E2>ehBRI9mhfMLjwjySM zCCx&vq-iVVYUfA|MYVTwfp!oH0aTXzQA;~!V-4>VmBC}NHh!=6Y#bs?)KwL6)7-9Z zTN2oFbc+&*?gvyQBig;jAKTt&lpF%Tby0o0%f<_H>;|l^6X?pGPD!A>9KJxSqg;gf z6oH0WvX7D~+SfrLLO+KXX#Xgex~@TBomNv2z{~~|W6#TW5A5U*DnAg&{Nh6km;j3$ zBy|lwcasl09E7wX=WX)6M7yoy!F4DLuywY;Fc!cv*iHAm;VA8y(jzP*vfsZLJX;qL ztSk2UZ)7Aj#(~L(I~z(dP~RAl2f$dvhDGXYRG+=t8$DybtU)K!PI|Sk68jzxoon}a z-h`+FFcU_krt~(`OOqT`Kwpz122_26(>|$Sic3zZrWye+9p9e%nC8;s9ps^T6wo}3 zj0dP#=uX@^3@OkCQVbQ_nTe)*vuZq!r_dJ;wH zOT+NETbPeJ?3|`|HvQT1Lr-2W&Lv@fH-v}x@j$(*SX0wL^QFk!R zq{CxG*3SVpJQ9!19-*Vu87})rt%di9O6U3zw`5FRqfONmXpGw`IG2buE3c236CG!L z(0Is5r$UV)eM00(tjAYhGEw=#7TLB*%1_bB%7!S|G&m@Tr>G*7c&gJ=;&`UHwHik< zJ*p1pUZTq2RU&5iVbG`|`jps&W&O=;2n4^PPQJdKHt4`&O`-A*qI1SU8tbFyxgsJI z7U*@iM#FtTofwmH? zfLzx=bH|dL=B^G6&Md4!X6l$4uo{x4=-{JzILK_nAFTWV69|UYj9;| z)|e8FWBLHBj-muCjv~Z*i0Nkh9}vrdqj2{^)U>Qv?BL|U&x(kitTG=&4Et7Cn#EWkrM)Ajo~b}KpEqp{V)8NOJ&7^A_{jX~wy zqEuT0#!`hNP8KQbbnZ3qb`i^m#_o=IGx&AkUE@yw#^y1~ZA&oHqgG<98Qrl&Io1s*Uqwec+7+)birT~A4{Oxz z1KR{g5Dj*?17n}j2E?v&z*|;15wWv`O%_c|Tjy-uh2UZ-hn(T(U@0nZp*zWtrCC7uh>b&jn8v^OJ z30r_M7n2`R6stsvHP~S+gI3oPYT#~61sx(06%Mn=i!@(o40lE(YH*ekSV)Lm(uq+l zO1(>6EjlSr>Zoa1A7#`ycM{4j(7Zz$p498fFfpMsrFJEIca}w|{#z{z%7LE^&A0gg z#LMd4koJNVvpgj140v|`St=G9Doi!bs2&&x3?9UNT0Zh%uJ3@iPa6(AvzAJ3dn#5 ziB@uiTn#HS8sIXDNyD9ox}!nOi8O*dxQ)b0hj27v^=o;L zV?SmeV230p5X>ibNGhsBa*#Yg>gjj@9fO=*bpXc3o;&iI&wci}hgQF$j&V z+xgq^E<&KYeT;c*0iy8`YiDfE#_r$RG((w~E!2Aqi%L5a9oteHJ*23Dvvs!qn60A$ z$6>-1zq7Hgb9Em*3BYt_sW33<2}Z|;4k{TFPvGzx8%z3Xcro5!*6Dn-=&XCcba=Vz z-pcs8w_`M+VqbBTw2VeS+4XlEFoZT^Li)^mqL6jpBT>~kj=$BJQ?c4w$&YXi%Q z_Hv9%%n#=yjoIQTByBa^7{bIIvy~aeHQVMpLx;1Nt%)SV=)y=cjn<7XnR&y+k=2lg zI-?9lhv_4Fn8QEC#LX6HqzR3TicFst$GO3oKjNdIr9&rwFz+)CX5{?g}wBxIxos6Pj!i`K2#ZjWi!?`vVExMWyk$;~o#o65&hwRyd9mj!=9w~{ut?ygKs>*@frzbnFe>cMhF;%J0-T9B3209#ntR-Y zBSOcF$SaF4ma`9xbBD}dd2npUhZ!?w`Dm9~PR!LlUJ-TC{cDiO#6wg+HXb5q^LU7R zECxSmVCLHJBnk&{^jyWBni)%9F{pg&cnsQlyRpK<6uOl0X1_JTX|1>(d+Y?_n{DKm zMNK0Ihv+G1u_?_qSX1p{befHh@PtXuUMn6p#mdhKo8nn;oSg2!oex6~V22hB@~=N? z`L~-7BgaCkx5qXQsXI)7D z#3N_A)MA9yiIx)W;w~_&!Z9yK(-kGdow*zup+RCwWOsCrqCBxfBF4O&vmsdf#n+pL z0+XS!b~5W7r--?Q*mD>P5FHk=0~C=DXa20|grN|H^9Mvrw}HAV(m^cSuNGpftOSo; zt$6IPAv9Q%5F5m?fXF$1JPvCg$EwSMzu*wH3q?(}u~S9)7&i1Hb+&<&Xrw`O>*vNw z#o^%*jFrzQn2%pVCp5O$HwR0UH`_Fhda^!KqNA2UO#c%iKJ=#(9Wf}D99)aIOpa8{ zjVB(!Sf)8U)G5YOO?3&3;BYJEcp%-xiaA&nZ4p*a}3#2J&^Lo4&0DlpIvH4fT2Vqz9ZhsRwZ z-UJg%D4=gVGL|H(C)Zt4`~PUnIR0chzV7)u9xeUTwhzs{TC`+}ySINZPUZT!fBr@q zMiUz}+(xVGq+PmCrNt2Oh{ zT>ny|o`<^^ShQU?fuvc0I5tGAr$jmUNsfh~X3ak=ZnYAWas#ro?BOvQ43iO2LVQi| z4;cABV@+VU5Yh1~yC(Suj-vlx*dxRB#VptvJuH|flt9Z5yE!rBmPM*1&g80l;W9Jo|KW7uj59dhvkDCFta*4d!)dTaQ zlUL68)N`a}Z%}K85$xG*K1=6L?`GD+b5N)SV+Bt@jeerD=Q?K5By)r!n!}^1GS&k) zN5OT)IA^{QAH(yaT9{SY^P=cL3f9t&;7i;H4p_O)439rU6nt@_B6Ko9r#dKlNX}MJ zTpNR%?l1%S0gjE}Xt>qK7OV zCU~ABOn%-!+n9HV4Gra=*6$257ChLxpCOTNvBPPo4n%Q8@n^g`#3g5V zRMHG!y>TOtx9sEI+)0DyKpfX(&z7n-M>(y73mNS=HVl?A_812CH0%=&NO6HY#5c}p z0=pUY9LjQn_5Bm0R?#Wiv+>fD$&mxeSx7Z#DUIyXA7QVJzvN;V=JP zmx^(x89hvC?lk{>j@f;w)BJZ^Dq0VOv6FjU(YlKPjw{0O(`!d`IfKl~krx$pZ}UQ{B&TH%Q~?hv}MiX^4yS5 zlxxZ#9LX$UADbU*=lq!CJ2V^;v7Pf_sNOrg*_!hR*U27fXS)Sv#y-mUP{%`>HK*ex zbN!>Z%tdjR`ERkej&{;5oKF7lK7V%OI~7sjnh|hZ^p5+{w)To>)<)G4Z_j;l-98?6 z`g<>B#zW{%wEeH2O%5$YLW?n5a@{6|!QVKYtYbz!3Ld@5P*68e?TlNA8q1Stj>Ny? zS+o?eCoYUPf_pUE*JxpB9D&&wyUsBMN(OI-T7w=IEfeJWwl1G#K+87TCSVhtJKzx| zr}L6aN_N=|->5@bRA>e(?kC9jMEk{4T4glfTD#$WQUwA%S;-bHoKL{b)9oB^Gh65 zblvK2y@%qTv7-B@Iw%eP#XZsgjuo9V55ufuS0`egimpjV45!u}uD3yaTPzE{#s;@@ zcZGZ;Xp4hP_rkh)h~2$(oE++5*e_=-=dfvh?b5m^tmn)kC_D?mQRF(Uxc78#N{BOz z9SVqP!Z{m2@9M1c;LVKhv_8!GL-+B&b*t{3aU-?de=x0$q5^tO+Z+afLhSn}97pKv zhs_%)R6{W@75ONXG){1`&a2Yi2Ax;o&^WLD{mZ<_%~2cfG7l)1d6Y(1eQ;N~Zjxa@ zrNE9jVipSn8hP=A&yun#*K^6ta*%azxIb9A&NJJ}nv3T7YSj1Lj+NYlq+@g!Ja7JKpiF%<8t{{Ei*@!$5Pf8%)7m-y1$Wz|=2 z-aw!I-EZCqmzOfMy6Y(o4lT@<_DGeE2|PWC)+aFwbsnP7<;E6xaG}=a#tu>7xk>Yt zl5-m^wjIXl+Q7dGb}h)k(`>_RSD?5*!o{QBD%h34|%3SecSg9 zjW-TKcFsl5P%Tt}Z2OM-c=juP+_K@q}^`|4>E>@hk$ z_b)t{t}a1+esnB7*NwOV0a)bU^~gOoHrz=AW5ap&&Y==MgF;lm30yjJMvR%e`i3;k z533t@JHQza;s@NThh{|_J&m%yPa~-DBe=5Tjfue3wyqD^0DHoYiUevO!7J)UR%OiL z#*=kOF|P8m0~>_kU_>y%yeh(dB83s?-cUA?S1SzkVI!|vyIq=x-j54&B{vK6Fdkqh z6_k`IrKPo}dCP(E4DtKO81>FuPwYND=iMg^B!mZdzhs$cH^G$Rub;sUPvQUn=JKN( zbo|#GDs$~KdgyFs5w22Vhsta+jhQFO@ZdrxM2>lVjKL!|YJ(g-_EED~A;-F7+tJ&O znvY4lYE-+&6=XZea)M?E9ftK`yx_@nh@yHqj>BPT&yUDeNUR%kXJIp4^T=&DfNH@m z=Y$zojgiH3`fGMii}T?>^QKlfD$Fj*zP9jRdDJo7gU3-&PNLh>re89%{f~pm|JDHzcW%lu z_}tPnE_wb{i1+Sfop%=Vg`=Sp&AmgNwN!?q~PF+!yzc_O_hDlqbe#Gi^4fMPqFN>`_RZ2 znKg%V4FpF3jF@Yd<>G-HG3(}g^w!C;fdhNPhb+r1|tuy`?Kky2TR*SZ9EvyH*TV@uYN0hLRy##QOspt-AZ#)xdg!-WI~49~jj z3c=nES09O|^=t`=a68<{*33oQjW^3c9L8s*5fYy@E)Hw!NM=R|;l#{18f6GX8LYGh6&9^?z(M~dV4tH|4u|Zkg7}=m~u>@svJ>DFryTk>;N4fqh zW?k@BMj|t<&5e_qFz39;IU|nix_Ug_irQm{5zn=ryoD!RW09b$4@g&=O&^LUzN zd|~{AC!A{h{E{s27DrCi^NxuS<6&KI8r~;v*_#>%THppczRa6Oc4b}{kczuk`$HD! zTRtEyaUSXbEwwe^4FmRGQCchwna$q82p*;m^D`Fzi@j;wEOTEe<34PN-6W3Lw!8Yn zAadWW0p}3CS;Mg`q~i^0#wpmX3@;3+!^FBT%C#=Vaj53OSG4|fiDRPS5P{{%;m)@& zTGtH}K}|O|_hqiuvA4KcQzt&$nHb!oP~yMw`X+j#_*G%2PAH3>RlT}>cbcpcog2b@ z2Bp7o0at3qBb}ZNSLV)xd=3Wbbmqe8db4nXQ#GD+5}hR+s$Do?)%X9{dk^ras;zH4 z=d8)FLzRS3yhXrXNWc!60N(pvH8a6-RhUTt3ouClfh02_2_zvi3B>{lO;MT91)QK1 z3kgjT4BbWoh$tFBtT2I4RQ&(eIx`_4_g?RP-tRts&;O&$Icx8I_St8bwO8K;W(}Fn zqXCTl&&LvIR3X3E)=0YsdN0(Y;6@sv%5xQ1IQNBw#lWQe&IcN5n)a9WT-Ae(6GY7w z8W4W`q0olF`1j!uAfz4;e+rVjx~@XOydn)$~5#p!jRl0+ya<*hV13V z$dfmTM?=cW$3k7pU-Gy-f-ZQ%z>@zQDKhbS3B>3;k11K1WiZKxRThdjMw>j#|L^xZ zy4bGsytu1D11~%4|8;)Fm?n+=jxc!V1;FR`@(WN^2#W@34~~N;IEE+JCESp(ywBs% zU(-1u@5^9qzm8jEpr*zKSklwXN(WI}FkTVAKWKynjCtub6*3&a+aUhM$A{f!tOCTk z3kiCRDgXcGF#3q;kKav@xeF#?=SKTwXby7$wz0Ux9R9Z@L5)cOo>*c8^N%f@FFo5> zSj)S(%(fVwZL!8|Lky7%XIr-m67U88Z~FcJdiohi?;k7C8?$dAD-$-pYM55^fiK;2MLCbWEIk!PyfRRP$@&jPq~2pkPRb#P7pUhrH$*gyt99 zY8dn4B9pYB`CpJ}LTIG(FJu1GU>)vlj0zGM72wFNi^S44nJ>t@Fv=Qcd!s08h8Uz# zq&1d@U$A%mL(8v_aDqa@2~$u+a$bI7KEIB+Lz*=Hm^2?SyY?f_;?eMj_j>$`b!TS8ri~ah+&y?mZ1$bEKYIJEU52NP zaA$W(8R3q7BF&W<_RouC<^)R&PkSOZWze8sS8_+F{(n&uzbw|3Giu0%uM7)&^6|70 zF@wJiol6f{vG7aDtWZvx>edAqE-=EQaSP}}YDzKx5Jz=VXvaDqk z;TxXnPKZsQ3>6cmn>4d>nRGKPEAXMz$6*zC!Y|c+7-pX+1)Q9}xIl43_J!$JYGrhf zig|!?WBx+9c3ew_n~2uQYu*d1x)H#d0v8Iu7pDBEfs~tnyYNqZ!(A-jWlqQI?)RYV zEy_}c`$T@uqTiwoOmKIhtSTfWpn)32{P zsdOq#SygPN4Yg?IYV(XTN{>;oG}`W_VfOfkychs)3Vz&3s>FX9Sfw1RjpBA5w>R^u z(4YglilNM^N*Zi$sLjXOTk=YfT}CR#iwY}esGjmBzxhy6rkfs9R<6{G|78#H9lr2Y zsc?s`keq5)QL9tr33=IuJjHK&9o0EFm1^@{(kU``R%<@`Mhj4jDr#L-)+PSQ8k31m z=PN4;PS%uF>am(@D7p&MR5{D2sd7@YY88bcYv!y>Qc-K`)No`)a#6iA_pSD2k^G%R z%_>kZ9tFK>_}B5&0v~KqZJ(hQR!3a?0E(!lrd8Q0T6Nl{)~ai3CN0N&+K`LsjMu*x zu3}Ey)Ro>M=ZO=lc8To^1!E=uT|y{N-= zysFG`=&3{alnAGEVzVl~4CbFC{`uJK;fwk8vT55W+FFXWTS8xi`P9vNuV@wh+#PuR z!WXTZ+la|w9X7jMR|wBJEU1=!6&-;18JO}XV;~#n{r3uoBglT5=!oiSzhPK#7ggOPlyZ z09EENqS<6dJ8;h}J==uu$7f5WO?;}%E2vB_Fh0>t&Fs|FM>#Iwnxvv(Dp_?;rdGh* zcxqg>On|4ALRZkq(fkz?m7P(c{uMbevu|gNRy$gXy=)ZQE5#Nx6l*1)Rb`ZU+bFYM z%B%~PIYLI6SB*0Jj53R)Oie?XmQv4iqj`pYqhvnM7|q>Y)kGi2t$iz7dTvh>y)%Q0 zdCX~wna6~VOBb&&>ko3)&K$1fJG1_nrl!*$1jB1)zj=pB)vt*{fp4?98_$}JipS^3 z_Ze%-ospn>_&%8Dw3AUq&YTPzkw?);q8u&jpmu}SBkg0 zkAqo$$@*BbW-9$=e)rd-ohZ0MNk{A)%@c2v;+IwiAKD}jRmwvLjQZvUvkpksJgH$@ zu)f!&iegQ_v!SV{W!L#i)BErXpU?N{i!|(UBNS7Y^FZYM$JFKjIoeUko8L$~Hlh+6 zh({sVE~XekQHCf+CLS-Q7(vzz200Dt34a=qdm)Mp&-`yteiu=7LJs4d203d`Z*tFM zGSh?rn3TKhLB4{Nd&Q)+!HyoV#;d3~`@CIjYlf7i(ztxyLynB)nL3Mj3LY8D^wcb3 zy6(tWo>(uEa;>3HHCe0U$8h#p6Bivnh7mrQ^%!h9a!2P(dIC=u&ls+8VmOGqxdqDV zJT?B%{!H)8naHXf1C)u(*Gw|Y-yg%v@*NW=>alj{9Yfab-7t!p360YTw zQ(Q;USgcd5M3O3=8_QLkVQh}P2?G5}T@9CM8jwBi# zP_cNVPWI4=MuSdE6XpgR^qI7w)M(HT0=#52=o+W*^g4>Dtt*TjR=HobTS1TOS8Lvn zQQs?4?n9%#Wl|rySz0$)vJM*cl?m{jNxu~zSes{8k*8IM1B}F}1#k_cDV~i+NH$bu{#`~WtlAj;W!JVIaVs)}y# zQOk;sC~!a~&;pXZZvR*y8|>wP)YaCz91}o4pv-$?8GUUqTDU<5Yy-KtMJd51uIH&I zO?;bbf0ed@cmvoV({{5_OT}2;H#U?0H;tC$`+;Da1;}m1RyaJXF3vGL>EpyQ)Cazz zqj~14MD-M?FNW1h{OX$>Tl(=#_*lN~RdlnLuCmi(m?Vz4lhjPVPE#qLa!DE%Sf=W5 zt;*xYQK@5~R0oB2(^~0`ZMqJf)=* zE)x=fK9f3T>UwvEz7}Y_j-k=%tN<_b6zJlkb73md_I6ip^nB@u@5A&vH2!Rm748^n zR;71oqcSN`MW%b>;vM%MQk{k>TP8)>X_S>Nv(q4Dp-y;fK4!$Bd|t0U4FoY*2LWbl z7RO-+xG0LS>s_NV@uC-H_xdVKn)7@Ce^R05aZjOaC$*@ciUMxI?pSKBO2`$MNx9Xf z!xq!KVfOje)I6~Mgx@g+l9YqNj~p` z`!wv0)USlP+iA2Or#(g>40S4#<{iSf7VSZ6=Lk4ct1Sm`R627O7?)7@cnWce_0CYrhP+!CShnmd%Ws>osWEl5f zb7eHgBn;utIZR-B&5S00&S8}4HQO0@aSVp%i+l_EntS{hiYHIdyR`i~Wm~Y6Yt?#H zmLTmeF~3H2`SxA$aW+T4c$NA}vKsgZWm%|&pAP5N>bJDplAyLbRPQYb`0&IE)V49) zZ>w~S{y33FV{HGVI_ft>*|=Av1vAV%xZlYA^Jc$(ZIt`tfj#yxu{$SM7-BQfsVq7( zRe(fC#%7_hj)7El1DcY{!}3G8eZwY|raEoJia$gfFdeA31y_q>I*lt(F$pR@zHCT* zf+MM4TzovJuUF`XYTAVf`&U%*W)3zIplj?6fF|S$CNSHnte~n#kk|ByKA(ju(JLav|?3v@^$^5oY-tbak0K(-SSVr7Y33FRB) zRUi!hk-Q3Wq@aKch5iv;^Pdtk7ZETQh^5YpvVvqw*zh3P(gn->v>H*qTt&_M3pFpn zlo`R(Bg#Gvw?ldIwDmaR`;{LBIEcYNc^ox|UvVTYD~hE@m=*jQdp;(9OWug=yzAfY z0g{Yt$J>FfcWX^eU65Q@dqRi=p+@AX17(nSs3=AgJ4I}=LbIeS_wxJR6|}KNbA{fx zRuVQMq2}v3w%|R1z5(?s$_)9Jp>-R zsq;%}>ZwaXYgXb-U&%%^Pq){+254^{f7#2r$5B_O+U$y>V_|;!AYZ>;E2Z|eW8E|g z+fA~Iu4aNvd##}BJ@fMz%^l>;qU_&7i_ zm;fPU)lw%F`95}lMU<^9{1bULNx73$tnn{dC8=_nsOdLp`zhBl-0@t^bBPIkFqDk@ zb^X@X)Ev?+e!~)>VGo$3IrGNw>kgPIuD;`H&AYS=ECMF!NcE4Ovt-yi@b8}Cbp?~8_Sp22;pyu{i)Uq#EFzBLiY~GOH zjq+2JXWtX`)YSUP0T3Skc{WI>I&zb9nM7F|4oSv&AV%(a^Vtw?KN3rARiyLGhfh+D z9Ul>Mn0e{KiFcs+k1i%+WDts&q%&>~?4ndQ%M!&K3)PiF{U^gV<6ze?wy3BHclW*%ImKgn&HqT2-T(@P68@27EQ$pv1W&+( zX_AMov7Z0E(U}mB2Ywg>^uXUqdT*Y7FUY!hmoWKvhxxmur`_163_>#1hG)UvF}#B3 zne=Nly$QC-cYr$euu;FuZL)y_9>i!}xaohP*SX|Ic+r;hZ!+qQc=LaiX+a&UT@< zb+N^%=(v<}6-7DL|DkLb{>M*<3^g5-(2TSi1)_X@DXQ) z44V-A+g&>C-v>A&(PZ3o5lG=+a-T3bPzgyDqAHu2=EIPKxCE&lGA$~i_h{- ziJ!^@t=|3YP}T3WYWqA2ugqs&^J7iKSN?px8_)XBG|>3ep11f(l7C3U+}=W`@_jT( zb4}gLwa^dwijj;?Q#FfRzt49n7RW9v;FW)bcUWbk19+%|sycrBcs&(ExE~2V_oMt; zy3B1pI7EbLo-E-5Ny?FG9Y=0AU^mAL)aYk|9tf^UOIw{8Q zq;{WDKnER7Y2Dd6p3;dF6I; zJ^i7YuE2(#YNZYkDR3&KDDEYKR?WD!6fPTTCZskI*?SZ7G`>&g9~PK5$-ow7%S=YY zOY%heI*Ifi%nY3pbTmmsL&kkM#0Sa&_7ZQ{Iu<&qYV^x2Ql7b}h!lTJuys97B_+hq z=IZH~BY6pxnDShmQcFl0_zJPQHNZe#s7=y z`#*eNQjea=ac%?k`3ksE-wE+!P$Qo*9&Mql7Zog)g5yEw>QpFXOMS3l^qHuBNURei zGu03)059=77c$eJ(0}<$1xCTn?&&NCJLPCmOk1su?+fSa5|YTu4}Du z85^Or6oC75lU6I_!RNBD+W$Tmma#QoVqIO54EVSC;YK?@7Egn){K93$+xTPCgHv^y z(mGHp=Y4l$gHFkXKGy2>x}lD>-bGJzjI+hk$Xdu{VmHva9LTw1OUAgp6XToNyveOM7>T6Hxi<+*31TH4QZHtHY+h%jqXAq7QgBhfj z&Ktbm)YyTT*VM}Dop{Ftda`2fJ$+PGkDjr~)HH@%wMmrZuZfFKW8(=swJ5Qb$M>ZO z&uDdT&zs2R8f)9)?J@9*_&B;vMZV*J1hjABZMMwB_{83^G^&DM=l0P$y|&#Q^9OSF zy${?;?P9#P(f7sDebscchaTuiU1Ok>_u44KN&E7c{IDc0dB6PclwnCKyFYdhW%w!D zvm6t?0t+qi?OUPMPAa1)>vzi&9FzfyqMBS*Ff6J=8{2yR7r#SpHnfSQ&efME4jgqW zHLs=!ZG7VFvc&lA1CuDTf}&!K#ECr;yL=VbV-~B+cZYE?S)W$(^am4Xt0*o{P3@Fg zkxzeuuG2!TG@EMEV*nBzc%X!uYKF0avY6AlQ%n0x)G|QLjY0$WKpJ_z%KJhM*g%WN z2BsZSnImWq`Ow5Hl>2+)8PH%!TPebNJa#*l)&4AA`3oXgnzuiT34sL>5Uk^#m)pA$ zda0%{@l+}5zl~CEZI%alni9H55Or5z3=C!{)gJdxak6{(Y|TQ7~-!Keoaz;tVcrb9I54 zRb%@rZdxOgs$W}~HBzema|H5$FNi?8YVGRV(nmtuJit`sEh@m0oCLn_p#rbs9$I9` zY}uj;z*^yOH-p3FtTzidFTu#VgP%#ne2Mm7b?6;ciWO{7j?q{YH2bm4>}-m1mD3Qv zJ0shj?#^|Oa=WwK6zM82r{VrF5Pjihl;7=kQ?v`S8T)TJza@!havCZIW6e`>x$ITD z!g!i47w&#n7*F%%vT1(A3I=yVN|&$HDN}xik(GYcW%YUlChJDokh=dqCu@V%-0x_{h9)WIx-naM$LcsgIN`3* zmfumUW;npaP$qT-&qI}JsG7M2!*?Ykra_REKy*r%*HSLXEK2p!pILWkfy~cIZVRl;=~zArt`ermmygF$VU*Y#JjrBQ6cZ~?VhU*#EvdtJ zVnwskWEdmJKR}9;#q!k0m_@q^TAdL99_FlXG2vkf7+5y~k~$*A&};S5pBpUSFasI&W3z$;bzt=z49>$-xs(?QL=7{BL8GqaoVL(3# z3s&!w>~R`6F=URDD#u9=LPx?4@o4h0bHYS>M3Zz*nlw=hRapo1JPc7nE&fWf=c2`Q z6Zk^@+E?XkcY~8I?H8NWH`bkn#4_e?Vee+VV4D^){*d9j%IH zfGMWi@xLqnpUub5D_SjVl-grAFD)&dPotc;Pz#?jQ6?9S9| z8;cz@bA@@{O^GRGA^_^hOE85edk3C2PG6~x)4*BU(w=jM`RQ}eS_=yF>owg9b4X-d z#u=miN9LAM>ym}AO4tGgZ%S!G5*WGuypdTTO)8C#b3l2(N=M!qU1_lG1!2>Jc7#>M zl{ymQ=?_d&O$aWb>N!+WP~xDD9=ff1+499pm+#*F0qV1}xM3LVk~G>2JHso%@38{0 zUM760=E40B!d;bW6{vI?9$6|Z*bc@z%>#QMNp?(N<#@vV-B~>Uyu1&zIE+C9>Q)G` za=kO@iU8g2n}4Dxqvr@!+9iJYE)}a%CaSjERMey$@5e&XQ@b5WjxO=TRP=OI13m!l znxa*A2XI1`cPVrqsubY&A|{)`BDMFo1O7}TT|SNV5?@Hs`K(8V9-LJ|J4*Rot7Add zK7|5r36d(+Ar=GlLmms!)@n>7K)j#NSI`rh{-w?dYef|v&|pbW2k=<|$3Y>(&@UpP znyka#3s4}>r+2_wo{WHkdYBzl$f`zgf$jF~9+&J@}uXe*r0H4@M z0Q2PIu2gKPz+@NEkrzvt4e5p~K@|R#DOe*u^8)++3#2cTKTrM5ajPu1p`tRscarwV(o z1y@U|`?(_UzdaJ!2xpa>t!ANvX^M@P9;}^rQ;ItUWJ8KOp4=V*TKeVUHZDP^lb;sB zUKxv@DdA%-Lld*Msos~j?~QI2%WQ6{cVVbPpps@-hxBv4>evP}RBat(wczwy!@R~{ zCx6Jrg5x?jW4$>|^;lkNufdEC7!T^-7RLrfPIeP$?iolU zRL3F_Et_Fr)25Ol?W-sm)*+t%VIIAc-93rEO@{=Ynpeo%s>~`Cir|t57J{V*4uW?E zUIYTB;%|MD_R=5xG{i-Ju!3~7PJu)$RdrfjTIfisJl)SRKux4^Eq(DcHv_7*1I?A? zToyf_$t-IXh&6f&DU@w}$`H1dm|^w)7Szh1F!qHx%hi~;@JTx$8*fX*0DVW!l1(tu{>fN|~|g;$oeVq981N_mvm zv1Ltkh4EY~CR4u{r79f#${H`G)X{xRq7BxqcumlH4Hv04f&SA z8h}p;_(KSsAYdQ_772J9V6g5&sr%UZmz`_LZ?7{FvQXiVl2Cs>;j|>2IiGM+5`H>g zM?eyOIiK)@B#ckT7jPTDZOQ%lY50QTrXfn2wWrJ z+7P%}zzrer4FNZXz?A}S4uP);xFrOZ3%ET5E){TB2z*(<4@2Mr0e6SMxdQG9fj$90 z34t#PxDVh7H(Sm<-;!+(HTskbuo1@$DNq{%rwVu^1Wpm~DS*88=M>Jpxh8HBaH@hu z@uSq6nMvoxsmZ=_+h%X6*WpF=KSOVY*PRMgc%}tUl3zmLNdd=U=A!IwV}&j>*6Rlb zw8VgR7*M$ZZ84zb2DHh5UN@k(4d`V9+R)rU>gx@#G6=ro#uwFvTaw;UZQdeJuAfeX zfI#@z6HCP~misZs4vRvg+_zi~UAC?TBc*pT*xYEH z(bcOmu#3j3C$oEOO0!d8n;S~Zx}Uhl^WlY8q1}| zkBk}(;L|KWUb|C_yjH-|MgZ>Pm8KH6*e!f3nC59?Fm{U({wr|VG0|?Z@$#Ew{vS2w z|F?|rj$wrgdME})I35Cu00ct7jM4ns5Wgv}{XtqiEjVNgWym(UWRg_`k0y~0};stRA4Cc%`0<_j{GiMznkgR zX+hW??owRnzpd6}26zNJ zdb>t|y+R)a6TpInQi7Z<_|}U!+XfBE{|2M_Pi>1EI9Fkwxogl^+&8iwxR9Y`v36c) zTAYg1+OsZ{Swz>(kS@`1*R5F)P{X^xVz7_b^$@A0BW{0|8zp_oaxHTR| zx(?0~MnEpnli>v$z75VhPdo8vKaj=(t_5wurJTvHO`|rjodvVv^4Vyy?xFp8o;$O# z+7=IGiRu1mD{qkVhq7(zXVJA(0>=*8ombm^^eyGk(vZ_deh5xG{?*`g48}@zORjTI zqZXE)P{GVkv1RU|oDv%DVGgLaP4dXAgP(Dd){~DmjkUl*wIi-*2H&h7>(8QVl_v`R z7_3ij=|V5WKZv>#6W!@-YO2A;cPmXVaK`UWEu*90q91hDCG|+<2Xb8TxxxCkur-lp zWk-erzHKn;MzuTK40=2x6yf6KiHoar{%mKRiYz>RSSNq@!lFExCJK zZ(5(HoHd_(n7Mx6E;#cg{_UXo#}XRhAl9f6#O8z$bJkEawx3wyxTnrPOXDZIOG<1h7tA16KT0L98MXILLVfIia zU!k6{>bFIq86UufI-RXaNB6?dU(jK8x(b316P+8W-=m#>2v(*Sd>JaaMCYQ$4J_%f zxijPFGQZkN({#H^Oqr^dAq<5}4H=#6ez-SApZ9vtNGA4P*YvxXYFpb%!KbJ-3eZEU zb`Gl*vmB3PsVJ0OIMR-iD>VH9E;*yMPj#d3^D2s$(Ulddl%6)}w`oyR?n{=Q3z${$ zH}{>{)gNZNZ9-KHY}@p26P~ zL^g?XPs6`9C!KhEHI6g}*{-{t)HZH{uRSNJbapi4w_0&)5)54rz*D&a{(`O#RD z+bB3dWBT~lQ|*Ds;8c5Fga7_GEzlMuL7)vBiUUz}P75r*!+A=z1L;KVVRz%A$DI_( z&cZ*7|JX#R`+#F~8tktt+T0V^4EN_mZwQi=O;V5LG2Qzuys@qe&;Ve56o&~tBkjqe znmmJuLI5U+dB8ahwjXn7Xcb*=ag5J?qBna1>=#|)Vx8qqd&FI9v2Ld?VLMI>^;%k) zr>vde!1^egwEcm}=f^S0qbmBSs0U3tX14mCK7xV499ZXnu2oo1(+hBqJ*3$kHmFmc z%eT@|;AXyltNBjY?)o6!T}%r}S<C?}pGVf8^*+d+fkMx{`U@+3O8_RUIS zfk~wDY)Pdb!LSsE`*5|=_;5d+&9&2{a7${Bp?CHtSA{q$(v2u>anO=H4{gkgp|!dT zR|~EcxLUy~RM9V5Ezr$Zc_1J9dgz7<>T9K&ROHcOTBHX?r}ye^Jz1JEoY|w+zQIW_ z;6vzCre84Q>QBW98tZLGcn_YSHG%_epNKxV5j@hQPeC3e8xi)yeV^vdi2_QQxT2y zh_0;KcT-BSyo_Wqo3fF6_FmmJ}Yk6*KxE=KRX=^V{hx31uPc(8mw3ulzlL> z^T2lvy0N2t_Z;8BiizzM=8N&r=j^uzXpUG59W)&6@g(XP2`4Zx1CX|#LNKO6)b)7{7ccQSzst=p?7W&hxVv3SLUbX~ z^t&dH8uqltn^%Lm0`|`fH!>rqQB<07*9LdB*}4`*UxWpsGCRhXmC+}deU%6Un9_wx z^8HzZd-9%fNcI;W_7@#d?Ra_lz>_2&!LkQuMwuqfJ^EG55Dr!F?Ht@>Vfyf{r`p2e z<};JFE10R;n&@tm)*q;Zi=}%|RV#Q}o{UcSvH6c!Ew+OJu8RIsukORUrOz!(oWZV^ z5A)=_4hr2tU?&3b_qABh{LCc(X!`=(;474Y|#9E(`bc-rWbg0S5 zE*Bfzo!}Q2vU4|5ykapto~;4rX#VVn@9XzSeeo;22d)-}GejF<%u+7E4!sISoB=Aq zUV1D)22OB@&DVncg5QpZ=tZwcm?%BVxapi5QViBUgF=m<~ zO+PMXlvBi{^0*ipPZ6VIq;njbXXJ~20Ul+~8I}vfd=l|NQWMA9$nA$w{}6XEDu1fL zQ0vu)u@Ti%5|#uGK3@PZssJDvJatasot)0qAwZ=ETlG+7IRhiFwR2}EmPa9W3nMqb3y&42_%B3uI2$P3U1H7+sHM=>^4!0_M`Or$S%Cfv!*8iNB$ueG)tfPUj#CYH8Ql zDj3wktYrF~X*b@NJg65v?BUvCV<@AVT3IOF3Hy_5nn%FC74=)`i!mb29-+)PNEOS@+81+YCVZEJI69x zw3_TH9+qw`ofP4skyZGZC*eH_x&zLWuPL|qelHWHB!UHT&*9OxBzVwP5GF+kf=L6h z?|@0JKp+`JDXT80%c`j^Pj)c+7Gxrxm@Bb?HtGD0m9iY((d~VfsObLaiJ3Cr5yPmX zL%+J+-fUSxlcdxcoh{)fNP#nY73b4rARRgbvTOn(aqdDGhGn3w7SMJ;P@RCT%=6I_ zViRffr^E>SNq0R8;AbQ9;yAL?OKeU34T5Rb6-OqA4ScbEa0QVc_m!qOS-dO^2OZuUEYlm z{nO(<>Mmb~^gR$NqZ*Jzku-U%iusa$)Omnsfv80K`#O^$Fjm4x<%ksx2>*WWRy=nmJd0)cNEJI{Q(Gk6muqD4+ub1;icmL&` z|9^vFWfMt5S<`r*zi@A7ZOy1&!R`EXnAVoM2ilxzOO+b9)a}frPSsgi_#-B>M#b=t z=6fF8Vp&~3%8ve&ZZAKKXmlXhCxU1E5aNH~88O=J`MDur8CwU0W#kQC9iv4iXlb^B z2Lo-}hyjFCx}eNvjTk_p;WAGng#mmC4B*>f0M~=pdmF6PdS(E7KH~7w8bI$Nbq$!W zD&_#wzUMDFds%XnyVvj zEQs8KE`AviZ};YRq&md=y8n)xk#{}hI~8hi>ciQvHo-PN8f<8UeMl@J$QvR0n;i^f zCVEhHMNqK7ckD^DKdfXWzM12K+&4NS>qZvAvJy(AZAtD@8kYj!LLj4*_^r@E4T8Uk zD(QvM|5W(DIVO8CM-c(*hw<%dr&CZoO@h+v1bO1=Y22J93-f^;K~NOaV`w%!_=fs8 zLdWxYz@I-uBH+~+r9UH7L*t$O1Tzw$Z5}|R0KDUPAOS`Qfk=qrtTe2aW@yS&=T_|z zoH)5}63nrkv;-0lssXRF2(;2Zn0Imt3ej$UZaMBz+X3NW7D@myf}<|8Xp1!9O6=L9 z=1y0&h?mU#8odp=YZF(oqOKAKl_>J2c%rP+Tws0(ekr^cZ(!pF2AKIt=kIDIG}SKA zp2HqOj6t?(wRH~F2Dt{DUInp;!ca{^gO6#J!^oK}lw>+HXSxW$x(`alAIAF_(GIGEgf%cDuX)NzRtpa58P&X&t z?^26~lycY}DnW+ooZ^_1o=Dd~!_ZB|zDV~4xa@TZu1M<(s@$^?0?xC5ehSkEFi-gQ z7;Xk=ng&iz*twb-Fmzz&gq!=DVw^tf_sPu#-7x;kg387y_}@nE4Gdc&!DC}@lE%E- zKUB>Bij5ofKoIXw(phYr^I^?BU z1=V`5c7Gd?R-~@*4pvECHGOW;D~0;4ZMGP9h~^Zfrm3r*xw%YFZJz{eq+&-WZFUp_ z{SY0LT+#T91t&2p$|bW05NvCu7+r%-x%zKG$ABwTYJ zWw9mLhS*el;46aWjxVeEhwY>(0j_Wr-a>aj8^;G_e(FV8P-obci;AI`gOgLPmkg0b#F zfFgK4zgl#nM?Y`TO+8dnQM{VIw_l3t(&xSSDc(B0bKBX|RlFY84hGA??nr#E5H=2u zLYT<>aWLOz+=x2UjCrE-^CZ=rq`x*ozbrm<#@H5jKA9GjH> zr-E*9siD#(H(cB$+i3te1oZkCHsN{J1gm%&%nbPyq2m$bh=tC@0?gxhrhpENVN*5) zGwTnNLWCuc>X{LnnVfzL#8)fLzG#FskAPolIW_gi!e9aqyf1;Sw{qBPxE66%Yd?*O zp#x#CE%oyhfYrHGwEBoz9_M(n27#{}{UG{f7Id*h3E$I%`Mbs0+}#J8*n!qsdBDiQ z^(d3Bb|DHo-N)5m1{MRUk0G^_iyq~-ugqpF{3)W0L(JHb+La*oSk+z*%?52TWtJdl zKaH;4`e`N{eZ<330=c`l9J+U0paC0DL#NhJ(0900HwnKydkH%u(iA7r-|cVoz)m zITqDx+C9Cy#NT#j|1N9Y_w=-Nhh{SdA>=IOHbP*DYOd|*Si3rn4C+DDr%$(UpVm2Su|UZX@?SD8s-|`nsggiG+n~Xy@fDvDyj?5(r3^kcu^T~ zzaEspWM$a#*F(m8dW@)h4hbt)jkur6CXX!16$JW6eVPP27c0L%vJt>w?)FYVc;Nf6 zuug+n)@cZ{`ki285!ElA5WY4hDU-?(*Bq};q3f&M{qo%X$b&6nUl{k^Vu`H3unFiL z1U*4NAOcDgJN=Yr?~8;LBBqNikabEmXsc=j1r69TE7djAKY}Y8 zs%^=9H=-EvmJQRg+Yx!xMGsmj)(*o!WR;211)koxw{j)GsV24!<1Gx4D6H)0D*-F+ zRQ57;&!ZA7{V$UJl%{_MDbFjAAgNx1PNHBHWPlLD8Z8-h}{=7b@^|+_kz+Ul5e18jNnTsb@NRb*8nNvpVO#Z;hX%5Hz(Asu_m+uWb zP-0saP#0>Q8=UEsoG1f%hzMZkC(|vJ8$dfIgJKEXyM7k3vSOIz}U+ zK0;g5FNp2T`xvC(c=jk>DDwmkb+J&G@yES8R=4nrPMh$;QWafB>+>sM7sb2QRCy}E z!c`k>$>;uB77pzMH+O*QtU9fNJ~MJ(Vl2x3kR{kSfb$JI3@DL321E}11%A0Ej)yifL#0=;m0e| zRb=5IYVRK!MZE+4AI^Tbo?9Ss@6;8jccVOxI68MDDCgVR*u^XAGkHi(hy-a0qQuJB zMN~{*!+r5to=7OCg7oH*`YumK>Ur$g{G}g-sg9nr@_dmzKMv=&aBo6lJbe#8|J_&? zc4|}v8kQ?SAbcLar^u*a55jkX#l0Ol&&shZr*#&l7MWB`M$#GRz!M9S;%)cx*-e8j z^hdUb)yz)wes3k6&UV_$>FFjA>jV&{)S;##WZCxVuT6~w^$!boY`e|2+eYQQCBoAiCmd-s6+1H=$U#~lBm{<&)A@dyDmjAysmcQ9(*WXf zr#M(A?`HD9KHEx9VJAJ6Z7rum2q5TyT*yBi-?C6nLjf6y==I>)$!@2smDTa8igmNu z83b-Ih`4+nTUU;ceg}ggm`9J$)_*3H+XevJrYE77GZSm7M8#q))Ma zT@>5NnGjO#xrB0oY)EHvfEef{xG>e`SmWtMvj;aZoKWVbgE^R>{_{mn3F1vGFf-Bhri{T3L?>6BPSo*uEz6Pdsxj!HB|;C?m}MNuUczP@GiK5O zsp2%W$Btom=2JN=W}g{fU&++@s~oxBOIbKvftRU~y^>EUx6` z)XWDBbO*Xw8_fFz{DV%tP$jx!5&KdEGhUQ4dlof;%<9Gb3S~K)K5{;HT)l{~jgFfI z8fmKfi@I&KV~2iSo5G}oiT5Ox-`I;fI4PwHL4r7Pn0{?EUCVyLemtup55e}uPy2Jx zX9=ZWiC(XkHWdnRFrfY$T?2i51Nqru>qw9`W}7d z+ch2Gg(3P1x6>!NIK$~@%=5zJ!Cvagv73wKl$;3&qz~ZZ91p7SOH}!fg{*zmj6@}9P zKe()a0AA>v(X-T@;B`PDS_=gq6gUL;Rr@KFeleT7=bI*2>R(o#gl-Sg4A`lZLtJ~p z7Hy-Z<#Ip}XlMdH)hEO2;%)A)l9jg}!i(*#=y zFJbj3UcHD93~8H>3daC#S=22MQFE*}C4s>a^%zS%wed~_%^nYdU-UFzvN~@2spDP* zQIx&Dg!M!OT_yL%7O1xXyeXDtTXd&;YJQTtPURc}>sjRnneVFe9yx^Y$uLLuQBx*~ z-j%ZNzzS{Li8>X_&92N7cj$2@a3gN~%|b-;<+KCGt-;2`MVs?o5TJNqYr>oTVnNxT z;CYpZPDWq7h5)PteI_GBpTy<dH$mVI)6LYl5i=u1%|;PXQfLS!8D4>(U^nz4}7Ek4<3Qg zNQer->VI^oXDCj`Z)Iy53up&r4C;2fVN=T7&av4+ZfA{R6Hy)9&M64u5Rgg^r2CY& zu@gD|C@PHzR1df#XfE2xM@}a8re(n?0n>6qQwhd=#?4s!s|X+h7>pu+hD0PhX%K@? z8)WcL5$wn?+)iyEGK!}(&@LdilbK|_$^r*vctYy%`{bJ57e()DqPt-09(tufm4rB# z6=M3a4QL)GdA@rnwgE_<#}LJ|X#EhFT^z)BDk*b5xu<0{IPp;<{ik zGKj4ht8I}d-$bY@!a**~_q>N#s9xk$Ngb=T=pMRLDC%q2X`0?}UqV%f}mVeg>r!~JJ@25I`dsML}0mDuWlSm16l#92(} zN)B%h?`ZlSkSLrovx49G-fr2sxk4!VD^qnB>QK`3GUT`2;5e* z7G&8FR~d)3*eOEoQnIg6!imlkONcExNFUVsrU=Wnh(`BKLDYMIsOeR$8s7@SBn&Ke zVF7llZD1>Cp#A!rs5KN-Bds%@o(9joZPdo6PTiXnI|q&^E{gPYq0Y|oa#TFYuueE@ zY)#`08wXggoa4cE#NW$udC)wRTLm-Q+Oh=q5ZD57{O|R8=Qc2rwaZ|>Y#f6XFlsRj z5sm{NFJ=A~+oxdlG8_};V7c5uyYAi$WmK@82=+bhLQtdX`x1q#A zd87<1p8z~W3*=@lf$=1>zPmf^r!IVg`SCyAci^LX8-jP<7 ziC9`V9m`mB&qZR^u>~`e7e5(c2q&Qp^z29<6}PTH2(FSo1t)ED_RRfo;2|81Cn!jOQP_$*Rw^qvO~_} zTqz2O511aKO*t1eayRQ0LXBL96HM@J?=?XqcjfqKqq%~rOeMAT+aNUc_dih%4TJQZ zql{j6aZO&D-b_{XPwLBgBUEylBZYQLPNR-E(p-0-J6YWR9BbG2=X4UImzl%_#N zk%3Y-5-HpCm?Pnv)O>g)q2RHB?`GDZ$aLTOJ1FECF_W@&5TqdN}_&pnBK z`=n$#I0%*Dx0T6vwh;;CdbcRG;%Gd5kl~3-?(2R!c8(Q9|2t?0z5x8OMEc%;-`` zqg3ZD#@vnW=2+w|bSK5a`2rQ98k`o(8*+t^8JlGo*C~jj_GDkQRNlehHY}A7aFQ9G zT7@G_>5FU_Ei|dXc@8BFtlKWIZp=4;S+7zRr_xzq`W=EMx<#eDXbACkj^sVO?lK;YXW7Y^PQuZW=8oc#;JFeUi8n4|RwNd2 zcfjs-&2%i|9|W)RlfM-X=f-_cKTJu%{#BgKfaq-?&*`T#xl_(G=Q;fy4)vQEt~#Dj z?as2wyU~P>uX86*dk;i5I4$YzOxI+3yE)w8?FdQYag@`l<`Ci_GUCQeG;CvY_Uc@j z!4r5#i}UwSY4-Sj@hRSMvFO=26geTJU`-1Su~CHhG&nn>CAcILV*l`079w^O=ASIO z&G47obAENKlFC15A&X!XSi=J0u8K0br@rE3$l0*L%r1bsQ>EBt6#l{nXW+44*q|a<_o$G}$ z1K8BP#u97FJTzosaJ_)gw6o@2g8-EZF6CD%SIr^BsKb~;+|F%6v4e0l$7>I^;L$A0 z;P3ph1uP#|;`HxKu__3T<`MP~#3bWrBrE z=U%k>wlcdA+NieV$m&}IPkD%iAYTv1DUX+xfQEf7b~11%j*v(k%gtq;-HX?9zW zM3{E8h5RzjJ`U>pS#AB>jOe0rvO+8T{cx&5F}FkaQC2mz z^O3Khx*je+etLCifIf}3JVJ|xS`+9%v>lNb>^9mHZ9zN+9QXbSZWa!;;Og0iZbGlH z1XctX3)AES4z`tPQ=eY~QyCLeTKY z!M6S%0W3&k+;OliFSv&;gsFI_vfJ)WjEi^Ew6?yaGTtu=jW-mdXWb6kmZv&i{n=d( zFCuk^{uPC8jFkTvELNRLxhmr~r3h}R#dB^aC->bEIg)QhG{|bov~pzU6DLlbJaK|< z4^U!&?*wf0Lw^kb9R})8&^vhnHT{YDiG7pCC3%bLN)IG2Npd)f%7L-b#~Pg*jvZU> zCPe{_8K>=~V8S3x=ef;!W}5OO6PHr1FbaeL=N{l6kfFhvei_bt>-UjB3G_$bK6MS{ zI!{l!CynhxnnAq)qecEnTY#fVw+w-OP0BeVvAs&^f^gKG68L92KAf|R5(sA4D360y z3wS|V8e6*uGvp<0F7ZrCLz>YDekPQLHZ4SpZ-@CN2>yoJXowT8mDt#=+;=cgNrf4S z^ae+s(0yhCDI6L4`cH>5LVSz+My1}=lcsArN3IYkkB@M9A1N(kfQvVMCLfFPx}O?$&fL2(Tx7rCB|2 zOd(3mPT^I3tUW}Okg=wf(%e++2ONa5VS7K*9)uRa@lteCdkhm^HoX)ffm7&K6`3?H zi$|EvO!~8p%b%H}I^|>tt?dAtYuMBr&-d`yA$^yVH^0w2@Dp>Sg+E>{TJ2(aU~32F;z5?nhZX;U zWk5d;<_3RyIp5EhQpY<03h{8gtiNY5?HjRyWppwXq{#&+Lpx_g4u!8yCpAiBsnTWpKmUM3wSj> z=A;+|Y=TvPfKSW5(uLJQ-CZD!tG7Sws#m$J22l@;fjPbEhPQK11e*sdzGTee!lB&l zg>7AZlT_D6xlP#&MT2gaZBd><{5M3Nj0S_ipQ0Y*UzpR;ElzM^dOXgHeZ01qyKo`g z-ca;-G_XUiaKzJxiXwenTcJnCNlja#xnCjw5@=^ML;`dt=)e&mb|cTiHU95uP*;Md zbXP$J>>El~_$bjnU50g`IK<(Y)xe3G@msLi2jDAqi}KDN?sEY6NX{pH6H5PB6(!VH*JSb>-YFW*72!PCJLLrF8k~`e(;`YH;?zy1 zX!#R^Gkqo~+Wr6!=Kx!xwxcF~>^YICEeU5cB*KIm{c8 zQpX;C;K@W>2MY~0;h8MY*Rx#=TsWStgC-bBebWfCKsNs@6^GR8~B8RLlw zlJRq}GOuL)WMmad)-Uo*p=6vhD)UH2VK^g(U&M0?-k036agtFa89zxh1W!1B%sJ^x zPdH0I&q>cWzAp|JMD(N7R2&}Qg^36S`1~vOnqSIZyQ0@0_ z9>@7jF||!p?Uqq}y(zPx+uXcYzK+ABAk4GShfQiRru3ehNu(uBu{fesOt6x-rIPoJ zN|qRvd?A(iq>?XC$waQ?mnOB_QOOH#MvB!^i9cA!bgAQKqmG{-4?~G5&A1`QUEGi< z&7gSa)7$+@8uA@ZEQZXJWod018gkghkG;}NzGkOU$y%voqg1jMm6UTO`;1D~OC`%M ztmG}JWUo=l9HWwNq>>p@$v3Fv7nlvvL>R5$Yf4@GHJ@=M?>F;TGuGcOSbtMH?0_a( zl`1mpns)p#OH%n`YG7hLZ5XOJ(WZ9G#D<+g@Ri5BCn;%gQW+nV%*F?El9HBU*JyxZ z5l}#4AuLX1T76qPy!Qqdoy)8U_T*F2{t3;c69Spile3!h%a3I8%V)u^;{$I08xhiz zUuJSoKHD7iynuzGBI~!YT~&jq7Z3jUByZ1CA}vWws+IqL+eh8+Iz3P_S$Q&y-yR)L;LIv z@OCTz%u7u)6+b?N-J?Kw6s|2KJUxWGk1s}Of+f36tDR@z#_qw%Gkk9W^3=rI_R%3I z{WaL)n+NyWxZYtXhhf=Uo4OVN=^wmD^~g~2m_ErK?@s<`%ilSD^U%aO=EWmJDFo}u zM$(SI8d^co>KDNQcHVgpJc{()Y-V3Qj6->Mhe@ejGmN$*9z<9i9$vtOB>Y5gUKm38nElnoeH3lfmZ(|-wAH$oXe?I%5_TbQZ=D7=`c(d@Y>2wQHb#_u_5A%7RJDV5!ZnEFc%})z}XN7q1PX z3f&zg`1L``63`yfo+z>T?jWUUZ(@`W29cM2L^oV%JC~9XFlH-G>ve6kZ;W+4dv-yA zz2YFa=tJM9rTL~B3T-n}xGcV5Bl z^_4go-Ul0{!r8Wc)OyIpr|baSJh*};ttTQRU7H6_1pI6E()|kS`A!w@0g7eL(2e$} zE;4U6+9!88mymak+BB-d5*mWj z@!%M)ezIFDnn2-CQJN<=psn!m5|i72qxZWI(Ygm00d?a83fJO$@2zl<{2GeU!56+0 zj{jP0v_W;#vd~9Pnf)-^VxzB_r~Va)QNq(+4t`m&Zz6ev-O_;=5BugNT}gY_KI`xi z!m}sGS`a7%TgDmv3?g&#&q;1VZ^rG*5z2M#l8H(C!+jE+cGr@+r2Wx8I6s^-!?(MW zVmEf-Hci})Kz|2sxj)tnw)gS|z*X2Ai96$9j_X~IO8c|aEr6fkdwE)j9#f`L^Rng7 zidY@cI|d=7m>{mbl#=X0JDp8-Rd>#bLvYaz%K1CTDt7G$r_Xctcl+#_>n^o#T}pl2 ztTs75Ry#8H><1yU4?|-Nus3p^Er@j_msPy07Ap47Z2(Q(LRgG_xi0 zEY5Mf3J3Ff^IInDp^E8XO;G+L5B>Xw=G?&hy}xTDp}d!`e%i*WF)G`4{24gUG5+&MLZiS5%o%!- z0k`CYQ!?yWaTrj3QcEoEI1;<<_%dCO-Dt3w>W(?UxrS+8J%VZO4iFQcXJz71WcX`< zm|i!co3^We8(_UZVvDe=Vrq7T@a{!Me0T(u4fZJ+@wpKl_M&e7B;Fz~FFUsHcmPNb zaE|RGFsorc;~f7nA|D#v;A-+5v2z?QJ;|{){7arQu;|k*|HG#hzwy|>w>rM~pEx2A zjfPY>j5kUK@k=$;eA%$NknkHm`#SPeL|V~(etU9!^u4A0P*O~=$0|(1Wx>w)9I}3`4K!ZmFugvuV0A0u6%;*197Acw?@H&!lhXc zwfBu1GkHSb#Pgl?%L|;UTdP9ft2~d^g7~;MZgj)(uC4|4pDnnw@d2vN^|8t2m=P+R z%kU*Oy!e1#tfm(?;{_c9`*FKdar`MKoD-s$g7b5ZJGA9dx=eH}qGxD&pzpOz#7Elf zn|yu6h>1f~O#=VdO@r$M@fY{|>MG&QcwuQ@=O&`~Fz$YXE$>Xj35P`G*PWZF{8xMx zojrDFn{&pyb}y1|!8QxU*zC58IucW3RqL^U@0ru^%$x?YlwRPETCGRSJ|2F{w@%%{ zhb4QJIO8cV&dUL76?_u zF?*g+zW;Ri-v7J$@E$5Mr=N|Y2t@*kFm%Q~{q7<6s*lt&MH|l4I%0zFI!MoPw3y8~ z{vf+4A750mV;wlxFw!1Qc9p}y=gz=Q1n;FkdGu!t-9X-gOByS_v=cb&3(xXsIFj*7 z-NnuJjWh5)PX-+9+^??+AF9h6Q@RTCFnwHV(7M~oZY%qAdHG~~bZJA*35U-q`_;eA z;e;O*AmO;fr<{Vv%EF>a&ebi>VX4^BPpgV5oj}X=a~BkpepYpx^Lq&I`yA+XgRcVj zY2kquTsQkF<~d8S$9#-)EIu2JwHPf?e#Cb&{S9Y>_<_dRZo~);BJZgWoyTS+I2 zI0;wQ0hPg(6y~NAk;Um93F2dDpMgm8i!W$#&(P)k4Rf6+`7ZbM@{KPS@+kVp|JG3i z(X6TQMRfy&t}zs$E8Eb@|JC!gOB_~Hzj>Nl0)-;oa}9xaTzW<> z1-}lSsE6g_xF2=TaO}?ab$oW&Ip^bCU9VH`%)vOj0@s$nAr$SqWE0=v*j|UV|ML2C z=B%`j+Ud9bP;BNYm`mm>Q!&>F$ zyfOBY-U|>Iw{GO5`?oujLPuSOJ^wy-hy0Fbqo4YAp4zbJnadF#*l{6l;p}X8Ucdyl z1pmKOxzd?*&X~sF7~F??(ipoOd`((FpAz_DDXl54@xe`q&oMHct9=#p9h*K5X~hkS z^hSN#_TTa5t_65}gQwctX{gWxjmA5Dy%*4{ZT#w9^=ccxTIcIsh-1Xq&>nz;;AA&% z@%8naqVxmLR0r{8!mH4_|5M+B{I3i_?>Cn<1@WQ7U;@`t2V>r0XC@hlIMlrvcKwIr z|8$gkJQxlJ5^8R8&)3EyfkoA|wRDv*af_!Q;b_kB6%fxyKSK055Og2vTw4PWgUKCn z$YJV@7vFr*v3C+xeCc_<|M}Z2L)ANldP3%1UQoVgID5vvsUPNN1^e|~RA8Tmeb+QS z?BDSDZY!G;{j`(51=5yygG}P&+%fRGb!@_Y$eUVm-_15`Y~kBA-&=JpCasV7j*9E; zitV@>VH{4^w7?g5Oo4qAZSFmNiQ3$|-|oAdzSepvn|XaXIbpH}uhCC*&EPd0Q2iB- zZQX@iAZf&{U;}V3Uoy9X->%5%`?=lPO*aU`3)JZxe0G)HR@eCw-C!|%9npW2Zm@(e z0ddp29;v@(`1md+seLN`--o5R7oaWNjS-^r=CyxzV5clgqwlBfAF z%Vtox7Eg~ei@4H?VOl>wor7B1&FfZG-ba_`J+94EI)_S`$!2~&2YwN|it_B>{6EQ| zD(>K-e~K#JLiKx@b3VYNU*=aYpFV9m5&6=(eL@E(i8T)<0X6 z{@FxroD+s!4nolV!2HJ# zcthzO>;~fL7FLDt@VBFGQ6Izp3-2t@1xeHwZ{cE0y44ylX}e;t4{bx$znm+C+ptO3 zUd~j$^z~w6yt@QGw!6^JiM>#)4>FPMzMWT0U4I3RJmM0Lwe9)NVfOye^@Zh=x0X-F zQDJBLax6CX!95?e2D!qwt#aJ_RfR}Uk#axu^}T>nuHerR|K5V9sMCJiqGLn9<_sIv zRZ&~`sPsnucJLPFXcJvs73(H`UuAyR`RM%CtNikP3o{+Px{-~z_xQTZ8~N-3yrZg< zujW^~`NGVr`PEbOJ#)6Yp4y+*F3T|j|Mg}B=x_SiZ2ICvnGXKCNGuVm3k7S9&iwDc z9N}A8OOt7bu(NY z-3*uiDcsx>@s;g~bIa&<^#^d5^~;F)pxI2_6+SH85&wXoP^#b^8#ImJ@4FO-lB9JDBF}C^RBlDiaYGTN-@69BUmSmOoRJ0CD_GfrPbb3H z(Tq!n?sA%+bI1w3s)eh$*Fjix%}#qHZA2_@!N>)*9TbZ^got0y5zD(BxC60i!9Lub z4&1zUwA(%zcZI_zbObEEkuw(I20;6u{7!rENc*7Pp8$JVD>cGpj*1QWk`HZP=2TQ3 zjX+1dzAWqOpS5qhaXYRKI&U%Ete2B>#t^JB@tyM((R$h^*vMzNU)WdCeUR@>`R%?H z=fOQc+Bt3J!c&0Ltxj&g!6&y7C|lWkc>&n6zu#vX=$9>h_Aj}C?BAe$er4LH_1?m* z|8dvkF}PxtBYWQD@4elkV(;JKCb*lL0L8r4LUYX{+#m}{R^H=;U$B?^JKYH0+ICuL z%kt7aTW?so3vr*cY5iM16o4b{H1qzJ?{ry@+nWfc_WCKqFLE7!zAyYSc1iDP<+ECr zmk0K2b8$3we`Pw?@7v`x;LUqX>EHJymApKs8$NY> z9e{2UpcO9Ozs7eP+>JZq`GJPe-EjWPi+dQ}&Pewtr0u*z;C*r5ezejUjE?|eX-i%7 zL^HXhpWct-2Y$&n8{mPc{*t!_p5CwGZ+PfsvRlzVNvC^7w1=|(s#zUi*h(~US;9}- z`&^#!es42RP*?7UW7DfA$4*7k9<^<7BZ_;#e)wYAVW0_-zOB7q-`+L$$4hVl;mU`V|CzehR&tyoH}gJ;5&!S z^et`N(&CKIIc1phy<6-9x;t-K^n5)o)WwOPoD+v3#`FE}pZ0HDo9=;YSK1T1?cC9D zHI8xK!KWV(KLvLOPMG!LJ6#j6fI)ISjLgZtHTFe)4;Dd1zRg!R-88Uc&V&N`BJMkU zgnlhh@G(S zZr_=6DqYy-Lx{jS=O(;=gQINra31I<^wx(shkhVwIw)S$@ypn;`In;&3xNKYs`_6Az!TDR^%V>%wjPa6^vLg?Re~A5y%H zK8ZKD!(Nk9H*zxW(prmyNp^sYr!9Qr=f(jQbedcq^6`}$`zgMsRj%r<*+%LiYbpmMXsG_sXX>FY+PQ%at)d>UId+qHwyMNCB9PPh2 z-(EjJl?xgl@l`W-4*(53y>>C_O++FLKpQ%fA3)OEIF*5v6?7<&jvcMSw1F_H3bG;h zRyxP!oPqoNp0!VLCSGz2#zbeMQH#fSp{aOW%7e4ai)YM)$T=Rqq#N$j>uD(rU1K4*Pp z66=uOL!yZ(c=I`bLG{OY118?Q2!$Y$?O+Ol_#J;v^*$W$c^8Lx?OTWLY`zq?gLW-# zZrQ;pqd#^h4lG?m#J@-* z{ud7A{Y(*G$;7WfBy7??LWu9+IN*&cJofPrbH0^{Kg7hhg80*65Pxh~D(81F@ki+t zl5Ic1*e^2is~7dEZ)4fN8MI|s&MCud-vP$&nuyt61d!2Z;^@N=OX~ji(O>=d*{fsN zRfb8I#8sxaQ)*4?LvSlOmz|GO?;Sn#&Ga3(Xcc*H$34!K3zAi*j!7>19LX2{>gg9QR^hP^;DRhXzRc2iAKQW8h$Bz$9I&%zz5NSJ5zc0u z&Ddj~QDGNUz*~irfjadm?Bdc1xx@4AQ3-EyH*tAggRcLrcWd+nljq};>?()$B2r{VL!pKSkRJ7V)kx4?#nDUXx*6JcQ{@C6qK z2WDn}$YR%xMW$vE;e3{7)OI5N&ve0|TCrDA)_nxcTjcVP6chf0xs@rnK#W=BJtwj|Tbp zHEyd#>uueSl+i=HaHAF3(`~5l&wM*^N6{Ah$$_-AJ1ytmhEN^XHItRJ4$Cd-pf#oT zV8mTi%zfYz+~;};h^*pe-B(O-ITQQ}1lPC(p|w9%6rDH`+{?ED;ZD6?`wMuii=UeL zc_lnLaI`F9NAYLFY5nsC{J_{w>Yh_IVb~sM9_QHwjQR&&X5ULE@^{;nqjw|2 zmz?3lfvi`qT9=P|HG^*UW9kkh43 zJ6-VgIu8GQe=uD$i$kIOw0kfu8ql>-h>CK)w4Q1bNGrpP{X_yA@=XXN!w;T{gw;4V=%@J?zsFjB3Z9Po8X-D#G(94;RQMM zxABGoS8VMN_*AgF&_v|#7=mD%QMfW?41Id8LfkMn?1meLl-Z-q#1n%#i#!k$k1`Wa z4JNpkS$JkJIZyCusFAMty-OnYUYN!2#$hC4U&1lLfj!+{j4LZht{OL?sA?WzZO0YV zVCbIxNr(}&yKPv^J< z=TMTycdl?2IrWpD+Kg}`ghrfP!JYHrW;#92Z3|6i^yU@O{%O2Tb zA403F9Juc|Tmn~cMxpLG>El89{JT(L9Ip;25e8bE-#j;{VijhxkAQT*;L?zi*Pz*M0x8TaO(e#Ou=)`Sw zm>CE2_jeMs!#xc^mwjMYCoXQxw}&7i-8uA`s(T9;b=q~?I_;5Yt2NJ5E||M!{k1)} zp(?9lbjiy{xIBPh>dL<|ygEjzc=u%Tb0$e5x`*IYDUJ1M& zzPJ6;Bj}D;*eUgPb;2H*Z(o?GZ!K%Ayt$wtR5k5;vywe)*8=&fAQ64%2rS$2^aLNV zd=y742__Z2^9c5;+{}jsck+vy@xsOz;HdlFID$nE=-X?_oI~vM5jfXbh;JI(Bgq}J zCCHwVzZ^k%UJa7Db`_Dt{1c>3`TFpjLOMhYr_AttJ3J8rIlK!ep!@7&o$lF%&c)7@ zKcZ>qJ2tp>3ZGXf0nvXjH!F_7E-w!EP2BXF-)`-jI&)HIXH{qC3yeU#UwH(ac4(b^ z7`mt1IM-qyJ`s_eD0^=m2NS-4!;^Hpon>`5GxyQqv~`S+Q`Hf7cN`9df$Kh;p+$?& z#s1&8LZ^P2jgbZ8t!>@xbI+aCxqeF7^0hA{=_-eH&RF_HAVS2J^nJRAZuKB_c?%zy z{0zq;Z^P4N_0(+d9Y!M%-wzwP6Xsx#b2{#$I&jO`RUa3=glYJMEwywL7UIkf%CD{* z3s2E%=cLN2$z^ly#TswFEn~=mdZMptS)o$`^aC+GLmyREy@-!i*H)p7O${W9|8Xb{ z`&oL3HQ3Pj@Brl9kP|(ph`i;@PIY_jE5$M;|QRMggR)%kk&a ztuHz!gUat3Nq8To4?OtTYk!hZEv= zqL1mrPhE?alb4$OBh#)-D=t8m@wYFvzmwU=$L=IQvaLm)x)K;8M*AvC$J z=1Kc+Ln?3#Zoe&`BBg^-|DjMj81)~F+QFzDLxBpke>9TzymlyE?R`ey!8x%*5rMpA zwbPSVdH>nYv1d1wZ=SUkbN>f$M8KqkMTwwhwNiPS_uV(|k9iU^S@~rXingA6O>;SJ z^Bdi*?g($3GGW0S=MEI}CC|?*55VN_G+()9^B7#~Ky&pN&i8Db4on}DZy%L!*XG+J zx^P#49oT{oj*P$w0Bm} zMW&M$IRB3S+nh~w!wr8i(zcheW!#0+YW9L|6mYsTaV2ihZo+|9+`x&?9z{$EJK}e_B(M*hI*)`Kc= zd)S5RdN3DOtjEVP@X-wWOiYBMhoEor?UT1mg7=5Iv!K#BXBPx$^rh(YAIE4I{{nYD z*`+&^U>IMtK@B^vL@2^9Fsq`hck9{JaMNKG(6cnjy<1Nl;#s|Y#W@6AtNmaQ%wHsks&Q%s;8JazgzCU2O4=s+@g>JX4DYJ(XH8jJF!t=pvy1Eo(o7%K(*St} zDijY7vp#+9FoJ*19CfoceKDt_ z-0O_|9F^PD!b<2Br+0o49`A17 z*!+ZgT14{j>*1tdkEOtqM>yfh;Z(gxnD&#y$+~=G5h=qrheODwkx%8ME?nVe+Yd3y zR#oIfjI)(_Q7@hyUO}tNpEK5T3hU>L^&DfV7tar`!1gYde2n&@LX(FI`ikX){N^R# z9aFe*%sG>SlQD5)K;VuM-0#(%kKI_Q%Z+q%2`;s;|K5m?m9H3Dk%tQh69k-NKZfg3 zfOsdj)9b37JGq@+SFL#$m-DCL6?8o&Z}LL5E`mt|za*{eDan4_>V0n*Zg)XMY0fDJ zgI;f#8u9sI2xrAkH4=Ur=6&B+hLQb4Dt$!P12$GnzTF@0{=A%0RNn&iUWNLHVL2r} z?EZ~j1)Y^w5nB;mxa-pE@cwD0{UK=Ywr6m zoI3pU2K<&j=a>s{%w$EhXfaM|V3o|7{x}TP8XGH!pJA6^P57h*W9@-`Nq4+hOD5k- zIBbTKr+jwo;UnFvko8^26ps4Z4q&Wf?7uPgj~M&+9&Ej}1KeAIdlln;c_cBucw|$E4i)Y#mkKlpKQ{OvF9MYpUbX|LGogW4OP4+%@gA(vBql_1g{o_R)eQ6OX;E zWdi+*?!A#W06)Nu#~UzWS6)Jz1a~Y?RDJs#_w5b;i~ANq{%!yNb}n`3$ai#y{+K)T zY3|TR(V-8ZLpO4VK5K7N{n?7(`W)+z|6BW0P6ef%HvI2Z&!CXgHo2%)7AWoWn zYEsm4p|@F@pYXEyzzOHOUuKaqcqA$KyK@KvBX`)!2i4F6>hMF`u2eD^CIjaLj>2&m&_T?@T5X}giCym?zP7K%DMnrHvQIzrQy0yUqEB6WSq}@Dj1qi zRDS9621Bdw4gB7RmD!+*>#vKFr)M`GxVSE-yVE(8F9`fveQDrR!a5-FSfBm(AM_2# z`5}tJ2O4mq1*_q59L**-A7TI!t5!M3R64`%yEX0{v(V{`*Q0s-G^byU?*gns&>g-_ z_AWdkxJS)Cq}PtoLcg$jJKYzJC=>o_<%4tt8ZK()upa$Qg~;e@NUKvHpH+`*6Gy=SawvgU`$;^KTXAtsLvS_?vc8z)~Nt;9*U&Tl|4m zY2$qdQ-eFr{P$G)%ePUUIK(O{GNCQRuT zzw{@gwfJOVEtOCcUK9^42`UiBx8hcDaUK^}K7BeV41Y8UKH37|pg#~vHYLDcU1P$U zTReU4j9kl~H`hPjKMpL{A`;6_rzQhokg)>ESS;9-@KeZ?wKy3Jhw({~NIhy9=S=bH z=Ab{=RBMHrLZBaMsteVt<6zKRD5E}9>rW6@jno9xI4B`p-Ik17pbzd9x$4HoV2la2 z#6n1fB^5Me{L~~Cnyx6f2qbHgp)e+6KQ(YP5N-1Z8Wvf8=C(SSh#-`VGDH0}MXY$V zF#x*$#FD1!#-PhF)7PDV9tZ{SF3?aNYVxp%lw=H53MU)U{)kb7MIR$J{Bw)_CAm{) zpjxp2$_g|_Q3S}Krhc?kq5(g_rshyA(qvI<5&v9kJZS)}k1tL(CF+>_Xrv_=i`3OA zBewQ*NF%XCf>W3~!(TkB$XmRBcAkX>PsAeOc%mA8)zFNd3dZnIqX;P}iARG0 zKAd7CuxM^+o~49`Sw^>5g?XiAc{7Cm^x1jE{@jwOrMXneP*Xixz0My^#8{MSlTjrQ zMqV3OD$zGe3_&$q7Xl|Rim3@%DyUjB^9mtsJOM6=G(nC-;UM=6BqSNCRju!@4aMpB zaw3HGYpD(|^2i9p1~Ol5#VKQg%Etssvt+P#Bswq#IV74SaXhpdn&Z(xV{Nciw|k%t z!?Y;~(FinzqAV)WNEq_e7>pznRzt8F0{|SNzbS~%9}h=RdGxDh-X9H<=)!>R#}to= zY96!EWH=sd3DrUhsQ3IdxUHt*{LG3BYjpJ6BdQ?vj zmjxwxWlY`MP@Z<5kz1ZOJ=csX5;$sOt0B@DtPRDirU>f=Q?>G$mBeTb3THfB4AsM* zTT$kpI%7tOtGh4+(Ug2f)SrliX|R#Lu&C!7gHXM-!Y2)Df8kunVItNBm5HvTFR6y*5*CJ|&OCkOsQQtk=8hjZs*cCy zDAYNDGq;i0D6~DqiA7JTDQFESLre#WW(+WNJNg8o1+8gCqEK?s?J^}`kVYd-;71Ky zjMzEQ+!(Ux5-1y%3a!E+byA_CsTCGZry(d6Q%Q9q(PsJU!qxTh@l*`Y7||BeJbu-a zs+CFDS-@CL>LntN)!JY@5DP_77ppd+rW4Eq$tKK6wc{-#+%!WdmG0>n7BIA}76FoU z@6fBE1mj!^mA)1shZfi+zP(}=pWRS3$rLs!OPy{O?+#7MDf&;GOjhaf#yS_DO#`t zgc1#GU3+dGo|aATscF#)2GLQCXbrH8sU;l5Oz%!DxZecRFJ>J+Ijt2UYy^z^Xoxj5 zF-VgJ%MkY!sV=CN+Og_qocbBBeoj+Ar>mbctog+=rk3UMQU?Z5OiU$zoW=>XIL{i5 z)vdY_^vr2mm8~z>7d*YDs%t-~_8OWpwJgH;0CSj-F^pw|P*>@RkH$(9rVW@w)iCm6 zFk8T;sy>Vle_eGbY++c%8+3E2#`UY2NCq(X77I^9byKaHqsaOb@$xIlqN#|cY*GOD zPgvyP;!Z8@?B%ApvS+4562fqGBGAB=U)-8rR_HG+n>xL~UtEkT(7;c)Ga(fXH4#;f z=~dk{cGc96*QBwi;kXN2inGg0i%FA-S^)E8Fp=#E=E>B9RqM*)jJ#5sk7f`8y--#G z*a-&7WFzT855dx40rJNiaK@JUKHL;+g&^U*)^?b;{m5;`lhR>&Mq!m8whs3;ELT5` zaHvAD$a$E7L@T-!4PG6K2T=xos~e%+sFlt<9gHcbC>eSIGDzK;&zU@y$JZUe*7jo>fb>C` z^wWlxXP|Od5Sn)xpv_Q{_5|iZ{s~)SXyP4H6R8<9BN$%FXQD=-EH`c5z zrp=!@lLmYs5ep+LtsN}xsF5UiY`RIctwggQvlnSP7zP%^f$SoYeaqhrs}*Y#t?J2~ zhB8JkpyokXI;t;pr3bSd#EoBRQ1k(2+kQ$rrCm+URikkA{eJ3JZrE@n z62;hw2P z!}Oy`6!bC45>T6D+ZmHNFZz^CS;N*OY8p$>B`R2*Hw7%@Kri)b^Hf7P_!DecD&Vc1NUbNPR z>M^`1g*8x|+7E>^L)lk1dDtSE0b6(_G+{PjFk_;2m#4xdt(+{#E~f0fQdI(gc(fYJ zXDSL~7?Ml+8Dhi+Vq>jU2aSV4LH3VcD{HPux8{{b(NaN_Blf+ z$=?uSIdO%71~E$~sgy8GFAsCbK-Mp_1hFQ?L2E}C$BPTWWX{H zxE%ON>dfl^b3qD?SL7rGF?wHzjm zO03W<106%Nk?;val;5FWiBSj$|3qp1LUoGNL7Q7GN})s=qhTy-YAq}~*{elbm{q1! z)C!Xs5aUs#%;dbe-boiV^#gapxUpu!CSMh?Ln8uQ)WHp=7Jh2>@Rv_5oS#dMBfoMM znXyYVHU=aaL>hJO{IcTtWvBu50J$rm=Um?i4Mq=g-mE!uOO*N46l{TNV)Fs*K_@4< zeJB~3_!&#J02vY<0<@aVEyaomElc(V(Z@8Q3XG_-RU6F6osl;kcC&KiXlC=~5U>4a zV}GEAsezK2>4-Wp!V054>Q2Q_J205opdpV;1cFfq&EvI@SDRmH`?5`vU~Mh8-3ydIs! zUQl>cSqDNhsO3LO)dl(!)j%_B$Aa~Kc1|*f${n>4g6uMBp)UH)<#-j5qjR9+3#t5 zzo*msJ)Pd~>5P6)ERRGMVni>{v7SQ6F$+&P8qSjlBZfSju%Vii?}BU_<^9xaL=YiW z(?TyuJF=g@J_5U(Y{yW9YoXd zj@{Pue(LdKte_3nh9rEpHCL$tx;Szq4~I7$}i9l+f13b%+8$3y_r;1jrf; z&Px<4r=m#7p~oj*Uj$1UPT&u}$I*JhgV$j(v$s@z=(x>mi|}Ye@$Z zt+qCr=wLozh}K6EaQE{yP0i!|rf@-3Z^#>La$~d@xF(svLaHv@W>TmUtsopvMB?-l zALmjRqEKP24b{mwCaQ3C4I`^&09(utmIo9zV2DC(Vq_6D*eW!ow6#^&VDhBghUI8& z$Yg->fY$WKfS8C?H^s4*r)G|g!ynd!l(QxokA}!8VX{%fAS?Eofd})9eq!VC2VF%o zCK*Z84JLz%T``YL9Hglj(!S{Ics2gAhn;?cFrQR!V`0^lIEyy4aOtSqFlcBjg)vi@ zWwZN^gaoLGac4@UO-9p!y0<-YV%kT)s%rW_#v;%HSKcyN2xqTwT+j1UJJh1i{FX$S=x#LPe@(wo$SM&^J@a#J0rHJu*@ z4_L;6=>_Bh@gIy~P z+EJ9d0nq(R$L`*K&wLn%@nl#~%oj^2rZ&1l7 ztXEFp#TJ$fgsYbfNT*5JuR4mnegXIp2pv-*Ed01tS?MQdM=rK+%g8TD#se(nI+*!w zZ8YC;Bf_^HY{fKGlcX`@kGEhOwSo9DsD54-V}n!j!ma`v>X8@ARP|^QuEc(6v>rz> z|ib2?GN%-$6AYwL?DNxi7Nz<44wvV7bMvV|-yLa%A!4@Hu3Q(J$4u;Fwd zUSLzH^6`MZ8PYnzra0UV9yVF|p!-;`&;_(A=9XviML%N(Q9@7j^bRi3Bh#8n(FKZ$ zOXY$A&V!DgK6`2j^TK_^Y+_WQS72(Vw3VNRCp-u+xu_}0t%7ITw8z%5!bO5oxk^rq za44+|-!T?cbo~kHz}kVl2!O~UBU+ff!$Jwd6{JrsP!Z&2tPe+Os>5-sJ_c)?xhJud zs`DUGMeETaa}M82Hr~3eK^p-u?vTd4 zFGIT@2EB!Y2J1Sh5N)6uV7uH%HeTL4J3Vuh9&~4HO;8)S95q|2&DJmeLlmaj+JqcSxuEgbAcRrB=emKIs;}mMM0N;dON*g>*oi zm59S(%H6BxCbFD(Tam7?qyb8PG&6y)9V@emGXM1x1WnReRbsMW_W`fsY0`o+m-&l2 zO~v=madYlr*st(A1jiAdPTpp>1h* z1MXs_6|iIB=ZKk5Qy`|g52hi-5@9En+ZoFc&l6{DK|BX}72)2bMYJvgt;{`&hQJGP z*vnf_z56H8+}A%v)m(Qc)B~<(o-n~5r_onO-3w<_l-x~NN$H|ZV^}d%k$OwNU`Ks* zBO-B_HQFm=nR3l#%Bp6w2=7L?Z#>cv3kI5LD7t1g<|kyP3;Ldy!B%V(qQj6FiD7uE zty_#fu*^O+C{34?a_Fg*sVCX(J4KA7&dsERq;)*kL|4jvs~FIJFw)=dD;mknnVaOY z%M!>teL2VxVdTe zLl=wG0LBcl*i$yiO-kP@v38fuaJFLQ11iM2C#!N&*3o9ZmQK%0%;maiT>dcXp%|2q z5{uNT?ptxhQEzh%xC7kx{S_jxXfMEhtrS@-(ClTA=+HI>G? ztMMKbkFs{x@}m3Q6lUIiOx4rw8%*Qut|7ad12o)MG`di-I1EJV%Cphs28H#7yw=*t zy!7q{xrrYA<0f(|xsMsEoH|pI1}Ae|Yd+z^C`~;Nxm1<0;65we&5GKS2)`FOv)mMy zpw`{)tCV5mzEGmzK8qr9Q<$o2cepRe-axguR)K2xBfPwL$DFBfEo{gBSng!(sYk!L zGN9aaZm}YWZVKV|r)yfmLzUQNUU@hq!-y7Pe;#e%D8qrGfDk+YzcvqF$e2|#o*u0P zwnF#?rN!~bAZQx2R_AFGGHb!n$8&lutZcY_2!DKy6`=X631^lT;fn~ceBlSjvV#c1 z$|W)wbpaI?tcivi8xigsq2Wk-oV4l46##u2_{16LhMI_QT_~a}p({m%Nn#>(amvq= zG72JGDo-jOBZU@9M5-}u(|!+XO#E6@kY7bm)`lpkmX;J;dNNLHbNIXA3Z<|R#gZzO z8%uGI0Y`zRaAsO6o`CT{nlu?|0{=f;U`bkdU}-+y3Lt6~mD2tUY=9Uu&7>*alnfwL zv$$$17^IypJc0%6J5g)Wl%!&SC_mRZ3BMy{s3bAIF~1A4M~AR3=kj?#u_r;$P#~=thjxoyF%FQk-yktbGZ$-n{%`p%mRW=k6&HZ2l-MlH$Qz-%R< z@Hpbw$T9UWN;esrPkXOi?Ls(Mr66S$C^0qVL57mG@WUA_TK7?!N$?or87Pf|WRk6m zW?^$#P-NaQ1?gH*ZD|l_Jcy~}=r0!(Wzg7WUh<^nHm7P3$*Gj6JdvV-l}tk%#t*eB z&(5CLSRv38?exHnQe96=L#47=?v>oC4pFj0K0+9>Fcj2cLud)hB7fXNhG#v^B||f5 zonwT8mln!O2b&1Hr**hQlzP};k&)r$iUrNY6yz;DX!U8HJ=3P3xav3=o)(EDWVA)Z zJ{CmuJ&A{*MNNq)0jzXl(3xhe>#o!@6Xaay&x54(3U2o!_jj0LV9GxbYtLAddva3>*12}2YHUk!rl zB7X4hlBWSL(HBIAH&;DdLs%rRci5C6(q|Gx{h0*lu3*Ajh8jt#u2i1)opgy7UqeLY zVaGBL6O3Z`9lbd{4MSB#Pg3wie0u5pBJ3Q|4|W<++8l4+^e;{id$m9tt9JoB-2?HI zz(lwjMB(=DA5Q~J3rB=rcsQ#>?gw;fp*o<%rcur(3Fy{hlxXUEQsV) z<)Ve@he+b*H1%^jQwA3HThLs3ETp+ESU7st zjfPPV@;H5(BvjjKB}1jy%qb-gDk&hh&NPrv7__SrAoop_r~3E|jxA-)pfwhG?NiFb zu!vBX2Fdp*CckPQgGrswb6YMi9E%}~#X8)P966$PplmTVVJVx8G>pxhLe5}BFH;L9 zgH6~UFler-Lw$%<4l*>aJ>$b)+X7RM$G*D-nCFi-2H36bZF{3<3>}{DfI>QF8ce`q z1jeV%B(TVv>T&)CQ4TFYoJw2jGhua8ou^^@NuA3>pHP34Qn(%5UNkurLS%!nQkcBt zyP*v#c)X38!g`nXI^tGtuGj7EpN#qIk(Hrd>A;a$zchm-DOe4Wd*!d+Ln2 z3xpo37ov~R5+$0mb%-SI)~j|3_yb%-z#l<%&`oM9U-yrCkji6#3NHU9I4in6z*{yt ztH=rVAlWQdG;}Ykhkkvgl5|Jo0ij#GNvzW8Bp`jr6nvtq@D>|o>J7^SO4h7^V;pco z*d@Hisv`6k%q0RSn_me<2@B$H0%~d^>G5jp$u)+;9QjD*FeqTzDTxH~a1S+|Nx$&> zMxq>3TsjxWDoUm9`QSwWy!*Le12S3!PGo(;T^F=-)a7XmYzXs9uI-VOoJ6BVxSJ!kh(V08+F` zq6$OcUhY&?9=P+@CJ;u7*^=Vr_0Ak+;fi92Qsv3}ZlMUSJDt&^#3eYs$}C_53d6Di z0r<4ppxcUC5IkT3-i(~A{b+Kc4^gUC(UR97ikq}Zoi2oVrR+*v6=yV=6O(5$A7_!R z)I`*9Bw#H4!O9HHL4jz*N==)Jvf_52L93*kPGHlFNL`47Ch*r_|B!;C>uOcw;9SSF zLi8%?p$f7ZNNcG6qEnkzl%9>mP(7=0D1pwW>Q)1_CbiqbxuzG+&8QZ z$B64XnqD#QxU3a6DK+KUheMVDEax5_eP z%gv&NRBaNj2bx#WL?Ik|l27W<5n1g8bBltCi(M|>*S>Te?aPYiDE3)O*pG#53s+7jnMvwcxe+3b# zM|^O#a74MRvN)ISEXbpSWO;M=Ko6JCC7UT2g;DGpcaw${f~RQ}Lk-Q`MY5vQ+K>7b z@kTT`s33kRy0okSgt0hLCvDjmq6mS}G~$|hx6S;Gi^f}Y3a*I4X5q~sLycTvh6Zop z@phEFVq*;vb_T^*Z^or1+|8d;FlX+9IhH)ur@*ulXI z7R(r6RFou|%xFaM^wAWc3MYMmfgr;Zo_VTZlL}8@1Ioh6mQPEl4BS`VEJ!BdG)hGF zWYxw^zbf+RG%4h*_hjxrv8iJEj}xjCjpZhoE#92&@Yj`sl%8_cPD+=vZlfiEvicxU6r4t( zuP)*Xk z5;BF=;|+MjunanC3d66`%v? zjDk{^G3?mUrkk2H6<4GNIf17PiYYgf5~fh}j@u7L4n)hio$3)g=8cD!Om4~wP;*-& zO;MhCL9KsGmG#6yn#(g6&@kvfs?i6YB2D)GYTjipt-ahUJyl)_FZYfoNi(xye^eGl z9c$l&5ZD?uC8`t%Gypm;;6ga5Zm{yo@^DLx9~Z{VH132%Ypm6x%WBYBxY!03ID0JM zw?LdRMQvh#6%!ejpyV|auLdbUnEm9W!$vDbilcl0uZHpo=JAq939>U15Z?TtJaBMNyta(0o?8fFflIQJyZGVt5o#q)Z{olL#6p z3Mf*h5ame(4Tu7Ylqp1cy41*Axqu>N3Q?X!&_Gc@kurrSPaIZMqf3;pJ#pdJv;VKLKMxZy6Y%SU{N<{IqCEY z)5GPWV^(-_3M>;GF(R<7yPZl9Skw>UiNuHkA-tbzxj0?-Jf#UN0z!EO76~Cdfkn?` zP#Z{64eb6MHCDk(^ly$exkum*o#wOV3Ajcl4Yc4-wnp^ash=M=*~j(>{H#vm=J+?CX)K?o2Jw)CkvW71M20%|Zch z(@C~oPe@BC5ZqfxBT;?V{q`|Fj(yJPL*G)R?G(~o-{zZwaHF%SobcY6?c9UM#;BGg` zr(1o9>5$?o4PM|TU8liY-K5VZ=q7My3{e3sMp+jNc(F;U(Amt7h}o-JW_(tO^!_P^ zc8P!@5VjS~=`l1kaMu_Gh$xZN24qhG0?RxKGy!G) zBs75!G81U2fCV~<&;-8DMH5hl6QKz#bFkuAo@A7P6#-?yDMZoZqPu}8s#^3kl0-j? z{zX#iU{&N~=!yacV!E|gnmVdgUK!(}sHt`Wi&6$X(ZQ={D}h4N1`R%@e<`QHVg~|E zjK6F3f`ib+&TG^w4ocgi;ZHqjVkF$8jRe9Ic#~^52AMbJ?V6jPBDBygPR4m|wCTXDzDj88=J-s&NJ7+28_v+sa z)1K(sOZ8kw0x9sLdagptzq+~o*ZN83ew8XunRN9e<7%P&qG3nq*+Au&CsCqQzQCor zg%zf>Buy$Qd8$_l`8XyXeX6=wI0JVAFEWEl0Dspc98B82aCd$3D+~4 zft#Tdk(%0xztHxjbf#D59pmb}otxX`X|ztI(JZj1XMrhCuAI9zt4Dl+DZTCKSES05 z^siSBdfEe+(jK0gBQ-kDo_8UmcYzVOQe3wS^_ge zEs>g`mPq~QwRClsEV@viyEnJX(+NgfkL?lo8h3~TQ&wiu0xG{ex$WUl$5&>l!lZI54lgSV0jX4Zl7$BiLs3>@ z*(yv~EO-VdYAfC3QC3LJpsbLZq4SWM+Iga+UUY}&jhGztleiVoQ36WWfK4FEjN_3; zq)MkqgDYHVc2AXnD^>F78>D7n9;vC!f0Nx*=~ig%=5~1!Zwe|Tpr=AWl&4IR=cyzx zGgK0(Qe~-Z7DWrp3>8OehKeIKwc_uj3_07{?`vZ>y`pVxwECNy+vRC{y5mXesu1N# zYR)t>^e<>;s5(+ptIhnL1b1$Ri3MkfBA8DlH;wCPg8kS5O|q8o2+goxD?V zpDQ5GZElyR&vYsTM6|aw3Gg^^I6pbN<%0_d6H)FlFraPAf2Ikkeb>& zUOFO6o(4gV3=M+R3=M)*sjU2_jw7#pta9aJ%jR}@65lK2LqMrI8Ul#&Bn^>8K7g5_ z0g#&70ABgP748-Rr|O(! z#|kX%05p+<-tQF${nup!h|BC7>7zz!Fe~IIskC{bv5uMH4cnu9%RNx?Dn1 zy2H&c_J~*>C~>|vO_FAtYFtn1dJ4qE-63`gk^~f!1;hlDB^R({z2&+<{i#+BGKv(7 zNrR+Rdj?6VQjH`LW%(767DeVA%Oao{qOWakmnRWXuei$aRhaT5LY!qVgQiHW3}2OB zo@e+7?DtZnTJ~i7y%Yz($a%k)BIzQ_{a%V-i){9L zDbgt};(jkBQTE~cHJ>EP-fF*`(gE@-BA7{BR_n+L5&?lvGP^3DQJ%Vg>(8=4Q@0^=Q}zS?r8ms*o%k;SGY;y z;GU*;Zh$4M{@o1=6R;>>l?*Ha8%)x|mP>0S=rpM~rHxIgIi<;Hl_sDv1Rk!NgYf<$_YOx?La8!B`Ak6 zmKHyUxC~*U&6HR!B?|cr(HkG0t5}xW>~Gm046r#ZZAb|27dj6jSyg8DuUHPR=pYA> ztN43PW^#YhI1<`IxL;+#O|>h4`-hw?Y%bO9E43bI_0{O2Tt)#2o^*oGD(m+i4+rZl zo|E0pv{aNSx-@BPaMtyYEVWpo2iiP6cu2womVrWgW|k^M#!03z1GH2XLTKqaWTEJg zMy)sqO<++bGy(;_%GEVp8Z6OU#3*!u23_@&7OFB)*KUUX9c*1R zt%1kN8&NWYQZSB{s=cbUV;VwgFWjZey5E%fgOoDmjVSLyuw%Sj9V<@AIIo^pfOFKw#UCTT$xs`a&bS-hAY!epNo64FAH6nhAMR%frksT z;jY#=KX-8_+nVk%dU}#s8+6P&u94@@W}RO~F>s57jt7lFX-65}+4PgVmuV6-56VVU zc$8@rxC^r3zNrV52t07NWNY`aT3AGhd=swVh;sQRenr`chWRGkEt&@r+;8Gxgcj-v z`uCe~1xHlcH}N384GDHcpM8>PPD#asn8pvAi(hN`5e8mp3?jqWtp z!Vyr4f_bsQ^|?zyDmAqjm6}?}1WkOp{zaQP+2&!v6)w;g0!sGGg)G#>zrj`$6x{K^ z|A>&kN1hTo6?Rx^1v>Pr>-8@xa74BWq~c~Ecf0mji7yZ227j7GH}0eNvcxY8+>Lv( z;7YW@CuaX^e`|1>22IDJ{!Oj&EbWmM$1BQxGh4Y!G_FWYHepM}%g{9MYEmES-+d5b z@MwFFJnq%W2n`lc&J$?N)OrX(LCa9)<9d<&s{Tb)ANw*(6ASKd&5?yPYgQIbEA={? zdhD|-+~;LE~C{czQ{c;&91#!XbR4eI>M96&xTv7am29+Tqj%A1xKQ5fqP>% zseMk<_28bItqrQQn^fGUp!;z)>wkyF{k#4J?v!j+#i82wbe8@FZZsRNEO5oo0o-`D znQ)7yCvGg_H(Q&DkK_`)6aen@Y>Fe*`wQHPY;;rI!ocmy*1oC!V&IO=MpwMX7oDrd z5pdtkCOb)uBW`8jK9#L*cW7MMYXYwGc^3H{IYpH{PXA^b6M6dmLj4Px%d*vLt;TuE zgPTpp#2OPOqi=1;5S%+^@3rn^@78=@kHQ2WJ~Qf+M>W#6vb**}jmd zZQ#z%)^Fn9+~e|aR<`yPoPD%q54u-m!xfxEG;TIIm-iE0np?8b6r3^_w=-MYR%#px zPY17!2kRA=mGVz;ZvQ8|iZepO+q2b4-e2ji4i;zQQ*b0q{+sv|oE@5Ow({k@Sl*zy zJX`sKGe8F_P@iVA+K$#ZV#5RX!fd#LBcbHLt;jat2#$nK0C!3@J3(+HumZRzWUHIt zta0nsnr$3hI7bP^68#IOqkvbKqzVDA(Mfc?b$(BZI9Wn#xye{2pb+p`l>&Ncm1U(B zH?-ynC7E53+v3XgEwHRV00t$f~Yt@AUdx@1~C3cY^Rv}=!Nh%i5ORFM{R=v(3 z1bo*2JFS(PCM0BCHor`2xj9y=B|I$B`E#sjY6n|m^}Bri3uzIs!X#A)c!5sJEGsZ_uVbdqhwb9&^V&c#bD@YlL3 zZ|Yxk`IFhYJYSO$vY2x3)fQtvvdc8y?fMrqpUp<|F^#iB|3VxD+*GWnq74LmLMN%d zm!|{g8N_~k;6cdmGUTfTlw6tmUb4MzvXu$gY`7{FQ207vdt|dq=1w8*a&V1-gIJ^Oa@Dw=pf>NxGb~OnJouPB%&C z3+Q3t#xzn7YW^P9ztp`hg9;jzy|^82aRR<=lG64AQ|n8GNriuAviVcX?>tPU+^m1$ z?i27!lXSj-*B!2~(c;V6kI~gS!|jG;?X&d5rQXCJ>j!BFL{kXpX~1P^4H(pX3zH;r zmEb_w5Dp|=3YGFCJ+;z8SDF?42>1;xe2i|7Y5JF1_-)-FIc{~=wx_a@soyv1s!6$o zBk)fSRSbhI0iQQXRRV6)Nw)O^UynQ-;`W(<(s<~z&zDNeJ)-&cSyci`V*)R|3Y%#NrFEN&D3wf_(O4|tGM$8*5W+q3 zAfo8dV7qR>j1fJO;%Sn*O_NCNQPsQCM356*Rur^SmwL6!kbqB_q=f=X;fNU((8I?S zhL0EBuDPOJ9)4@&tyn-AIz&&u^;F@COjWodtqU*Fd`g?a@D)(T397!VUB-upW3;I* z_EwkUW$kzA2N@QKR}s*|-m*;Wr7N%-HG50VXebr1!z9fYKK`VOh7K0+6O&Xdpl|`K zOSRS!eV1XcW|@{pX$_cGq8N@c9Fzzs%`*@|7MEDZ_6TP(!jL<)OhHW*u2kjV(Xo46 z;S%=#Y=+H3DbuZI+FU2JMKrNi5bzU2$S;JRGHsY9Xpp^BzSCQ$IJI?9mDE;1QYs;- z<(Im)xX-4&$2=G|7up&;R{t_yDzQOnNX@<;$uY$xmaD;1mzb|d9;C6+T&eWs)m4U6 z`9DYb7Hv0A+D<0V{j8-F*zAlvu_v{F^p-D6%?Gc2-o(_BrC3iHpD)c&#^+1L(DRh>`O*w!e7^Ksl(Eqmlb(8PG{&T-jE(IX z%1F23Gt^^4rZP5UDq};YGSXKVyLA^zzmN$h@O-0lN>f`8N;!2+A45=jow;9@D(UzB@bBnyv%^N^vqzvWBQRH;}QI%|sNqEi2&0s^*} zq*4LfbW-LDOwn)4OvW++TTN2AfL>bZE>fYTqrEHyh6w1*nC=dhj8Y3+?IoZ$W4h~e zux9Zj!|HqiC+MWi)s~D$nT%xudNZciQ8FHDGR_mwn=!qPl2Q0W9R>7eOt0fhx}@Km z66Xup;Ztdu>nIubnv7)vdNZciQ8Ml^8RrS;&6r+C$@sp>SR$Y|WA-`@)D^-ox-nY} zyWos+aqrEBJ6q#a>fdZL;syHs#V*a+1G5a{;(b)@I`uC`pMbBMq=f?R)k&(01W}3ixI}MBVu2M;Puh+?5F^{7?yHJ@RCm63PS=E)}9Y zo#i45=w&5cvV@hZ4J-2myiOrGOHks=NBXhIuI4;KF_jdr;-f>eym7b!1hh?fhv%p?`B*Pv7@ zgH`@hUEVgsLbaoFNqIP=ev3|e$-z`(`$} z!lu+4xEr(K3eL+e4^B27y0j*HQ2#~ zZwcvYA-#kWDM6YQ!&5+Sp(Uo!LrtM20!o{z0WVL|te_~Mm%H=<|DLY5l#c-~v`S5( z#R4ucNofOqvnKRs(~#AEjoof?RbQ#Wb#78>pGymj(kPJhpJ$u5h1CidcksShMw@W6 z%*EZ1ZSEE}*Sol{Wy5__m1hkcplX6qAYhS6Di^RpC#ex6Pd|1M1-#!R%@^>=etG37 z->A280q5!@RY+pp9Lyd4$AEm)_-K12>kY?Ddb7Sbelx;W( z_wTv571<^v;bxdF8gxI-MpxLJ;^H2bjqYQ5c)qQFG4uo+u16*80s+V9BNVrpv&ckdbQ$^?|ciIp7gi(!Ur%05FiXHaKofQQ3C=3qKyiO z69y0&9+iLyh=KuBK&CJ$GKruV5#-zFp8s!Gr|O(ezwf(T>&seD|GjI^Rj1BWeXdR4 zC1qQCDZ^GWXR@W=6QC|+Y_jvqeyW2E8JO(6mGY^aJOrJsc;|R6n!s;~RXlxBJj@jv zz;8OM4(zm*&Pr^}b;TO6Q!$;DsbXJ|Vmd2PJVqYN9#?%){oh!Q+&s;(Z>zOc0Jz9m zb>Pin6<2nidM{UN@2-J2IjaTiw3SvCTW7jr4cMueRu;vJT(J+>shCz4#UD!1CSU1q zM|hI*;T3aXs~YeQXAJ@G6f3V9)N3x-1U@hxb3?#CJF5wN-C0AxHGKXxfm=Fj2>4EC zHGz9OYe;E(ljhhUM^eZVYP6xq!iF747P%nQbDls0NFuo))J7g%14u5pAk@x55J+aZ zpl2mOa+7=zYQXO~YY<3=nXQ`VJI7pmccgTT&!(`ik>41qmi1a?N( z=g~0)CJ3bdStxyNsF!>+`he6w7lc~LW9|czPA&*FJqQ9jlS>ahGHI&x<153qPk!=8 zCb!`XF59!$;e%j>rJh9I7uA@h~ zHksUp^(F7hwX7?iWN{$2Rc<&DI!)1Ds@9gB{<3r44EZD*lYPAG5|ivm#blo?lU*pg zH>oW)0OIf6hzg7Iq}3c#3w!I zCXgc9p?_iAk*Kfbp9|^THs?`1yZ8)iZt z5~>TNx+50jNN!XFOVrwlZt2P;_q5lj1W&0o*(s}($WkUsWU>p&WRFwH=Bq6`zf)4G zVK)2AY$Eep*)-Yv%TCG^l!eS>7napvMb&pbwI;h;nJh9hgY29#S;p_sAUml{mLuuh zAp5tnYp2C)?6Yv@ya05t`woCvCF$=g+5b!Jlu6P^`AR*?uP(*1?fSm!Sj{?$wYXp3< z=P(5947lb2f5wMm2zX7$P}JH`{|JIWGR)GbwW0p)15^X<*irXd8)|ni%n-0M-}F{5 z&9{$yf9Cntft~sG735nl%D2z+z0lLB18){9%eSu$Mc#I)1pKS(_5m5>To;OQHeFz6 z3DV1~E0yQ3J>M#DW*DG2GrNL`b1)V`yv@g<3S@{1E`5gN`FkM(Dvet^fghj>e8DS` zJp8>jN+r8AAeXg0mwGrpbM#)R)q;N@ho)U;6B4u6SkKGm=nxW+aWg535-KnVWRhBX zKnBee<2YZ?^7kLLS$g1pkG(~J<21uIx$!FSac8wwRu!gsg{#0Y zfm-QoN!+a}1MgI8r=!KImYkB$l+4%FmYrrFQvYLW?FY2!a{+{wNXVY50nsbi_=FZB z7Ve_5U(_C=u{c+)$u1~MEv}TwR?0S7vtld`c4wB^WfH8UgVXFzDwAcRY!_tTUbcZd zo=BP9va@|W%T4y+vKSWXir^--cD4upN~~<@Yqp^t41&PFEh88oP^pJTk%xwR__KRx z06RUT=hM_ft;j>oJv{CnYQRnp=@~5b&{yQ4&prIkJ@f%PJ)|cH%1g#}bO4|0C~ulP ziX>vsK7gHyX-+5-pFLLvb}E*K%JAEi0Y2-Y9)J088>-V>`gt4TK+0z8;<9V>%If*- z8d7Vnfxp&zozK>I5~hlcBE_`4sbUSq(-ef=B`rPSxrw>U)fC1m8S|X6XFX^Co7{ev zxCg4WQxWiRu|}-KVZWn1-_b$uwG$x51^YniV)kDcEQ>t9cmHhPciXsNEFhG^TQ7`okmY_;yXa ztQg>J#j|Tf;0``N?Gpj-6>(gU1AeAc?u#P6=S*7^Ag&g3f_)V#dsQ=UavRpQQP=R~ zcG1|y^Ng_embxuO*&0;x8_`(0;0i1j$v#?qQZjL$lsnczTg5jjyOu%rS?Sm+9%sQj ziNES$jEMlR^m9yhSyHC>cUNoxI~CJ~9*-}&Vh#9NKbg0HU+)N_)`t2)5CnEQP0zu9 zkh4FlolrTZGXB7g=TW`3C0qa;*U%1~c=GHq_oO*Z>BP1F^?VCB3CfGwcDOEDtK=>a*{{2Y7}uIOc%5KZ(ZFxI)&LOC`RGDD76gHK&IO@D9Lbmy zN7HT9fG0U?2zY_BTEI)4HAGyGI;#cbvHA-35r7>wZKr`Hdth2J@^Lp-1>)KsW8(79 zE;S3=&pWFc7av1syNJh5pasvR=1V%buj2lHV~^|Npb`0< z4BLS)zwAJmt~VZg_&b;;@F8c_fqxP!pXE?ncmhc%nE#;LY5*U0Rtt#1d`?0I^T{EP z`H#D;8W1g8kS`yOD|E2rPjS5}@D^tc62N57ZxA@mS;>?cifm`sUl{+s8y~tt@TR~@ z{SC$bGGlQv-;jmxxTPwVRu5qU*LPMj+lca8ZfF+pDzU~?hKJh_p;WVQxQ<(&6^Dt) z1`@GZSuLBD3$=;l*S<-q34GC6b>Mw^kC@L&C|+k593Ys#$!#@&OP$pMVlbbTP{DjM zD=|;Vc7+ez(|3yu0r%>NzSf3X5Cnl|Eh7jO;z$<8G>$&v*vZWg;PJS?!uGEM3wWoq z`hjPOf~3;|h#VF>l@zTxurC_j>TpK>D z=}QioWh#!v&fpp0k*6(Rll?b)`1S|};$3298`Vf@ai<`I(=Dl66y8IAlvRO5Y)di$ zKPvOaij5l!KeK(1lM#JF2~}js*2w+K)<|U5kgUDVKJv%$6ft^G{a+3?Z`aQjLA*;&GeK~_c=pf> z_#6EOBNGEZBc6!?2{sdp|E1B^i1tx0Mhi%M`A9+$p&imdBDDKGAOV^b@F|bA27Fbl z+ym4KUhWofC9!frC{i^i%g?kg&2*?J)4q0^=}?+!Uz+IYU1MuI>Dd8!=5VYy!i;AYA5c0} zns#LZBpB06KX?3j$)6YWfZrBtjqG)UpxxBu+s{%K3*1+9@PddxT>oZ{}t{1#Bu$VqopX1eU3Emu7%-bz|(W(NsaaQug z@ot@!Hc&R%6a~+4-i$VwtZi`49FFtOl;gxl1ep&Uz?mRNE~8L%aLiK#U-C${O(tS0 zlRlu0WeUEn{E9|pJ=NVVkEX0q@`PePRs9sTCOf-K_A<%b7Gx)tJ24tj`dJ#K<$CFZ?p~o$t|;0 z^Gu1-1c3*795o;zniOzBkOFo_n_k;exPv^}J|H35T1S)wV=UmHd+Y-eOqNq$8|suG z2)snBTre)=t_mr{F+?2LEO?z4e{IZ8-h6nBkGR>~!_amf)GQ#0*=O4q>GNwLvacwn zi`9;^17|hH!3d|>u*f9T! zo38;0%FbBn`^r?W54}}9tO3HoRKa;BHPnwGw6bKjNYgK{4P#r_0U{|WZV7m@H*(XOe zc2|>|j|X=^wgcMeT|7)(_Vl_`PZMkh7Vu%QOf`Mxu!&r47F+^17ptpY5E}nRa@?iH zo3ZhNq8};0q-^KdxKI}=rSGb>ga5^{cQeRd?v+V);!q*xkC~fN_M8dX$I8vEq!Ipz zk93j%li{-xF^{EBt4Mw)0Xr1{-{IfdtOMUAR=y%ZT@nN_7q{_M(b_SeYV59-} z5%30XYmm@zV;2~}VVCLywmYIte;$x}>`y%o;T+HTN(zN@Tm68?dmR11&dk$Q_z(qx zCp*>gX>-9NXI&4)0-r#$LTEN@H%2!1wJ~m+U7x>09f>2xeF3#kFjyN{cD|&lE z44mL`>;vTc3U*GtZWw}a^3@aSxu6XsoLmsaNW)`lV|J3RwCou;cQPT5muznud9+?@^rag#aibEmHcK_F$w1)&I~;Gx$>vhh>5 zH9!JO11mL@ytdy;(mT0U6}ZS*L%>^|)x_Ov&KgSHB@duilJwrLRR=Osw)6w94^p`M zM_{Gyl1r51CH*v&><2liIYlh9%I>plihYoV`on%sU{*!5Q`ibw2~pGi*dG>udgpo zvZ+*Jxq=%Y7KTlHDQg15v68HAsa9XAl_Wby%gRZqHwWZpMT$9qc?##DXwX%*g)~0ZfgL@2Fc7;qYbsXhdKc4beh)m2eSNQ z_fQ2s=d3#L1!q<9INm)bH6@{2rIpnbd`GYZ490!8@~UpU1tgs=l_#{!9~iZ4>rA|; zO;jv=@zXBvfHe=Z4m?Y&;z4|~df)DfRp0_=wSd?vNCvIlTq`-icUKpYnHAvau2lzq z&RL0}IeI5_s#+@m@Y~L+19??dTmWo+!4(_8e>!Ur_?lSxEQZ2E!37n63E+0ORRuod ztmM>kp1OXZHk%pXJ6&xS@ORE?0fX^b@$~sxWZZ@U+mE}UIxrYYhM`-OK`l9PqZUMx zt4AJOe?||bZGeFrd5A6G;bIjJ@M*H~Hdm|ycXd`BxQDZT0UZ9s`tBg12ECctTC!e6flv5i4e+ zhUVwoSaL+nP}gy4$J=($2}?J$uPMSgJ@gFcJ@I7NQ4;&BwOc_TMpiJh@7y4;}0*B4+O5GIJBP z)2pV|Rtexooz(~Yy|V^@4~dmeOQ^lHY0F+(0QoF`E(o==c2=1nu;HvG@Cax10q2NS zd^nKSULJ4*$lolrTN5BrXSNz`sIbFu5J=RyAQXX{Mc^SGa05u-R$*Xg4(W|OIq;{= z?C=HN>uI%sM4g3J^Bn#Y1c57SPv6+evGa!8Pz0W!jVOQE z7_-?j4Bk%1guQwB>F|3+Fo*0g1`^7MoK^&H-m1}izgl}!%0A_VVvYPL{>LJ24syUp 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 diff --git a/buildroot/share/vscode/avrdude_5.10_macOS b/buildroot/share/vscode/avrdude_5.10_macOS deleted file mode 100644 index dbcfc997e4b38549229131c49f40811eaa561d00..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 346784 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

&@;gZ7-Z7~G`%wWNxP{dWNkzCee17xit&z2uV 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 [, [, ] ...] ; # are quoted strings -# desc = ; # quoted string -# type = par | stk500 | stk500v2 | stk500pp | stk500hvsp | stk500generic | -# stk600 | stk600pp | stk600hvsp | -# avr910 | butterfly | usbasp | -# jtagmki | jtagmkii | jtagmkii_isp | jtagmkii_dw | -# jtagmkII_avr32 | jtagmkii_pdi | -# dragon_dw | dragon_jtag | dragon_isp | dragon_pp | -# dragon_hvsp | dragon_pdi | arduino; # programmer type -# baudrate = ; # baudrate for avr910-programmer -# vcc = [, ... ] ; # pin number(s) -# reset = ; # pin number -# sck = ; # pin number -# mosi = ; # pin number -# miso = ; # pin number -# errled = ; # pin number -# rdyled = ; # pin number -# pgmled = ; # pin number -# vfyled = ; # pin number -# ; -# -# part -# id = ; # quoted string -# desc = ; # quoted string -# has_jtag = ; # part has JTAG i/f -# has_debugwire = ; # part has debugWire i/f -# has_pdi = ; # part has PDI i/f -# has_tpi = ; # part has TPI i/f -# devicecode = ; # deprecated, use stk500_devcode -# stk500_devcode = ; # numeric -# avr910_devcode = ; # numeric -# signature = ; # signature bytes -# chip_erase_delay = ; # micro-seconds -# reset = dedicated | io; -# retry_pulse = reset | sck; -# pgm_enable = ; -# chip_erase = ; -# chip_erase_delay = ; # chip erase delay (us) -# # STK500 parameters (parallel programming IO lines) -# pagel = ; # pin name in hex, i.e., 0xD7 -# bs2 = ; # pin name in hex, i.e., 0xA0 -# serial = ; # can use serial downloading -# parallel = ; # can use par. programming -# # STK500v2 parameters, to be taken from Atmel's XML files -# timeout = ; -# stabdelay = ; -# cmdexedelay = ; -# synchloops = ; -# bytedelay = ; -# pollvalue = ; -# pollindex = ; -# predelay = ; -# postdelay = ; -# pollmethod = ; -# mode = ; -# delay = ; -# blocksize = ; -# readsize = ; -# hvspcmdexedelay = ; -# # STK500v2 HV programming parameters, from XML -# pp_controlstack = , , ...; # PP only -# hvsp_controlstack = , , ...; # HVSP only -# hventerstabdelay = ; -# progmodedelay = ; # PP only -# latchcycles = ; -# togglevtg = ; -# poweroffdelay = ; -# resetdelayms = ; -# resetdelayus = ; -# hvleavestabdelay = ; -# resetdelay = ; -# synchcycles = ; # HVSP only -# chiperasepulsewidth = ; # PP only -# chiperasepolltimeout = ; -# chiperasetime = ; # HVSP only -# programfusepulsewidth = ; # PP only -# programfusepolltimeout = ; -# programlockpulsewidth = ; # PP only -# programlockpolltimeout = ; -# # JTAG ICE mkII parameters, also from XML files -# allowfullpagebitstream = ; -# enablepageprogramming = ; -# idr = ; # IO addr of IDR (OCD) reg. -# rampz = ; # IO addr of RAMPZ reg. -# spmcr = ; # mem addr of SPMC[S]R reg. -# eecr = ; # mem addr of EECR reg. -# # (only when != 0x3c) -# is_avr32 = ; # AVR32 part -# -# memory -# paged = ; # yes / no -# size = ; # bytes -# page_size = ; # bytes -# num_pages = ; # numeric -# min_write_delay = ; # micro-seconds -# max_write_delay = ; # micro-seconds -# readback_p1 = ; # byte value -# readback_p2 = ; # byte value -# pwroff_after_write = ; # yes / no -# read = ; -# write = ; -# read_lo = ; -# read_hi = ; -# write_lo = ; -# write_hi = ; -# loadpage_lo = ; -# loadpage_hi = ; -# writepage = ; -# ; -# ; -# -# If any of the above parameters are not specified, the default value -# of 0 is used for numerics or the empty string ("") for string -# values. If a required parameter is left empty, AVRDUDE will -# complain. -# -# NOTES: -# * 'devicecode' is the device code used by the STK500 (see codes -# listed below) -# * Not all memory types will implement all instructions. -# * AVR Fuse bits and Lock bits are implemented as a type of memory. -# * Example memory types are: -# "flash", "eeprom", "fuse", "lfuse" (low fuse), "hfuse" (high -# fuse), "signature", "calibration", "lock" -# * The memory type specified on the avrdude command line must match -# one of the memory types defined for the specified chip. -# * The pwroff_after_write flag causes avrdude to attempt to -# power the device off and back on after an unsuccessful write to -# the affected memory area if VCC programmer pins are defined. If -# VCC pins are not defined for the programmer, a message -# indicating that the device needs a power-cycle is printed out. -# This flag was added to work around a problem with the -# at90s4433/2333's; see the at90s4433 errata page 2 at: -# -# https://ww1.microchip.com/downloads/en/AppNotes/doc2574.pdf -# -# INSTRUCTION FORMATS -# -# Instruction formats are specified as a comma separated list of -# string values containing information (bit specifiers) about each -# of the 32 bits of the instruction. Bit specifiers may be one of -# the following formats: -# -# '1' = the bit is always set on input as well as output -# -# '0' = the bit is always clear on input as well as output -# -# 'x' = the bit is ignored on input and output -# -# 'a' = the bit is an address bit, the bit-number matches this bit -# specifier's position within the current instruction byte -# -# 'aN' = the bit is the Nth address bit, bit-number = N, i.e., a12 -# is address bit 12 on input, a0 is address bit 0. -# -# 'i' = the bit is an input data bit -# -# 'o' = the bit is an output data bit -# -# Each instruction must be composed of 32 bit specifiers. The -# instruction specification closely follows the instruction data -# provided in Atmel's data sheets for their parts. -# -# See below for some examples. -# -# -# The following are STK500 part device codes to use for the -# "devicecode" field of the part. These came from Atmel's software -# section avr061.zip which accompanies the application note -# AVR061 available from: -# -# https://www.microchip.com/en-us/application-notes/an2525 -# - -#define ATTINY10 0x10 /* the _old_ one that never existed! */ -#define ATTINY11 0x11 -#define ATTINY12 0x12 -#define ATTINY15 0x13 -#define ATTINY13 0x14 - -#define ATTINY22 0x20 -#define ATTINY26 0x21 -#define ATTINY28 0x22 -#define ATTINY2313 0x23 - -#define AT90S1200 0x33 - -#define AT90S2313 0x40 -#define AT90S2323 0x41 -#define AT90S2333 0x42 -#define AT90S2343 0x43 - -#define AT90S4414 0x50 -#define AT90S4433 0x51 -#define AT90S4434 0x52 -#define ATMEGA48 0x59 - -#define AT90S8515 0x60 -#define AT90S8535 0x61 -#define AT90C8534 0x62 -#define ATMEGA8515 0x63 -#define ATMEGA8535 0x64 - -#define ATMEGA8 0x70 -#define ATMEGA88 0x73 -#define ATMEGA168 0x86 - -#define ATMEGA161 0x80 -#define ATMEGA163 0x81 -#define ATMEGA16 0x82 -#define ATMEGA162 0x83 -#define ATMEGA169 0x84 - -#define ATMEGA323 0x90 -#define ATMEGA32 0x91 - -#define ATMEGA64 0xA0 - -#define ATMEGA103 0xB1 -#define ATMEGA128 0xB2 -#define AT90CAN128 0xB3 -#define AT90CAN64 0xB3 -#define AT90CAN32 0xB3 - -#define AT86RF401 0xD0 - -#define AT89START 0xE0 -#define AT89S51 0xE0 -#define AT89S52 0xE1 - -# The following table lists the devices in the original AVR910 -# appnote: -# |Device |Signature | Code | -# +-------+----------+------+ -# |tiny12 | 1E 90 05 | 0x55 | -# |tiny15 | 1E 90 06 | 0x56 | -# | | | | -# | S1200 | 1E 90 01 | 0x13 | -# | | | | -# | S2313 | 1E 91 01 | 0x20 | -# | S2323 | 1E 91 02 | 0x48 | -# | S2333 | 1E 91 05 | 0x34 | -# | S2343 | 1E 91 03 | 0x4C | -# | | | | -# | S4414 | 1E 92 01 | 0x28 | -# | S4433 | 1E 92 03 | 0x30 | -# | S4434 | 1E 92 02 | 0x6C | -# | | | | -# | S8515 | 1E 93 01 | 0x38 | -# | S8535 | 1E 93 03 | 0x68 | -# | | | | -# |mega32 | 1E 95 01 | 0x72 | -# |mega83 | 1E 93 05 | 0x65 | -# |mega103| 1E 97 01 | 0x41 | -# |mega161| 1E 94 01 | 0x60 | -# |mega163| 1E 94 02 | 0x64 | - -# Appnote AVR109 also has a table of AVR910 device codes, which -# lists: -# dev avr910 signature -# ATmega8 0x77 0x1E 0x93 0x07 -# ATmega8515 0x3B 0x1E 0x93 0x06 -# ATmega8535 0x6A 0x1E 0x93 0x08 -# ATmega16 0x75 0x1E 0x94 0x03 -# ATmega162 0x63 0x1E 0x94 0x04 -# ATmega163 0x66 0x1E 0x94 0x02 -# ATmega169 0x79 0x1E 0x94 0x05 -# ATmega32 0x7F 0x1E 0x95 0x02 -# ATmega323 0x73 0x1E 0x95 0x01 -# ATmega64 0x46 0x1E 0x96 0x02 -# ATmega128 0x44 0x1E 0x97 0x02 -# -# These codes refer to "BOOT" device codes which are apparently -# different than standard device codes, for whatever reasons -# (often one above the standard code). - -# There are several extended versions of AVR910 implementations around -# in the Internet. These add the following codes (only devices that -# actually exist are listed): - -# ATmega8515 0x3A -# ATmega128 0x43 -# ATmega64 0x45 -# ATtiny26 0x5E -# ATmega8535 0x69 -# ATmega32 0x72 -# ATmega16 0x74 -# ATmega8 0x76 -# ATmega169 0x78 - -# -# Overall avrdude defaults -# -default_parallel = "/dev/parport0"; -default_serial = "/dev/ttyS0"; - - -# -# PROGRAMMER DEFINITIONS -# - -programmer - id = "arduino"; - desc = "Arduino"; - type = arduino; -; - -programmer - id = "avrisp"; - desc = "Atmel AVR ISP"; - type = stk500; -; - -programmer - id = "avrispv2"; - desc = "Atmel AVR ISP V2"; - type = stk500v2; -; - -programmer - id = "avrispmkII"; - desc = "Atmel AVR ISP mkII"; - type = stk500v2; -; - -programmer - id = "avrisp2"; - desc = "Atmel AVR ISP mkII"; - type = stk500v2; -; - -programmer - id = "buspirate"; - desc = "The Bus Pirate"; - type = buspirate; -; - -# This is supposed to be the "default" STK500 entry. -# Attempts to select the correct firmware version -# by probing for it. Better use one of the entries -# below instead. -programmer - id = "stk500"; - desc = "Atmel STK500"; - type = stk500generic; -; - -programmer - id = "stk500v1"; - desc = "Atmel STK500 Version 1.x firmware"; - type = stk500; -; - -programmer - id = "mib510"; - desc = "Crossbow MIB510 programming board"; - type = stk500; -; - -programmer - id = "stk500v2"; - desc = "Atmel STK500 Version 2.x firmware"; - type = stk500v2; -; - -programmer - id = "stk500pp"; - desc = "Atmel STK500 V2 in parallel programming mode"; - type = stk500pp; -; - -programmer - id = "stk500hvsp"; - desc = "Atmel STK500 V2 in high-voltage serial programming mode"; - type = stk500hvsp; -; - -programmer - id = "stk600"; - desc = "Atmel STK600"; - type = stk600; -; - -programmer - id = "stk600pp"; - desc = "Atmel STK600 in parallel programming mode"; - type = stk600pp; -; - -programmer - id = "stk600hvsp"; - desc = "Atmel STK600 in high-voltage serial programming mode"; - type = stk600hvsp; -; - -programmer - id = "avr910"; - desc = "Atmel Low Cost Serial Programmer"; - type = avr910; -; - -programmer - id = "usbasp"; - desc = "USBasp, https://www.fischl.de/usbasp/"; - type = usbasp; -; - -programmer - id = "usbtiny"; - desc = "USBtiny simple USB programmer, https://learn.adafruit.com/usbtinyisp"; - type = usbtiny; -; - -programmer - id = "butterfly"; - desc = "Atmel Butterfly Development Board"; - type = butterfly; -; - -programmer - id = "avr109"; - desc = "Atmel AppNote AVR109 Boot Loader"; - type = butterfly; -; - -programmer - id = "avr911"; - desc = "Atmel AppNote AVR911 AVROSP"; - type = butterfly; -; - -programmer - id = "jtagmkI"; - desc = "Atmel JTAG ICE (mkI)"; - baudrate = 115200; # default is 115200 - type = jtagmki; -; - -# easier to type -programmer - id = "jtag1"; - desc = "Atmel JTAG ICE (mkI)"; - baudrate = 115200; # default is 115200 - type = jtagmki; -; - -# easier to type -programmer - id = "jtag1slow"; - desc = "Atmel JTAG ICE (mkI)"; - baudrate = 19200; - type = jtagmki; -; - -programmer - id = "jtagmkII"; - desc = "Atmel JTAG ICE mkII"; - baudrate = 19200; # default is 19200 - type = jtagmkii; -; - -# easier to type -programmer - id = "jtag2slow"; - desc = "Atmel JTAG ICE mkII"; - baudrate = 19200; # default is 19200 - type = jtagmkii; -; - -# JTAG ICE mkII @ 115200 Bd -programmer - id = "jtag2fast"; - desc = "Atmel JTAG ICE mkII"; - baudrate = 115200; - type = jtagmkii; -; - -# make the fast one the default, people will love that -programmer - id = "jtag2"; - desc = "Atmel JTAG ICE mkII"; - baudrate = 115200; - type = jtagmkii; -; - -# JTAG ICE mkII in ISP mode -programmer - id = "jtag2isp"; - desc = "Atmel JTAG ICE mkII in ISP mode"; - baudrate = 115200; - type = jtagmkii_isp; -; - -# JTAG ICE mkII in debugWire mode -programmer - id = "jtag2dw"; - desc = "Atmel JTAG ICE mkII in debugWire mode"; - baudrate = 115200; - type = jtagmkii_dw; -; - -# JTAG ICE mkII in AVR32 mode -programmer - id = "jtagmkII_avr32"; - desc = "Atmel JTAG ICE mkII im AVR32 mode"; - baudrate = 115200; - type = jtagmkii_avr32; -; - -# JTAG ICE mkII in AVR32 mode -programmer - id = "jtag2avr32"; - desc = "Atmel JTAG ICE mkII im AVR32 mode"; - baudrate = 115200; - type = jtagmkii_avr32; -; - -# JTAG ICE mkII in PDI mode -programmer - id = "jtag2pdi"; - desc = "Atmel JTAG ICE mkII PDI mode"; - baudrate = 115200; - type = jtagmkii_pdi; -; - -# AVR Dragon in JTAG mode -programmer - id = "dragon_jtag"; - desc = "Atmel AVR Dragon in JTAG mode"; - baudrate = 115200; - type = dragon_jtag; -; - -# AVR Dragon in ISP mode -programmer - id = "dragon_isp"; - desc = "Atmel AVR Dragon in ISP mode"; - baudrate = 115200; - type = dragon_isp; -; - -# AVR Dragon in PP mode -programmer - id = "dragon_pp"; - desc = "Atmel AVR Dragon in PP mode"; - baudrate = 115200; - type = dragon_pp; -; - -# AVR Dragon in HVSP mode -programmer - id = "dragon_hvsp"; - desc = "Atmel AVR Dragon in HVSP mode"; - baudrate = 115200; - type = dragon_hvsp; -; - -# AVR Dragon in debugWire mode -programmer - id = "dragon_dw"; - desc = "Atmel AVR Dragon in debugWire mode"; - baudrate = 115200; - type = dragon_dw; -; - -# AVR Dragon in PDI mode -programmer - id = "dragon_pdi"; - desc = "Atmel AVR Dragon in PDI mode"; - baudrate = 115200; - type = dragon_pdi; -; - -programmer - id = "pavr"; - desc = "Jason Kyle's pAVR Serial Programmer"; - type = avr910; -; - -# Parallel port programmers. - -programmer - id = "bsd"; - desc = "Brian Dean's Programmer, https://savannah.nongnu.org/projects/avrdude"; - type = par; - vcc = 2, 3, 4, 5; - reset = 7; - sck = 8; - mosi = 9; - miso = 10; -; - -programmer - id = "stk200"; - desc = "STK200"; - type = par; - buff = 4, 5; - sck = 6; - mosi = 7; - reset = 9; - miso = 10; -; - -# The programming dongle used by the popular Ponyprog -# utility. It is almost similar to the STK200 one, -# except that there is a LED indicating that the -# programming is currently in progress. - -programmer - id = "pony-stk200"; - desc = "Pony Prog STK200"; - type = par; - buff = 4, 5; - sck = 6; - mosi = 7; - reset = 9; - miso = 10; - pgmled = 8; -; - -programmer - id = "dt006"; - desc = "Dontronics DT006"; - type = par; - reset = 4; - sck = 5; - mosi = 2; - miso = 11; -; - -programmer - id = "bascom"; - desc = "Bascom SAMPLE programming cable"; - type = par; - reset = 4; - sck = 5; - mosi = 2; - miso = 11; -; - -programmer - id = "alf"; - desc = "Nightshade ALF-PgmAVR, http://nightshade.homeip.net/"; - type = par; - vcc = 2, 3, 4, 5; - buff = 6; - reset = 7; - sck = 8; - mosi = 9; - miso = 10; - errled = 1; - rdyled = 14; - pgmled = 16; - vfyled = 17; -; - -programmer - id = "sp12"; - desc = "Steve Bolt's Programmer"; - type = par; - vcc = 4,5,6,7,8; - reset = 3; - sck = 2; - mosi = 9; - miso = 11; -; - -programmer - id = "picoweb"; - desc = "Picoweb Programming Cable, http://www.picoweb.net/"; - type = par; - reset = 2; - sck = 3; - mosi = 4; - miso = 13; -; - -programmer - id = "abcmini"; - desc = "ABCmini Board, aka Dick Smith HOTCHIP"; - type = par; - reset = 4; - sck = 3; - mosi = 2; - miso = 10; -; - -programmer - id = "futurlec"; - desc = "Futurlec.com programming cable."; - type = par; - reset = 3; - sck = 2; - mosi = 1; - miso = 10; -; - - -# From the contributor of the "xil" jtag cable: -# The "vcc" definition isn't really vcc (the cable gets its power from -# the programming circuit) but is necessary to switch one of the -# buffer lines (trying to add it to the "buff" lines doesn't work). -# With this, TMS connects to RESET, TDI to MOSI, TDO to MISO and TCK -# to SCK (plus vcc/gnd of course) -programmer - id = "xil"; - desc = "Xilinx JTAG cable"; - type = par; - mosi = 2; - sck = 3; - reset = 4; - buff = 5; - miso = 13; - vcc = 6; -; - - -programmer - id = "dapa"; - desc = "Direct AVR Parallel Access cable"; - type = par; - vcc = 3; - reset = 16; - sck = 1; - mosi = 2; - miso = 11; -; - -programmer - id = "atisp"; - desc = "AT-ISP V1.1 programming cable for AVR-SDK1 from micro-research.co.th"; - type = par; - reset = ~6; - sck = ~8; - mosi = ~7; - miso = ~10; -; - -programmer - id = "ere-isp-avr"; - desc = "ERE ISP-AVR "; - type = par; - reset = ~4; - sck = 3; - mosi = 2; - miso = 10; -; - -programmer - id = "blaster"; - desc = "Altera ByteBlaster"; - type = par; - sck = 2; - miso = 11; - reset = 3; - mosi = 8; - buff = 14; -; - -# It is almost same as pony-stk200, except vcc on pin 5 to auto -# disconnect port download on http://www.electropol.fr -programmer - id = "frank-stk200"; - desc = "Frank STK200"; - type = par; - vcc = 5; - sck = 6; - mosi = 7; - reset = 9; - miso = 10; - pgmled = 8; -; - -# The AT98ISP Cable is a simple parallel dongle for AT89 family. -# https://www.microchip.com/wwwAppNotes/AppNotes.aspx?appnote=en592141 -programmer -id = "89isp"; -desc = "Atmel at89isp cable"; -type = par; -reset = 17; -sck = 1; -mosi = 2; -miso = 10; -; - - -# -# some ultra cheap programmers use bitbanging on the -# serialport. -# -# PC - DB9 - Pins for RS232: -# -# GND 5 -- |O -# | O| <- 9 RI -# DTR 4 <- |O | -# | O| <- 8 CTS -# TXD 3 <- |O | -# | O| -> 7 RTS -# RXD 2 -> |O | -# | O| <- 6 DSR -# DCD 1 -> |O -# -# Using RXD is currently not supported. -# Using RI is not supported under Win32 but is supported under Posix. - -# serial ponyprog design (dasa2 in uisp) -# reset=!txd sck=rts mosi=dtr miso=cts - -programmer - id = "ponyser"; - desc = "design ponyprog serial, reset=!txd sck=rts mosi=dtr miso=cts"; - type = serbb; - reset = ~3; - sck = 7; - mosi = 4; - miso = 8; -; - -# Same as above, different name -# reset=!txd sck=rts mosi=dtr miso=cts - -programmer - id = "siprog"; - desc = "Lancos SI-Prog "; - type = serbb; - reset = ~3; - sck = 7; - mosi = 4; - miso = 8; -; - -# unknown (dasa in uisp) -# reset=rts sck=dtr mosi=txd miso=cts - -programmer - id = "dasa"; - desc = "serial port banging, reset=rts sck=dtr mosi=txd miso=cts"; - type = serbb; - reset = 7; - sck = 4; - mosi = 3; - miso = 8; -; - -# unknown (dasa3 in uisp) -# reset=!dtr sck=rts mosi=txd miso=cts - -programmer - id = "dasa3"; - desc = "serial port banging, reset=!dtr sck=rts mosi=txd miso=cts"; - type = serbb; - reset = ~4; - sck = 7; - mosi = 3; - miso = 8; -; - -# C2N232i (jumper configuration "auto") -# reset=dtr sck=!rts mosi=!txd miso=!cts - -programmer - id = "c2n232i"; - desc = "serial port banging, reset=dtr sck=!rts mosi=!txd miso=!cts"; - type = serbb; - reset = 4; - sck = ~7; - mosi = ~3; - miso = ~8; -; - -# -# PART DEFINITIONS -# - -#------------------------------------------------------------ -# ATtiny11 -#------------------------------------------------------------ - -# This is an HVSP-only device. - -part - id = "t11"; - desc = "ATtiny11"; - stk500_devcode = 0x11; - signature = 0x1e 0x90 0x04; - chip_erase_delay = 20000; - - timeout = 200; - hvsp_controlstack = - 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x00, - 0x68, 0x78, 0x68, 0x68, 0x00, 0x00, 0x68, 0x78, - 0x78, 0x00, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, - 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - hvspcmdexedelay = 0; - synchcycles = 6; - latchcycles = 1; - togglevtg = 1; - poweroffdelay = 25; - resetdelayms = 0; - resetdelayus = 50; - hvleavestabdelay = 100; - resetdelay = 25; - chiperasepolltimeout = 40; - chiperasetime = 0; - programfusepolltimeout = 25; - programlockpolltimeout = 25; - - memory "eeprom" - size = 64; - blocksize = 64; - readsize = 256; - delay = 5; - ; - - memory "flash" - size = 1024; - blocksize = 128; - readsize = 256; - delay = 3; - ; - - memory "signature" - size = 3; - ; - - memory "lock" - size = 1; - ; - - memory "calibration" - size = 1; - ; - - memory "fuse" - size = 1; - ; -; - -#------------------------------------------------------------ -# ATtiny12 -#------------------------------------------------------------ - -part - id = "t12"; - desc = "ATtiny12"; - stk500_devcode = 0x12; - avr910_devcode = 0x55; - signature = 0x1e 0x90 0x05; - chip_erase_delay = 20000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - hvsp_controlstack = - 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x00, - 0x68, 0x78, 0x68, 0x68, 0x00, 0x00, 0x68, 0x78, - 0x78, 0x00, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, - 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00; - hventerstabdelay = 100; - hvspcmdexedelay = 0; - synchcycles = 6; - latchcycles = 1; - togglevtg = 1; - poweroffdelay = 25; - resetdelayms = 0; - resetdelayus = 50; - hvleavestabdelay = 100; - resetdelay = 25; - chiperasepolltimeout = 40; - chiperasetime = 0; - programfusepolltimeout = 25; - programlockpolltimeout = 25; - - memory "eeprom" - size = 64; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 x x x x x x x x", - "x x a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 x x x x x x x x", - "x x a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - mode = 0x04; - delay = 8; - blocksize = 64; - readsize = 256; - ; - - memory "flash" - size = 1024; - min_write_delay = 4500; - max_write_delay = 20000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - write_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 5; - blocksize = 128; - readsize = 256; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x x x x x x o o x"; - - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "fuse" - size = 1; - read = "0 1 0 1 0 0 0 0 x x x x x x x x", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 x x x x x", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; -; - -#------------------------------------------------------------ -# ATtiny13 -#------------------------------------------------------------ - -part - id = "t13"; - desc = "ATtiny13"; - has_debugwire = yes; - flash_instr = 0xB4, 0x0E, 0x1E; - eeprom_instr = 0xBB, 0xFE, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, - 0xBC, 0x0E, 0xB4, 0x0E, 0xBA, 0x0D, 0xBB, 0xBC, - 0x99, 0xE1, 0xBB, 0xAC; - stk500_devcode = 0x14; - signature = 0x1e 0x90 0x07; - chip_erase_delay = 4000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - hvsp_controlstack = - 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x66, - 0x68, 0x78, 0x68, 0x68, 0x7A, 0x6A, 0x68, 0x78, - 0x78, 0x7D, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, - 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - hvspcmdexedelay = 0; - synchcycles = 6; - latchcycles = 1; - togglevtg = 1; - poweroffdelay = 25; - resetdelayms = 0; - resetdelayus = 90; - hvleavestabdelay = 100; - resetdelay = 25; - chiperasepolltimeout = 40; - chiperasetime = 0; - programfusepolltimeout = 25; - programlockpolltimeout = 25; - - memory "eeprom" - size = 64; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x x", - "x x a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x x", - "x x a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " x x a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 5; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 1024; - page_size = 32; - num_pages = 32; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 0 0 0 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 0 0 0 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 0 0 0 a8", - " a7 a6 a5 a4 x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 32; - readsize = 256; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "calibration" - size = 2; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 a0 o o o o o o o o"; - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - ; - -; - - -#------------------------------------------------------------ -# ATtiny15 -#------------------------------------------------------------ - -part - id = "t15"; - desc = "ATtiny15"; - stk500_devcode = 0x13; - avr910_devcode = 0x56; - signature = 0x1e 0x90 0x06; - chip_erase_delay = 8200; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - hvsp_controlstack = - 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x00, - 0x68, 0x78, 0x68, 0x68, 0x00, 0x00, 0x68, 0x78, - 0x78, 0x00, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, - 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00; - hventerstabdelay = 100; - hvspcmdexedelay = 5; - synchcycles = 6; - latchcycles = 16; - togglevtg = 1; - poweroffdelay = 25; - resetdelayms = 0; - resetdelayus = 50; - hvleavestabdelay = 100; - resetdelay = 25; - chiperasepolltimeout = 40; - chiperasetime = 0; - programfusepolltimeout = 25; - programlockpolltimeout = 25; - - memory "eeprom" - size = 64; - min_write_delay = 8200; - max_write_delay = 8200; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 x x x x x x x x", - "x x a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 x x x x x x x x", - "x x a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - mode = 0x04; - delay = 10; - blocksize = 64; - readsize = 256; - ; - - memory "flash" - size = 1024; - min_write_delay = 4100; - max_write_delay = 4100; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - write_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 5; - blocksize = 128; - readsize = 256; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x x x x x x o o x"; - - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "fuse" - size = 1; - read = "0 1 0 1 0 0 0 0 x x x x x x x x", - "x x x x x x x x o o o o x x o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 x x x x x", - "x x x x x x x x i i i i 1 1 i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; -; - -#------------------------------------------------------------ -# AT90s1200 -#------------------------------------------------------------ - -part - id = "1200"; - desc = "AT90S1200"; - stk500_devcode = 0x33; - avr910_devcode = 0x13; - signature = 0x1e 0x90 0x01; - pagel = 0xd7; - bs2 = 0xa0; - chip_erase_delay = 20000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 1; - bytedelay = 0; - pollindex = 0; - pollvalue = 0xFF; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 0; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 15; - chiperasepolltimeout = 0; - programfusepulsewidth = 2; - programfusepolltimeout = 0; - programlockpulsewidth = 0; - programlockpolltimeout = 1; - - memory "eeprom" - size = 64; - min_write_delay = 4000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 x x x x x x x x", - "x x a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 x x x x x x x x", - "x x a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - mode = 0x04; - delay = 20; - blocksize = 32; - readsize = 256; - ; - memory "flash" - size = 1024; - min_write_delay = 4000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - write_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x02; - delay = 15; - blocksize = 128; - readsize = 256; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "fuse" - size = 1; - ; - memory "lock" - size = 1; - min_write_delay = 9000; - max_write_delay = 20000; - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", - "x x x x x x x x x x x x x x x x"; - ; - ; - -#------------------------------------------------------------ -# AT90s4414 -#------------------------------------------------------------ - -part - id = "4414"; - desc = "AT90S4414"; - stk500_devcode = 0x50; - avr910_devcode = 0x28; - signature = 0x1e 0x92 0x01; - chip_erase_delay = 20000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 0; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 15; - chiperasepolltimeout = 0; - programfusepulsewidth = 2; - programfusepolltimeout = 0; - programlockpulsewidth = 0; - programlockpolltimeout = 1; - - memory "eeprom" - size = 256; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0x80; - readback_p2 = 0x7f; - read = " 1 0 1 0 0 0 0 0 x x x x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0 x x x x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 64; - readsize = 256; - ; - memory "flash" - size = 4096; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0x7f; - readback_p2 = 0x7f; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write_lo = " 0 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - write_hi = " 0 1 0 0 1 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 64; - readsize = 256; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "fuse" - size = 1; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - ; - -#------------------------------------------------------------ -# AT90s2313 -#------------------------------------------------------------ - -part - id = "2313"; - desc = "AT90S2313"; - stk500_devcode = 0x40; - avr910_devcode = 0x20; - signature = 0x1e 0x91 0x01; - chip_erase_delay = 20000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 0; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 15; - chiperasepolltimeout = 0; - programfusepulsewidth = 2; - programfusepolltimeout = 0; - programlockpulsewidth = 0; - programlockpolltimeout = 1; - - memory "eeprom" - size = 128; - min_write_delay = 4000; - max_write_delay = 9000; - readback_p1 = 0x80; - readback_p2 = 0x7f; - read = "1 0 1 0 0 0 0 0 x x x x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 x x x x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 64; - readsize = 256; - ; - memory "flash" - size = 2048; - min_write_delay = 4000; - max_write_delay = 9000; - readback_p1 = 0x7f; - readback_p2 = 0x7f; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - write_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 128; - readsize = 256; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "fuse" - size = 1; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x i i x", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - ; - -#------------------------------------------------------------ -# AT90s2333 -#------------------------------------------------------------ - -part - id = "2333"; -##### WARNING: No XML file for device 'AT90S2333'! ##### - desc = "AT90S2333"; - stk500_devcode = 0x42; - avr910_devcode = 0x34; - signature = 0x1e 0x91 0x05; - chip_erase_delay = 20000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 0; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 15; - chiperasepolltimeout = 0; - programfusepulsewidth = 2; - programfusepolltimeout = 0; - programlockpulsewidth = 0; - programlockpolltimeout = 1; - - memory "eeprom" - size = 128; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0x00; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 x x x x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 x x x x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 128; - readsize = 256; - ; - - memory "flash" - size = 2048; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - write_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 128; - readsize = 256; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "fuse" - size = 1; - min_write_delay = 9000; - max_write_delay = 20000; - pwroff_after_write = yes; - read = "0 1 0 1 0 0 0 0 x x x x x x x x", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 i i i i i", - "x x x x x x x x x x x x x x x x"; - ; - memory "lock" - size = 1; - min_write_delay = 9000; - max_write_delay = 20000; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x x x x x x o o x"; - - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", - "x x x x x x x x x x x x x x x x"; - ; - ; - - -#------------------------------------------------------------ -# AT90s2343 (also AT90s2323 and ATtiny22) -#------------------------------------------------------------ - -part - id = "2343"; - desc = "AT90S2343"; - stk500_devcode = 0x43; - avr910_devcode = 0x4c; - signature = 0x1e 0x91 0x03; - chip_erase_delay = 18000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - hvsp_controlstack = - 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x00, - 0x68, 0x78, 0x68, 0x68, 0x00, 0x00, 0x68, 0x78, - 0x78, 0x00, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, - 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00; - hventerstabdelay = 100; - hvspcmdexedelay = 0; - synchcycles = 6; - latchcycles = 1; - togglevtg = 0; - poweroffdelay = 25; - resetdelayms = 0; - resetdelayus = 50; - hvleavestabdelay = 100; - resetdelay = 25; - chiperasepolltimeout = 40; - chiperasetime = 0; - programfusepolltimeout = 25; - programlockpolltimeout = 25; - - memory "eeprom" - size = 128; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0x00; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0", - "x a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0", - "x a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 64; - readsize = 256; - ; - memory "flash" - size = 2048; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - write_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 128; - readsize = 128; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "fuse" - size = 1; - min_write_delay = 9000; - max_write_delay = 20000; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x o o o x x x x o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 1 1 1 1 i", - "x x x x x x x x x x x x x x x x"; - ; - memory "lock" - size = 1; - min_write_delay = 9000; - max_write_delay = 20000; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x o o o x x x x o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", - "x x x x x x x x x x x x x x x x"; - ; - ; - - -#------------------------------------------------------------ -# AT90s4433 -#------------------------------------------------------------ - -part - id = "4433"; - desc = "AT90S4433"; - stk500_devcode = 0x51; - avr910_devcode = 0x30; - signature = 0x1e 0x92 0x03; - chip_erase_delay = 20000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 0; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 15; - chiperasepolltimeout = 0; - programfusepulsewidth = 2; - programfusepolltimeout = 0; - programlockpulsewidth = 0; - programlockpolltimeout = 1; - - memory "eeprom" - size = 256; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0x00; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0 x x x x x x x x", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0 x x x x x x x x", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 128; - readsize = 256; - ; - memory "flash" - size = 4096; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write_lo = " 0 1 0 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - write_hi = " 0 1 0 0 1 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 128; - readsize = 256; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "fuse" - size = 1; - min_write_delay = 9000; - max_write_delay = 20000; - pwroff_after_write = yes; - read = "0 1 0 1 0 0 0 0 x x x x x x x x", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 i i i i i", - "x x x x x x x x x x x x x x x x"; - ; - memory "lock" - size = 1; - min_write_delay = 9000; - max_write_delay = 20000; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x x x x x x o o x"; - - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", - "x x x x x x x x x x x x x x x x"; - ; - ; - -#------------------------------------------------------------ -# AT90s4434 -#------------------------------------------------------------ - -part - id = "4434"; -##### WARNING: No XML file for device 'AT90S4434'! ##### - desc = "AT90S4434"; - stk500_devcode = 0x52; - avr910_devcode = 0x6c; - signature = 0x1e 0x92 0x02; - chip_erase_delay = 20000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - memory "eeprom" - size = 256; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0x00; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0 x x x x x x x x", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0 x x x x x x x x", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - ; - memory "flash" - size = 4096; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write_lo = " 0 1 0 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - write_hi = " 0 1 0 0 1 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "fuse" - size = 1; - min_write_delay = 9000; - max_write_delay = 20000; - read = "0 1 0 1 0 0 0 0 x x x x x x x x", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 i i i i i", - "x x x x x x x x x x x x x x x x"; - ; - memory "lock" - size = 1; - min_write_delay = 9000; - max_write_delay = 20000; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x x x x x x o o x"; - - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", - "x x x x x x x x x x x x x x x x"; - ; - ; - -#------------------------------------------------------------ -# AT90s8515 -#------------------------------------------------------------ - -part - id = "8515"; - desc = "AT90S8515"; - stk500_devcode = 0x60; - avr910_devcode = 0x38; - signature = 0x1e 0x93 0x01; - chip_erase_delay = 20000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 0; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - resetdelay = 15; - chiperasepulsewidth = 15; - chiperasepolltimeout = 0; - programfusepulsewidth = 2; - programfusepolltimeout = 0; - programlockpulsewidth = 0; - programlockpolltimeout = 1; - - memory "eeprom" - size = 512; - min_write_delay = 4000; - max_write_delay = 9000; - readback_p1 = 0x80; - readback_p2 = 0x7f; - read = " 1 0 1 0 0 0 0 0 x x x x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0 x x x x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 128; - readsize = 256; - ; - memory "flash" - size = 8192; - min_write_delay = 4000; - max_write_delay = 9000; - readback_p1 = 0x7f; - readback_p2 = 0x7f; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write_lo = " 0 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - write_hi = " 0 1 0 0 1 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 128; - readsize = 256; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "fuse" - size = 1; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - ; - -#------------------------------------------------------------ -# AT90s8535 -#------------------------------------------------------------ - -part - id = "8535"; - desc = "AT90S8535"; - stk500_devcode = 0x61; - avr910_devcode = 0x68; - signature = 0x1e 0x93 0x03; - chip_erase_delay = 20000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 0; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 15; - chiperasepolltimeout = 0; - programfusepulsewidth = 2; - programfusepolltimeout = 0; - programlockpulsewidth = 0; - programlockpolltimeout = 1; - - memory "eeprom" - size = 512; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0x00; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0 x x x x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0 x x x x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 128; - readsize = 256; - ; - memory "flash" - size = 8192; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write_lo = " 0 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - write_hi = " 0 1 0 0 1 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 128; - readsize = 256; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "fuse" - size = 1; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x x x x x x x x o"; - write = "1 0 1 0 1 1 0 0 1 0 1 1 1 1 1 i", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x o o x x x x x x"; - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - ; - -#------------------------------------------------------------ -# ATmega103 -#------------------------------------------------------------ - -part - id = "m103"; - desc = "ATMEGA103"; - stk500_devcode = 0xB1; - avr910_devcode = 0x41; - signature = 0x1e 0x97 0x01; - chip_erase_delay = 112000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x8E, 0x9E, 0x2E, 0x3E, 0xAE, 0xBE, - 0x4E, 0x5E, 0xCE, 0xDE, 0x6E, 0x7E, 0xEE, 0xDE, - 0x66, 0x76, 0xE6, 0xF6, 0x6A, 0x7A, 0xEA, 0x7A, - 0x7F, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 0; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 15; - chiperasepolltimeout = 0; - programfusepulsewidth = 2; - programfusepolltimeout = 0; - programlockpulsewidth = 0; - programlockpolltimeout = 10; - - memory "eeprom" - size = 4096; - min_write_delay = 4000; - max_write_delay = 9000; - readback_p1 = 0x80; - readback_p2 = 0x7f; - read = " 1 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 64; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 131072; - page_size = 256; - num_pages = 512; - min_write_delay = 22000; - max_write_delay = 56000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x11; - delay = 70; - blocksize = 256; - readsize = 256; - ; - - memory "fuse" - size = 1; - read = "0 1 0 1 0 0 0 0 x x x x x x x x", - "x x x x x x x x x x o x o 1 o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 1 i 1 i i", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x x x x x x o o x"; - - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - - -#------------------------------------------------------------ -# ATmega64 -#------------------------------------------------------------ - -part - id = "m64"; - desc = "ATMEGA64"; - has_jtag = yes; - stk500_devcode = 0xA0; - avr910_devcode = 0x45; - signature = 0x1e 0x96 0x02; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x22; - spmcr = 0x68; - allowfullpagebitstream = yes; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 2048; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 20; - blocksize = 64; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 65536; - page_size = 256; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 6; - blocksize = 128; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 4; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - - - - -#------------------------------------------------------------ -# ATmega128 -#------------------------------------------------------------ - -part - id = "m128"; - desc = "ATMEGA128"; - has_jtag = yes; - stk500_devcode = 0xB2; - avr910_devcode = 0x43; - signature = 0x1e 0x97 0x02; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x22; - spmcr = 0x68; - rampz = 0x3b; - allowfullpagebitstream = yes; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 4096; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 64; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 131072; - page_size = 256; - num_pages = 512; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 6; - blocksize = 128; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 4; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# AT90CAN128 -#------------------------------------------------------------ - -part - id = "c128"; - desc = "AT90CAN128"; - has_jtag = yes; - stk500_devcode = 0xB3; -# avr910_devcode = 0x43; - signature = 0x1e 0x97 0x81; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - eecr = 0x3f; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 4096; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - - mode = 0x41; - delay = 20; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 131072; - page_size = 256; - num_pages = 512; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# AT90CAN64 -#------------------------------------------------------------ - -part - id = "c64"; - desc = "AT90CAN64"; - has_jtag = yes; - stk500_devcode = 0xB3; -# avr910_devcode = 0x43; - signature = 0x1e 0x96 0x81; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - eecr = 0x3f; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 2048; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - - mode = 0x41; - delay = 20; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 65536; - page_size = 256; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# AT90CAN32 -#------------------------------------------------------------ - -part - id = "c32"; - desc = "AT90CAN32"; - has_jtag = yes; - stk500_devcode = 0xB3; -# avr910_devcode = 0x43; - signature = 0x1e 0x95 0x81; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - eecr = 0x3f; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 1024; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - - mode = 0x41; - delay = 20; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 32768; - page_size = 256; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - - -#------------------------------------------------------------ -# ATmega16 -#------------------------------------------------------------ - -part - id = "m16"; - desc = "ATMEGA16"; - has_jtag = yes; - stk500_devcode = 0x82; - avr910_devcode = 0x74; - signature = 0x1e 0x94 0x03; - pagel = 0xd7; - bs2 = 0xa0; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 100; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - resetdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - allowfullpagebitstream = yes; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 512; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x04; - delay = 10; - blocksize = 128; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 16384; - page_size = 128; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 6; - blocksize = 128; - readsize = 256; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "calibration" - size = 4; - - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - ; - - -#------------------------------------------------------------ -# ATmega164P -#------------------------------------------------------------ - -# close to ATmega16 - -part - id = "m164p"; - desc = "ATMEGA164P"; - has_jtag = yes; - stk500_devcode = 0x82; # no STK500v1 support, use the ATmega16 one - avr910_devcode = 0x74; - signature = 0x1e 0x94 0x0a; - pagel = 0xd7; - bs2 = 0xa0; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 512; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 128; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 16384; - page_size = 128; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 6; - blocksize = 128; - readsize = 256; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x 1 1 1 1 1 i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - - -#------------------------------------------------------------ -# ATmega324P -#------------------------------------------------------------ - -# similar to ATmega164P - -part - id = "m324p"; - desc = "ATMEGA324P"; - has_jtag = yes; - stk500_devcode = 0x82; # no STK500v1 support, use the ATmega16 one - avr910_devcode = 0x74; - signature = 0x1e 0x95 0x08; - pagel = 0xd7; - bs2 = 0xa0; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 1024; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 128; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 32768; - page_size = 128; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x 1 1 1 1 1 i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - - -#------------------------------------------------------------ -# ATmega644 -#------------------------------------------------------------ - -# similar to ATmega164 - -part - id = "m644"; - desc = "ATMEGA644"; - has_jtag = yes; - stk500_devcode = 0x82; # no STK500v1 support, use the ATmega16 one - avr910_devcode = 0x74; - signature = 0x1e 0x96 0x09; - pagel = 0xd7; - bs2 = 0xa0; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 2048; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 128; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 65536; - page_size = 256; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x 1 1 1 1 1 i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega644P -#------------------------------------------------------------ - -# similar to ATmega164p - -part - id = "m644p"; - desc = "ATMEGA644P"; - has_jtag = yes; - stk500_devcode = 0x82; # no STK500v1 support, use the ATmega16 one - avr910_devcode = 0x74; - signature = 0x1e 0x96 0x0a; - pagel = 0xd7; - bs2 = 0xa0; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 2048; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 128; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 65536; - page_size = 256; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x 1 1 1 1 1 i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - - - -#------------------------------------------------------------ -# ATmega1284P -#------------------------------------------------------------ - -# similar to ATmega164p - -part - id = "m1284p"; - desc = "ATMEGA1284P"; - has_jtag = yes; - stk500_devcode = 0x82; # no STK500v1 support, use the ATmega16 one - avr910_devcode = 0x74; - signature = 0x1e 0x97 0x05; - pagel = 0xd7; - bs2 = 0xa0; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 4096; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 128; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 131072; - page_size = 256; - num_pages = 512; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 256; - readsize = 256; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x 1 1 1 1 1 i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - - - -#------------------------------------------------------------ -# ATmega162 -#------------------------------------------------------------ - -part - id = "m162"; - desc = "ATMEGA162"; - has_jtag = yes; - stk500_devcode = 0x83; - avr910_devcode = 0x63; - signature = 0x1e 0x94 0x04; - chip_erase_delay = 9000; - pagel = 0xd7; - bs2 = 0xa0; - - idr = 0x04; - spmcr = 0x57; - allowfullpagebitstream = yes; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - memory "flash" - paged = yes; - size = 16384; - page_size = 128; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - mode = 0x41; - delay = 10; - blocksize = 128; - readsize = 256; - - ; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 512; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - - read = " 1 0 1 0 0 0 0 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 4; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 16000; - max_write_delay = 16000; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 16000; - max_write_delay = 16000; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - min_write_delay = 16000; - max_write_delay = 16000; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x 1 1 1 1 1 i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 16000; - max_write_delay = 16000; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "signature" - size = 3; - - read = "0 0 1 1 0 0 0 0 0 0 x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - - read = "0 0 1 1 1 0 0 0 0 0 x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; -; - - - -#------------------------------------------------------------ -# ATmega163 -#------------------------------------------------------------ - -part - id = "m163"; - desc = "ATMEGA163"; - stk500_devcode = 0x81; - avr910_devcode = 0x64; - signature = 0x1e 0x94 0x02; - chip_erase_delay = 32000; - pagel = 0xd7; - bs2 = 0xa0; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 0; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 30; - programfusepulsewidth = 0; - programfusepolltimeout = 2; - programlockpulsewidth = 0; - programlockpolltimeout = 2; - - - memory "eeprom" - size = 512; - min_write_delay = 4000; - max_write_delay = 4000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - mode = 0x41; - delay = 20; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 16384; - page_size = 128; - num_pages = 128; - min_write_delay = 16000; - max_write_delay = 16000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x11; - delay = 20; - blocksize = 128; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o x x o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i 1 1 i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x x x x x 1 o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x 1 1 1 1 1 i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x 0 x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega169 -#------------------------------------------------------------ - -part - id = "m169"; - desc = "ATMEGA169"; - has_jtag = yes; - stk500_devcode = 0x85; - avr910_devcode = 0x78; - signature = 0x1e 0x94 0x05; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 512; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 16384; - page_size = 128; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 128; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - ; - - memory "lock" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega329 -#------------------------------------------------------------ - -part - id = "m329"; - desc = "ATMEGA329"; - has_jtag = yes; -# stk500_devcode = 0x85; # no STK500 support, only STK500v2 -# avr910_devcode = 0x?; # try the ATmega169 one: - avr910_devcode = 0x75; - signature = 0x1e 0x95 0x03; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 1024; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 32768; - page_size = 128; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega329P -#------------------------------------------------------------ -# Identical to ATmega329 except of the signature - -part - id = "m329p"; - desc = "ATMEGA329P"; - has_jtag = yes; -# stk500_devcode = 0x85; # no STK500 support, only STK500v2 -# avr910_devcode = 0x?; # try the ATmega169 one: - avr910_devcode = 0x75; - signature = 0x1e 0x95 0x0b; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 1024; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 32768; - page_size = 128; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega3290 -#------------------------------------------------------------ - -# identical to ATmega329 - -part - id = "m3290"; - desc = "ATMEGA3290"; - has_jtag = yes; -# stk500_devcode = 0x85; # no STK500 support, only STK500v2 -# avr910_devcode = 0x?; # try the ATmega169 one: - avr910_devcode = 0x75; - signature = 0x1e 0x95 0x04; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 1024; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a3 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 32768; - page_size = 128; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega3290P -#------------------------------------------------------------ - -# identical to ATmega3290 except of the signature - -part - id = "m3290p"; - desc = "ATMEGA3290P"; - has_jtag = yes; -# stk500_devcode = 0x85; # no STK500 support, only STK500v2 -# avr910_devcode = 0x?; # try the ATmega169 one: - avr910_devcode = 0x75; - signature = 0x1e 0x95 0x0c; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 1024; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a3 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 32768; - page_size = 128; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega649 -#------------------------------------------------------------ - -part - id = "m649"; - desc = "ATMEGA649"; - has_jtag = yes; -# stk500_devcode = 0x85; # no STK500 support, only STK500v2 -# avr910_devcode = 0x?; # try the ATmega169 one: - avr910_devcode = 0x75; - signature = 0x1e 0x96 0x03; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 2048; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 65536; - page_size = 256; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega6490 -#------------------------------------------------------------ - -# identical to ATmega649 - -part - id = "m6490"; - desc = "ATMEGA6490"; - has_jtag = yes; -# stk500_devcode = 0x85; # no STK500 support, only STK500v2 -# avr910_devcode = 0x?; # try the ATmega169 one: - avr910_devcode = 0x75; - signature = 0x1e 0x96 0x04; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 2048; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 65536; - page_size = 256; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega32 -#------------------------------------------------------------ - -part - id = "m32"; - desc = "ATMEGA32"; - has_jtag = yes; - stk500_devcode = 0x91; - avr910_devcode = 0x72; - signature = 0x1e 0x95 0x02; - chip_erase_delay = 9000; - pagel = 0xd7; - bs2 = 0xa0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - allowfullpagebitstream = yes; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 1024; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x04; - delay = 10; - blocksize = 64; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 32768; - page_size = 128; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 6; - blocksize = 64; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 4; - read = "0 0 1 1 1 0 0 0 0 0 x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega161 -#------------------------------------------------------------ - -part - id = "m161"; - desc = "ATMEGA161"; - stk500_devcode = 0x80; - avr910_devcode = 0x60; - signature = 0x1e 0x94 0x01; - chip_erase_delay = 28000; - pagel = 0xd7; - bs2 = 0xa0; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 0; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 30; - programfusepulsewidth = 0; - programfusepolltimeout = 2; - programlockpulsewidth = 0; - programlockpolltimeout = 2; - - memory "eeprom" - size = 512; - min_write_delay = 3400; - max_write_delay = 3400; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 5; - blocksize = 128; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 16384; - page_size = 128; - num_pages = 128; - min_write_delay = 14000; - max_write_delay = 14000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 16; - blocksize = 128; - readsize = 256; - ; - - memory "fuse" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 0 0 0 0 x x x x x x x x", - "x x x x x x x x x o x o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 x x x x x", - "x x x x x x x x 1 i 1 i i i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - - -#------------------------------------------------------------ -# ATmega8 -#------------------------------------------------------------ - -part - id = "m8"; - desc = "ATMEGA8"; - stk500_devcode = 0x70; - avr910_devcode = 0x76; - signature = 0x1e 0x93 0x07; - pagel = 0xd7; - bs2 = 0xc2; - chip_erase_delay = 10000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 2; - resetdelayus = 0; - hvleavestabdelay = 15; - resetdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - size = 512; - page_size = 4; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 20; - blocksize = 128; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 8192; - page_size = 64; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 0 x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 0 x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 10; - blocksize = 64; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "calibration" - size = 4; - read = "0 0 1 1 1 0 0 0 0 0 x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - - - -#------------------------------------------------------------ -# ATmega8515 -#------------------------------------------------------------ - -part - id = "m8515"; - desc = "ATMEGA8515"; - stk500_devcode = 0x63; - avr910_devcode = 0x3A; - signature = 0x1e 0x93 0x06; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - size = 512; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 10; - blocksize = 128; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 8192; - page_size = 64; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 0 x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 0 x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 6; - blocksize = 64; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "calibration" - size = 4; - read = "0 0 1 1 1 0 0 0 0 0 x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - - - - -#------------------------------------------------------------ -# ATmega8535 -#------------------------------------------------------------ - -part - id = "m8535"; - desc = "ATMEGA8535"; - stk500_devcode = 0x64; - avr910_devcode = 0x69; - signature = 0x1e 0x93 0x08; - pagel = 0xd7; - bs2 = 0xa0; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - size = 512; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 10; - blocksize = 128; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 8192; - page_size = 64; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 0 x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 0 x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 6; - blocksize = 64; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "calibration" - size = 4; - read = "0 0 1 1 1 0 0 0 0 0 x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - - -#------------------------------------------------------------ -# ATtiny26 -#------------------------------------------------------------ - -part - id = "t26"; - desc = "ATTINY26"; - stk500_devcode = 0x21; - avr910_devcode = 0x5e; - signature = 0x1e 0x91 0x09; - pagel = 0xb3; - bs2 = 0xb2; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0xC4, 0xE4, 0xC4, 0xE4, 0xCC, 0xEC, 0xCC, 0xEC, - 0xD4, 0xF4, 0xD4, 0xF4, 0xDC, 0xFC, 0xDC, 0xFC, - 0xC8, 0xE8, 0xD8, 0xF8, 0x4C, 0x6C, 0x5C, 0x7C, - 0xEC, 0xBC, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 2; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - size = 128; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 x x x x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 x x x x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - mode = 0x04; - delay = 10; - blocksize = 64; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 2048; - page_size = 32; - num_pages = 64; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 6; - blocksize = 16; - readsize = 256; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x x x x x x x o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 1 i i", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x x x x i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x x x x o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 4; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - -; - - -#------------------------------------------------------------ -# ATtiny261 -#------------------------------------------------------------ -# Close to ATtiny26 - -part - id = "t261"; - desc = "ATTINY261"; - has_debugwire = yes; - flash_instr = 0xB4, 0x00, 0x10; - eeprom_instr = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, - 0xBC, 0x00, 0xB4, 0x00, 0xBA, 0x0D, 0xBB, 0xBC, - 0x99, 0xE1, 0xBB, 0xAC; -# stk500_devcode = 0x21; -# avr910_devcode = 0x5e; - signature = 0x1e 0x91 0x0c; - pagel = 0xb3; - bs2 = 0xb2; - chip_erase_delay = 4000; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0xC4, 0xE4, 0xC4, 0xE4, 0xCC, 0xEC, 0xCC, 0xEC, - 0xD4, 0xF4, 0xD4, 0xF4, 0xDC, 0xFC, 0xDC, 0xFC, - 0xC8, 0xE8, 0xD8, 0xF8, 0x4C, 0x6C, 0x5C, 0x7C, - 0xEC, 0xBC, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 2; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - paged = no; - size = 128; - page_size = 4; - num_pages = 32; - min_write_delay = 4000; - max_write_delay = 4000; - readback_p1 = 0xff; - readback_p2 = 0xff; - - read = "1 0 1 0 0 0 0 0 x x x x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 x x x x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 2048; - page_size = 32; - num_pages = 64; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 32; - readsize = 256; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x x x x x x x o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 1 i i", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x x x x x x x x o"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - -; - - -#------------------------------------------------------------ -# ATtiny461 -#------------------------------------------------------------ -# Close to ATtiny261 - -part - id = "t461"; - desc = "ATTINY461"; - has_debugwire = yes; - flash_instr = 0xB4, 0x00, 0x10; - eeprom_instr = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, - 0xBC, 0x00, 0xB4, 0x00, 0xBA, 0x0D, 0xBB, 0xBC, - 0x99, 0xE1, 0xBB, 0xAC; -# stk500_devcode = 0x21; -# avr910_devcode = 0x5e; - signature = 0x1e 0x92 0x08; - pagel = 0xb3; - bs2 = 0xb2; - chip_erase_delay = 4000; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0xC4, 0xE4, 0xC4, 0xE4, 0xCC, 0xEC, 0xCC, 0xEC, - 0xD4, 0xF4, 0xD4, 0xF4, 0xDC, 0xFC, 0xDC, 0xFC, - 0xC8, 0xE8, 0xD8, 0xF8, 0x4C, 0x6C, 0x5C, 0x7C, - 0xEC, 0xBC, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 2; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - paged = no; - size = 256; - page_size = 4; - num_pages = 64; - min_write_delay = 4000; - max_write_delay = 4000; - readback_p1 = 0xff; - readback_p2 = 0xff; - - read = " 1 0 1 0 0 0 0 0 x x x x x x x x", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0 x x x x x x x x", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 4096; - page_size = 64; - num_pages = 64; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 64; - readsize = 256; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x x x x x x x o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 1 i i", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x x x x x x x x o"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - -; - - -#------------------------------------------------------------ -# ATtiny861 -#------------------------------------------------------------ -# Close to ATtiny461 - -part - id = "t861"; - desc = "ATTINY861"; - has_debugwire = yes; - flash_instr = 0xB4, 0x00, 0x10; - eeprom_instr = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, - 0xBC, 0x00, 0xB4, 0x00, 0xBA, 0x0D, 0xBB, 0xBC, - 0x99, 0xE1, 0xBB, 0xAC; -# stk500_devcode = 0x21; -# avr910_devcode = 0x5e; - signature = 0x1e 0x93 0x0d; - pagel = 0xb3; - bs2 = 0xb2; - chip_erase_delay = 4000; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0xC4, 0xE4, 0xC4, 0xE4, 0xCC, 0xEC, 0xCC, 0xEC, - 0xD4, 0xF4, 0xD4, 0xF4, 0xDC, 0xFC, 0xDC, 0xFC, - 0xC8, 0xE8, 0xD8, 0xF8, 0x4C, 0x6C, 0x5C, 0x7C, - 0xEC, 0xBC, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 2; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - paged = no; - size = 512; - num_pages = 128; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4000; - readback_p1 = 0xff; - readback_p2 = 0xff; - - read = " 1 0 1 0 0 0 0 0 x x x x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0 x x x x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 8192; - page_size = 64; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 64; - readsize = 256; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x x x x x x x o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 1 i i", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x x x x x x x x o"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - -; - - -#------------------------------------------------------------ -# ATmega48 -#------------------------------------------------------------ - -part - id = "m48"; - desc = "ATMEGA48"; - has_debugwire = yes; - flash_instr = 0xB6, 0x01, 0x11; - eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00, - 0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF, - 0x99, 0xF9, 0xBB, 0xAF; - stk500_devcode = 0x59; -# avr910_devcode = 0x; - signature = 0x1e 0x92 0x05; - pagel = 0xd7; - bs2 = 0xc2; - chip_erase_delay = 45000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - resetdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - paged = no; - page_size = 4; - size = 256; - min_write_delay = 3600; - max_write_delay = 3600; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 x x x x x", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 5; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 4096; - page_size = 64; - num_pages = 64; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 64; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x x x x x x x x o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - - -#------------------------------------------------------------ -# ATmega88 -#------------------------------------------------------------ - -part - id = "m88"; - desc = "ATMEGA88"; - has_debugwire = yes; - flash_instr = 0xB6, 0x01, 0x11; - eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00, - 0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF, - 0x99, 0xF9, 0xBB, 0xAF; - stk500_devcode = 0x73; -# avr910_devcode = 0x; - signature = 0x1e 0x93 0x0a; - pagel = 0xd7; - bs2 = 0xc2; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - resetdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - paged = no; - page_size = 4; - size = 512; - min_write_delay = 3600; - max_write_delay = 3600; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 5; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 8192; - page_size = 64; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 64; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x x x x x x o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega168 -#------------------------------------------------------------ - -part - id = "m168"; - desc = "ATMEGA168"; - has_debugwire = yes; - flash_instr = 0xB6, 0x01, 0x11; - eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00, - 0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF, - 0x99, 0xF9, 0xBB, 0xAF; - stk500_devcode = 0x86; - # avr910_devcode = 0x; - signature = 0x1e 0x94 0x06; - pagel = 0xd7; - bs2 = 0xc2; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - resetdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - paged = no; - page_size = 4; - size = 512; - min_write_delay = 3600; - max_write_delay = 3600; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 5; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 16384; - page_size = 128; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 128; - readsize = 256; - - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x x x x x x o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; -; - -#------------------------------------------------------------ -# ATtiny88 -#------------------------------------------------------------ - -part - id = "t88"; - desc = "attiny88"; - has_debugwire = yes; - flash_instr = 0xB6, 0x01, 0x11; - eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00, - 0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF, - 0x99, 0xF9, 0xBB, 0xAF; - stk500_devcode = 0x73; -# avr910_devcode = 0x; - signature = 0x1e 0x93 0x11; - pagel = 0xd7; - bs2 = 0xc2; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - resetdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - paged = no; - page_size = 4; - size = 64; - min_write_delay = 3600; - max_write_delay = 3600; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 5; - blocksize = 4; - readsize = 64; - ; - memory "flash" - paged = yes; - size = 8192; - page_size = 64; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 64; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x x x x x x o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega328P -#------------------------------------------------------------ - -part - id = "m328p"; - desc = "ATMEGA328P"; - has_debugwire = yes; - flash_instr = 0xB6, 0x01, 0x11; - eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00, - 0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF, - 0x99, 0xF9, 0xBB, 0xAF; - stk500_devcode = 0x86; - # avr910_devcode = 0x; - signature = 0x1e 0x95 0x0F; - pagel = 0xd7; - bs2 = 0xc2; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - resetdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - paged = no; - page_size = 4; - size = 1024; - min_write_delay = 3600; - max_write_delay = 3600; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 5; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 32768; - page_size = 128; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 128; - readsize = 256; - - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x x x x x x o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; -; - -#------------------------------------------------------------ -# ATtiny2313 -#------------------------------------------------------------ - -part - id = "t2313"; - desc = "ATtiny2313"; - has_debugwire = yes; - flash_instr = 0xB2, 0x0F, 0x1F; - eeprom_instr = 0xBB, 0xFE, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, - 0xBA, 0x0F, 0xB2, 0x0F, 0xBA, 0x0D, 0xBB, 0xBC, - 0x99, 0xE1, 0xBB, 0xAC; - stk500_devcode = 0x23; -## Use the ATtiny26 devcode: - avr910_devcode = 0x5e; - signature = 0x1e 0x91 0x0a; - pagel = 0xD4; - bs2 = 0xD6; - reset = io; - chip_erase_delay = 9000; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0E, 0x1E, 0x2E, 0x3E, 0x2E, 0x3E, - 0x4E, 0x5E, 0x4E, 0x5E, 0x6E, 0x7E, 0x6E, 0x7E, - 0x26, 0x36, 0x66, 0x76, 0x2A, 0x3A, 0x6A, 0x7A, - 0x2E, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - size = 128; - paged = no; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 2048; - page_size = 32; - num_pages = 64; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - -# The information in the data sheet of April/2004 is wrong, this works: - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - -# The information in the data sheet of April/2004 is wrong, this works: - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - -# The information in the data sheet of April/2004 is wrong, this works: - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 32; - readsize = 256; - ; -# ATtiny2313 has Signature Bytes: 0x1E 0x91 0x0A. - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; -# The Tiny2313 has calibration data for both 4 MHz and 8 MHz. -# The information in the data sheet of April/2004 is wrong, this works: - - memory "calibration" - size = 2; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# AT90PWM2 -#------------------------------------------------------------ - -part - id = "pwm2"; - desc = "AT90PWM2"; - has_debugwire = yes; - flash_instr = 0xB6, 0x01, 0x11; - eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00, - 0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF, - 0x99, 0xF9, 0xBB, 0xAF; - stk500_devcode = 0x65; -## avr910_devcode = ?; - signature = 0x1e 0x93 0x81; - pagel = 0xD8; - bs2 = 0xE2; - reset = io; - chip_erase_delay = 9000; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - size = 512; - paged = no; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 8192; - page_size = 64; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 64; - readsize = 256; - ; -# AT90PWM2 has Signature Bytes: 0x1E 0x93 0x81. - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# AT90PWM3 -#------------------------------------------------------------ - -# Completely identical to AT90PWM2 (including the signature!) - -part - id = "pwm3"; - desc = "AT90PWM3"; - has_debugwire = yes; - flash_instr = 0xB6, 0x01, 0x11; - eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00, - 0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF, - 0x99, 0xF9, 0xBB, 0xAF; - stk500_devcode = 0x65; -## avr910_devcode = ?; - signature = 0x1e 0x93 0x81; - pagel = 0xD8; - bs2 = 0xE2; - reset = io; - chip_erase_delay = 9000; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - size = 512; - paged = no; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 8192; - page_size = 64; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 64; - readsize = 256; - ; -# AT90PWM2 has Signature Bytes: 0x1E 0x93 0x81. - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# AT90PWM2B -#------------------------------------------------------------ -# Same as AT90PWM2 but different signature. - -part - id = "pwm2b"; - desc = "AT90PWM2B"; - has_debugwire = yes; - flash_instr = 0xB6, 0x01, 0x11; - eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00, - 0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF, - 0x99, 0xF9, 0xBB, 0xAF; - stk500_devcode = 0x65; -## avr910_devcode = ?; - signature = 0x1e 0x93 0x83; - pagel = 0xD8; - bs2 = 0xE2; - reset = io; - chip_erase_delay = 9000; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - size = 512; - paged = no; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 8192; - page_size = 64; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 64; - readsize = 256; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# AT90PWM3B -#------------------------------------------------------------ - -# Completely identical to AT90PWM2B (including the signature!) - -part - id = "pwm3b"; - desc = "AT90PWM3B"; - has_debugwire = yes; - flash_instr = 0xB6, 0x01, 0x11; - eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00, - 0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF, - 0x99, 0xF9, 0xBB, 0xAF; - stk500_devcode = 0x65; -## avr910_devcode = ?; - signature = 0x1e 0x93 0x83; - pagel = 0xD8; - bs2 = 0xE2; - reset = io; - chip_erase_delay = 9000; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - size = 512; - paged = no; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 8192; - page_size = 64; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 64; - readsize = 256; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATtiny25 -#------------------------------------------------------------ - -part - id = "t25"; - desc = "ATtiny25"; - has_debugwire = yes; - flash_instr = 0xB4, 0x02, 0x12; - eeprom_instr = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, - 0xBC, 0x02, 0xB4, 0x02, 0xBA, 0x0D, 0xBB, 0xBC, - 0x99, 0xE1, 0xBB, 0xAC; -## no STK500 devcode in XML file, use the ATtiny45 one - stk500_devcode = 0x14; -## avr910_devcode = ?; -## Try the AT90S2313 devcode: - avr910_devcode = 0x20; - signature = 0x1e 0x91 0x08; - reset = io; - chip_erase_delay = 4500; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - hvsp_controlstack = - 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x66, - 0x68, 0x78, 0x68, 0x68, 0x7A, 0x6A, 0x68, 0x78, - 0x78, 0x7D, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, - 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00; - hventerstabdelay = 100; - hvspcmdexedelay = 0; - synchcycles = 6; - latchcycles = 1; - togglevtg = 1; - poweroffdelay = 25; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 100; - resetdelay = 25; - chiperasepolltimeout = 40; - chiperasetime = 0; - programfusepolltimeout = 25; - programlockpolltimeout = 25; - - memory "eeprom" - size = 128; - paged = no; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 2048; - page_size = 32; - num_pages = 64; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 32; - readsize = 256; - ; -# ATtiny25 has Signature Bytes: 0x1E 0x91 0x08. - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 2; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATtiny45 -#------------------------------------------------------------ - -part - id = "t45"; - desc = "ATtiny45"; - has_debugwire = yes; - flash_instr = 0xB4, 0x02, 0x12; - eeprom_instr = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, - 0xBC, 0x02, 0xB4, 0x02, 0xBA, 0x0D, 0xBB, 0xBC, - 0x99, 0xE1, 0xBB, 0xAC; - stk500_devcode = 0x14; -## avr910_devcode = ?; -## Try the AT90S2313 devcode: - avr910_devcode = 0x20; - signature = 0x1e 0x92 0x06; - reset = io; - chip_erase_delay = 4500; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - hvsp_controlstack = - 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x66, - 0x68, 0x78, 0x68, 0x68, 0x7A, 0x6A, 0x68, 0x78, - 0x78, 0x7D, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, - 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - hvspcmdexedelay = 0; - synchcycles = 6; - latchcycles = 1; - togglevtg = 1; - poweroffdelay = 25; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 100; - resetdelay = 25; - chiperasepolltimeout = 40; - chiperasetime = 0; - programfusepolltimeout = 25; - programlockpolltimeout = 25; - - memory "eeprom" - size = 256; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x x", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x x", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 4096; - page_size = 64; - num_pages = 64; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 32; - readsize = 256; - ; -# ATtiny45 has Signature Bytes: 0x1E 0x92 0x08. (Data sheet 2586C-AVR-06/05 (doc2586.pdf) indicates otherwise!) - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 2; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATtiny85 -#------------------------------------------------------------ - -part - id = "t85"; - desc = "ATtiny85"; - has_debugwire = yes; - flash_instr = 0xB4, 0x02, 0x12; - eeprom_instr = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, - 0xBC, 0x02, 0xB4, 0x02, 0xBA, 0x0D, 0xBB, 0xBC, - 0x99, 0xE1, 0xBB, 0xAC; -## no STK500 devcode in XML file, use the ATtiny45 one - stk500_devcode = 0x14; -## avr910_devcode = ?; -## Try the AT90S2313 devcode: - avr910_devcode = 0x20; - signature = 0x1e 0x93 0x0b; - reset = io; - chip_erase_delay = 4500; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - hvsp_controlstack = - 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x66, - 0x68, 0x78, 0x68, 0x68, 0x7A, 0x6A, 0x68, 0x78, - 0x78, 0x7D, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, - 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00; - hventerstabdelay = 100; - hvspcmdexedelay = 0; - synchcycles = 6; - latchcycles = 1; - togglevtg = 1; - poweroffdelay = 25; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 100; - resetdelay = 25; - chiperasepolltimeout = 40; - chiperasetime = 0; - programfusepolltimeout = 25; - programlockpolltimeout = 25; - - memory "eeprom" - size = 512; - paged = no; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x a8", - "a8 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 8192; - page_size = 64; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 32; - readsize = 256; - ; -# ATtiny85 has Signature Bytes: 0x1E 0x93 0x08. - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 2; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega640 -#------------------------------------------------------------ -# Almost same as ATmega1280, except for different memory sizes - -part - id = "m640"; - desc = "ATMEGA640"; - signature = 0x1e 0x96 0x08; - has_jtag = yes; -# stk500_devcode = 0xB2; -# avr910_devcode = 0x43; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 4096; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 65536; - page_size = 256; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega1280 -#------------------------------------------------------------ - -part - id = "m1280"; - desc = "ATMEGA1280"; - signature = 0x1e 0x97 0x03; - has_jtag = yes; -# stk500_devcode = 0xB2; -# avr910_devcode = 0x43; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 4096; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 131072; - page_size = 256; - num_pages = 512; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega1281 -#------------------------------------------------------------ -# Identical to ATmega1280 - -part - id = "m1281"; - desc = "ATMEGA1281"; - signature = 0x1e 0x97 0x04; - has_jtag = yes; -# stk500_devcode = 0xB2; -# avr910_devcode = 0x43; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 4096; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 131072; - page_size = 256; - num_pages = 512; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega2560 -#------------------------------------------------------------ - -part - id = "m2560"; - desc = "ATMEGA2560"; - signature = 0x1e 0x98 0x01; - has_jtag = yes; -# stk500_devcode = 0xB2; -# avr910_devcode = 0x43; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 4096; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 262144; - page_size = 256; - num_pages = 1024; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - load_ext_addr = " 0 1 0 0 1 1 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 0 a16", - " 0 0 0 0 0 0 0 0"; - - mode = 0x41; - delay = 10; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega2561 -#------------------------------------------------------------ - -part - id = "m2561"; - desc = "ATMEGA2561"; - signature = 0x1e 0x98 0x02; - has_jtag = yes; -# stk500_devcode = 0xB2; -# avr910_devcode = 0x43; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 4096; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 262144; - page_size = 256; - num_pages = 1024; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - load_ext_addr = " 0 1 0 0 1 1 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 0 a16", - " 0 0 0 0 0 0 0 0"; - - mode = 0x41; - delay = 10; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega128RFA1 -#------------------------------------------------------------ -# Identical to ATmega2561 but half the ROM - -part - id = "m128rfa1"; - desc = "ATMEGA128RFA1"; - signature = 0x1e 0xa7 0x01; - has_jtag = yes; -# stk500_devcode = 0xB2; -# avr910_devcode = 0x43; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xE2; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 4096; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 131072; - page_size = 256; - num_pages = 512; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATtiny24 -#------------------------------------------------------------ - -part - id = "t24"; - desc = "ATtiny24"; - has_debugwire = yes; - flash_instr = 0xB4, 0x07, 0x17; - eeprom_instr = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, - 0xBC, 0x07, 0xB4, 0x07, 0xBA, 0x0D, 0xBB, 0xBC, - 0x99, 0xE1, 0xBB, 0xAC; -## no STK500 devcode in XML file, use the ATtiny45 one - stk500_devcode = 0x14; -## avr910_devcode = ?; -## Try the AT90S2313 devcode: - avr910_devcode = 0x20; - signature = 0x1e 0x91 0x0b; - reset = io; - chip_erase_delay = 4500; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - hvsp_controlstack = - 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x66, - 0x68, 0x78, 0x68, 0x68, 0x7A, 0x6A, 0x68, 0x78, - 0x78, 0x7D, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, - 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x0F; - hventerstabdelay = 100; - hvspcmdexedelay = 0; - synchcycles = 6; - latchcycles = 1; - togglevtg = 1; - poweroffdelay = 25; - resetdelayms = 0; - resetdelayus = 70; - hvleavestabdelay = 100; - resetdelay = 25; - chiperasepolltimeout = 40; - chiperasetime = 0; - programfusepolltimeout = 25; - programlockpolltimeout = 25; - - memory "eeprom" - size = 128; - paged = no; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 2048; - page_size = 32; - num_pages = 64; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 32; - readsize = 256; - ; -# ATtiny24 has Signature Bytes: 0x1E 0x91 0x0B. - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x x x x x x x i i"; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATtiny44 -#------------------------------------------------------------ - -part - id = "t44"; - desc = "ATtiny44"; - has_debugwire = yes; - flash_instr = 0xB4, 0x07, 0x17; - eeprom_instr = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, - 0xBC, 0x07, 0xB4, 0x07, 0xBA, 0x0D, 0xBB, 0xBC, - 0x99, 0xE1, 0xBB, 0xAC; -## no STK500 devcode in XML file, use the ATtiny45 one - stk500_devcode = 0x14; -## avr910_devcode = ?; -## Try the AT90S2313 devcode: - avr910_devcode = 0x20; - signature = 0x1e 0x92 0x07; - reset = io; - chip_erase_delay = 4500; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - hvsp_controlstack = - 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x66, - 0x68, 0x78, 0x68, 0x68, 0x7A, 0x6A, 0x68, 0x78, - 0x78, 0x7D, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, - 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x0F; - hventerstabdelay = 100; - hvspcmdexedelay = 0; - synchcycles = 6; - latchcycles = 1; - togglevtg = 1; - poweroffdelay = 25; - resetdelayms = 0; - resetdelayus = 70; - hvleavestabdelay = 100; - resetdelay = 25; - chiperasepolltimeout = 40; - chiperasetime = 0; - programfusepolltimeout = 25; - programlockpolltimeout = 25; - - memory "eeprom" - size = 256; - paged = no; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x x", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x x", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 4096; - page_size = 64; - num_pages = 64; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 32; - readsize = 256; - ; -# ATtiny44 has Signature Bytes: 0x1E 0x92 0x07. - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x x x x x x x i i"; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATtiny84 -#------------------------------------------------------------ - -part - id = "t84"; - desc = "ATtiny84"; - has_debugwire = yes; - flash_instr = 0xB4, 0x07, 0x17; - eeprom_instr = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, - 0xBC, 0x07, 0xB4, 0x07, 0xBA, 0x0D, 0xBB, 0xBC, - 0x99, 0xE1, 0xBB, 0xAC; -## no STK500 devcode in XML file, use the ATtiny45 one - stk500_devcode = 0x14; -## avr910_devcode = ?; -## Try the AT90S2313 devcode: - avr910_devcode = 0x20; - signature = 0x1e 0x93 0x0c; - reset = io; - chip_erase_delay = 4500; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - hvsp_controlstack = - 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x66, - 0x68, 0x78, 0x68, 0x68, 0x7A, 0x6A, 0x68, 0x78, - 0x78, 0x7D, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, - 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x0F; - hventerstabdelay = 100; - hvspcmdexedelay = 0; - synchcycles = 6; - latchcycles = 1; - togglevtg = 1; - poweroffdelay = 25; - resetdelayms = 0; - resetdelayus = 70; - hvleavestabdelay = 100; - resetdelay = 25; - chiperasepolltimeout = 40; - chiperasetime = 0; - programfusepolltimeout = 25; - programlockpolltimeout = 25; - - memory "eeprom" - size = 512; - paged = no; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x a8", - "a8 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 8192; - page_size = 64; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 32; - readsize = 256; - ; -# ATtiny84 has Signature Bytes: 0x1E 0x93 0x0C. - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x x x x x x x i i"; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega32u4 -#------------------------------------------------------------ - -part - id = "m32u4"; - desc = "ATmega32U4"; - signature = 0x1e 0x95 0x87; - has_jtag = yes; -# stk500_devcode = 0xB2; -# avr910_devcode = 0x43; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 1024; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 32768; - page_size = 128; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 128; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# AT90USB646 -#------------------------------------------------------------ - -part - id = "usb646"; - desc = "AT90USB646"; - signature = 0x1e 0x96 0x82; - has_jtag = yes; -# stk500_devcode = 0xB2; -# avr910_devcode = 0x43; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 2048; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 65536; - page_size = 256; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# AT90USB647 -#------------------------------------------------------------ -# identical to AT90USB646 - -part - id = "usb647"; - desc = "AT90USB647"; - signature = 0x1e 0x96 0x82; - has_jtag = yes; -# stk500_devcode = 0xB2; -# avr910_devcode = 0x43; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 2048; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 65536; - page_size = 256; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# AT90USB1286 -#------------------------------------------------------------ - -part - id = "usb1286"; - desc = "AT90USB1286"; - signature = 0x1e 0x97 0x82; - has_jtag = yes; -# stk500_devcode = 0xB2; -# avr910_devcode = 0x43; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 4096; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 131072; - page_size = 256; - num_pages = 512; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# AT90USB1287 -#------------------------------------------------------------ -# identical to AT90USB1286 - -part - id = "usb1287"; - desc = "AT90USB1287"; - signature = 0x1e 0x97 0x82; - has_jtag = yes; -# stk500_devcode = 0xB2; -# avr910_devcode = 0x43; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 4096; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 131072; - page_size = 256; - num_pages = 512; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - - -#------------------------------------------------------------ -# AT90USB162 -#------------------------------------------------------------ - -part - id = "usb162"; - desc = "AT90USB162"; - has_jtag = no; - has_debugwire = yes; - signature = 0x1e 0x94 0x82; - chip_erase_delay = 9000; - reset = io; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - pagel = 0xD7; - bs2 = 0xC6; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 512; - num_pages = 128; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 16384; - page_size = 128; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 128; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# AT90USB82 -#------------------------------------------------------------ -# Changes against AT90USB162 (beside IDs) -# memory "flash" -# size = 8192; -# num_pages = 64; - -part - id = "usb82"; - desc = "AT90USB82"; - has_jtag = no; - has_debugwire = yes; - signature = 0x1e 0x93 0x82; - chip_erase_delay = 9000; - reset = io; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - pagel = 0xD7; - bs2 = 0xC6; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 512; - num_pages = 128; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 8192; - page_size = 128; - num_pages = 64; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 128; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega325 -#------------------------------------------------------------ - -part - id = "m325"; - desc = "ATMEGA325"; - signature = 0x1e 0x95 0x05; - has_jtag = yes; -# stk500_devcode = 0x??; # No STK500v1 support? -# avr910_devcode = 0x??; # Try the ATmega16 one - avr910_devcode = 0x74; - pagel = 0xd7; - bs2 = 0xa0; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 1024; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 32768; - page_size = 128; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 0 0 0 0 0", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 0 0 0 0 0", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 128; - readsize = 256; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 0 0 0 0 0", - "0 0 0 0 0 0 0 0 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "0 0 0 0 0 0 0 0 i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "0 0 0 0 0 0 0 0 i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "0 0 0 0 0 0 0 0 1 1 1 1 1 i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - - read = "0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega645 -#------------------------------------------------------------ - -part - id = "m645"; - desc = "ATMEGA645"; - signature = 0x1E 0x96 0x05; - has_jtag = yes; -# stk500_devcode = 0x??; # No STK500v1 support? -# avr910_devcode = 0x??; # Try the ATmega16 one - avr910_devcode = 0x74; - pagel = 0xd7; - bs2 = 0xa0; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 2048; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 65536; - page_size = 256; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 0 0 0 0 0", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 0 0 0 0 0", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " 0 0 0 0 0 0 0 0"; - - mode = 0x41; - delay = 10; - blocksize = 128; - readsize = 256; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 0 0 0 0 0", - "0 0 0 0 0 0 0 0 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "0 0 0 0 0 0 0 0 i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "0 0 0 0 0 0 0 0 i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "0 0 0 0 0 0 0 0 1 1 1 1 1 i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - - read = "0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega3250 -#------------------------------------------------------------ - -part - id = "m3250"; - desc = "ATMEGA3250"; - signature = 0x1E 0x95 0x06; - has_jtag = yes; -# stk500_devcode = 0x??; # No STK500v1 support? -# avr910_devcode = 0x??; # Try the ATmega16 one - avr910_devcode = 0x74; - pagel = 0xd7; - bs2 = 0xa0; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 1024; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 32768; - page_size = 128; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 0 0 0 0 0", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 0 0 0 0 0", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 128; - readsize = 256; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 0 0 0 0 0", - "0 0 0 0 0 0 0 0 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "0 0 0 0 0 0 0 0 i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "0 0 0 0 0 0 0 0 i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "0 0 0 0 0 0 0 0 1 1 1 1 1 i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - - read = "0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega6450 -#------------------------------------------------------------ - -part - id = "m6450"; - desc = "ATMEGA6450"; - signature = 0x1E 0x96 0x06; - has_jtag = yes; -# stk500_devcode = 0x??; # No STK500v1 support? -# avr910_devcode = 0x??; # Try the ATmega16 one - avr910_devcode = 0x74; - pagel = 0xd7; - bs2 = 0xa0; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 2048; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 65536; - page_size = 256; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 0 0 0 0 0", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 0 0 0 0 0", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " 0 0 0 0 0 0 0 0"; - - mode = 0x41; - delay = 10; - blocksize = 128; - readsize = 256; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 0 0 0 0 0", - "0 0 0 0 0 0 0 0 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "0 0 0 0 0 0 0 0 i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "0 0 0 0 0 0 0 0 i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "0 0 0 0 0 0 0 0 1 1 1 1 1 i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - - read = "0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATXMEGA64A1 -#------------------------------------------------------------ - -part - id = "x64a1"; - desc = "ATXMEGA64A1"; - signature = 0x1e 0x96 0x4e; - has_jtag = yes; - has_pdi = yes; - nvm_base = 0x01c0; - - memory "eeprom" - size = 0x0800; - offset = 0x08c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x00010000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x00001000; - offset = 0x0080f000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x00001000; - offset = 0x00810000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x00011000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "prodsig" - size = 0x200; - offset = 0x8e0200; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; - - memory "signature" - size = 3; - offset = 0x1000090; - ; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; - - memory "fuse1" - size = 1; - offset = 0x8f0021; - ; - - memory "fuse2" - size = 1; - offset = 0x8f0022; - ; - - memory "fuse4" - size = 1; - offset = 0x8f0024; - ; - - memory "fuse5" - size = 1; - offset = 0x8f0025; - ; - - memory "lock" - size = 1; - offset = 0x8f0027; - ; -; - -#------------------------------------------------------------ -# ATXMEGA128A1 -#------------------------------------------------------------ - -part - id = "x128a1"; - desc = "ATXMEGA128A1"; - signature = 0x1e 0x97 0x4c; - has_jtag = yes; - has_pdi = yes; - nvm_base = 0x01c0; - - memory "eeprom" - size = 0x0800; - offset = 0x08c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x00020000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x00002000; - offset = 0x0081e000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x00002000; - offset = 0x00820000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x00022000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "prodsig" - size = 0x200; - offset = 0x8e0200; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; - - memory "signature" - size = 3; - offset = 0x1000090; - ; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; - - memory "fuse1" - size = 1; - offset = 0x8f0021; - ; - - memory "fuse2" - size = 1; - offset = 0x8f0022; - ; - - memory "fuse4" - size = 1; - offset = 0x8f0024; - ; - - memory "fuse5" - size = 1; - offset = 0x8f0025; - ; - - memory "lock" - size = 1; - offset = 0x8f0027; - ; -; - -#------------------------------------------------------------ -# ATXMEGA128A1REVD -#------------------------------------------------------------ - -part - id = "x128a1d"; - desc = "ATXMEGA128A1REVD"; - signature = 0x1e 0x97 0x41; - has_jtag = yes; - has_pdi = yes; - nvm_base = 0x01c0; - - memory "eeprom" - size = 0x0800; - offset = 0x08c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x00020000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x00002000; - offset = 0x0081e000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x00002000; - offset = 0x00820000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x00022000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "prodsig" - size = 0x200; - offset = 0x8e0200; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; - - memory "signature" - size = 3; - offset = 0x1000090; - ; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; - - memory "fuse1" - size = 1; - offset = 0x8f0021; - ; - - memory "fuse2" - size = 1; - offset = 0x8f0022; - ; - - memory "fuse4" - size = 1; - offset = 0x8f0024; - ; - - memory "fuse5" - size = 1; - offset = 0x8f0025; - ; - - memory "lock" - size = 1; - offset = 0x8f0027; - ; -; - -#------------------------------------------------------------ -# ATXMEGA192A1 -#------------------------------------------------------------ - -part - id = "x192a1"; - desc = "ATXMEGA192A1"; - signature = 0x1e 0x97 0x4e; - has_jtag = yes; - has_pdi = yes; - nvm_base = 0x01c0; - - memory "eeprom" - size = 0x0800; - offset = 0x08c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x00030000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x00002000; - offset = 0x0082e000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x00002000; - offset = 0x00830000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x00032000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "prodsig" - size = 0x200; - offset = 0x8e0200; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; - - memory "signature" - size = 3; - offset = 0x1000090; - ; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; - - memory "fuse1" - size = 1; - offset = 0x8f0021; - ; - - memory "fuse2" - size = 1; - offset = 0x8f0022; - ; - - memory "fuse4" - size = 1; - offset = 0x8f0024; - ; - - memory "fuse5" - size = 1; - offset = 0x8f0025; - ; - - memory "lock" - size = 1; - offset = 0x8f0027; - ; -; - -#------------------------------------------------------------ -# ATXMEGA256A1 -#------------------------------------------------------------ - -part - id = "x256a1"; - desc = "ATXMEGA256A1"; - signature = 0x1e 0x98 0x46; - has_jtag = yes; - has_pdi = yes; - nvm_base = 0x01c0; - - memory "eeprom" - size = 0x1000; - offset = 0x08c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x00040000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x00002000; - offset = 0x0083e000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x00002000; - offset = 0x00840000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x00042000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "prodsig" - size = 0x200; - offset = 0x8e0200; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; - - memory "signature" - size = 3; - offset = 0x1000090; - ; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; - - memory "fuse1" - size = 1; - offset = 0x8f0021; - ; - - memory "fuse2" - size = 1; - offset = 0x8f0022; - ; - - memory "fuse4" - size = 1; - offset = 0x8f0024; - ; - - memory "fuse5" - size = 1; - offset = 0x8f0025; - ; - - memory "lock" - size = 1; - offset = 0x8f0027; - ; -; - -#------------------------------------------------------------ -# ATXMEGA64A3 -#------------------------------------------------------------ - -part - id = "x64a3"; - desc = "ATXMEGA64A3"; - signature = 0x1e 0x96 0x42; - has_jtag = yes; - has_pdi = yes; - nvm_base = 0x01c0; - - memory "eeprom" - size = 0x0800; - offset = 0x08c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x00010000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x00001000; - offset = 0x0080f000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x00001000; - offset = 0x00810000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x00011000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "prodsig" - size = 0x200; - offset = 0x8e0200; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; - - memory "signature" - size = 3; - offset = 0x1000090; - ; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; - - memory "fuse1" - size = 1; - offset = 0x8f0021; - ; - - memory "fuse2" - size = 1; - offset = 0x8f0022; - ; - - memory "fuse4" - size = 1; - offset = 0x8f0024; - ; - - memory "fuse5" - size = 1; - offset = 0x8f0025; - ; - - memory "lock" - size = 1; - offset = 0x8f0027; - ; -; - -#------------------------------------------------------------ -# ATXMEGA128A3 -#------------------------------------------------------------ - -part - id = "x128a3"; - desc = "ATXMEGA128A3"; - signature = 0x1e 0x97 0x42; - has_jtag = yes; - has_pdi = yes; - nvm_base = 0x01c0; - - memory "eeprom" - size = 0x0800; - offset = 0x08c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x00020000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x00002000; - offset = 0x0081e000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x00002000; - offset = 0x00820000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x00022000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "prodsig" - size = 0x200; - offset = 0x8e0200; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; - - memory "signature" - size = 3; - offset = 0x1000090; - ; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; - - memory "fuse1" - size = 1; - offset = 0x8f0021; - ; - - memory "fuse2" - size = 1; - offset = 0x8f0022; - ; - - memory "fuse4" - size = 1; - offset = 0x8f0024; - ; - - memory "fuse5" - size = 1; - offset = 0x8f0025; - ; - - memory "lock" - size = 1; - offset = 0x8f0027; - ; -; - -#------------------------------------------------------------ -# ATXMEGA192A3 -#------------------------------------------------------------ - -part - id = "x192a3"; - desc = "ATXMEGA192A3"; - signature = 0x1e 0x97 0x44; - has_jtag = yes; - has_pdi = yes; - nvm_base = 0x01c0; - - memory "eeprom" - size = 0x0800; - offset = 0x08c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x00030000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x00002000; - offset = 0x0082e000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x00002000; - offset = 0x00830000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x00032000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "prodsig" - size = 0x200; - offset = 0x8e0200; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; - - memory "signature" - size = 3; - offset = 0x1000090; - ; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; - - memory "fuse1" - size = 1; - offset = 0x8f0021; - ; - - memory "fuse2" - size = 1; - offset = 0x8f0022; - ; - - memory "fuse4" - size = 1; - offset = 0x8f0024; - ; - - memory "fuse5" - size = 1; - offset = 0x8f0025; - ; - - memory "lock" - size = 1; - offset = 0x8f0027; - ; -; - -#------------------------------------------------------------ -# ATXMEGA256A3 -#------------------------------------------------------------ - -part - id = "x256a3"; - desc = "ATXMEGA256A3"; - signature = 0x1e 0x98 0x42; - has_jtag = yes; - has_pdi = yes; - nvm_base = 0x01c0; - - memory "eeprom" - size = 0x1000; - offset = 0x08c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x00040000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x00002000; - offset = 0x0083e000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x00002000; - offset = 0x00840000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x00042000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "prodsig" - size = 0x200; - offset = 0x8e0200; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; - - memory "signature" - size = 3; - offset = 0x1000090; - ; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; - - memory "fuse1" - size = 1; - offset = 0x8f0021; - ; - - memory "fuse2" - size = 1; - offset = 0x8f0022; - ; - - memory "fuse4" - size = 1; - offset = 0x8f0024; - ; - - memory "fuse5" - size = 1; - offset = 0x8f0025; - ; - - memory "lock" - size = 1; - offset = 0x8f0027; - ; -; - -#------------------------------------------------------------ -# ATXMEGA256A3B -#------------------------------------------------------------ - -part - id = "x256a3b"; - desc = "ATXMEGA256A3B"; - signature = 0x1e 0x98 0x43; - has_jtag = yes; - has_pdi = yes; - nvm_base = 0x01c0; - - memory "eeprom" - size = 0x1000; - offset = 0x08c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x00040000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x00002000; - offset = 0x0083e000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x00002000; - offset = 0x00840000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x00042000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "prodsig" - size = 0x200; - offset = 0x8e0200; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; - - memory "signature" - size = 3; - offset = 0x1000090; - ; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; - - memory "fuse1" - size = 1; - offset = 0x8f0021; - ; - - memory "fuse2" - size = 1; - offset = 0x8f0022; - ; - - memory "fuse4" - size = 1; - offset = 0x8f0024; - ; - - memory "fuse5" - size = 1; - offset = 0x8f0025; - ; - - memory "lock" - size = 1; - offset = 0x8f0027; - ; -; - -#------------------------------------------------------------ -# ATXMEGA16A4 -#------------------------------------------------------------ - -part - id = "x16a4"; - desc = "ATXMEGA16A4"; - signature = 0x1e 0x94 0x41; - has_jtag = yes; - has_pdi = yes; - nvm_base = 0x01c0; - - memory "eeprom" - size = 0x0400; - offset = 0x08c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x00004000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x00001000; - offset = 0x00803000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x00001000; - offset = 0x00804000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x00005000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "prodsig" - size = 0x200; - offset = 0x8e0200; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; - - memory "signature" - size = 3; - offset = 0x1000090; - ; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; - - memory "fuse1" - size = 1; - offset = 0x8f0021; - ; - - memory "fuse2" - size = 1; - offset = 0x8f0022; - ; - - memory "fuse4" - size = 1; - offset = 0x8f0024; - ; - - memory "fuse5" - size = 1; - offset = 0x8f0025; - ; - - memory "lock" - size = 1; - offset = 0x8f0027; - ; -; - -#------------------------------------------------------------ -# ATXMEGA32A4 -#------------------------------------------------------------ - -part - id = "x32a4"; - desc = "ATXMEGA32A4"; - signature = 0x1e 0x95 0x41; - has_jtag = yes; - has_pdi = yes; - nvm_base = 0x01c0; - - memory "eeprom" - size = 0x0400; - offset = 0x08c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x00008000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x00001000; - offset = 0x00807000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x00001000; - offset = 0x00808000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x00009000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "prodsig" - size = 0x200; - offset = 0x8e0200; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; - - memory "signature" - size = 3; - offset = 0x1000090; - ; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; - - memory "fuse1" - size = 1; - offset = 0x8f0021; - ; - - memory "fuse2" - size = 1; - offset = 0x8f0022; - ; - - memory "fuse4" - size = 1; - offset = 0x8f0024; - ; - - memory "fuse5" - size = 1; - offset = 0x8f0025; - ; - - memory "lock" - size = 1; - offset = 0x8f0027; - ; -; - -#------------------------------------------------------------ -# ATXMEGA64A4 -#------------------------------------------------------------ - -part - id = "x64a4"; - desc = "ATXMEGA64A4"; - signature = 0x1e 0x96 0x46; - has_jtag = yes; - has_pdi = yes; - nvm_base = 0x01c0; - - memory "eeprom" - size = 0x0800; - offset = 0x08c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x00010000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x00001000; - offset = 0x0080f000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x00001000; - offset = 0x00810000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x00011000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "prodsig" - size = 0x200; - offset = 0x8e0200; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; - - memory "signature" - size = 3; - offset = 0x1000090; - ; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; - - memory "fuse1" - size = 1; - offset = 0x8f0021; - ; - - memory "fuse2" - size = 1; - offset = 0x8f0022; - ; - - memory "fuse4" - size = 1; - offset = 0x8f0024; - ; - - memory "fuse5" - size = 1; - offset = 0x8f0025; - ; - - memory "lock" - size = 1; - offset = 0x8f0027; - ; -; - -#------------------------------------------------------------ -# ATXMEGA128A4 -#------------------------------------------------------------ - -part - id = "x128a4"; - desc = "ATXMEGA128A4"; - signature = 0x1e 0x97 0x46; - has_jtag = yes; - has_pdi = yes; - nvm_base = 0x01c0; - - memory "eeprom" - size = 0x0800; - offset = 0x08c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x00020000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x00002000; - offset = 0x0081e000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x00002000; - offset = 0x00820000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x00022000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "prodsig" - size = 0x200; - offset = 0x8e0200; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; - - memory "signature" - size = 3; - offset = 0x1000090; - ; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; - - memory "fuse1" - size = 1; - offset = 0x8f0021; - ; - - memory "fuse2" - size = 1; - offset = 0x8f0022; - ; - - memory "fuse4" - size = 1; - offset = 0x8f0024; - ; - - memory "fuse5" - size = 1; - offset = 0x8f0025; - ; - - memory "lock" - size = 1; - offset = 0x8f0027; - ; -; - - -#------------------------------------------------------------ -# AVR32UC3A0512 -#------------------------------------------------------------ - -part - id = "ucr2"; - desc = "32UC3A0512"; - signature = 0xED 0xC0 0x3F; - has_jtag = yes; - is_avr32 = yes; - - memory "flash" - paged = yes; - page_size = 512; # bytes - readsize = 512; # bytes - num_pages = 1024; # could be set dynamicly - size = 0x00080000; # could be set dynamicly - offset = 0x80000000; - ; -; - -#------------------------------------------------------------ -# ATtiny4 -#------------------------------------------------------------ - -part - id = "t4"; - desc = "ATtiny4"; - signature = 0x1e 0x8f 0x0a; - has_tpi = yes; - - memory "flash" - size = 512; - offset = 0x4000; - page_size = 16; - blocksize = 128; - ; - - memory "signature" - size = 3; - offset = 0x3fc0; - ; - - memory "fuse" - size = 1; - offset = 0x3f40; - blocksize = 4; - ; - - memory "calibration" - size = 1; - offset = 0x3f80; - ; - - memory "lockbits" - size = 1; - offset = 0x3f00; - ; -; - - -#------------------------------------------------------------ -# ATtiny5 -#------------------------------------------------------------ - -part - id = "t5"; - desc = "ATtiny5"; - signature = 0x1e 0x8f 0x09; - has_tpi = yes; - - memory "flash" - size = 512; - offset = 0x4000; - page_size = 16; - blocksize = 128; - ; - - memory "signature" - size = 3; - offset = 0x3fc0; - ; - - memory "fuse" - size = 1; - offset = 0x3f40; - blocksize = 4; - ; - - memory "calibration" - size = 1; - offset = 0x3f80; - ; - - memory "lockbits" - size = 1; - offset = 0x3f00; - ; -; - - -#------------------------------------------------------------ -# ATtiny9 -#------------------------------------------------------------ - -part - id = "t8"; - desc = "ATtiny9"; - signature = 0x1e 0x90 0x08; - has_tpi = yes; - - memory "flash" - size = 1024; - offset = 0x4000; - page_size = 16; - blocksize = 128; - ; - - memory "signature" - size = 3; - offset = 0x3fc0; - ; - - memory "fuse" - size = 1; - offset = 0x3f40; - blocksize = 4; - ; - - memory "calibration" - size = 1; - offset = 0x3f80; - ; - - memory "lockbits" - size = 1; - offset = 0x3f00; - ; -; - - -#------------------------------------------------------------ -# ATtiny10 -#------------------------------------------------------------ - -part - id = "t10"; - desc = "ATtiny10"; - signature = 0x1e 0x90 0x03; - has_tpi = yes; - - memory "flash" - size = 1024; - offset = 0x4000; - page_size = 16; - blocksize = 128; - ; - - memory "signature" - size = 3; - offset = 0x3fc0; - ; - - memory "fuse" - size = 1; - offset = 0x3f40; - blocksize = 4; - ; - - memory "calibration" - size = 1; - offset = 0x3f80; - ; - - memory "lockbits" - size = 1; - offset = 0x3f00; - ; -; - - diff --git a/buildroot/share/vscode/avrdude_macOS.conf b/buildroot/share/vscode/avrdude_macOS.conf deleted file mode 100644 index e2ff7cac98..0000000000 --- a/buildroot/share/vscode/avrdude_macOS.conf +++ /dev/null @@ -1,15272 +0,0 @@ -# $Id: avrdude.conf.in 916 2010-01-15 16:36:13Z joerg_wunsch $ -# -# AVRDUDE Configuration File -# -# This file contains configuration data used by AVRDUDE which describes -# the programming hardware pinouts and also provides part definitions. -# AVRDUDE's "-C" command line option specifies the location of the -# configuration file. The "-c" option names the programmer configuration -# which must match one of the entry's "id" parameter. The "-p" option -# identifies which part AVRDUDE is going to be programming and must match -# one of the parts' "id" parameter. -# -# Possible entry formats are: -# -# programmer -# id = [, [, ] ...] ; # are quoted strings -# desc = ; # quoted string -# type = par | stk500 | stk500v2 | stk500pp | stk500hvsp | stk500generic | -# stk600 | stk600pp | stk600hvsp | -# avr910 | butterfly | usbasp | -# jtagmki | jtagmkii | jtagmkii_isp | jtagmkii_dw | -# jtagmkII_avr32 | jtagmkii_pdi | -# dragon_dw | dragon_jtag | dragon_isp | dragon_pp | -# dragon_hvsp | dragon_pdi | arduino; # programmer type -# baudrate = ; # baudrate for avr910-programmer -# vcc = [, ... ] ; # pin number(s) -# reset = ; # pin number -# sck = ; # pin number -# mosi = ; # pin number -# miso = ; # pin number -# errled = ; # pin number -# rdyled = ; # pin number -# pgmled = ; # pin number -# vfyled = ; # pin number -# ; -# -# part -# id = ; # quoted string -# desc = ; # quoted string -# has_jtag = ; # part has JTAG i/f -# has_debugwire = ; # part has debugWire i/f -# has_pdi = ; # part has PDI i/f -# has_tpi = ; # part has TPI i/f -# devicecode = ; # deprecated, use stk500_devcode -# stk500_devcode = ; # numeric -# avr910_devcode = ; # numeric -# signature = ; # signature bytes -# chip_erase_delay = ; # micro-seconds -# reset = dedicated | io; -# retry_pulse = reset | sck; -# pgm_enable = ; -# chip_erase = ; -# chip_erase_delay = ; # chip erase delay (us) -# # STK500 parameters (parallel programming IO lines) -# pagel = ; # pin name in hex, i.e., 0xD7 -# bs2 = ; # pin name in hex, i.e., 0xA0 -# serial = ; # can use serial downloading -# parallel = ; # can use par. programming -# # STK500v2 parameters, to be taken from Atmel's XML files -# timeout = ; -# stabdelay = ; -# cmdexedelay = ; -# synchloops = ; -# bytedelay = ; -# pollvalue = ; -# pollindex = ; -# predelay = ; -# postdelay = ; -# pollmethod = ; -# mode = ; -# delay = ; -# blocksize = ; -# readsize = ; -# hvspcmdexedelay = ; -# # STK500v2 HV programming parameters, from XML -# pp_controlstack = , , ...; # PP only -# hvsp_controlstack = , , ...; # HVSP only -# hventerstabdelay = ; -# progmodedelay = ; # PP only -# latchcycles = ; -# togglevtg = ; -# poweroffdelay = ; -# resetdelayms = ; -# resetdelayus = ; -# hvleavestabdelay = ; -# resetdelay = ; -# synchcycles = ; # HVSP only -# chiperasepulsewidth = ; # PP only -# chiperasepolltimeout = ; -# chiperasetime = ; # HVSP only -# programfusepulsewidth = ; # PP only -# programfusepolltimeout = ; -# programlockpulsewidth = ; # PP only -# programlockpolltimeout = ; -# # JTAG ICE mkII parameters, also from XML files -# allowfullpagebitstream = ; -# enablepageprogramming = ; -# idr = ; # IO addr of IDR (OCD) reg. -# rampz = ; # IO addr of RAMPZ reg. -# spmcr = ; # mem addr of SPMC[S]R reg. -# eecr = ; # mem addr of EECR reg. -# # (only when != 0x3c) -# is_avr32 = ; # AVR32 part -# -# memory -# paged = ; # yes / no -# size = ; # bytes -# page_size = ; # bytes -# num_pages = ; # numeric -# min_write_delay = ; # micro-seconds -# max_write_delay = ; # micro-seconds -# readback_p1 = ; # byte value -# readback_p2 = ; # byte value -# pwroff_after_write = ; # yes / no -# read = ; -# write = ; -# read_lo = ; -# read_hi = ; -# write_lo = ; -# write_hi = ; -# loadpage_lo = ; -# loadpage_hi = ; -# writepage = ; -# ; -# ; -# -# If any of the above parameters are not specified, the default value -# of 0 is used for numerics or the empty string ("") for string -# values. If a required parameter is left empty, AVRDUDE will -# complain. -# -# NOTES: -# * 'devicecode' is the device code used by the STK500 (see codes -# listed below) -# * Not all memory types will implement all instructions. -# * AVR Fuse bits and Lock bits are implemented as a type of memory. -# * Example memory types are: -# "flash", "eeprom", "fuse", "lfuse" (low fuse), "hfuse" (high -# fuse), "signature", "calibration", "lock" -# * The memory type specified on the avrdude command line must match -# one of the memory types defined for the specified chip. -# * The pwroff_after_write flag causes avrdude to attempt to -# power the device off and back on after an unsuccessful write to -# the affected memory area if VCC programmer pins are defined. If -# VCC pins are not defined for the programmer, a message -# indicating that the device needs a power-cycle is printed out. -# This flag was added to work around a problem with the -# at90s4433/2333's; see the at90s4433 errata page 2 at: -# -# https://ww1.microchip.com/downloads/en/AppNotes/doc2574.pdf -# -# INSTRUCTION FORMATS -# -# Instruction formats are specified as a comma separated list of -# string values containing information (bit specifiers) about each -# of the 32 bits of the instruction. Bit specifiers may be one of -# the following formats: -# -# '1' = the bit is always set on input as well as output -# -# '0' = the bit is always clear on input as well as output -# -# 'x' = the bit is ignored on input and output -# -# 'a' = the bit is an address bit, the bit-number matches this bit -# specifier's position within the current instruction byte -# -# 'aN' = the bit is the Nth address bit, bit-number = N, i.e., a12 -# is address bit 12 on input, a0 is address bit 0. -# -# 'i' = the bit is an input data bit -# -# 'o' = the bit is an output data bit -# -# Each instruction must be composed of 32 bit specifiers. The -# instruction specification closely follows the instruction data -# provided in Atmel's data sheets for their parts. -# -# See below for some examples. -# -# -# The following are STK500 part device codes to use for the -# "devicecode" field of the part. These came from Atmel's software -# section avr061.zip which accompanies the application note -# AVR061 available from: -# -# https://www.microchip.com/en-us/application-notes/an2525 -# - -#define ATTINY10 0x10 /* the _old_ one that never existed! */ -#define ATTINY11 0x11 -#define ATTINY12 0x12 -#define ATTINY15 0x13 -#define ATTINY13 0x14 - -#define ATTINY22 0x20 -#define ATTINY26 0x21 -#define ATTINY28 0x22 -#define ATTINY2313 0x23 - -#define AT90S1200 0x33 - -#define AT90S2313 0x40 -#define AT90S2323 0x41 -#define AT90S2333 0x42 -#define AT90S2343 0x43 - -#define AT90S4414 0x50 -#define AT90S4433 0x51 -#define AT90S4434 0x52 -#define ATMEGA48 0x59 - -#define AT90S8515 0x60 -#define AT90S8535 0x61 -#define AT90C8534 0x62 -#define ATMEGA8515 0x63 -#define ATMEGA8535 0x64 - -#define ATMEGA8 0x70 -#define ATMEGA88 0x73 -#define ATMEGA168 0x86 - -#define ATMEGA161 0x80 -#define ATMEGA163 0x81 -#define ATMEGA16 0x82 -#define ATMEGA162 0x83 -#define ATMEGA169 0x84 - -#define ATMEGA323 0x90 -#define ATMEGA32 0x91 - -#define ATMEGA64 0xA0 - -#define ATMEGA103 0xB1 -#define ATMEGA128 0xB2 -#define AT90CAN128 0xB3 -#define AT90CAN64 0xB3 -#define AT90CAN32 0xB3 - -#define AT86RF401 0xD0 - -#define AT89START 0xE0 -#define AT89S51 0xE0 -#define AT89S52 0xE1 - -# The following table lists the devices in the original AVR910 -# appnote: -# |Device |Signature | Code | -# +-------+----------+------+ -# |tiny12 | 1E 90 05 | 0x55 | -# |tiny15 | 1E 90 06 | 0x56 | -# | | | | -# | S1200 | 1E 90 01 | 0x13 | -# | | | | -# | S2313 | 1E 91 01 | 0x20 | -# | S2323 | 1E 91 02 | 0x48 | -# | S2333 | 1E 91 05 | 0x34 | -# | S2343 | 1E 91 03 | 0x4C | -# | | | | -# | S4414 | 1E 92 01 | 0x28 | -# | S4433 | 1E 92 03 | 0x30 | -# | S4434 | 1E 92 02 | 0x6C | -# | | | | -# | S8515 | 1E 93 01 | 0x38 | -# | S8535 | 1E 93 03 | 0x68 | -# | | | | -# |mega32 | 1E 95 01 | 0x72 | -# |mega83 | 1E 93 05 | 0x65 | -# |mega103| 1E 97 01 | 0x41 | -# |mega161| 1E 94 01 | 0x60 | -# |mega163| 1E 94 02 | 0x64 | - -# Appnote AVR109 also has a table of AVR910 device codes, which -# lists: -# dev avr910 signature -# ATmega8 0x77 0x1E 0x93 0x07 -# ATmega8515 0x3B 0x1E 0x93 0x06 -# ATmega8535 0x6A 0x1E 0x93 0x08 -# ATmega16 0x75 0x1E 0x94 0x03 -# ATmega162 0x63 0x1E 0x94 0x04 -# ATmega163 0x66 0x1E 0x94 0x02 -# ATmega169 0x79 0x1E 0x94 0x05 -# ATmega32 0x7F 0x1E 0x95 0x02 -# ATmega323 0x73 0x1E 0x95 0x01 -# ATmega64 0x46 0x1E 0x96 0x02 -# ATmega128 0x44 0x1E 0x97 0x02 -# -# These codes refer to "BOOT" device codes which are apparently -# different than standard device codes, for whatever reasons -# (often one above the standard code). - -# There are several extended versions of AVR910 implementations around -# in the Internet. These add the following codes (only devices that -# actually exist are listed): - -# ATmega8515 0x3A -# ATmega128 0x43 -# ATmega64 0x45 -# ATtiny26 0x5E -# ATmega8535 0x69 -# ATmega32 0x72 -# ATmega16 0x74 -# ATmega8 0x76 -# ATmega169 0x78 - -# -# Overall avrdude defaults -# -default_parallel = "unknown"; -default_serial = "unknown"; - - -# -# PROGRAMMER DEFINITIONS -# - -programmer - id = "arduino"; - desc = "Arduino"; - type = arduino; -; - -programmer - id = "avrisp"; - desc = "Atmel AVR ISP"; - type = stk500; -; - -programmer - id = "avrispv2"; - desc = "Atmel AVR ISP V2"; - type = stk500v2; -; - -programmer - id = "avrispmkII"; - desc = "Atmel AVR ISP mkII"; - type = stk500v2; -; - -programmer - id = "avrisp2"; - desc = "Atmel AVR ISP mkII"; - type = stk500v2; -; - -programmer - id = "buspirate"; - desc = "The Bus Pirate"; - type = buspirate; -; - -# This is supposed to be the "default" STK500 entry. -# Attempts to select the correct firmware version -# by probing for it. Better use one of the entries -# below instead. -programmer - id = "stk500"; - desc = "Atmel STK500"; - type = stk500generic; -; - -programmer - id = "stk500v1"; - desc = "Atmel STK500 Version 1.x firmware"; - type = stk500; -; - -programmer - id = "mib510"; - desc = "Crossbow MIB510 programming board"; - type = stk500; -; - -programmer - id = "stk500v2"; - desc = "Atmel STK500 Version 2.x firmware"; - type = stk500v2; -; - -programmer - id = "stk500pp"; - desc = "Atmel STK500 V2 in parallel programming mode"; - type = stk500pp; -; - -programmer - id = "stk500hvsp"; - desc = "Atmel STK500 V2 in high-voltage serial programming mode"; - type = stk500hvsp; -; - -programmer - id = "stk600"; - desc = "Atmel STK600"; - type = stk600; -; - -programmer - id = "stk600pp"; - desc = "Atmel STK600 in parallel programming mode"; - type = stk600pp; -; - -programmer - id = "stk600hvsp"; - desc = "Atmel STK600 in high-voltage serial programming mode"; - type = stk600hvsp; -; - -programmer - id = "avr910"; - desc = "Atmel Low Cost Serial Programmer"; - type = avr910; -; - -programmer - id = "usbasp"; - desc = "USBasp, https://www.fischl.de/usbasp/"; - type = usbasp; -; - -programmer - id = "usbtiny"; - desc = "USBtiny simple USB programmer, https://learn.adafruit.com/usbtinyisp"; - type = usbtiny; -; - -programmer - id = "butterfly"; - desc = "Atmel Butterfly Development Board"; - type = butterfly; -; - -programmer - id = "avr109"; - desc = "Atmel AppNote AVR109 Boot Loader"; - type = butterfly; -; - -programmer - id = "avr911"; - desc = "Atmel AppNote AVR911 AVROSP"; - type = butterfly; -; - -programmer - id = "jtagmkI"; - desc = "Atmel JTAG ICE (mkI)"; - baudrate = 115200; # default is 115200 - type = jtagmki; -; - -# easier to type -programmer - id = "jtag1"; - desc = "Atmel JTAG ICE (mkI)"; - baudrate = 115200; # default is 115200 - type = jtagmki; -; - -# easier to type -programmer - id = "jtag1slow"; - desc = "Atmel JTAG ICE (mkI)"; - baudrate = 19200; - type = jtagmki; -; - -programmer - id = "jtagmkII"; - desc = "Atmel JTAG ICE mkII"; - baudrate = 19200; # default is 19200 - type = jtagmkii; -; - -# easier to type -programmer - id = "jtag2slow"; - desc = "Atmel JTAG ICE mkII"; - baudrate = 19200; # default is 19200 - type = jtagmkii; -; - -# JTAG ICE mkII @ 115200 Bd -programmer - id = "jtag2fast"; - desc = "Atmel JTAG ICE mkII"; - baudrate = 115200; - type = jtagmkii; -; - -# make the fast one the default, people will love that -programmer - id = "jtag2"; - desc = "Atmel JTAG ICE mkII"; - baudrate = 115200; - type = jtagmkii; -; - -# JTAG ICE mkII in ISP mode -programmer - id = "jtag2isp"; - desc = "Atmel JTAG ICE mkII in ISP mode"; - baudrate = 115200; - type = jtagmkii_isp; -; - -# JTAG ICE mkII in debugWire mode -programmer - id = "jtag2dw"; - desc = "Atmel JTAG ICE mkII in debugWire mode"; - baudrate = 115200; - type = jtagmkii_dw; -; - -# JTAG ICE mkII in AVR32 mode -programmer - id = "jtagmkII_avr32"; - desc = "Atmel JTAG ICE mkII im AVR32 mode"; - baudrate = 115200; - type = jtagmkii_avr32; -; - -# JTAG ICE mkII in AVR32 mode -programmer - id = "jtag2avr32"; - desc = "Atmel JTAG ICE mkII im AVR32 mode"; - baudrate = 115200; - type = jtagmkii_avr32; -; - -# JTAG ICE mkII in PDI mode -programmer - id = "jtag2pdi"; - desc = "Atmel JTAG ICE mkII PDI mode"; - baudrate = 115200; - type = jtagmkii_pdi; -; - -# AVR Dragon in JTAG mode -programmer - id = "dragon_jtag"; - desc = "Atmel AVR Dragon in JTAG mode"; - baudrate = 115200; - type = dragon_jtag; -; - -# AVR Dragon in ISP mode -programmer - id = "dragon_isp"; - desc = "Atmel AVR Dragon in ISP mode"; - baudrate = 115200; - type = dragon_isp; -; - -# AVR Dragon in PP mode -programmer - id = "dragon_pp"; - desc = "Atmel AVR Dragon in PP mode"; - baudrate = 115200; - type = dragon_pp; -; - -# AVR Dragon in HVSP mode -programmer - id = "dragon_hvsp"; - desc = "Atmel AVR Dragon in HVSP mode"; - baudrate = 115200; - type = dragon_hvsp; -; - -# AVR Dragon in debugWire mode -programmer - id = "dragon_dw"; - desc = "Atmel AVR Dragon in debugWire mode"; - baudrate = 115200; - type = dragon_dw; -; - -# AVR Dragon in PDI mode -programmer - id = "dragon_pdi"; - desc = "Atmel AVR Dragon in PDI mode"; - baudrate = 115200; - type = dragon_pdi; -; - -programmer - id = "pavr"; - desc = "Jason Kyle's pAVR Serial Programmer"; - type = avr910; -; - - -# -# some ultra cheap programmers use bitbanging on the -# serialport. -# -# PC - DB9 - Pins for RS232: -# -# GND 5 -- |O -# | O| <- 9 RI -# DTR 4 <- |O | -# | O| <- 8 CTS -# TXD 3 <- |O | -# | O| -> 7 RTS -# RXD 2 -> |O | -# | O| <- 6 DSR -# DCD 1 -> |O -# -# Using RXD is currently not supported. -# Using RI is not supported under Win32 but is supported under Posix. - -# serial ponyprog design (dasa2 in uisp) -# reset=!txd sck=rts mosi=dtr miso=cts - -programmer - id = "ponyser"; - desc = "design ponyprog serial, reset=!txd sck=rts mosi=dtr miso=cts"; - type = serbb; - reset = ~3; - sck = 7; - mosi = 4; - miso = 8; -; - -# Same as above, different name -# reset=!txd sck=rts mosi=dtr miso=cts - -programmer - id = "siprog"; - desc = "Lancos SI-Prog "; - type = serbb; - reset = ~3; - sck = 7; - mosi = 4; - miso = 8; -; - -# unknown (dasa in uisp) -# reset=rts sck=dtr mosi=txd miso=cts - -programmer - id = "dasa"; - desc = "serial port banging, reset=rts sck=dtr mosi=txd miso=cts"; - type = serbb; - reset = 7; - sck = 4; - mosi = 3; - miso = 8; -; - -# unknown (dasa3 in uisp) -# reset=!dtr sck=rts mosi=txd miso=cts - -programmer - id = "dasa3"; - desc = "serial port banging, reset=!dtr sck=rts mosi=txd miso=cts"; - type = serbb; - reset = ~4; - sck = 7; - mosi = 3; - miso = 8; -; - -# C2N232i (jumper configuration "auto") -# reset=dtr sck=!rts mosi=!txd miso=!cts - -programmer - id = "c2n232i"; - desc = "serial port banging, reset=dtr sck=!rts mosi=!txd miso=!cts"; - type = serbb; - reset = 4; - sck = ~7; - mosi = ~3; - miso = ~8; -; - -# -# PART DEFINITIONS -# - -#------------------------------------------------------------ -# ATtiny11 -#------------------------------------------------------------ - -# This is an HVSP-only device. - -part - id = "t11"; - desc = "ATtiny11"; - stk500_devcode = 0x11; - signature = 0x1e 0x90 0x04; - chip_erase_delay = 20000; - - timeout = 200; - hvsp_controlstack = - 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x00, - 0x68, 0x78, 0x68, 0x68, 0x00, 0x00, 0x68, 0x78, - 0x78, 0x00, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, - 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - hvspcmdexedelay = 0; - synchcycles = 6; - latchcycles = 1; - togglevtg = 1; - poweroffdelay = 25; - resetdelayms = 0; - resetdelayus = 50; - hvleavestabdelay = 100; - resetdelay = 25; - chiperasepolltimeout = 40; - chiperasetime = 0; - programfusepolltimeout = 25; - programlockpolltimeout = 25; - - memory "eeprom" - size = 64; - blocksize = 64; - readsize = 256; - delay = 5; - ; - - memory "flash" - size = 1024; - blocksize = 128; - readsize = 256; - delay = 3; - ; - - memory "signature" - size = 3; - ; - - memory "lock" - size = 1; - ; - - memory "calibration" - size = 1; - ; - - memory "fuse" - size = 1; - ; -; - -#------------------------------------------------------------ -# ATtiny12 -#------------------------------------------------------------ - -part - id = "t12"; - desc = "ATtiny12"; - stk500_devcode = 0x12; - avr910_devcode = 0x55; - signature = 0x1e 0x90 0x05; - chip_erase_delay = 20000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - hvsp_controlstack = - 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x00, - 0x68, 0x78, 0x68, 0x68, 0x00, 0x00, 0x68, 0x78, - 0x78, 0x00, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, - 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00; - hventerstabdelay = 100; - hvspcmdexedelay = 0; - synchcycles = 6; - latchcycles = 1; - togglevtg = 1; - poweroffdelay = 25; - resetdelayms = 0; - resetdelayus = 50; - hvleavestabdelay = 100; - resetdelay = 25; - chiperasepolltimeout = 40; - chiperasetime = 0; - programfusepolltimeout = 25; - programlockpolltimeout = 25; - - memory "eeprom" - size = 64; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 x x x x x x x x", - "x x a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 x x x x x x x x", - "x x a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - mode = 0x04; - delay = 8; - blocksize = 64; - readsize = 256; - ; - - memory "flash" - size = 1024; - min_write_delay = 4500; - max_write_delay = 20000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - write_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 5; - blocksize = 128; - readsize = 256; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x x x x x x o o x"; - - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "fuse" - size = 1; - read = "0 1 0 1 0 0 0 0 x x x x x x x x", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 x x x x x", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; -; - -#------------------------------------------------------------ -# ATtiny13 -#------------------------------------------------------------ - -part - id = "t13"; - desc = "ATtiny13"; - has_debugwire = yes; - flash_instr = 0xB4, 0x0E, 0x1E; - eeprom_instr = 0xBB, 0xFE, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, - 0xBC, 0x0E, 0xB4, 0x0E, 0xBA, 0x0D, 0xBB, 0xBC, - 0x99, 0xE1, 0xBB, 0xAC; - stk500_devcode = 0x14; - signature = 0x1e 0x90 0x07; - chip_erase_delay = 4000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - hvsp_controlstack = - 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x66, - 0x68, 0x78, 0x68, 0x68, 0x7A, 0x6A, 0x68, 0x78, - 0x78, 0x7D, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, - 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - hvspcmdexedelay = 0; - synchcycles = 6; - latchcycles = 1; - togglevtg = 1; - poweroffdelay = 25; - resetdelayms = 0; - resetdelayus = 90; - hvleavestabdelay = 100; - resetdelay = 25; - chiperasepolltimeout = 40; - chiperasetime = 0; - programfusepolltimeout = 25; - programlockpolltimeout = 25; - - memory "eeprom" - size = 64; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x x", - "x x a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x x", - "x x a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " x x a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 5; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 1024; - page_size = 32; - num_pages = 32; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 0 0 0 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 0 0 0 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 0 0 0 a8", - " a7 a6 a5 a4 x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 32; - readsize = 256; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "calibration" - size = 2; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 a0 o o o o o o o o"; - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - ; - -; - - -#------------------------------------------------------------ -# ATtiny15 -#------------------------------------------------------------ - -part - id = "t15"; - desc = "ATtiny15"; - stk500_devcode = 0x13; - avr910_devcode = 0x56; - signature = 0x1e 0x90 0x06; - chip_erase_delay = 8200; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - hvsp_controlstack = - 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x00, - 0x68, 0x78, 0x68, 0x68, 0x00, 0x00, 0x68, 0x78, - 0x78, 0x00, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, - 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00; - hventerstabdelay = 100; - hvspcmdexedelay = 5; - synchcycles = 6; - latchcycles = 16; - togglevtg = 1; - poweroffdelay = 25; - resetdelayms = 0; - resetdelayus = 50; - hvleavestabdelay = 100; - resetdelay = 25; - chiperasepolltimeout = 40; - chiperasetime = 0; - programfusepolltimeout = 25; - programlockpolltimeout = 25; - - memory "eeprom" - size = 64; - min_write_delay = 8200; - max_write_delay = 8200; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 x x x x x x x x", - "x x a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 x x x x x x x x", - "x x a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - mode = 0x04; - delay = 10; - blocksize = 64; - readsize = 256; - ; - - memory "flash" - size = 1024; - min_write_delay = 4100; - max_write_delay = 4100; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - write_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 5; - blocksize = 128; - readsize = 256; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x x x x x x o o x"; - - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "fuse" - size = 1; - read = "0 1 0 1 0 0 0 0 x x x x x x x x", - "x x x x x x x x o o o o x x o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 x x x x x", - "x x x x x x x x i i i i 1 1 i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; -; - -#------------------------------------------------------------ -# AT90s1200 -#------------------------------------------------------------ - -part - id = "1200"; - desc = "AT90S1200"; - stk500_devcode = 0x33; - avr910_devcode = 0x13; - signature = 0x1e 0x90 0x01; - pagel = 0xd7; - bs2 = 0xa0; - chip_erase_delay = 20000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 1; - bytedelay = 0; - pollindex = 0; - pollvalue = 0xFF; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 0; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 15; - chiperasepolltimeout = 0; - programfusepulsewidth = 2; - programfusepolltimeout = 0; - programlockpulsewidth = 0; - programlockpolltimeout = 1; - - memory "eeprom" - size = 64; - min_write_delay = 4000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 x x x x x x x x", - "x x a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 x x x x x x x x", - "x x a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - mode = 0x04; - delay = 20; - blocksize = 32; - readsize = 256; - ; - memory "flash" - size = 1024; - min_write_delay = 4000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - write_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x02; - delay = 15; - blocksize = 128; - readsize = 256; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "fuse" - size = 1; - ; - memory "lock" - size = 1; - min_write_delay = 9000; - max_write_delay = 20000; - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", - "x x x x x x x x x x x x x x x x"; - ; - ; - -#------------------------------------------------------------ -# AT90s4414 -#------------------------------------------------------------ - -part - id = "4414"; - desc = "AT90S4414"; - stk500_devcode = 0x50; - avr910_devcode = 0x28; - signature = 0x1e 0x92 0x01; - chip_erase_delay = 20000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 0; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 15; - chiperasepolltimeout = 0; - programfusepulsewidth = 2; - programfusepolltimeout = 0; - programlockpulsewidth = 0; - programlockpolltimeout = 1; - - memory "eeprom" - size = 256; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0x80; - readback_p2 = 0x7f; - read = " 1 0 1 0 0 0 0 0 x x x x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0 x x x x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 64; - readsize = 256; - ; - memory "flash" - size = 4096; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0x7f; - readback_p2 = 0x7f; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write_lo = " 0 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - write_hi = " 0 1 0 0 1 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 64; - readsize = 256; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "fuse" - size = 1; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - ; - -#------------------------------------------------------------ -# AT90s2313 -#------------------------------------------------------------ - -part - id = "2313"; - desc = "AT90S2313"; - stk500_devcode = 0x40; - avr910_devcode = 0x20; - signature = 0x1e 0x91 0x01; - chip_erase_delay = 20000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 0; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 15; - chiperasepolltimeout = 0; - programfusepulsewidth = 2; - programfusepolltimeout = 0; - programlockpulsewidth = 0; - programlockpolltimeout = 1; - - memory "eeprom" - size = 128; - min_write_delay = 4000; - max_write_delay = 9000; - readback_p1 = 0x80; - readback_p2 = 0x7f; - read = "1 0 1 0 0 0 0 0 x x x x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 x x x x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 64; - readsize = 256; - ; - memory "flash" - size = 2048; - min_write_delay = 4000; - max_write_delay = 9000; - readback_p1 = 0x7f; - readback_p2 = 0x7f; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - write_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 128; - readsize = 256; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "fuse" - size = 1; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x i i x", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - ; - -#------------------------------------------------------------ -# AT90s2333 -#------------------------------------------------------------ - -part - id = "2333"; -##### WARNING: No XML file for device 'AT90S2333'! ##### - desc = "AT90S2333"; - stk500_devcode = 0x42; - avr910_devcode = 0x34; - signature = 0x1e 0x91 0x05; - chip_erase_delay = 20000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 0; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 15; - chiperasepolltimeout = 0; - programfusepulsewidth = 2; - programfusepolltimeout = 0; - programlockpulsewidth = 0; - programlockpolltimeout = 1; - - memory "eeprom" - size = 128; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0x00; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 x x x x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 x x x x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 128; - readsize = 256; - ; - - memory "flash" - size = 2048; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - write_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 128; - readsize = 256; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "fuse" - size = 1; - min_write_delay = 9000; - max_write_delay = 20000; - pwroff_after_write = yes; - read = "0 1 0 1 0 0 0 0 x x x x x x x x", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 i i i i i", - "x x x x x x x x x x x x x x x x"; - ; - memory "lock" - size = 1; - min_write_delay = 9000; - max_write_delay = 20000; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x x x x x x o o x"; - - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", - "x x x x x x x x x x x x x x x x"; - ; - ; - - -#------------------------------------------------------------ -# AT90s2343 (also AT90s2323 and ATtiny22) -#------------------------------------------------------------ - -part - id = "2343"; - desc = "AT90S2343"; - stk500_devcode = 0x43; - avr910_devcode = 0x4c; - signature = 0x1e 0x91 0x03; - chip_erase_delay = 18000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - hvsp_controlstack = - 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x00, - 0x68, 0x78, 0x68, 0x68, 0x00, 0x00, 0x68, 0x78, - 0x78, 0x00, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, - 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00; - hventerstabdelay = 100; - hvspcmdexedelay = 0; - synchcycles = 6; - latchcycles = 1; - togglevtg = 0; - poweroffdelay = 25; - resetdelayms = 0; - resetdelayus = 50; - hvleavestabdelay = 100; - resetdelay = 25; - chiperasepolltimeout = 40; - chiperasetime = 0; - programfusepolltimeout = 25; - programlockpolltimeout = 25; - - memory "eeprom" - size = 128; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0x00; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0", - "x a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0", - "x a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 64; - readsize = 256; - ; - memory "flash" - size = 2048; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - write_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 128; - readsize = 128; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "fuse" - size = 1; - min_write_delay = 9000; - max_write_delay = 20000; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x o o o x x x x o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 1 1 1 1 i", - "x x x x x x x x x x x x x x x x"; - ; - memory "lock" - size = 1; - min_write_delay = 9000; - max_write_delay = 20000; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x o o o x x x x o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", - "x x x x x x x x x x x x x x x x"; - ; - ; - - -#------------------------------------------------------------ -# AT90s4433 -#------------------------------------------------------------ - -part - id = "4433"; - desc = "AT90S4433"; - stk500_devcode = 0x51; - avr910_devcode = 0x30; - signature = 0x1e 0x92 0x03; - chip_erase_delay = 20000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 0; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 15; - chiperasepolltimeout = 0; - programfusepulsewidth = 2; - programfusepolltimeout = 0; - programlockpulsewidth = 0; - programlockpolltimeout = 1; - - memory "eeprom" - size = 256; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0x00; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0 x x x x x x x x", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0 x x x x x x x x", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 128; - readsize = 256; - ; - memory "flash" - size = 4096; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write_lo = " 0 1 0 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - write_hi = " 0 1 0 0 1 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 128; - readsize = 256; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "fuse" - size = 1; - min_write_delay = 9000; - max_write_delay = 20000; - pwroff_after_write = yes; - read = "0 1 0 1 0 0 0 0 x x x x x x x x", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 i i i i i", - "x x x x x x x x x x x x x x x x"; - ; - memory "lock" - size = 1; - min_write_delay = 9000; - max_write_delay = 20000; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x x x x x x o o x"; - - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", - "x x x x x x x x x x x x x x x x"; - ; - ; - -#------------------------------------------------------------ -# AT90s4434 -#------------------------------------------------------------ - -part - id = "4434"; -##### WARNING: No XML file for device 'AT90S4434'! ##### - desc = "AT90S4434"; - stk500_devcode = 0x52; - avr910_devcode = 0x6c; - signature = 0x1e 0x92 0x02; - chip_erase_delay = 20000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - memory "eeprom" - size = 256; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0x00; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0 x x x x x x x x", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0 x x x x x x x x", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - ; - memory "flash" - size = 4096; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write_lo = " 0 1 0 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - write_hi = " 0 1 0 0 1 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "fuse" - size = 1; - min_write_delay = 9000; - max_write_delay = 20000; - read = "0 1 0 1 0 0 0 0 x x x x x x x x", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 i i i i i", - "x x x x x x x x x x x x x x x x"; - ; - memory "lock" - size = 1; - min_write_delay = 9000; - max_write_delay = 20000; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x x x x x x o o x"; - - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", - "x x x x x x x x x x x x x x x x"; - ; - ; - -#------------------------------------------------------------ -# AT90s8515 -#------------------------------------------------------------ - -part - id = "8515"; - desc = "AT90S8515"; - stk500_devcode = 0x60; - avr910_devcode = 0x38; - signature = 0x1e 0x93 0x01; - chip_erase_delay = 20000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 0; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - resetdelay = 15; - chiperasepulsewidth = 15; - chiperasepolltimeout = 0; - programfusepulsewidth = 2; - programfusepolltimeout = 0; - programlockpulsewidth = 0; - programlockpolltimeout = 1; - - memory "eeprom" - size = 512; - min_write_delay = 4000; - max_write_delay = 9000; - readback_p1 = 0x80; - readback_p2 = 0x7f; - read = " 1 0 1 0 0 0 0 0 x x x x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0 x x x x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 128; - readsize = 256; - ; - memory "flash" - size = 8192; - min_write_delay = 4000; - max_write_delay = 9000; - readback_p1 = 0x7f; - readback_p2 = 0x7f; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write_lo = " 0 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - write_hi = " 0 1 0 0 1 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 128; - readsize = 256; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "fuse" - size = 1; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - ; - -#------------------------------------------------------------ -# AT90s8535 -#------------------------------------------------------------ - -part - id = "8535"; - desc = "AT90S8535"; - stk500_devcode = 0x61; - avr910_devcode = 0x68; - signature = 0x1e 0x93 0x03; - chip_erase_delay = 20000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 0; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 15; - chiperasepolltimeout = 0; - programfusepulsewidth = 2; - programfusepolltimeout = 0; - programlockpulsewidth = 0; - programlockpolltimeout = 1; - - memory "eeprom" - size = 512; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0x00; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0 x x x x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0 x x x x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 128; - readsize = 256; - ; - memory "flash" - size = 8192; - min_write_delay = 9000; - max_write_delay = 20000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write_lo = " 0 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - write_hi = " 0 1 0 0 1 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 128; - readsize = 256; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "fuse" - size = 1; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x x x x x x x x o"; - write = "1 0 1 0 1 1 0 0 1 0 1 1 1 1 1 i", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x o o x x x x x x"; - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - ; - -#------------------------------------------------------------ -# ATmega103 -#------------------------------------------------------------ - -part - id = "m103"; - desc = "ATMEGA103"; - stk500_devcode = 0xB1; - avr910_devcode = 0x41; - signature = 0x1e 0x97 0x01; - chip_erase_delay = 112000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x8E, 0x9E, 0x2E, 0x3E, 0xAE, 0xBE, - 0x4E, 0x5E, 0xCE, 0xDE, 0x6E, 0x7E, 0xEE, 0xDE, - 0x66, 0x76, 0xE6, 0xF6, 0x6A, 0x7A, 0xEA, 0x7A, - 0x7F, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 0; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 15; - chiperasepolltimeout = 0; - programfusepulsewidth = 2; - programfusepolltimeout = 0; - programlockpulsewidth = 0; - programlockpolltimeout = 10; - - memory "eeprom" - size = 4096; - min_write_delay = 4000; - max_write_delay = 9000; - readback_p1 = 0x80; - readback_p2 = 0x7f; - read = " 1 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 64; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 131072; - page_size = 256; - num_pages = 512; - min_write_delay = 22000; - max_write_delay = 56000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x11; - delay = 70; - blocksize = 256; - readsize = 256; - ; - - memory "fuse" - size = 1; - read = "0 1 0 1 0 0 0 0 x x x x x x x x", - "x x x x x x x x x x o x o 1 o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 1 i 1 i i", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x x x x x x o o x"; - - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - - -#------------------------------------------------------------ -# ATmega64 -#------------------------------------------------------------ - -part - id = "m64"; - desc = "ATMEGA64"; - has_jtag = yes; - stk500_devcode = 0xA0; - avr910_devcode = 0x45; - signature = 0x1e 0x96 0x02; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x22; - spmcr = 0x68; - allowfullpagebitstream = yes; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 2048; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 20; - blocksize = 64; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 65536; - page_size = 256; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 6; - blocksize = 128; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 4; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - - - - -#------------------------------------------------------------ -# ATmega128 -#------------------------------------------------------------ - -part - id = "m128"; - desc = "ATMEGA128"; - has_jtag = yes; - stk500_devcode = 0xB2; - avr910_devcode = 0x43; - signature = 0x1e 0x97 0x02; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x22; - spmcr = 0x68; - rampz = 0x3b; - allowfullpagebitstream = yes; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 4096; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 12; - blocksize = 64; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 131072; - page_size = 256; - num_pages = 512; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 6; - blocksize = 128; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 4; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# AT90CAN128 -#------------------------------------------------------------ - -part - id = "c128"; - desc = "AT90CAN128"; - has_jtag = yes; - stk500_devcode = 0xB3; -# avr910_devcode = 0x43; - signature = 0x1e 0x97 0x81; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - eecr = 0x3f; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 4096; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - - mode = 0x41; - delay = 20; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 131072; - page_size = 256; - num_pages = 512; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# AT90CAN64 -#------------------------------------------------------------ - -part - id = "c64"; - desc = "AT90CAN64"; - has_jtag = yes; - stk500_devcode = 0xB3; -# avr910_devcode = 0x43; - signature = 0x1e 0x96 0x81; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - eecr = 0x3f; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 2048; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - - mode = 0x41; - delay = 20; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 65536; - page_size = 256; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# AT90CAN32 -#------------------------------------------------------------ - -part - id = "c32"; - desc = "AT90CAN32"; - has_jtag = yes; - stk500_devcode = 0xB3; -# avr910_devcode = 0x43; - signature = 0x1e 0x95 0x81; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - eecr = 0x3f; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 1024; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - - mode = 0x41; - delay = 20; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 32768; - page_size = 256; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - - -#------------------------------------------------------------ -# ATmega16 -#------------------------------------------------------------ - -part - id = "m16"; - desc = "ATMEGA16"; - has_jtag = yes; - stk500_devcode = 0x82; - avr910_devcode = 0x74; - signature = 0x1e 0x94 0x03; - pagel = 0xd7; - bs2 = 0xa0; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 100; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - resetdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - allowfullpagebitstream = yes; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 512; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x04; - delay = 10; - blocksize = 128; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 16384; - page_size = 128; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 6; - blocksize = 128; - readsize = 256; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "calibration" - size = 4; - - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - ; - - -#------------------------------------------------------------ -# ATmega164P -#------------------------------------------------------------ - -# close to ATmega16 - -part - id = "m164p"; - desc = "ATMEGA164P"; - has_jtag = yes; - stk500_devcode = 0x82; # no STK500v1 support, use the ATmega16 one - avr910_devcode = 0x74; - signature = 0x1e 0x94 0x0a; - pagel = 0xd7; - bs2 = 0xa0; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 512; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 128; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 16384; - page_size = 128; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 6; - blocksize = 128; - readsize = 256; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x 1 1 1 1 1 i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - - -#------------------------------------------------------------ -# ATmega324P -#------------------------------------------------------------ - -# similar to ATmega164P - -part - id = "m324p"; - desc = "ATMEGA324P"; - has_jtag = yes; - stk500_devcode = 0x82; # no STK500v1 support, use the ATmega16 one - avr910_devcode = 0x74; - signature = 0x1e 0x95 0x08; - pagel = 0xd7; - bs2 = 0xa0; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 1024; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 128; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 32768; - page_size = 128; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x 1 1 1 1 1 i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - - -#------------------------------------------------------------ -# ATmega644 -#------------------------------------------------------------ - -# similar to ATmega164 - -part - id = "m644"; - desc = "ATMEGA644"; - has_jtag = yes; - stk500_devcode = 0x82; # no STK500v1 support, use the ATmega16 one - avr910_devcode = 0x74; - signature = 0x1e 0x96 0x09; - pagel = 0xd7; - bs2 = 0xa0; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 2048; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 128; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 65536; - page_size = 256; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x 1 1 1 1 1 i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega644P -#------------------------------------------------------------ - -# similar to ATmega164p - -part - id = "m644p"; - desc = "ATMEGA644P"; - has_jtag = yes; - stk500_devcode = 0x82; # no STK500v1 support, use the ATmega16 one - avr910_devcode = 0x74; - signature = 0x1e 0x96 0x0a; - pagel = 0xd7; - bs2 = 0xa0; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 2048; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 128; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 65536; - page_size = 256; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x 1 1 1 1 1 i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - - - -#------------------------------------------------------------ -# ATmega1284P -#------------------------------------------------------------ - -# similar to ATmega164p - -part - id = "m1284p"; - desc = "ATMEGA1284P"; - has_jtag = yes; - stk500_devcode = 0x82; # no STK500v1 support, use the ATmega16 one - avr910_devcode = 0x74; - signature = 0x1e 0x97 0x05; - pagel = 0xd7; - bs2 = 0xa0; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 4096; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 128; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 131072; - page_size = 256; - num_pages = 512; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 256; - readsize = 256; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x 1 1 1 1 1 i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - - - -#------------------------------------------------------------ -# ATmega162 -#------------------------------------------------------------ - -part - id = "m162"; - desc = "ATMEGA162"; - has_jtag = yes; - stk500_devcode = 0x83; - avr910_devcode = 0x63; - signature = 0x1e 0x94 0x04; - chip_erase_delay = 9000; - pagel = 0xd7; - bs2 = 0xa0; - - idr = 0x04; - spmcr = 0x57; - allowfullpagebitstream = yes; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - memory "flash" - paged = yes; - size = 16384; - page_size = 128; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - mode = 0x41; - delay = 10; - blocksize = 128; - readsize = 256; - - ; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 512; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - - read = " 1 0 1 0 0 0 0 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 4; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 16000; - max_write_delay = 16000; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 16000; - max_write_delay = 16000; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - min_write_delay = 16000; - max_write_delay = 16000; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x 1 1 1 1 1 i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 16000; - max_write_delay = 16000; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "signature" - size = 3; - - read = "0 0 1 1 0 0 0 0 0 0 x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - - read = "0 0 1 1 1 0 0 0 0 0 x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; -; - - - -#------------------------------------------------------------ -# ATmega163 -#------------------------------------------------------------ - -part - id = "m163"; - desc = "ATMEGA163"; - stk500_devcode = 0x81; - avr910_devcode = 0x64; - signature = 0x1e 0x94 0x02; - chip_erase_delay = 32000; - pagel = 0xd7; - bs2 = 0xa0; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 0; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 30; - programfusepulsewidth = 0; - programfusepolltimeout = 2; - programlockpulsewidth = 0; - programlockpolltimeout = 2; - - - memory "eeprom" - size = 512; - min_write_delay = 4000; - max_write_delay = 4000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - mode = 0x41; - delay = 20; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 16384; - page_size = 128; - num_pages = 128; - min_write_delay = 16000; - max_write_delay = 16000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x11; - delay = 20; - blocksize = 128; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o x x o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i 1 1 i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x x x x x 1 o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x 1 1 1 1 1 i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x 0 x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega169 -#------------------------------------------------------------ - -part - id = "m169"; - desc = "ATMEGA169"; - has_jtag = yes; - stk500_devcode = 0x85; - avr910_devcode = 0x78; - signature = 0x1e 0x94 0x05; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 512; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 16384; - page_size = 128; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 128; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - ; - - memory "lock" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega329 -#------------------------------------------------------------ - -part - id = "m329"; - desc = "ATMEGA329"; - has_jtag = yes; -# stk500_devcode = 0x85; # no STK500 support, only STK500v2 -# avr910_devcode = 0x?; # try the ATmega169 one: - avr910_devcode = 0x75; - signature = 0x1e 0x95 0x03; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 1024; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 32768; - page_size = 128; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega329P -#------------------------------------------------------------ -# Identical to ATmega329 except of the signature - -part - id = "m329p"; - desc = "ATMEGA329P"; - has_jtag = yes; -# stk500_devcode = 0x85; # no STK500 support, only STK500v2 -# avr910_devcode = 0x?; # try the ATmega169 one: - avr910_devcode = 0x75; - signature = 0x1e 0x95 0x0b; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 1024; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 32768; - page_size = 128; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega3290 -#------------------------------------------------------------ - -# identical to ATmega329 - -part - id = "m3290"; - desc = "ATMEGA3290"; - has_jtag = yes; -# stk500_devcode = 0x85; # no STK500 support, only STK500v2 -# avr910_devcode = 0x?; # try the ATmega169 one: - avr910_devcode = 0x75; - signature = 0x1e 0x95 0x04; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 1024; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a3 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 32768; - page_size = 128; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega3290P -#------------------------------------------------------------ - -# identical to ATmega3290 except of the signature - -part - id = "m3290p"; - desc = "ATMEGA3290P"; - has_jtag = yes; -# stk500_devcode = 0x85; # no STK500 support, only STK500v2 -# avr910_devcode = 0x?; # try the ATmega169 one: - avr910_devcode = 0x75; - signature = 0x1e 0x95 0x0c; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 1024; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a3 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 32768; - page_size = 128; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega649 -#------------------------------------------------------------ - -part - id = "m649"; - desc = "ATMEGA649"; - has_jtag = yes; -# stk500_devcode = 0x85; # no STK500 support, only STK500v2 -# avr910_devcode = 0x?; # try the ATmega169 one: - avr910_devcode = 0x75; - signature = 0x1e 0x96 0x03; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 2048; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 65536; - page_size = 256; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega6490 -#------------------------------------------------------------ - -# identical to ATmega649 - -part - id = "m6490"; - desc = "ATMEGA6490"; - has_jtag = yes; -# stk500_devcode = 0x85; # no STK500 support, only STK500v2 -# avr910_devcode = 0x?; # try the ATmega169 one: - avr910_devcode = 0x75; - signature = 0x1e 0x96 0x04; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 2048; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 65536; - page_size = 256; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega32 -#------------------------------------------------------------ - -part - id = "m32"; - desc = "ATMEGA32"; - has_jtag = yes; - stk500_devcode = 0x91; - avr910_devcode = 0x72; - signature = 0x1e 0x95 0x02; - chip_erase_delay = 9000; - pagel = 0xd7; - bs2 = 0xa0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - allowfullpagebitstream = yes; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 1024; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x04; - delay = 10; - blocksize = 64; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 32768; - page_size = 128; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 6; - blocksize = 64; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 4; - read = "0 0 1 1 1 0 0 0 0 0 x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega161 -#------------------------------------------------------------ - -part - id = "m161"; - desc = "ATMEGA161"; - stk500_devcode = 0x80; - avr910_devcode = 0x60; - signature = 0x1e 0x94 0x01; - chip_erase_delay = 28000; - pagel = 0xd7; - bs2 = 0xa0; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 0; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 30; - programfusepulsewidth = 0; - programfusepolltimeout = 2; - programlockpulsewidth = 0; - programlockpolltimeout = 2; - - memory "eeprom" - size = 512; - min_write_delay = 3400; - max_write_delay = 3400; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 5; - blocksize = 128; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 16384; - page_size = 128; - num_pages = 128; - min_write_delay = 14000; - max_write_delay = 14000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 16; - blocksize = 128; - readsize = 256; - ; - - memory "fuse" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 0 0 0 0 x x x x x x x x", - "x x x x x x x x x o x o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 x x x x x", - "x x x x x x x x 1 i 1 i i i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - - -#------------------------------------------------------------ -# ATmega8 -#------------------------------------------------------------ - -part - id = "m8"; - desc = "ATMEGA8"; - stk500_devcode = 0x70; - avr910_devcode = 0x76; - signature = 0x1e 0x93 0x07; - pagel = 0xd7; - bs2 = 0xc2; - chip_erase_delay = 10000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 2; - resetdelayus = 0; - hvleavestabdelay = 15; - resetdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - size = 512; - page_size = 4; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 20; - blocksize = 128; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 8192; - page_size = 64; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 0 x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 0 x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 10; - blocksize = 64; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "calibration" - size = 4; - read = "0 0 1 1 1 0 0 0 0 0 x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - - - -#------------------------------------------------------------ -# ATmega8515 -#------------------------------------------------------------ - -part - id = "m8515"; - desc = "ATMEGA8515"; - stk500_devcode = 0x63; - avr910_devcode = 0x3A; - signature = 0x1e 0x93 0x06; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - size = 512; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 10; - blocksize = 128; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 8192; - page_size = 64; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 0 x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 0 x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 6; - blocksize = 64; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "calibration" - size = 4; - read = "0 0 1 1 1 0 0 0 0 0 x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - - - - -#------------------------------------------------------------ -# ATmega8535 -#------------------------------------------------------------ - -part - id = "m8535"; - desc = "ATMEGA8535"; - stk500_devcode = 0x64; - avr910_devcode = 0x69; - signature = 0x1e 0x93 0x08; - pagel = 0xd7; - bs2 = 0xa0; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 6; - togglevtg = 0; - poweroffdelay = 0; - resetdelayms = 0; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - size = 512; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - mode = 0x04; - delay = 10; - blocksize = 128; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 8192; - page_size = 64; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 0 x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 0 x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 6; - blocksize = 64; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 2000; - max_write_delay = 2000; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "calibration" - size = 4; - read = "0 0 1 1 1 0 0 0 0 0 x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - - -#------------------------------------------------------------ -# ATtiny26 -#------------------------------------------------------------ - -part - id = "t26"; - desc = "ATTINY26"; - stk500_devcode = 0x21; - avr910_devcode = 0x5e; - signature = 0x1e 0x91 0x09; - pagel = 0xb3; - bs2 = 0xb2; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0xC4, 0xE4, 0xC4, 0xE4, 0xCC, 0xEC, 0xCC, 0xEC, - 0xD4, 0xF4, 0xD4, 0xF4, 0xDC, 0xFC, 0xDC, 0xFC, - 0xC8, 0xE8, 0xD8, 0xF8, 0x4C, 0x6C, 0x5C, 0x7C, - 0xEC, 0xBC, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 2; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - size = 128; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 x x x x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 x x x x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - mode = 0x04; - delay = 10; - blocksize = 64; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 2048; - page_size = 32; - num_pages = 64; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 x x x x", - " x x x x x x x x"; - - mode = 0x21; - delay = 6; - blocksize = 16; - readsize = 256; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x x x x x x x o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 1 i i", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x x x x i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x x x x o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 4; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - -; - - -#------------------------------------------------------------ -# ATtiny261 -#------------------------------------------------------------ -# Close to ATtiny26 - -part - id = "t261"; - desc = "ATTINY261"; - has_debugwire = yes; - flash_instr = 0xB4, 0x00, 0x10; - eeprom_instr = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, - 0xBC, 0x00, 0xB4, 0x00, 0xBA, 0x0D, 0xBB, 0xBC, - 0x99, 0xE1, 0xBB, 0xAC; -# stk500_devcode = 0x21; -# avr910_devcode = 0x5e; - signature = 0x1e 0x91 0x0c; - pagel = 0xb3; - bs2 = 0xb2; - chip_erase_delay = 4000; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0xC4, 0xE4, 0xC4, 0xE4, 0xCC, 0xEC, 0xCC, 0xEC, - 0xD4, 0xF4, 0xD4, 0xF4, 0xDC, 0xFC, 0xDC, 0xFC, - 0xC8, 0xE8, 0xD8, 0xF8, 0x4C, 0x6C, 0x5C, 0x7C, - 0xEC, 0xBC, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 2; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - paged = no; - size = 128; - page_size = 4; - num_pages = 32; - min_write_delay = 4000; - max_write_delay = 4000; - readback_p1 = 0xff; - readback_p2 = 0xff; - - read = "1 0 1 0 0 0 0 0 x x x x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 x x x x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 2048; - page_size = 32; - num_pages = 64; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x x x x a9 a8", - " a7 a6 a5 a4 x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 32; - readsize = 256; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x x x x x x x o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 1 i i", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x x x x x x x x o"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - -; - - -#------------------------------------------------------------ -# ATtiny461 -#------------------------------------------------------------ -# Close to ATtiny261 - -part - id = "t461"; - desc = "ATTINY461"; - has_debugwire = yes; - flash_instr = 0xB4, 0x00, 0x10; - eeprom_instr = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, - 0xBC, 0x00, 0xB4, 0x00, 0xBA, 0x0D, 0xBB, 0xBC, - 0x99, 0xE1, 0xBB, 0xAC; -# stk500_devcode = 0x21; -# avr910_devcode = 0x5e; - signature = 0x1e 0x92 0x08; - pagel = 0xb3; - bs2 = 0xb2; - chip_erase_delay = 4000; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0xC4, 0xE4, 0xC4, 0xE4, 0xCC, 0xEC, 0xCC, 0xEC, - 0xD4, 0xF4, 0xD4, 0xF4, 0xDC, 0xFC, 0xDC, 0xFC, - 0xC8, 0xE8, 0xD8, 0xF8, 0x4C, 0x6C, 0x5C, 0x7C, - 0xEC, 0xBC, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 2; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - paged = no; - size = 256; - page_size = 4; - num_pages = 64; - min_write_delay = 4000; - max_write_delay = 4000; - readback_p1 = 0xff; - readback_p2 = 0xff; - - read = " 1 0 1 0 0 0 0 0 x x x x x x x x", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0 x x x x x x x x", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 4096; - page_size = 64; - num_pages = 64; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 64; - readsize = 256; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x x x x x x x o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 1 i i", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x x x x x x x x o"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - -; - - -#------------------------------------------------------------ -# ATtiny861 -#------------------------------------------------------------ -# Close to ATtiny461 - -part - id = "t861"; - desc = "ATTINY861"; - has_debugwire = yes; - flash_instr = 0xB4, 0x00, 0x10; - eeprom_instr = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, - 0xBC, 0x00, 0xB4, 0x00, 0xBA, 0x0D, 0xBB, 0xBC, - 0x99, 0xE1, 0xBB, 0xAC; -# stk500_devcode = 0x21; -# avr910_devcode = 0x5e; - signature = 0x1e 0x93 0x0d; - pagel = 0xb3; - bs2 = 0xb2; - chip_erase_delay = 4000; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 0; - - pp_controlstack = - 0xC4, 0xE4, 0xC4, 0xE4, 0xCC, 0xEC, 0xCC, 0xEC, - 0xD4, 0xF4, 0xD4, 0xF4, 0xDC, 0xFC, 0xDC, 0xFC, - 0xC8, 0xE8, 0xD8, 0xF8, 0x4C, 0x6C, 0x5C, 0x7C, - 0xEC, 0xBC, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 2; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - paged = no; - size = 512; - num_pages = 128; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4000; - readback_p1 = 0xff; - readback_p2 = 0xff; - - read = " 1 0 1 0 0 0 0 0 x x x x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0 x x x x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 8192; - page_size = 64; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - - read_lo = " 0 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 64; - readsize = 256; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 x x x x x x x x", - "x x x x x x x x x x x x x x o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 1 1 1 i i", - "x x x x x x x x x x x x x x x x"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x x x x x x x x o"; - min_write_delay = 4500; - max_write_delay = 4500; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - -; - - -#------------------------------------------------------------ -# ATmega48 -#------------------------------------------------------------ - -part - id = "m48"; - desc = "ATMEGA48"; - has_debugwire = yes; - flash_instr = 0xB6, 0x01, 0x11; - eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00, - 0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF, - 0x99, 0xF9, 0xBB, 0xAF; - stk500_devcode = 0x59; -# avr910_devcode = 0x; - signature = 0x1e 0x92 0x05; - pagel = 0xd7; - bs2 = 0xc2; - chip_erase_delay = 45000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - resetdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - paged = no; - page_size = 4; - size = 256; - min_write_delay = 3600; - max_write_delay = 3600; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 x x x x x", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 5; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 4096; - page_size = 64; - num_pages = 64; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 64; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x x x x x x x x o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - - -#------------------------------------------------------------ -# ATmega88 -#------------------------------------------------------------ - -part - id = "m88"; - desc = "ATMEGA88"; - has_debugwire = yes; - flash_instr = 0xB6, 0x01, 0x11; - eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00, - 0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF, - 0x99, 0xF9, 0xBB, 0xAF; - stk500_devcode = 0x73; -# avr910_devcode = 0x; - signature = 0x1e 0x93 0x0a; - pagel = 0xd7; - bs2 = 0xc2; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - resetdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - paged = no; - page_size = 4; - size = 512; - min_write_delay = 3600; - max_write_delay = 3600; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 5; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 8192; - page_size = 64; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 64; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x x x x x x o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega168 -#------------------------------------------------------------ - -part - id = "m168"; - desc = "ATMEGA168"; - has_debugwire = yes; - flash_instr = 0xB6, 0x01, 0x11; - eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00, - 0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF, - 0x99, 0xF9, 0xBB, 0xAF; - stk500_devcode = 0x86; - # avr910_devcode = 0x; - signature = 0x1e 0x94 0x06; - pagel = 0xd7; - bs2 = 0xc2; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - resetdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - paged = no; - page_size = 4; - size = 512; - min_write_delay = 3600; - max_write_delay = 3600; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 x x x x a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 5; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 16384; - page_size = 128; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 128; - readsize = 256; - - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x x x x x x o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; -; - -#------------------------------------------------------------ -# ATtiny88 -#------------------------------------------------------------ - -part - id = "t88"; - desc = "attiny88"; - has_debugwire = yes; - flash_instr = 0xB6, 0x01, 0x11; - eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00, - 0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF, - 0x99, 0xF9, 0xBB, 0xAF; - stk500_devcode = 0x73; -# avr910_devcode = 0x; - signature = 0x1e 0x93 0x11; - pagel = 0xd7; - bs2 = 0xc2; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - resetdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - paged = no; - page_size = 4; - size = 64; - min_write_delay = 3600; - max_write_delay = 3600; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 5; - blocksize = 4; - readsize = 64; - ; - memory "flash" - paged = yes; - size = 8192; - page_size = 64; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 64; - readsize = 256; - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x x x x x x o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega328P -#------------------------------------------------------------ - -part - id = "m328p"; - desc = "ATMEGA328P"; - has_debugwire = yes; - flash_instr = 0xB6, 0x01, 0x11; - eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00, - 0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF, - 0x99, 0xF9, 0xBB, 0xAF; - stk500_devcode = 0x86; - # avr910_devcode = 0x; - signature = 0x1e 0x95 0x0F; - pagel = 0xd7; - bs2 = 0xc2; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - resetdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - paged = no; - page_size = 4; - size = 1024; - min_write_delay = 3600; - max_write_delay = 3600; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 x x x a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 5; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 32768; - page_size = 128; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 a13 a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 128; - readsize = 256; - - ; - - memory "lfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "hfuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - ; - - memory "efuse" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x x x x x x o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - ; - - memory "lock" - size = 1; - min_write_delay = 4500; - max_write_delay = 4500; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; -; - -#------------------------------------------------------------ -# ATtiny2313 -#------------------------------------------------------------ - -part - id = "t2313"; - desc = "ATtiny2313"; - has_debugwire = yes; - flash_instr = 0xB2, 0x0F, 0x1F; - eeprom_instr = 0xBB, 0xFE, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, - 0xBA, 0x0F, 0xB2, 0x0F, 0xBA, 0x0D, 0xBB, 0xBC, - 0x99, 0xE1, 0xBB, 0xAC; - stk500_devcode = 0x23; -## Use the ATtiny26 devcode: - avr910_devcode = 0x5e; - signature = 0x1e 0x91 0x0a; - pagel = 0xD4; - bs2 = 0xD6; - reset = io; - chip_erase_delay = 9000; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0E, 0x1E, 0x2E, 0x3E, 0x2E, 0x3E, - 0x4E, 0x5E, 0x4E, 0x5E, 0x6E, 0x7E, 0x6E, 0x7E, - 0x26, 0x36, 0x66, 0x76, 0x2A, 0x3A, 0x6A, 0x7A, - 0x2E, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - size = 128; - paged = no; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 2048; - page_size = 32; - num_pages = 64; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - -# The information in the data sheet of April/2004 is wrong, this works: - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - -# The information in the data sheet of April/2004 is wrong, this works: - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - -# The information in the data sheet of April/2004 is wrong, this works: - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 32; - readsize = 256; - ; -# ATtiny2313 has Signature Bytes: 0x1E 0x91 0x0A. - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; -# The Tiny2313 has calibration data for both 4 MHz and 8 MHz. -# The information in the data sheet of April/2004 is wrong, this works: - - memory "calibration" - size = 2; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# AT90PWM2 -#------------------------------------------------------------ - -part - id = "pwm2"; - desc = "AT90PWM2"; - has_debugwire = yes; - flash_instr = 0xB6, 0x01, 0x11; - eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00, - 0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF, - 0x99, 0xF9, 0xBB, 0xAF; - stk500_devcode = 0x65; -## avr910_devcode = ?; - signature = 0x1e 0x93 0x81; - pagel = 0xD8; - bs2 = 0xE2; - reset = io; - chip_erase_delay = 9000; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - size = 512; - paged = no; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 8192; - page_size = 64; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 64; - readsize = 256; - ; -# AT90PWM2 has Signature Bytes: 0x1E 0x93 0x81. - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# AT90PWM3 -#------------------------------------------------------------ - -# Completely identical to AT90PWM2 (including the signature!) - -part - id = "pwm3"; - desc = "AT90PWM3"; - has_debugwire = yes; - flash_instr = 0xB6, 0x01, 0x11; - eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00, - 0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF, - 0x99, 0xF9, 0xBB, 0xAF; - stk500_devcode = 0x65; -## avr910_devcode = ?; - signature = 0x1e 0x93 0x81; - pagel = 0xD8; - bs2 = 0xE2; - reset = io; - chip_erase_delay = 9000; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - size = 512; - paged = no; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 8192; - page_size = 64; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 64; - readsize = 256; - ; -# AT90PWM2 has Signature Bytes: 0x1E 0x93 0x81. - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# AT90PWM2B -#------------------------------------------------------------ -# Same as AT90PWM2 but different signature. - -part - id = "pwm2b"; - desc = "AT90PWM2B"; - has_debugwire = yes; - flash_instr = 0xB6, 0x01, 0x11; - eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00, - 0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF, - 0x99, 0xF9, 0xBB, 0xAF; - stk500_devcode = 0x65; -## avr910_devcode = ?; - signature = 0x1e 0x93 0x83; - pagel = 0xD8; - bs2 = 0xE2; - reset = io; - chip_erase_delay = 9000; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - size = 512; - paged = no; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 8192; - page_size = 64; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 64; - readsize = 256; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# AT90PWM3B -#------------------------------------------------------------ - -# Completely identical to AT90PWM2B (including the signature!) - -part - id = "pwm3b"; - desc = "AT90PWM3B"; - has_debugwire = yes; - flash_instr = 0xB6, 0x01, 0x11; - eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00, - 0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF, - 0x99, 0xF9, 0xBB, 0xAF; - stk500_devcode = 0x65; -## avr910_devcode = ?; - signature = 0x1e 0x93 0x83; - pagel = 0xD8; - bs2 = 0xE2; - reset = io; - chip_erase_delay = 9000; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - size = 512; - paged = no; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 8192; - page_size = 64; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 64; - readsize = 256; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATtiny25 -#------------------------------------------------------------ - -part - id = "t25"; - desc = "ATtiny25"; - has_debugwire = yes; - flash_instr = 0xB4, 0x02, 0x12; - eeprom_instr = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, - 0xBC, 0x02, 0xB4, 0x02, 0xBA, 0x0D, 0xBB, 0xBC, - 0x99, 0xE1, 0xBB, 0xAC; -## no STK500 devcode in XML file, use the ATtiny45 one - stk500_devcode = 0x14; -## avr910_devcode = ?; -## Try the AT90S2313 devcode: - avr910_devcode = 0x20; - signature = 0x1e 0x91 0x08; - reset = io; - chip_erase_delay = 4500; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - hvsp_controlstack = - 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x66, - 0x68, 0x78, 0x68, 0x68, 0x7A, 0x6A, 0x68, 0x78, - 0x78, 0x7D, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, - 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00; - hventerstabdelay = 100; - hvspcmdexedelay = 0; - synchcycles = 6; - latchcycles = 1; - togglevtg = 1; - poweroffdelay = 25; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 100; - resetdelay = 25; - chiperasepolltimeout = 40; - chiperasetime = 0; - programfusepolltimeout = 25; - programlockpolltimeout = 25; - - memory "eeprom" - size = 128; - paged = no; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 2048; - page_size = 32; - num_pages = 64; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 32; - readsize = 256; - ; -# ATtiny25 has Signature Bytes: 0x1E 0x91 0x08. - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 2; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATtiny45 -#------------------------------------------------------------ - -part - id = "t45"; - desc = "ATtiny45"; - has_debugwire = yes; - flash_instr = 0xB4, 0x02, 0x12; - eeprom_instr = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, - 0xBC, 0x02, 0xB4, 0x02, 0xBA, 0x0D, 0xBB, 0xBC, - 0x99, 0xE1, 0xBB, 0xAC; - stk500_devcode = 0x14; -## avr910_devcode = ?; -## Try the AT90S2313 devcode: - avr910_devcode = 0x20; - signature = 0x1e 0x92 0x06; - reset = io; - chip_erase_delay = 4500; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - hvsp_controlstack = - 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x66, - 0x68, 0x78, 0x68, 0x68, 0x7A, 0x6A, 0x68, 0x78, - 0x78, 0x7D, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, - 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - hvspcmdexedelay = 0; - synchcycles = 6; - latchcycles = 1; - togglevtg = 1; - poweroffdelay = 25; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 100; - resetdelay = 25; - chiperasepolltimeout = 40; - chiperasetime = 0; - programfusepolltimeout = 25; - programlockpolltimeout = 25; - - memory "eeprom" - size = 256; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x x", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x x", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 4096; - page_size = 64; - num_pages = 64; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 32; - readsize = 256; - ; -# ATtiny45 has Signature Bytes: 0x1E 0x92 0x08. (Data sheet 2586C-AVR-06/05 (doc2586.pdf) indicates otherwise!) - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 2; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATtiny85 -#------------------------------------------------------------ - -part - id = "t85"; - desc = "ATtiny85"; - has_debugwire = yes; - flash_instr = 0xB4, 0x02, 0x12; - eeprom_instr = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, - 0xBC, 0x02, 0xB4, 0x02, 0xBA, 0x0D, 0xBB, 0xBC, - 0x99, 0xE1, 0xBB, 0xAC; -## no STK500 devcode in XML file, use the ATtiny45 one - stk500_devcode = 0x14; -## avr910_devcode = ?; -## Try the AT90S2313 devcode: - avr910_devcode = 0x20; - signature = 0x1e 0x93 0x0b; - reset = io; - chip_erase_delay = 4500; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - hvsp_controlstack = - 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x66, - 0x68, 0x78, 0x68, 0x68, 0x7A, 0x6A, 0x68, 0x78, - 0x78, 0x7D, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, - 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00; - hventerstabdelay = 100; - hvspcmdexedelay = 0; - synchcycles = 6; - latchcycles = 1; - togglevtg = 1; - poweroffdelay = 25; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 100; - resetdelay = 25; - chiperasepolltimeout = 40; - chiperasetime = 0; - programfusepolltimeout = 25; - programlockpolltimeout = 25; - - memory "eeprom" - size = 512; - paged = no; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x a8", - "a8 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 8192; - page_size = 64; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 32; - readsize = 256; - ; -# ATtiny85 has Signature Bytes: 0x1E 0x93 0x08. - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 2; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega640 -#------------------------------------------------------------ -# Almost same as ATmega1280, except for different memory sizes - -part - id = "m640"; - desc = "ATMEGA640"; - signature = 0x1e 0x96 0x08; - has_jtag = yes; -# stk500_devcode = 0xB2; -# avr910_devcode = 0x43; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 4096; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 65536; - page_size = 256; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega1280 -#------------------------------------------------------------ - -part - id = "m1280"; - desc = "ATMEGA1280"; - signature = 0x1e 0x97 0x03; - has_jtag = yes; -# stk500_devcode = 0xB2; -# avr910_devcode = 0x43; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 4096; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 131072; - page_size = 256; - num_pages = 512; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega1281 -#------------------------------------------------------------ -# Identical to ATmega1280 - -part - id = "m1281"; - desc = "ATMEGA1281"; - signature = 0x1e 0x97 0x04; - has_jtag = yes; -# stk500_devcode = 0xB2; -# avr910_devcode = 0x43; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 4096; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 131072; - page_size = 256; - num_pages = 512; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega2560 -#------------------------------------------------------------ - -part - id = "m2560"; - desc = "ATMEGA2560"; - signature = 0x1e 0x98 0x01; - has_jtag = yes; -# stk500_devcode = 0xB2; -# avr910_devcode = 0x43; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 4096; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 262144; - page_size = 256; - num_pages = 1024; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - load_ext_addr = " 0 1 0 0 1 1 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 0 a16", - " 0 0 0 0 0 0 0 0"; - - mode = 0x41; - delay = 10; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega2561 -#------------------------------------------------------------ - -part - id = "m2561"; - desc = "ATMEGA2561"; - signature = 0x1e 0x98 0x02; - has_jtag = yes; -# stk500_devcode = 0xB2; -# avr910_devcode = 0x43; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 4096; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 262144; - page_size = 256; - num_pages = 1024; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - load_ext_addr = " 0 1 0 0 1 1 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 0 a16", - " 0 0 0 0 0 0 0 0"; - - mode = 0x41; - delay = 10; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega128RFA1 -#------------------------------------------------------------ -# Identical to ATmega2561 but half the ROM - -part - id = "m128rfa1"; - desc = "ATMEGA128RFA1"; - signature = 0x1e 0xa7 0x01; - has_jtag = yes; -# stk500_devcode = 0xB2; -# avr910_devcode = 0x43; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xE2; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 4096; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 131072; - page_size = 256; - num_pages = 512; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATtiny24 -#------------------------------------------------------------ - -part - id = "t24"; - desc = "ATtiny24"; - has_debugwire = yes; - flash_instr = 0xB4, 0x07, 0x17; - eeprom_instr = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, - 0xBC, 0x07, 0xB4, 0x07, 0xBA, 0x0D, 0xBB, 0xBC, - 0x99, 0xE1, 0xBB, 0xAC; -## no STK500 devcode in XML file, use the ATtiny45 one - stk500_devcode = 0x14; -## avr910_devcode = ?; -## Try the AT90S2313 devcode: - avr910_devcode = 0x20; - signature = 0x1e 0x91 0x0b; - reset = io; - chip_erase_delay = 4500; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - hvsp_controlstack = - 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x66, - 0x68, 0x78, 0x68, 0x68, 0x7A, 0x6A, 0x68, 0x78, - 0x78, 0x7D, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, - 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x0F; - hventerstabdelay = 100; - hvspcmdexedelay = 0; - synchcycles = 6; - latchcycles = 1; - togglevtg = 1; - poweroffdelay = 25; - resetdelayms = 0; - resetdelayus = 70; - hvleavestabdelay = 100; - resetdelay = 25; - chiperasepolltimeout = 40; - chiperasetime = 0; - programfusepolltimeout = 25; - programlockpolltimeout = 25; - - memory "eeprom" - size = 128; - paged = no; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x x", - "x a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 2048; - page_size = 32; - num_pages = 64; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x x a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 32; - readsize = 256; - ; -# ATtiny24 has Signature Bytes: 0x1E 0x91 0x0B. - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x x x x x x x i i"; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATtiny44 -#------------------------------------------------------------ - -part - id = "t44"; - desc = "ATtiny44"; - has_debugwire = yes; - flash_instr = 0xB4, 0x07, 0x17; - eeprom_instr = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, - 0xBC, 0x07, 0xB4, 0x07, 0xBA, 0x0D, 0xBB, 0xBC, - 0x99, 0xE1, 0xBB, 0xAC; -## no STK500 devcode in XML file, use the ATtiny45 one - stk500_devcode = 0x14; -## avr910_devcode = ?; -## Try the AT90S2313 devcode: - avr910_devcode = 0x20; - signature = 0x1e 0x92 0x07; - reset = io; - chip_erase_delay = 4500; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - hvsp_controlstack = - 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x66, - 0x68, 0x78, 0x68, 0x68, 0x7A, 0x6A, 0x68, 0x78, - 0x78, 0x7D, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, - 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x0F; - hventerstabdelay = 100; - hvspcmdexedelay = 0; - synchcycles = 6; - latchcycles = 1; - togglevtg = 1; - poweroffdelay = 25; - resetdelayms = 0; - resetdelayus = 70; - hvleavestabdelay = 100; - resetdelay = 25; - chiperasepolltimeout = 40; - chiperasetime = 0; - programfusepolltimeout = 25; - programlockpolltimeout = 25; - - memory "eeprom" - size = 256; - paged = no; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x x", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x x", - "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 4096; - page_size = 64; - num_pages = 64; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 32; - readsize = 256; - ; -# ATtiny44 has Signature Bytes: 0x1E 0x92 0x07. - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x x x x x x x i i"; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATtiny84 -#------------------------------------------------------------ - -part - id = "t84"; - desc = "ATtiny84"; - has_debugwire = yes; - flash_instr = 0xB4, 0x07, 0x17; - eeprom_instr = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, - 0xBC, 0x07, 0xB4, 0x07, 0xBA, 0x0D, 0xBB, 0xBC, - 0x99, 0xE1, 0xBB, 0xAC; -## no STK500 devcode in XML file, use the ATtiny45 one - stk500_devcode = 0x14; -## avr910_devcode = ?; -## Try the AT90S2313 devcode: - avr910_devcode = 0x20; - signature = 0x1e 0x93 0x0c; - reset = io; - chip_erase_delay = 4500; - - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - hvsp_controlstack = - 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x66, - 0x68, 0x78, 0x68, 0x68, 0x7A, 0x6A, 0x68, 0x78, - 0x78, 0x7D, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, - 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x0F; - hventerstabdelay = 100; - hvspcmdexedelay = 0; - synchcycles = 6; - latchcycles = 1; - togglevtg = 1; - poweroffdelay = 25; - resetdelayms = 0; - resetdelayus = 70; - hvleavestabdelay = 100; - resetdelay = 25; - chiperasepolltimeout = 40; - chiperasetime = 0; - programfusepolltimeout = 25; - programlockpolltimeout = 25; - - memory "eeprom" - size = 512; - paged = no; - page_size = 4; - min_write_delay = 4000; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = "1 0 1 0 0 0 0 0 0 0 0 x x x x a8", - "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; - - write = "1 1 0 0 0 0 0 0 0 0 0 x x x x a8", - "a8 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x x x x", - " x a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 4; - readsize = 256; - ; - memory "flash" - paged = yes; - size = 8192; - page_size = 64; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 x x x x x", - " x x x a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 32; - readsize = 256; - ; -# ATtiny84 has Signature Bytes: 0x1E 0x93 0x0C. - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - - memory "lock" - size = 1; - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x x x x x x x i i"; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x x x x i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega32u4 -#------------------------------------------------------------ - -part - id = "m32u4"; - desc = "ATmega32U4"; - signature = 0x1e 0x95 0x87; - has_jtag = yes; -# stk500_devcode = 0xB2; -# avr910_devcode = 0x43; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 1024; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 32768; - page_size = 128; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 128; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# AT90USB646 -#------------------------------------------------------------ - -part - id = "usb646"; - desc = "AT90USB646"; - signature = 0x1e 0x96 0x82; - has_jtag = yes; -# stk500_devcode = 0xB2; -# avr910_devcode = 0x43; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 2048; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 65536; - page_size = 256; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# AT90USB647 -#------------------------------------------------------------ -# identical to AT90USB646 - -part - id = "usb647"; - desc = "AT90USB647"; - signature = 0x1e 0x96 0x82; - has_jtag = yes; -# stk500_devcode = 0xB2; -# avr910_devcode = 0x43; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 2048; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x x a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 65536; - page_size = 256; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# AT90USB1286 -#------------------------------------------------------------ - -part - id = "usb1286"; - desc = "AT90USB1286"; - signature = 0x1e 0x97 0x82; - has_jtag = yes; -# stk500_devcode = 0xB2; -# avr910_devcode = 0x43; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 4096; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 131072; - page_size = 256; - num_pages = 512; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# AT90USB1287 -#------------------------------------------------------------ -# identical to AT90USB1286 - -part - id = "usb1287"; - desc = "AT90USB1287"; - signature = 0x1e 0x97 0x82; - has_jtag = yes; -# stk500_devcode = 0xB2; -# avr910_devcode = 0x43; - chip_erase_delay = 9000; - pagel = 0xD7; - bs2 = 0xA0; - reset = dedicated; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "x x x x x x x x x x x x x x x x"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - rampz = 0x3b; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 4096; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " x x x x a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 x x x a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 131072; - page_size = 256; - num_pages = 512; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 x x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 256; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x x x x x i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 x x x x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 x x x x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - - -#------------------------------------------------------------ -# AT90USB162 -#------------------------------------------------------------ - -part - id = "usb162"; - desc = "AT90USB162"; - has_jtag = no; - has_debugwire = yes; - signature = 0x1e 0x94 0x82; - chip_erase_delay = 9000; - reset = io; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - pagel = 0xD7; - bs2 = 0xC6; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 512; - num_pages = 128; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 16384; - page_size = 128; - num_pages = 128; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 128; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# AT90USB82 -#------------------------------------------------------------ -# Changes against AT90USB162 (beside IDs) -# memory "flash" -# size = 8192; -# num_pages = 64; - -part - id = "usb82"; - desc = "AT90USB82"; - has_jtag = no; - has_debugwire = yes; - signature = 0x1e 0x93 0x82; - chip_erase_delay = 9000; - reset = io; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "x x x x x x x x x x x x x x x x"; - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", - "x x x x x x x x x x x x x x x x"; - pagel = 0xD7; - bs2 = 0xC6; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 512; - num_pages = 128; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0x00; - readback_p2 = 0x00; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 0 0 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 20; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 8192; - page_size = 128; - num_pages = 64; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0x00; - readback_p2 = 0x00; - read_lo = " 0 0 1 0 0 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " x x x x x x x x", - " x x a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - "a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 x x x x x x", - " x x x x x x x x"; - - mode = 0x41; - delay = 6; - blocksize = 128; - readsize = 256; - ; - - memory "lfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "x x x x x x x x i i i i i i i i"; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "x x x x x x x x o o o o o o o o"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", - "x x x x x x x x 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "calibration" - size = 1; - read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", - "x x x x x x a1 a0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega325 -#------------------------------------------------------------ - -part - id = "m325"; - desc = "ATMEGA325"; - signature = 0x1e 0x95 0x05; - has_jtag = yes; -# stk500_devcode = 0x??; # No STK500v1 support? -# avr910_devcode = 0x??; # Try the ATmega16 one - avr910_devcode = 0x74; - pagel = 0xd7; - bs2 = 0xa0; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 1024; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 32768; - page_size = 128; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 0 0 0 0 0", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 0 0 0 0 0", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 128; - readsize = 256; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 0 0 0 0 0", - "0 0 0 0 0 0 0 0 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "0 0 0 0 0 0 0 0 i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "0 0 0 0 0 0 0 0 i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "0 0 0 0 0 0 0 0 1 1 1 1 1 i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - - read = "0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega645 -#------------------------------------------------------------ - -part - id = "m645"; - desc = "ATMEGA645"; - signature = 0x1E 0x96 0x05; - has_jtag = yes; -# stk500_devcode = 0x??; # No STK500v1 support? -# avr910_devcode = 0x??; # Try the ATmega16 one - avr910_devcode = 0x74; - pagel = 0xd7; - bs2 = 0xa0; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 2048; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 8; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 65536; - page_size = 256; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 0 0 0 0 0", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 0 0 0 0 0", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " 0 0 0 0 0 0 0 0"; - - mode = 0x41; - delay = 10; - blocksize = 128; - readsize = 256; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 0 0 0 0 0", - "0 0 0 0 0 0 0 0 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "0 0 0 0 0 0 0 0 i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "0 0 0 0 0 0 0 0 i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "0 0 0 0 0 0 0 0 1 1 1 1 1 i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - - read = "0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega3250 -#------------------------------------------------------------ - -part - id = "m3250"; - desc = "ATMEGA3250"; - signature = 0x1E 0x95 0x06; - has_jtag = yes; -# stk500_devcode = 0x??; # No STK500v1 support? -# avr910_devcode = 0x??; # Try the ATmega16 one - avr910_devcode = 0x74; - pagel = 0xd7; - bs2 = 0xa0; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 4; /* for parallel programming */ - size = 1024; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 0 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 0 0 0 0 a9 a8", - " a7 a6 a5 a4 a3 a2 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 32768; - page_size = 128; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 0 0 0 0 0", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 0 0 0 0 0", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " 0 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 128; - readsize = 256; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 0 0 0 0 0", - "0 0 0 0 0 0 0 0 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "0 0 0 0 0 0 0 0 i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "0 0 0 0 0 0 0 0 i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "0 0 0 0 0 0 0 0 1 1 1 1 1 i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - - read = "0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATmega6450 -#------------------------------------------------------------ - -part - id = "m6450"; - desc = "ATMEGA6450"; - signature = 0x1E 0x96 0x06; - has_jtag = yes; -# stk500_devcode = 0x??; # No STK500v1 support? -# avr910_devcode = 0x??; # Try the ATmega16 one - avr910_devcode = 0x74; - pagel = 0xd7; - bs2 = 0xa0; - chip_erase_delay = 9000; - pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", - "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; - - chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; - - timeout = 200; - stabdelay = 100; - cmdexedelay = 25; - synchloops = 32; - bytedelay = 0; - pollindex = 3; - pollvalue = 0x53; - predelay = 1; - postdelay = 1; - pollmethod = 1; - - pp_controlstack = - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, - 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; - hventerstabdelay = 100; - progmodedelay = 0; - latchcycles = 5; - togglevtg = 1; - poweroffdelay = 15; - resetdelayms = 1; - resetdelayus = 0; - hvleavestabdelay = 15; - chiperasepulsewidth = 0; - chiperasepolltimeout = 10; - programfusepulsewidth = 0; - programfusepolltimeout = 5; - programlockpulsewidth = 0; - programlockpolltimeout = 5; - - idr = 0x31; - spmcr = 0x57; - allowfullpagebitstream = no; - - memory "eeprom" - paged = no; /* leave this "no" */ - page_size = 8; /* for parallel programming */ - size = 2048; - min_write_delay = 9000; - max_write_delay = 9000; - readback_p1 = 0xff; - readback_p2 = 0xff; - read = " 1 0 1 0 0 0 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - write = " 1 1 0 0 0 0 0 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_lo = " 1 1 0 0 0 0 0 1", - " 0 0 0 0 0 0 0 0", - " 0 0 0 0 0 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 1 1 0 0 0 0 1 0", - " 0 0 0 0 0 a10 a9 a8", - " a7 a6 a5 a4 a3 0 0 0", - " x x x x x x x x"; - - mode = 0x41; - delay = 10; - blocksize = 4; - readsize = 256; - ; - - memory "flash" - paged = yes; - size = 65536; - page_size = 256; - num_pages = 256; - min_write_delay = 4500; - max_write_delay = 4500; - readback_p1 = 0xff; - readback_p2 = 0xff; - read_lo = " 0 0 1 0 0 0 0 0", - " a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - read_hi = " 0 0 1 0 1 0 0 0", - " a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " o o o o o o o o"; - - loadpage_lo = " 0 1 0 0 0 0 0 0", - " 0 0 0 0 0 0 0 0", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - loadpage_hi = " 0 1 0 0 1 0 0 0", - " 0 0 0 0 0 0 0 0", - " a7 a6 a5 a4 a3 a2 a1 a0", - " i i i i i i i i"; - - writepage = " 0 1 0 0 1 1 0 0", - " a15 a14 a13 a12 a11 a10 a9 a8", - " a7 a6 a5 a4 a3 a2 a1 a0", - " 0 0 0 0 0 0 0 0"; - - mode = 0x41; - delay = 10; - blocksize = 128; - readsize = 256; - ; - - memory "lock" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", - "x x x x x x x x x x o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 1 1 0 0 0 0 0", - "0 0 0 0 0 0 0 0 1 1 i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "lfuse" - size = 1; - read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", - "0 0 0 0 0 0 0 0 i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "hfuse" - size = 1; - read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", - "0 0 0 0 0 0 0 0 i i i i i i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "efuse" - size = 1; - - read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - - write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", - "0 0 0 0 0 0 0 0 1 1 1 1 1 i i i"; - min_write_delay = 9000; - max_write_delay = 9000; - ; - - memory "signature" - size = 3; - read = "0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 a1 a0 o o o o o o o o"; - ; - - memory "calibration" - size = 1; - - read = "0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0", - "0 0 0 0 0 0 0 0 o o o o o o o o"; - ; - ; - -#------------------------------------------------------------ -# ATXMEGA64A1 -#------------------------------------------------------------ - -part - id = "x64a1"; - desc = "ATXMEGA64A1"; - signature = 0x1e 0x96 0x4e; - has_jtag = yes; - has_pdi = yes; - nvm_base = 0x01c0; - - memory "eeprom" - size = 0x0800; - offset = 0x08c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x00010000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x00001000; - offset = 0x0080f000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x00001000; - offset = 0x00810000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x00011000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "prodsig" - size = 0x200; - offset = 0x8e0200; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; - - memory "signature" - size = 3; - offset = 0x1000090; - ; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; - - memory "fuse1" - size = 1; - offset = 0x8f0021; - ; - - memory "fuse2" - size = 1; - offset = 0x8f0022; - ; - - memory "fuse4" - size = 1; - offset = 0x8f0024; - ; - - memory "fuse5" - size = 1; - offset = 0x8f0025; - ; - - memory "lock" - size = 1; - offset = 0x8f0027; - ; -; - -#------------------------------------------------------------ -# ATXMEGA128A1 -#------------------------------------------------------------ - -part - id = "x128a1"; - desc = "ATXMEGA128A1"; - signature = 0x1e 0x97 0x4c; - has_jtag = yes; - has_pdi = yes; - nvm_base = 0x01c0; - - memory "eeprom" - size = 0x0800; - offset = 0x08c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x00020000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x00002000; - offset = 0x0081e000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x00002000; - offset = 0x00820000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x00022000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "prodsig" - size = 0x200; - offset = 0x8e0200; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; - - memory "signature" - size = 3; - offset = 0x1000090; - ; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; - - memory "fuse1" - size = 1; - offset = 0x8f0021; - ; - - memory "fuse2" - size = 1; - offset = 0x8f0022; - ; - - memory "fuse4" - size = 1; - offset = 0x8f0024; - ; - - memory "fuse5" - size = 1; - offset = 0x8f0025; - ; - - memory "lock" - size = 1; - offset = 0x8f0027; - ; -; - -#------------------------------------------------------------ -# ATXMEGA128A1REVD -#------------------------------------------------------------ - -part - id = "x128a1d"; - desc = "ATXMEGA128A1REVD"; - signature = 0x1e 0x97 0x41; - has_jtag = yes; - has_pdi = yes; - nvm_base = 0x01c0; - - memory "eeprom" - size = 0x0800; - offset = 0x08c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x00020000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x00002000; - offset = 0x0081e000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x00002000; - offset = 0x00820000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x00022000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "prodsig" - size = 0x200; - offset = 0x8e0200; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; - - memory "signature" - size = 3; - offset = 0x1000090; - ; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; - - memory "fuse1" - size = 1; - offset = 0x8f0021; - ; - - memory "fuse2" - size = 1; - offset = 0x8f0022; - ; - - memory "fuse4" - size = 1; - offset = 0x8f0024; - ; - - memory "fuse5" - size = 1; - offset = 0x8f0025; - ; - - memory "lock" - size = 1; - offset = 0x8f0027; - ; -; - -#------------------------------------------------------------ -# ATXMEGA192A1 -#------------------------------------------------------------ - -part - id = "x192a1"; - desc = "ATXMEGA192A1"; - signature = 0x1e 0x97 0x4e; - has_jtag = yes; - has_pdi = yes; - nvm_base = 0x01c0; - - memory "eeprom" - size = 0x0800; - offset = 0x08c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x00030000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x00002000; - offset = 0x0082e000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x00002000; - offset = 0x00830000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x00032000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "prodsig" - size = 0x200; - offset = 0x8e0200; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; - - memory "signature" - size = 3; - offset = 0x1000090; - ; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; - - memory "fuse1" - size = 1; - offset = 0x8f0021; - ; - - memory "fuse2" - size = 1; - offset = 0x8f0022; - ; - - memory "fuse4" - size = 1; - offset = 0x8f0024; - ; - - memory "fuse5" - size = 1; - offset = 0x8f0025; - ; - - memory "lock" - size = 1; - offset = 0x8f0027; - ; -; - -#------------------------------------------------------------ -# ATXMEGA256A1 -#------------------------------------------------------------ - -part - id = "x256a1"; - desc = "ATXMEGA256A1"; - signature = 0x1e 0x98 0x46; - has_jtag = yes; - has_pdi = yes; - nvm_base = 0x01c0; - - memory "eeprom" - size = 0x1000; - offset = 0x08c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x00040000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x00002000; - offset = 0x0083e000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x00002000; - offset = 0x00840000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x00042000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "prodsig" - size = 0x200; - offset = 0x8e0200; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; - - memory "signature" - size = 3; - offset = 0x1000090; - ; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; - - memory "fuse1" - size = 1; - offset = 0x8f0021; - ; - - memory "fuse2" - size = 1; - offset = 0x8f0022; - ; - - memory "fuse4" - size = 1; - offset = 0x8f0024; - ; - - memory "fuse5" - size = 1; - offset = 0x8f0025; - ; - - memory "lock" - size = 1; - offset = 0x8f0027; - ; -; - -#------------------------------------------------------------ -# ATXMEGA64A3 -#------------------------------------------------------------ - -part - id = "x64a3"; - desc = "ATXMEGA64A3"; - signature = 0x1e 0x96 0x42; - has_jtag = yes; - has_pdi = yes; - nvm_base = 0x01c0; - - memory "eeprom" - size = 0x0800; - offset = 0x08c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x00010000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x00001000; - offset = 0x0080f000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x00001000; - offset = 0x00810000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x00011000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "prodsig" - size = 0x200; - offset = 0x8e0200; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; - - memory "signature" - size = 3; - offset = 0x1000090; - ; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; - - memory "fuse1" - size = 1; - offset = 0x8f0021; - ; - - memory "fuse2" - size = 1; - offset = 0x8f0022; - ; - - memory "fuse4" - size = 1; - offset = 0x8f0024; - ; - - memory "fuse5" - size = 1; - offset = 0x8f0025; - ; - - memory "lock" - size = 1; - offset = 0x8f0027; - ; -; - -#------------------------------------------------------------ -# ATXMEGA128A3 -#------------------------------------------------------------ - -part - id = "x128a3"; - desc = "ATXMEGA128A3"; - signature = 0x1e 0x97 0x42; - has_jtag = yes; - has_pdi = yes; - nvm_base = 0x01c0; - - memory "eeprom" - size = 0x0800; - offset = 0x08c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x00020000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x00002000; - offset = 0x0081e000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x00002000; - offset = 0x00820000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x00022000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "prodsig" - size = 0x200; - offset = 0x8e0200; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; - - memory "signature" - size = 3; - offset = 0x1000090; - ; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; - - memory "fuse1" - size = 1; - offset = 0x8f0021; - ; - - memory "fuse2" - size = 1; - offset = 0x8f0022; - ; - - memory "fuse4" - size = 1; - offset = 0x8f0024; - ; - - memory "fuse5" - size = 1; - offset = 0x8f0025; - ; - - memory "lock" - size = 1; - offset = 0x8f0027; - ; -; - -#------------------------------------------------------------ -# ATXMEGA192A3 -#------------------------------------------------------------ - -part - id = "x192a3"; - desc = "ATXMEGA192A3"; - signature = 0x1e 0x97 0x44; - has_jtag = yes; - has_pdi = yes; - nvm_base = 0x01c0; - - memory "eeprom" - size = 0x0800; - offset = 0x08c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x00030000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x00002000; - offset = 0x0082e000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x00002000; - offset = 0x00830000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x00032000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "prodsig" - size = 0x200; - offset = 0x8e0200; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; - - memory "signature" - size = 3; - offset = 0x1000090; - ; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; - - memory "fuse1" - size = 1; - offset = 0x8f0021; - ; - - memory "fuse2" - size = 1; - offset = 0x8f0022; - ; - - memory "fuse4" - size = 1; - offset = 0x8f0024; - ; - - memory "fuse5" - size = 1; - offset = 0x8f0025; - ; - - memory "lock" - size = 1; - offset = 0x8f0027; - ; -; - -#------------------------------------------------------------ -# ATXMEGA256A3 -#------------------------------------------------------------ - -part - id = "x256a3"; - desc = "ATXMEGA256A3"; - signature = 0x1e 0x98 0x42; - has_jtag = yes; - has_pdi = yes; - nvm_base = 0x01c0; - - memory "eeprom" - size = 0x1000; - offset = 0x08c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x00040000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x00002000; - offset = 0x0083e000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x00002000; - offset = 0x00840000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x00042000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "prodsig" - size = 0x200; - offset = 0x8e0200; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; - - memory "signature" - size = 3; - offset = 0x1000090; - ; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; - - memory "fuse1" - size = 1; - offset = 0x8f0021; - ; - - memory "fuse2" - size = 1; - offset = 0x8f0022; - ; - - memory "fuse4" - size = 1; - offset = 0x8f0024; - ; - - memory "fuse5" - size = 1; - offset = 0x8f0025; - ; - - memory "lock" - size = 1; - offset = 0x8f0027; - ; -; - -#------------------------------------------------------------ -# ATXMEGA256A3B -#------------------------------------------------------------ - -part - id = "x256a3b"; - desc = "ATXMEGA256A3B"; - signature = 0x1e 0x98 0x43; - has_jtag = yes; - has_pdi = yes; - nvm_base = 0x01c0; - - memory "eeprom" - size = 0x1000; - offset = 0x08c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x00040000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x00002000; - offset = 0x0083e000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x00002000; - offset = 0x00840000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x00042000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "prodsig" - size = 0x200; - offset = 0x8e0200; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; - - memory "signature" - size = 3; - offset = 0x1000090; - ; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; - - memory "fuse1" - size = 1; - offset = 0x8f0021; - ; - - memory "fuse2" - size = 1; - offset = 0x8f0022; - ; - - memory "fuse4" - size = 1; - offset = 0x8f0024; - ; - - memory "fuse5" - size = 1; - offset = 0x8f0025; - ; - - memory "lock" - size = 1; - offset = 0x8f0027; - ; -; - -#------------------------------------------------------------ -# ATXMEGA16A4 -#------------------------------------------------------------ - -part - id = "x16a4"; - desc = "ATXMEGA16A4"; - signature = 0x1e 0x94 0x41; - has_jtag = yes; - has_pdi = yes; - nvm_base = 0x01c0; - - memory "eeprom" - size = 0x0400; - offset = 0x08c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x00004000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x00001000; - offset = 0x00803000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x00001000; - offset = 0x00804000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x00005000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "prodsig" - size = 0x200; - offset = 0x8e0200; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; - - memory "signature" - size = 3; - offset = 0x1000090; - ; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; - - memory "fuse1" - size = 1; - offset = 0x8f0021; - ; - - memory "fuse2" - size = 1; - offset = 0x8f0022; - ; - - memory "fuse4" - size = 1; - offset = 0x8f0024; - ; - - memory "fuse5" - size = 1; - offset = 0x8f0025; - ; - - memory "lock" - size = 1; - offset = 0x8f0027; - ; -; - -#------------------------------------------------------------ -# ATXMEGA32A4 -#------------------------------------------------------------ - -part - id = "x32a4"; - desc = "ATXMEGA32A4"; - signature = 0x1e 0x95 0x41; - has_jtag = yes; - has_pdi = yes; - nvm_base = 0x01c0; - - memory "eeprom" - size = 0x0400; - offset = 0x08c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x00008000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x00001000; - offset = 0x00807000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x00001000; - offset = 0x00808000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x00009000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "prodsig" - size = 0x200; - offset = 0x8e0200; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; - - memory "signature" - size = 3; - offset = 0x1000090; - ; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; - - memory "fuse1" - size = 1; - offset = 0x8f0021; - ; - - memory "fuse2" - size = 1; - offset = 0x8f0022; - ; - - memory "fuse4" - size = 1; - offset = 0x8f0024; - ; - - memory "fuse5" - size = 1; - offset = 0x8f0025; - ; - - memory "lock" - size = 1; - offset = 0x8f0027; - ; -; - -#------------------------------------------------------------ -# ATXMEGA64A4 -#------------------------------------------------------------ - -part - id = "x64a4"; - desc = "ATXMEGA64A4"; - signature = 0x1e 0x96 0x46; - has_jtag = yes; - has_pdi = yes; - nvm_base = 0x01c0; - - memory "eeprom" - size = 0x0800; - offset = 0x08c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x00010000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x00001000; - offset = 0x0080f000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x00001000; - offset = 0x00810000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x00011000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "prodsig" - size = 0x200; - offset = 0x8e0200; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; - - memory "signature" - size = 3; - offset = 0x1000090; - ; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; - - memory "fuse1" - size = 1; - offset = 0x8f0021; - ; - - memory "fuse2" - size = 1; - offset = 0x8f0022; - ; - - memory "fuse4" - size = 1; - offset = 0x8f0024; - ; - - memory "fuse5" - size = 1; - offset = 0x8f0025; - ; - - memory "lock" - size = 1; - offset = 0x8f0027; - ; -; - -#------------------------------------------------------------ -# ATXMEGA128A4 -#------------------------------------------------------------ - -part - id = "x128a4"; - desc = "ATXMEGA128A4"; - signature = 0x1e 0x97 0x46; - has_jtag = yes; - has_pdi = yes; - nvm_base = 0x01c0; - - memory "eeprom" - size = 0x0800; - offset = 0x08c0000; - page_size = 0x20; - readsize = 0x100; - ; - - memory "application" - size = 0x00020000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "apptable" - size = 0x00002000; - offset = 0x0081e000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "boot" - size = 0x00002000; - offset = 0x00820000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "flash" - size = 0x00022000; - offset = 0x0800000; - page_size = 0x100; - readsize = 0x100; - ; - - memory "prodsig" - size = 0x200; - offset = 0x8e0200; - page_size = 0x100; - readsize = 0x100; - ; - - memory "usersig" - size = 0x200; - offset = 0x8e0400; - page_size = 0x100; - readsize = 0x100; - ; - - memory "signature" - size = 3; - offset = 0x1000090; - ; - - memory "fuse0" - size = 1; - offset = 0x8f0020; - ; - - memory "fuse1" - size = 1; - offset = 0x8f0021; - ; - - memory "fuse2" - size = 1; - offset = 0x8f0022; - ; - - memory "fuse4" - size = 1; - offset = 0x8f0024; - ; - - memory "fuse5" - size = 1; - offset = 0x8f0025; - ; - - memory "lock" - size = 1; - offset = 0x8f0027; - ; -; - - -#------------------------------------------------------------ -# AVR32UC3A0512 -#------------------------------------------------------------ - -part - id = "ucr2"; - desc = "32UC3A0512"; - signature = 0xED 0xC0 0x3F; - has_jtag = yes; - is_avr32 = yes; - - memory "flash" - paged = yes; - page_size = 512; # bytes - readsize = 512; # bytes - num_pages = 1024; # could be set dynamicly - size = 0x00080000; # could be set dynamicly - offset = 0x80000000; - ; -; - -#------------------------------------------------------------ -# ATtiny4 -#------------------------------------------------------------ - -part - id = "t4"; - desc = "ATtiny4"; - signature = 0x1e 0x8f 0x0a; - has_tpi = yes; - - memory "flash" - size = 512; - offset = 0x4000; - page_size = 16; - blocksize = 128; - ; - - memory "signature" - size = 3; - offset = 0x3fc0; - ; - - memory "fuse" - size = 1; - offset = 0x3f40; - blocksize = 4; - ; - - memory "calibration" - size = 1; - offset = 0x3f80; - ; - - memory "lockbits" - size = 1; - offset = 0x3f00; - ; -; - - -#------------------------------------------------------------ -# ATtiny5 -#------------------------------------------------------------ - -part - id = "t5"; - desc = "ATtiny5"; - signature = 0x1e 0x8f 0x09; - has_tpi = yes; - - memory "flash" - size = 512; - offset = 0x4000; - page_size = 16; - blocksize = 128; - ; - - memory "signature" - size = 3; - offset = 0x3fc0; - ; - - memory "fuse" - size = 1; - offset = 0x3f40; - blocksize = 4; - ; - - memory "calibration" - size = 1; - offset = 0x3f80; - ; - - memory "lockbits" - size = 1; - offset = 0x3f00; - ; -; - - -#------------------------------------------------------------ -# ATtiny9 -#------------------------------------------------------------ - -part - id = "t8"; - desc = "ATtiny9"; - signature = 0x1e 0x90 0x08; - has_tpi = yes; - - memory "flash" - size = 1024; - offset = 0x4000; - page_size = 16; - blocksize = 128; - ; - - memory "signature" - size = 3; - offset = 0x3fc0; - ; - - memory "fuse" - size = 1; - offset = 0x3f40; - blocksize = 4; - ; - - memory "calibration" - size = 1; - offset = 0x3f80; - ; - - memory "lockbits" - size = 1; - offset = 0x3f00; - ; -; - - -#------------------------------------------------------------ -# ATtiny10 -#------------------------------------------------------------ - -part - id = "t10"; - desc = "ATtiny10"; - signature = 0x1e 0x90 0x03; - has_tpi = yes; - - memory "flash" - size = 1024; - offset = 0x4000; - page_size = 16; - blocksize = 128; - ; - - memory "signature" - size = 3; - offset = 0x3fc0; - ; - - memory "fuse" - size = 1; - offset = 0x3f40; - blocksize = 4; - ; - - memory "calibration" - size = 1; - offset = 0x3f80; - ; - - memory "lockbits" - size = 1; - offset = 0x3f00; - ; -; - - From 05e67a92624b148b1490e272e25661d7c7747890 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Tue, 17 Dec 2024 00:29:50 +0000 Subject: [PATCH 010/787] [cron] Bump distribution date (2024-12-17) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 69ec210a65..1998c16d1c 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2024-12-16" +//#define STRING_DISTRIBUTION_DATE "2024-12-17" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index ca04b24869..5f0b149004 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2024-12-16" + #define STRING_DISTRIBUTION_DATE "2024-12-17" #endif /** From 7b7add3843f7f74739244dc4425a0368afca4bd1 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 17 Dec 2024 11:53:44 -0600 Subject: [PATCH 011/787] =?UTF-8?q?=F0=9F=93=9D=20Config=20feedrate=20unit?= =?UTF-8?q?s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Followup to #27579 --- Marlin/Configuration.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 7226d337d1..6d5ae49de8 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -1648,12 +1648,12 @@ // X and Y axis travel speed between probes. // Leave undefined to use the average of the current XY homing feedrate. -#define XY_PROBE_FEEDRATE (133*60) // (mm/min) +#define XY_PROBE_FEEDRATE (133*60) // (mm/min) -// Feedrate (mm/min) for the first approach when double-probing (MULTIPLE_PROBING == 2) -#define Z_PROBE_FEEDRATE_FAST (4*60) // (mm/min) +// Feedrate for the first approach when double-probing (MULTIPLE_PROBING == 2) +#define Z_PROBE_FEEDRATE_FAST (4*60) // (mm/min) -// Feedrate (mm/min) for the "accurate" probe of each point +// Feedrate for the "accurate" probe of each point #define Z_PROBE_FEEDRATE_SLOW (Z_PROBE_FEEDRATE_FAST / 2) // (mm/min) /** From 106795069740bede91cb5fbc20cd506a48776653 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 17 Dec 2024 12:45:58 -0600 Subject: [PATCH 012/787] =?UTF-8?q?=F0=9F=94=A8=20Fix=20and=20improve=20sc?= =?UTF-8?q?hema=20exports?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- buildroot/share/PlatformIO/scripts/schema.py | 41 +++++++++++---- .../share/PlatformIO/scripts/signature.py | 50 +++++++++++++------ 2 files changed, 66 insertions(+), 25 deletions(-) diff --git a/buildroot/share/PlatformIO/scripts/schema.py b/buildroot/share/PlatformIO/scripts/schema.py index d5179d43b5..d23e5c4716 100755 --- a/buildroot/share/PlatformIO/scripts/schema.py +++ b/buildroot/share/PlatformIO/scripts/schema.py @@ -183,18 +183,28 @@ def extract_files(filekey): # - The line starts with '======' so just skip it. # def use_comment(c, opt, sec, bufref): - if c.startswith(':'): # If the comment starts with : then it has magic JSON - d = c[1:].strip() # Strip the leading : - cbr = c.rindex('}') if d.startswith('{') else c.rindex(']') if d.startswith('[') else 0 + ''' + c - The comment line to parse + opt - Options JSON string to return (if not updated) + sec - Section to return (if not updated) + bufref - The comment buffer to add to + ''' + sc = c.strip() # Strip for special patterns + if sc.startswith(':'): # If the comment starts with : then it has magic JSON + d = sc[1:].strip() # Strip the leading : and spaces + # Look for a JSON container + cbr = sc.rindex('}') if d.startswith('{') else sc.rindex(']') if d.startswith('[') else 0 if cbr: - opt, cmt = c[1:cbr+1].strip(), c[cbr+1:].strip() + opt, cmt = sc[1:cbr+1].strip(), sc[cbr+1:].strip() if cmt != '': bufref.append(cmt) else: - opt = c[1:].strip() - elif c.startswith('@section'): # Start a new section - sec = c[8:].strip() - elif not c.startswith('========'): - bufref.append(c) + opt = sc[1:].strip() # Some literal value not in a JSON container? + else: + m = re.match(r'@section\s*(.+)', sc) # Start a new section? + if m: + sec = m[1] + elif not sc.startswith('========'): + bufref.append(c) # Anything else is part of the comment return opt, sec # For slash comments, capture consecutive slash comments. @@ -225,7 +235,7 @@ def extract_files(filekey): # Collect temperature sensors if state == Parse.GET_SENSORS: - sens = re.match(r'^(-?\d+)\s*:\s*(.+)$', cline) + sens = re.match(r'^\s*(-?\d+)\s*:\s*(.+)$', cline) if sens: s2 = sens[2].replace("'", "''") options_json += f"{sens[1]}:'{sens[1]} - {s2}', " @@ -433,6 +443,17 @@ def dump_json(schema:dict, jpath:Path): def dump_yaml(schema:dict, ypath:Path): import yaml + + # Custom representer for all multi-line strings + def str_literal_representer(dumper, data): + if '\n' in data: # Check for multi-line strings + # Add a newline to trigger '|+' + if not data.endswith('\n'): data += '\n' + return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='|') + return dumper.represent_scalar('tag:yaml.org,2002:str', data) + + yaml.add_representer(str, str_literal_representer) + with ypath.open('w', encoding='utf-8') as yfile: yaml.dump(schema, yfile, default_flow_style=False, width=120, indent=2) diff --git a/buildroot/share/PlatformIO/scripts/signature.py b/buildroot/share/PlatformIO/scripts/signature.py index efb8527869..f47d509bab 100755 --- a/buildroot/share/PlatformIO/scripts/signature.py +++ b/buildroot/share/PlatformIO/scripts/signature.py @@ -206,15 +206,21 @@ def compute_build_signature(env): print(red + "Error: " + str(exc)) conf_schema = None + optorder = ('MOTHERBOARD','SERIAL_PORT','BAUDRATE','USE_WATCHDOG','THERMAL_PROTECTION_HOTENDS','THERMAL_PROTECTION_HYSTERESIS','THERMAL_PROTECTION_PERIOD','BUFSIZE','BLOCK_BUFFER_SIZE','MAX_CMD_SIZE','EXTRUDERS','TEMP_SENSOR_0','TEMP_HYSTERESIS','HEATER_0_MINTEMP','HEATER_0_MAXTEMP','PREHEAT_1_TEMP_HOTEND','BANG_MAX','PIDTEMP','PID_K1','PID_MAX','PID_FUNCTIONAL_RANGE','DEFAULT_KP','DEFAULT_KI','DEFAULT_KD','X_DRIVER_TYPE','Y_DRIVER_TYPE','Z_DRIVER_TYPE','E0_DRIVER_TYPE','X_BED_SIZE','X_MIN_POS','X_MAX_POS','Y_BED_SIZE','Y_MIN_POS','Y_MAX_POS','Z_MIN_POS','Z_MAX_POS','X_HOME_DIR','Y_HOME_DIR','Z_HOME_DIR','X_MIN_ENDSTOP_HIT_STATE','Y_MIN_ENDSTOP_HIT_STATE','Z_MIN_ENDSTOP_HIT_STATE','DEFAULT_AXIS_STEPS_PER_UNIT','AXIS_RELATIVE_MODES','DEFAULT_MAX_FEEDRATE','DEFAULT_MAX_ACCELERATION','HOMING_FEEDRATE_MM_M','HOMING_BUMP_DIVISOR','X_ENABLE_ON','Y_ENABLE_ON','Z_ENABLE_ON','E_ENABLE_ON','INVERT_X_DIR','INVERT_Y_DIR','INVERT_Z_DIR','INVERT_E0_DIR','STEP_STATE_E','STEP_STATE_X','STEP_STATE_Y','STEP_STATE_Z','DISABLE_X','DISABLE_Y','DISABLE_Z','DISABLE_E','PROPORTIONAL_FONT_RATIO','DEFAULT_NOMINAL_FILAMENT_DIA','JUNCTION_DEVIATION_MM','DEFAULT_ACCELERATION','DEFAULT_TRAVEL_ACCELERATION','DEFAULT_RETRACT_ACCELERATION','DEFAULT_MINIMUMFEEDRATE','DEFAULT_MINTRAVELFEEDRATE','MINIMUM_PLANNER_SPEED','MIN_STEPS_PER_SEGMENT','DEFAULT_MINSEGMENTTIME','BED_OVERSHOOT','BUSY_WHILE_HEATING','DEFAULT_EJERK','DEFAULT_KEEPALIVE_INTERVAL','DEFAULT_LEVELING_FADE_HEIGHT','DISABLE_OTHER_EXTRUDERS','DISPLAY_CHARSET_HD44780','EEPROM_BOOT_SILENT','EEPROM_CHITCHAT','ENDSTOPPULLUPS','EXTRUDE_MAXLENGTH','EXTRUDE_MINTEMP','HOST_KEEPALIVE_FEATURE','HOTEND_OVERSHOOT','JD_HANDLE_SMALL_SEGMENTS','LCD_INFO_SCREEN_STYLE','LCD_LANGUAGE','MAX_BED_POWER','MESH_INSET','MIN_SOFTWARE_ENDSTOPS','MAX_SOFTWARE_ENDSTOPS','MIN_SOFTWARE_ENDSTOP_X','MIN_SOFTWARE_ENDSTOP_Y','MIN_SOFTWARE_ENDSTOP_Z','MAX_SOFTWARE_ENDSTOP_X','MAX_SOFTWARE_ENDSTOP_Y','MAX_SOFTWARE_ENDSTOP_Z','PREHEAT_1_FAN_SPEED','PREHEAT_1_LABEL','PREHEAT_1_TEMP_BED','PREVENT_COLD_EXTRUSION','PREVENT_LENGTHY_EXTRUDE','PRINTJOB_TIMER_AUTOSTART','PROBING_MARGIN','SHOW_BOOTSCREEN','SOFT_PWM_SCALE','STRING_CONFIG_H_AUTHOR','TEMP_BED_HYSTERESIS','TEMP_BED_RESIDENCY_TIME','TEMP_BED_WINDOW','TEMP_RESIDENCY_TIME','TEMP_WINDOW','VALIDATE_HOMING_ENDSTOPS','XY_PROBE_FEEDRATE','Z_CLEARANCE_BETWEEN_PROBES','Z_CLEARANCE_DEPLOY_PROBE','Z_CLEARANCE_MULTI_PROBE','ARC_SUPPORT','AUTO_REPORT_TEMPERATURES','AUTOTEMP','AUTOTEMP_OLDWEIGHT','BED_CHECK_INTERVAL','DEFAULT_STEPPER_TIMEOUT_SEC','DEFAULT_VOLUMETRIC_EXTRUDER_LIMIT','DISABLE_IDLE_X','DISABLE_IDLE_Y','DISABLE_IDLE_Z','DISABLE_IDLE_E','E0_AUTO_FAN_PIN','ENCODER_100X_STEPS_PER_SEC','ENCODER_10X_STEPS_PER_SEC','ENCODER_RATE_MULTIPLIER','EXTENDED_CAPABILITIES_REPORT','EXTRUDER_AUTO_FAN_SPEED','EXTRUDER_AUTO_FAN_TEMPERATURE','FANMUX0_PIN','FANMUX1_PIN','FANMUX2_PIN','FASTER_GCODE_PARSER','HOMING_BUMP_MM','MAX_ARC_SEGMENT_MM','MIN_ARC_SEGMENT_MM','MIN_CIRCLE_SEGMENTS','N_ARC_CORRECTION','SERIAL_OVERRUN_PROTECTION','SLOWDOWN','SLOWDOWN_DIVISOR','TEMP_SENSOR_BED','THERMAL_PROTECTION_BED_HYSTERESIS','THERMOCOUPLE_MAX_ERRORS','TX_BUFFER_SIZE','WATCH_BED_TEMP_INCREASE','WATCH_BED_TEMP_PERIOD','WATCH_TEMP_INCREASE','WATCH_TEMP_PERIOD') + + def optsort(x, optorder): + return optorder.index(x) if x in optorder else float('inf') + # - # CONFIG_EXPORT 2 = config.ini, 5 = Config.h + # CONFIG_EXPORT 102 = config.ini, 105 = Config.h # Get sections using the schema class # if extended_dump and config_dump in (2, 5): if not conf_schema: exit(1) # Start with a preferred @section ordering - preorder = ('info','user','machine','extruder','bed temp','fans','stepper drivers','geometry','homing','endstops','probes','lcd','interface','host','reporting') + preorder = ('test','custom','info','machine','eeprom','stepper drivers','multi stepper','idex','extruder','geometry','homing','kinematics','motion','motion control','endstops','filament runout sensors','probe type','probes','bltouch','leveling','temperature','hotend temp','mpctemp','pid temp','mpc temp','bed temp','chamber temp','fans','tool change','advanced pause','calibrate','calibration','media','lcd','lights','caselight','interface','custom main menu','custom config menu','custom buttons','develop','debug matrix','delta','scara','tpara','polar','polargraph','cnc','nozzle park','nozzle clean','gcode','serial','host','filament width','i2c encoders','i2cbus','joystick','multi-material','nanodlp','network','photo','power','psu control','reporting','safety','security','servos','stats','tmc/config','tmc/hybrid','tmc/serial','tmc/smart','tmc/spi','tmc/stallguard','tmc/status','tmc/stealthchop','tmc/tmc26x','units','volumetrics','extras') + sections = { key:{} for key in preorder } # Group options by schema @section @@ -229,7 +235,7 @@ def compute_build_signature(env): sections[sect][name] = ddict # - # CONFIG_EXPORT 2 = config.ini + # CONFIG_EXPORT 2 or 102 = config.ini # if config_dump == 2: print(yellow + "Generating config.ini ...") @@ -337,7 +343,9 @@ f'''# sani = re.sub(r'[- ]+', '_', skey).lower() outfile.write(f"\n[config:{sani}]\n") opts = sections[skey] - for name in sorted(opts): + opts_keys = sorted(opts.keys(), key=lambda x: optsort(x, optorder)) + for name in opts_keys: + if name in ignore: continue val = opts[name]['value'] if val == '': val = 'on' #print(f" {name} = {val}") @@ -348,14 +356,16 @@ f'''# # Standard export just dumps config:basic and config:advanced sections for header in real_config: outfile.write(f'\n[{filegrp[header]}]\n') - for name in sorted(real_config[header]): + opts = real_config[header] + opts_keys = sorted(opts.keys(), key=lambda x: optsort(x, optorder)) + for name in opts_keys: if name in ignore: continue - val = real_config[header][name]['value'] + val = opts[name]['value'] if val == '': val = 'on' outfile.write(ini_fmt.format(name.lower(), val) + '\n') # - # CONFIG_EXPORT 5 = Config.h + # CONFIG_EXPORT 5 or 105 = Config.h # if config_dump == 5: print(yellow + "Generating Config-export.h ...") @@ -382,7 +392,8 @@ f'''# #print(f" skey: {skey}") opts = sections[skey] headed = False - for name in sorted(opts): + opts_keys = sorted(opts.keys(), key=lambda x: optsort(x, optorder)) + for name in opts_keys: if name in ignore: continue val = opts[name]['value'] if not headed: @@ -395,17 +406,19 @@ f'''# # Dump config options in just two sections, by file for header in real_config: out_text += f'\n/**\n * Overrides for {header}\n */\n' - for name in sorted(real_config[header]): + opts = real_config[header] + opts_keys = sorted(opts.keys(), key=lambda x: optsort(x, optorder)) + for name in opts_keys: if name in ignore: continue - val = real_config[header][name]['value'] + val = opts[name]['value'] out_text += define_fmt.format(name, val).strip() + '\n' outfile.write(out_text) # - # CONFIG_EXPORT 3 = schema.json, 4 = schema.yml + # CONFIG_EXPORT 3 = schema.json, 13 = schema_grouped.json, 4 = schema.yml # - if config_dump in (3, 4): + if config_dump in (3, 4, 13): if conf_schema: # @@ -434,7 +447,7 @@ f'''# schema.dump_yaml(conf_schema, build_path / 'schema.yml') # - # Produce a JSON file for CONFIGURATION_EMBEDDING or CONFIG_EXPORT == 1 + # Produce a JSON file for CONFIGURATION_EMBEDDING or CONFIG_EXPORT == 1 or 101 # Skip if an identical JSON file was already present. # if not same_hash and (config_dump == 1 or 'CONFIGURATION_EMBEDDING' in build_defines): @@ -502,5 +515,12 @@ f'''# if __name__ == "__main__": # Build required. From command line just explain usage. - print("Use schema.py to export JSON and YAML from the command-line.") - print("Build Marlin with CONFIG_EXPORT 2 to export 'config.ini'.") + print("*** THIS SCRIPT USED BY common-dependencies.py ***\n\n" + + "Current options for config and schema export:\n" + + " - marlin_config.json : Build Marlin with CONFIG_EXPORT 1 or 101. (Use CONFIGURATION_EMBEDDING for 'mc.zip')\n" + + " - config.ini : Build Marlin with CONFIG_EXPORT 2 or 102.\n" + + " - schema.json : Run 'schema.py json' (CONFIG_EXPORT 3).\n" + + " - schema_grouped.json : Run 'schema.py group' (CONFIG_EXPORT 13).\n" + + " - schema.yml : Run 'schema.py yml' (CONFIG_EXPORT 4).\n" + + " - Config-export.h : Build Marlin with CONFIG_EXPORT 5 or 105.\n" + ) From 6f71a141501403fd55a4fd148a63010c3200b8c3 Mon Sep 17 00:00:00 2001 From: Giuliano Zaro <3684609+GMagician@users.noreply.github.com> Date: Tue, 17 Dec 2024 21:07:05 +0100 Subject: [PATCH 013/787] =?UTF-8?q?=F0=9F=90=9B=20Fix=20S6=20V2=20TMC=20co?= =?UTF-8?q?mmunication=20error=20(#27595)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/pins/stm32f4/pins_FYSETC_S6.h | 324 +----------------- Marlin/src/pins/stm32f4/pins_FYSETC_S6_V2_0.h | 13 +- .../src/pins/stm32f4/pins_FYSETC_S6_common.h | 294 ++++++++++++++++ 3 files changed, 312 insertions(+), 319 deletions(-) create mode 100644 Marlin/src/pins/stm32f4/pins_FYSETC_S6_common.h diff --git a/Marlin/src/pins/stm32f4/pins_FYSETC_S6.h b/Marlin/src/pins/stm32f4/pins_FYSETC_S6.h index 8658191dbe..0a3584e622 100644 --- a/Marlin/src/pins/stm32f4/pins_FYSETC_S6.h +++ b/Marlin/src/pins/stm32f4/pins_FYSETC_S6.h @@ -1,6 +1,6 @@ /** * Marlin 3D Printer Firmware - * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * Copyright (c) 2024 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm @@ -21,321 +21,29 @@ */ #pragma once -#include "env_validate.h" - -#if HOTENDS > 3 || E_STEPPERS > 3 - #error "FYSETC S6 supports up to 3 hotends / E steppers." -#endif - -#ifndef BOARD_INFO_NAME - #define BOARD_INFO_NAME "FYSETC S6" -#endif -#ifndef DEFAULT_MACHINE_NAME - #define DEFAULT_MACHINE_NAME BOARD_INFO_NAME -#endif - -// Avoid conflict with TIMER_TONE defined in variant -#define STEP_TIMER 10 - -// -// EEPROM Emulation -// -#if NO_EEPROM_SELECTED - #define FLASH_EEPROM_EMULATION - //#define I2C_EEPROM -#endif - -#if ENABLED(FLASH_EEPROM_EMULATION) - // Decrease delays and flash wear by spreading writes across the - // 128 kB sector allocated for EEPROM emulation. - #define FLASH_EEPROM_LEVELING -#elif ENABLED(I2C_EEPROM) - #define MARLIN_EEPROM_SIZE 0x1000 // 4K -#endif - -// -// Servos -// -#ifndef SERVO0_PIN - #define SERVO0_PIN PA3 -#endif - -// -// Limit Switches -// -#define X_MIN_PIN PB14 -#define X_MAX_PIN PA1 -#define Y_MIN_PIN PB13 -#define Y_MAX_PIN PA2 -#define Z_MIN_PIN PA0 -#define Z_MAX_PIN PA3 - -// -// Filament Sensor -// share with X_MAX_PIN -// -#ifndef FIL_RUNOUT_PIN - #define FIL_RUNOUT_PIN PA1 -#endif +#define BOARD_INFO_NAME "FYSETC S6" // // Steppers // -#define X_STEP_PIN PE11 -#define X_DIR_PIN PE10 -#ifndef X_ENABLE_PIN - #define X_ENABLE_PIN PE12 -#endif -#define X_CS_PIN PE7 - -#define Y_STEP_PIN PD8 -#define Y_DIR_PIN PB12 -#define Y_ENABLE_PIN PD9 -#define Y_CS_PIN PE15 - -#define Z_STEP_PIN PD14 -#define Z_DIR_PIN PD13 -#define Z_ENABLE_PIN PD15 -#define Z_CS_PIN PD10 - -#define E0_STEP_PIN PD5 -#define E0_DIR_PIN PD6 -#define E0_ENABLE_PIN PD4 -#define E0_CS_PIN PD7 - -#define E1_STEP_PIN PE6 -#define E1_DIR_PIN PC13 -#define E1_ENABLE_PIN PE5 -#define E1_CS_PIN PC14 - -#define E2_STEP_PIN PE2 -#define E2_DIR_PIN PE4 -#define E2_ENABLE_PIN PE3 -#define E2_CS_PIN PC15 +#define X_ENABLE_PIN PE12 #if HAS_TMC_UART // // TMC2208/TMC2209 stepper drivers // - - #ifndef X_SERIAL_TX_PIN - #define X_SERIAL_TX_PIN PE9 - #endif - #ifndef X_SERIAL_RX_PIN - #define X_SERIAL_RX_PIN PE8 - #endif - #ifndef Y_SERIAL_TX_PIN - #define Y_SERIAL_TX_PIN PE14 - #endif - #ifndef Y_SERIAL_RX_PIN - #define Y_SERIAL_RX_PIN PE13 - #endif - #ifndef Z_SERIAL_TX_PIN - #define Z_SERIAL_TX_PIN PD11 - #endif - #ifndef Z_SERIAL_RX_PIN - #define Z_SERIAL_RX_PIN PD12 - #endif - #ifndef E0_SERIAL_TX_PIN - #define E0_SERIAL_TX_PIN PD3 - #endif - #ifndef E0_SERIAL_RX_PIN - #define E0_SERIAL_RX_PIN PA15 - #endif - #ifndef E1_SERIAL_TX_PIN - #define E1_SERIAL_TX_PIN PC4 - #endif - #ifndef E1_SERIAL_RX_PIN - #define E1_SERIAL_RX_PIN PC5 - #endif - #ifndef E2_SERIAL_TX_PIN - #define E2_SERIAL_TX_PIN PE1 - #endif - #ifndef E2_SERIAL_RX_PIN - #define E2_SERIAL_RX_PIN PE0 - #endif + #define X_SERIAL_TX_PIN PE9 + #define X_SERIAL_RX_PIN PE8 + #define Y_SERIAL_TX_PIN PE14 + #define Y_SERIAL_RX_PIN PE13 + #define Z_SERIAL_TX_PIN PD11 + #define Z_SERIAL_RX_PIN PD12 + #define E0_SERIAL_TX_PIN PD3 + #define E0_SERIAL_RX_PIN PA15 + #define E1_SERIAL_TX_PIN PC4 + #define E1_SERIAL_RX_PIN PC5 + #define E2_SERIAL_TX_PIN PE1 + #define E2_SERIAL_RX_PIN PE0 #endif -// -// Temperature Sensors -// -#define TEMP_0_PIN PC0 -#define TEMP_1_PIN PC1 -#define TEMP_2_PIN PC2 -#ifndef TEMP_BED_PIN - #define TEMP_BED_PIN PC3 -#endif - -// -// Heaters / Fans -// -#ifndef HEATER_0_PIN - #define HEATER_0_PIN PB3 -#endif -#ifndef HEATER_1_PIN - #define HEATER_1_PIN PB4 -#endif -#ifndef HEATER_2_PIN - #define HEATER_2_PIN PB15 -#endif -#ifndef HEATER_BED_PIN - #define HEATER_BED_PIN PC8 -#endif - -#ifndef FAN0_PIN - #define FAN0_PIN PB0 -#endif -#ifndef FAN1_PIN - #define FAN1_PIN PB1 -#endif -#define FAN2_PIN PB2 - -// -// Misc. Functions -// -//#define LED_PIN PB14 -//#define PS_ON_PIN PE11 -//#define KILL_PIN PC5 - -/** - * ------ ------ - * PC9 | 1 2 | PA8 PA6 | 1 2 | PA5 - * PC11 | 3 4 | PD2 PC6 | 3 4 | PA4 - * PC10 5 6 | PC12 PC7 5 6 | PA7 - * PD0 | 7 8 | PD1 PB10 | 7 8 | RESET - * GND | 9 10 | 5V GND | 9 10 | 5V - * ------ ------ - * EXP1 EXP2 - */ -#define EXP1_01_PIN PC9 -#define EXP1_02_PIN PA8 -#define EXP1_03_PIN PC11 -#define EXP1_04_PIN PD2 -#define EXP1_05_PIN PC10 -#define EXP1_06_PIN PC12 -#define EXP1_07_PIN PD0 -#define EXP1_08_PIN PD1 - -#define EXP2_01_PIN PA6 -#define EXP2_02_PIN PA5 -#define EXP2_03_PIN PC6 -#define EXP2_04_PIN PA4 -#define EXP2_05_PIN PC7 -#define EXP2_06_PIN PA7 -#define EXP2_07_PIN PB10 -#define EXP2_08_PIN -1 // RESET - -// -// SPI / SD Card -// -#define SD_SCK_PIN EXP2_02_PIN -#define SD_MISO_PIN EXP2_01_PIN -#define SD_MOSI_PIN EXP2_06_PIN - -#define SDSS EXP2_04_PIN -#define SD_DETECT_PIN EXP2_07_PIN - -// -// LCD / Controller -// - -#if ENABLED(FYSETC_242_OLED_12864) - - #define BTN_EN1 EXP1_01_PIN - #define BTN_EN2 EXP1_08_PIN - #define BTN_ENC EXP1_02_PIN - - #define BEEPER_PIN EXP2_03_PIN - - #define LCD_PINS_DC EXP1_06_PIN - #define LCD_PINS_RS EXP2_05_PIN // LCD_RST - #define DOGLCD_CS EXP1_04_PIN - #define DOGLCD_MOSI EXP1_05_PIN - #define DOGLCD_SCK EXP1_03_PIN - #define DOGLCD_A0 LCD_PINS_DC - #define FORCE_SOFT_SPI - - #define KILL_PIN -1 // NC - #define BOARD_NEOPIXEL_PIN EXP1_07_PIN - -#elif HAS_WIRED_LCD - - #define BEEPER_PIN EXP1_01_PIN - #define BTN_ENC EXP1_02_PIN - - #if ENABLED(CR10_STOCKDISPLAY) - #define LCD_PINS_RS EXP1_07_PIN - - #define BTN_EN1 EXP1_03_PIN - #define BTN_EN2 EXP1_05_PIN - - #define LCD_PINS_EN EXP1_08_PIN - #define LCD_PINS_D4 EXP1_06_PIN - - #else - - #define LCD_PINS_RS EXP1_04_PIN - - #define BTN_EN1 EXP2_03_PIN - #define BTN_EN2 EXP2_05_PIN - - #define LCD_SDSS EXP2_04_PIN - - #define LCD_PINS_EN EXP1_03_PIN - #define LCD_PINS_D4 EXP1_05_PIN - - #if ENABLED(FYSETC_MINI_12864) - // See https://wiki.fysetc.com/Mini12864_Panel - #define DOGLCD_CS EXP1_03_PIN - #define DOGLCD_A0 EXP1_04_PIN - #if ENABLED(FYSETC_GENERIC_12864_1_1) - #define LCD_BACKLIGHT_PIN EXP1_07_PIN - #endif - #define LCD_RESET_PIN EXP1_05_PIN // Must be high or open for LCD to operate normally. - #if ANY(FYSETC_MINI_12864_1_2, FYSETC_MINI_12864_2_0) - #ifndef RGB_LED_R_PIN - #define RGB_LED_R_PIN EXP1_06_PIN - #endif - #ifndef RGB_LED_G_PIN - #define RGB_LED_G_PIN EXP1_07_PIN - #endif - #ifndef RGB_LED_B_PIN - #define RGB_LED_B_PIN EXP1_08_PIN - #endif - #elif ENABLED(FYSETC_MINI_12864_2_1) - #define NEOPIXEL_PIN EXP1_06_PIN - #endif - #endif - - #if IS_ULTIPANEL - #define LCD_PINS_D5 EXP1_06_PIN - #define LCD_PINS_D6 EXP1_07_PIN - #define LCD_PINS_D7 EXP1_08_PIN - #if ENABLED(REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER) - #define BTN_ENC_EN LCD_PINS_D7 // Detect the presence of the encoder - #endif - #endif - - #endif - -#endif // HAS_WIRED_LCD - -// Alter timing for graphical display -#if IS_U8GLIB_ST7920 - #define BOARD_ST7920_DELAY_1 96 - #define BOARD_ST7920_DELAY_2 48 - #define BOARD_ST7920_DELAY_3 640 -#endif - -#ifndef RGB_LED_R_PIN - #define RGB_LED_R_PIN PB6 -#endif -#ifndef RGB_LED_G_PIN - #define RGB_LED_G_PIN PB5 -#endif -#ifndef RGB_LED_B_PIN - #define RGB_LED_B_PIN PB7 -#endif -#ifndef RGB_LED_W_PIN - #define RGB_LED_W_PIN -1 -#endif +#include "pins_FYSETC_S6_common.h" diff --git a/Marlin/src/pins/stm32f4/pins_FYSETC_S6_V2_0.h b/Marlin/src/pins/stm32f4/pins_FYSETC_S6_V2_0.h index 9d9eb1d37c..7d0823046b 100644 --- a/Marlin/src/pins/stm32f4/pins_FYSETC_S6_V2_0.h +++ b/Marlin/src/pins/stm32f4/pins_FYSETC_S6_V2_0.h @@ -1,6 +1,6 @@ /** * Marlin 3D Printer Firmware - * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * Copyright (c) 2024 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm @@ -23,15 +23,6 @@ #define BOARD_INFO_NAME "FYSETC S6 2.0" -// -// EEPROM Emulation -// -#if NO_EEPROM_SELECTED - #undef NO_EEPROM_SELECTED - //#define FLASH_EEPROM_EMULATION - #define I2C_EEPROM -#endif - // // Steppers // @@ -60,4 +51,4 @@ #define TMC_SPI_SCK PE12 #endif -#include "pins_FYSETC_S6.h" +#include "pins_FYSETC_S6_common.h" diff --git a/Marlin/src/pins/stm32f4/pins_FYSETC_S6_common.h b/Marlin/src/pins/stm32f4/pins_FYSETC_S6_common.h new file mode 100644 index 0000000000..b016db655c --- /dev/null +++ b/Marlin/src/pins/stm32f4/pins_FYSETC_S6_common.h @@ -0,0 +1,294 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2024 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +#include "env_validate.h" + +#if HOTENDS > 3 || E_STEPPERS > 3 + #error "FYSETC S6 supports up to 3 hotends / E steppers." +#endif + +#ifndef DEFAULT_MACHINE_NAME + #define DEFAULT_MACHINE_NAME BOARD_INFO_NAME +#endif + +// Avoid conflict with TIMER_TONE defined in variant +#define STEP_TIMER 10 + +// +// EEPROM Emulation +// +#if NO_EEPROM_SELECTED + #undef NO_EEPROM_SELECTED + //#define FLASH_EEPROM_EMULATION + #define I2C_EEPROM +#endif + +#if ENABLED(FLASH_EEPROM_EMULATION) + // Decrease delays and flash wear by spreading writes across the + // 128 kB sector allocated for EEPROM emulation. + #define FLASH_EEPROM_LEVELING +#elif ENABLED(I2C_EEPROM) + #define MARLIN_EEPROM_SIZE 0x1000 // 4K +#endif + +// +// Servos +// +#ifndef SERVO0_PIN + #define SERVO0_PIN PA3 +#endif + +// +// Limit Switches +// +#define X_MIN_PIN PB14 +#define X_MAX_PIN PA1 +#define Y_MIN_PIN PB13 +#define Y_MAX_PIN PA2 +#define Z_MIN_PIN PA0 +#define Z_MAX_PIN PA3 + +// +// Filament Sensor +// share with X_MAX_PIN +// +#ifndef FIL_RUNOUT_PIN + #define FIL_RUNOUT_PIN PA1 +#endif + +// +// Steppers +// +#define X_STEP_PIN PE11 +#define X_DIR_PIN PE10 +//#define X_ENABLE_PIN +#define X_CS_PIN PE7 + +#define Y_STEP_PIN PD8 +#define Y_DIR_PIN PB12 +#define Y_ENABLE_PIN PD9 +#define Y_CS_PIN PE15 + +#define Z_STEP_PIN PD14 +#define Z_DIR_PIN PD13 +#define Z_ENABLE_PIN PD15 +#define Z_CS_PIN PD10 + +#define E0_STEP_PIN PD5 +#define E0_DIR_PIN PD6 +#define E0_ENABLE_PIN PD4 +#define E0_CS_PIN PD7 + +#define E1_STEP_PIN PE6 +#define E1_DIR_PIN PC13 +#define E1_ENABLE_PIN PE5 +#define E1_CS_PIN PC14 + +#define E2_STEP_PIN PE2 +#define E2_DIR_PIN PE4 +#define E2_ENABLE_PIN PE3 +#define E2_CS_PIN PC15 + +// +// Temperature Sensors +// +#define TEMP_0_PIN PC0 +#define TEMP_1_PIN PC1 +#define TEMP_2_PIN PC2 +#ifndef TEMP_BED_PIN + #define TEMP_BED_PIN PC3 +#endif + +// +// Heaters / Fans +// +#ifndef HEATER_0_PIN + #define HEATER_0_PIN PB3 +#endif +#ifndef HEATER_1_PIN + #define HEATER_1_PIN PB4 +#endif +#ifndef HEATER_2_PIN + #define HEATER_2_PIN PB15 +#endif +#ifndef HEATER_BED_PIN + #define HEATER_BED_PIN PC8 +#endif + +#ifndef FAN0_PIN + #define FAN0_PIN PB0 +#endif +#ifndef FAN1_PIN + #define FAN1_PIN PB1 +#endif +#define FAN2_PIN PB2 + +// +// Misc. Functions +// +//#define LED_PIN PB14 +//#define PS_ON_PIN PE11 +//#define KILL_PIN PC5 + +/** + * ------ ------ + * PC9 | 1 2 | PA8 PA6 | 1 2 | PA5 + * PC11 | 3 4 | PD2 PC6 | 3 4 | PA4 + * PC10 5 6 | PC12 PC7 5 6 | PA7 + * PD0 | 7 8 | PD1 PB10 | 7 8 | RESET + * GND | 9 10 | 5V GND | 9 10 | 5V + * ------ ------ + * EXP1 EXP2 + */ +#define EXP1_01_PIN PC9 +#define EXP1_02_PIN PA8 +#define EXP1_03_PIN PC11 +#define EXP1_04_PIN PD2 +#define EXP1_05_PIN PC10 +#define EXP1_06_PIN PC12 +#define EXP1_07_PIN PD0 +#define EXP1_08_PIN PD1 + +#define EXP2_01_PIN PA6 +#define EXP2_02_PIN PA5 +#define EXP2_03_PIN PC6 +#define EXP2_04_PIN PA4 +#define EXP2_05_PIN PC7 +#define EXP2_06_PIN PA7 +#define EXP2_07_PIN PB10 +#define EXP2_08_PIN -1 // RESET + +// +// SPI / SD Card +// +#define SD_SCK_PIN EXP2_02_PIN +#define SD_MISO_PIN EXP2_01_PIN +#define SD_MOSI_PIN EXP2_06_PIN + +#define SDSS EXP2_04_PIN +#define SD_DETECT_PIN EXP2_07_PIN + +// +// LCD / Controller +// + +#if ENABLED(FYSETC_242_OLED_12864) + + #define BTN_EN1 EXP1_01_PIN + #define BTN_EN2 EXP1_08_PIN + #define BTN_ENC EXP1_02_PIN + + #define BEEPER_PIN EXP2_03_PIN + + #define LCD_PINS_DC EXP1_06_PIN + #define LCD_PINS_RS EXP2_05_PIN // LCD_RST + #define DOGLCD_CS EXP1_04_PIN + #define DOGLCD_MOSI EXP1_05_PIN + #define DOGLCD_SCK EXP1_03_PIN + #define DOGLCD_A0 LCD_PINS_DC + #define FORCE_SOFT_SPI + + #define KILL_PIN -1 // NC + #define BOARD_NEOPIXEL_PIN EXP1_07_PIN + +#elif HAS_WIRED_LCD + + #define BEEPER_PIN EXP1_01_PIN + #define BTN_ENC EXP1_02_PIN + + #if ENABLED(CR10_STOCKDISPLAY) + #define LCD_PINS_RS EXP1_07_PIN + + #define BTN_EN1 EXP1_03_PIN + #define BTN_EN2 EXP1_05_PIN + + #define LCD_PINS_EN EXP1_08_PIN + #define LCD_PINS_D4 EXP1_06_PIN + + #else + + #define LCD_PINS_RS EXP1_04_PIN + + #define BTN_EN1 EXP2_03_PIN + #define BTN_EN2 EXP2_05_PIN + + #define LCD_SDSS EXP2_04_PIN + + #define LCD_PINS_EN EXP1_03_PIN + #define LCD_PINS_D4 EXP1_05_PIN + + #if ENABLED(FYSETC_MINI_12864) + // See https://wiki.fysetc.com/Mini12864_Panel + #define DOGLCD_CS EXP1_03_PIN + #define DOGLCD_A0 EXP1_04_PIN + #if ENABLED(FYSETC_GENERIC_12864_1_1) + #define LCD_BACKLIGHT_PIN EXP1_07_PIN + #endif + #define LCD_RESET_PIN EXP1_05_PIN // Must be high or open for LCD to operate normally. + #if ANY(FYSETC_MINI_12864_1_2, FYSETC_MINI_12864_2_0) + #ifndef RGB_LED_R_PIN + #define RGB_LED_R_PIN EXP1_06_PIN + #endif + #ifndef RGB_LED_G_PIN + #define RGB_LED_G_PIN EXP1_07_PIN + #endif + #ifndef RGB_LED_B_PIN + #define RGB_LED_B_PIN EXP1_08_PIN + #endif + #elif ENABLED(FYSETC_MINI_12864_2_1) + #define NEOPIXEL_PIN EXP1_06_PIN + #endif + #endif + + #if IS_ULTIPANEL + #define LCD_PINS_D5 EXP1_06_PIN + #define LCD_PINS_D6 EXP1_07_PIN + #define LCD_PINS_D7 EXP1_08_PIN + #if ENABLED(REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER) + #define BTN_ENC_EN LCD_PINS_D7 // Detect the presence of the encoder + #endif + #endif + + #endif + +#endif // HAS_WIRED_LCD + +// Alter timing for graphical display +#if IS_U8GLIB_ST7920 + #define BOARD_ST7920_DELAY_1 96 + #define BOARD_ST7920_DELAY_2 48 + #define BOARD_ST7920_DELAY_3 640 +#endif + +#ifndef RGB_LED_R_PIN + #define RGB_LED_R_PIN PB6 +#endif +#ifndef RGB_LED_G_PIN + #define RGB_LED_G_PIN PB5 +#endif +#ifndef RGB_LED_B_PIN + #define RGB_LED_B_PIN PB7 +#endif +#ifndef RGB_LED_W_PIN + #define RGB_LED_W_PIN -1 +#endif From d2814c7aa756e7026114455eb0b38cb5812c5dd0 Mon Sep 17 00:00:00 2001 From: ellensp <530024+ellensp@users.noreply.github.com> Date: Wed, 18 Dec 2024 09:09:01 +1300 Subject: [PATCH 014/787] =?UTF-8?q?=E2=9C=8F=EF=B8=8F=20Fix=20variant.h=20?= =?UTF-8?q?comment=20typo=20(#27594)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- buildroot/share/PlatformIO/variants/MARLIN_F103Rx/variant.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildroot/share/PlatformIO/variants/MARLIN_F103Rx/variant.h b/buildroot/share/PlatformIO/variants/MARLIN_F103Rx/variant.h index d3e9e08bba..2167e2ad9c 100644 --- a/buildroot/share/PlatformIO/variants/MARLIN_F103Rx/variant.h +++ b/buildroot/share/PlatformIO/variants/MARLIN_F103Rx/variant.h @@ -31,7 +31,7 @@ extern "C" { #define PA0 PIN_A0 // | 0 | A0 | | | | | #define PA1 PIN_A1 // | 1 | A1 | | | | | #define PA2 PIN_A2 // | 2 | A2 | USART2_TX | | | | -#define PA3 PIN_A3 // | 2 | A2, DAC_OUT1** | USART2_RX | | | | +#define PA3 PIN_A3 // | 2 | A3, DAC_OUT1** | USART2_RX | | | | #define PA4 PIN_A4 // | 4 | A4, DAC_OUT2** | | | SPI1_SS | | #define PA5 PIN_A5 // | 5 | A5 | | | SPI1_SCK | | #define PA6 PIN_A6 // | 6 | A6 | | | SPI1_MISO | | From 4eb8a871930ef152e4fa73fc1782e2ed22348c85 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Wed, 18 Dec 2024 00:28:42 +0000 Subject: [PATCH 015/787] [cron] Bump distribution date (2024-12-18) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 1998c16d1c..a524fbe07d 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2024-12-17" +//#define STRING_DISTRIBUTION_DATE "2024-12-18" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 5f0b149004..00da505168 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2024-12-17" + #define STRING_DISTRIBUTION_DATE "2024-12-18" #endif /** From 30697cb53fcf6784679d3ad9785e867a7fe093a8 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Wed, 8 Jan 2025 16:06:31 -0600 Subject: [PATCH 016/787] =?UTF-8?q?=F0=9F=A9=B9=20Fix=20DGUS=5FLCD=5FUI=5F?= =?UTF-8?q?MKS=20typo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #27508 Co-Authored-By: vehystrix <7142781+vehystrix@users.noreply.github.com> --- Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.h b/Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.h index 0e61080e67..2a026f751e 100644 --- a/Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.h +++ b/Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.h @@ -78,7 +78,7 @@ public: static void handleFeedRateMinChange(DGUS_VP_Variable &var, void *val_ptr); static void handleMin_T_F(DGUS_VP_Variable &var, void *val_ptr); - #if HAS_PID_HEATING + #if ENABLED(DGUS_FILAMENT_LOADUNLOAD) static void filamentLoadUnload(DGUS_VP_Variable &var, void *val_ptr, const int filamentDir); static void filamentLoad(DGUS_VP_Variable &var, void *val_ptr); static void filamentUnload(DGUS_VP_Variable &var, void *val_ptr); From 83278bdc17cb36682208f93188b7fade4afa57ab Mon Sep 17 00:00:00 2001 From: ellensp <530024+ellensp@users.noreply.github.com> Date: Thu, 9 Jan 2025 11:40:57 +1300 Subject: [PATCH 017/787] =?UTF-8?q?=F0=9F=94=A8=20Some=20boards=20with=20b?= =?UTF-8?q?oth=20LPC1768/9=20(#27586)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/pins/lpc1768/env_validate.h | 15 ++++++++++----- Marlin/src/pins/lpc1768/pins_MKS_SBASE.h | 1 + Marlin/src/pins/lpc1769/env_validate.h | 8 ++++++-- Marlin/src/pins/lpc1769/pins_SMOOTHIEBOARD.h | 1 + Marlin/src/pins/pins.h | 4 ++-- 5 files changed, 20 insertions(+), 9 deletions(-) diff --git a/Marlin/src/pins/lpc1768/env_validate.h b/Marlin/src/pins/lpc1768/env_validate.h index 8a6a1cebd3..a1b1dde128 100644 --- a/Marlin/src/pins/lpc1768/env_validate.h +++ b/Marlin/src/pins/lpc1768/env_validate.h @@ -22,12 +22,17 @@ #ifndef ENV_VALIDATE_H #define ENV_VALIDATE_H -#if ENABLED(REQUIRE_LPC1769) && NOT_TARGET(MCU_LPC1769) - #error "Oops! Make sure you have the LPC1769 environment selected in your IDE." -#elif DISABLED(REQUIRE_LPC1769) && NOT_TARGET(MCU_LPC1768) - #error "Oops! Make sure you have the LPC1768 environment selected in your IDE." +#if NOT_TARGET(MCU_LPC1768, MCU_LPC1769) + #if ENABLED(ALLOW_LPC1768_OR_9) + #error "Oops! Make sure you have the LPC1768 or LPC1769 environment selected in your IDE." + #elif ENABLED(REQUIRE_LPC1769) + #error "Oops! Make sure you have the LPC1769 environment selected in your IDE." + #else + #error "Oops! Make sure you have the LPC1768 environment selected in your IDE." + #endif #endif +#undef ALLOW_LPC1768_OR_9 #undef REQUIRE_LPC1769 -#endif +#endif // ENV_VALIDATE_H diff --git a/Marlin/src/pins/lpc1768/pins_MKS_SBASE.h b/Marlin/src/pins/lpc1768/pins_MKS_SBASE.h index 6bfc4c3c64..b028d49098 100644 --- a/Marlin/src/pins/lpc1768/pins_MKS_SBASE.h +++ b/Marlin/src/pins/lpc1768/pins_MKS_SBASE.h @@ -25,6 +25,7 @@ * Makerbase MKS SBASE pin assignments */ +#define ALLOW_LPC1768_OR_9 #include "env_validate.h" #ifndef BOARD_INFO_NAME diff --git a/Marlin/src/pins/lpc1769/env_validate.h b/Marlin/src/pins/lpc1769/env_validate.h index 0f62412453..1c6031a293 100644 --- a/Marlin/src/pins/lpc1769/env_validate.h +++ b/Marlin/src/pins/lpc1769/env_validate.h @@ -22,8 +22,12 @@ #ifndef ENV_VALIDATE_H #define ENV_VALIDATE_H -#if NOT_TARGET(MCU_LPC1769) +#if ENABLED(ALLOW_LPC1768_OR_9) && NOT_TARGET(MCU_LPC1768, MCU_LPC1769) + #error "Oops! Make sure you have the LPC1768 or LPC1769 environment selected in your IDE." +#elif NOT_TARGET(MCU_LPC1769) #error "Oops! Make sure you have the LPC1769 environment selected in your IDE." #endif -#endif +#undef ALLOW_LPC1768_OR_9 + +#endif // ENV_VALIDATE_H diff --git a/Marlin/src/pins/lpc1769/pins_SMOOTHIEBOARD.h b/Marlin/src/pins/lpc1769/pins_SMOOTHIEBOARD.h index fd9c1d94fd..062e572605 100644 --- a/Marlin/src/pins/lpc1769/pins_SMOOTHIEBOARD.h +++ b/Marlin/src/pins/lpc1769/pins_SMOOTHIEBOARD.h @@ -26,6 +26,7 @@ * See https://smoothieware.github.io/Webif-pack/documentation/web/html/smoothieboard.html */ +#define ALLOW_LPC1768_OR_9 #include "env_validate.h" #define BOARD_INFO_NAME "Smoothieboard" diff --git a/Marlin/src/pins/pins.h b/Marlin/src/pins/pins.h index eb26103380..aee437c245 100644 --- a/Marlin/src/pins/pins.h +++ b/Marlin/src/pins/pins.h @@ -458,7 +458,7 @@ #elif MB(RAMPS_14_RE_ARM_EFB, RAMPS_14_RE_ARM_EEB, RAMPS_14_RE_ARM_EFF, RAMPS_14_RE_ARM_EEF, RAMPS_14_RE_ARM_SF) #include "lpc1768/pins_RAMPS_RE_ARM.h" // LPC1768 env:LPC1768 #elif MB(MKS_SBASE) - #include "lpc1768/pins_MKS_SBASE.h" // LPC1768 env:LPC1768 + #include "lpc1768/pins_MKS_SBASE.h" // LPC1768/9 env:LPC1768 env:LPC1769 #elif MB(AZSMZ_MINI) #include "lpc1768/pins_AZSMZ_MINI.h" // LPC1768 env:LPC1768 #elif MB(BIQU_BQ111_A4) @@ -497,7 +497,7 @@ #elif MB(COHESION3D_MINI) #include "lpc1769/pins_COHESION3D_MINI.h" // LPC1769 env:LPC1769 #elif MB(SMOOTHIEBOARD) - #include "lpc1769/pins_SMOOTHIEBOARD.h" // LPC1769 env:LPC1769 + #include "lpc1769/pins_SMOOTHIEBOARD.h" // LPC1768/9 env:LPC1768 env:LPC1769 #elif MB(TH3D_EZBOARD) #include "lpc1769/pins_TH3D_EZBOARD.h" // LPC1769 env:LPC1769 #elif MB(BTT_SKR_V1_4_TURBO) From 36623a238291b7e6d6ca7fec1e537dc0b8d3bc6e Mon Sep 17 00:00:00 2001 From: ellensp <530024+ellensp@users.noreply.github.com> Date: Thu, 9 Jan 2025 11:44:31 +1300 Subject: [PATCH 018/787] =?UTF-8?q?=F0=9F=90=9B=20Fix=20config=20embed=20a?= =?UTF-8?q?nd=20restore=20(#27628)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Scott Lahteine --- buildroot/bin/config.py | 18 ++- buildroot/share/PlatformIO/scripts/config.py | 102 ++++++++++++ .../share/PlatformIO/scripts/mc-apply.py | 148 +++++++++++------- .../share/PlatformIO/scripts/signature.py | 16 +- 4 files changed, 215 insertions(+), 69 deletions(-) create mode 100755 buildroot/share/PlatformIO/scripts/config.py diff --git a/buildroot/bin/config.py b/buildroot/bin/config.py index b1a67ad965..980c6ecc65 100755 --- a/buildroot/bin/config.py +++ b/buildroot/bin/config.py @@ -1,5 +1,10 @@ ''' config.py - Helper functions for config manipulation + +Make sure both copies always match: + - buildroot/bin/config.py + - buildroot/share/PlatformIO/scripts/config.py + ''' import re @@ -17,24 +22,25 @@ def set(file_path, define_name, value): modified = False for i in range(len(content)): # Regex to match the desired pattern - match = re.match(r'^(\s*)(/*)(\s*)(#define\s+{})\s+(.*)$'.format(re.escape(define_name)), content[i]) + match = re.match(r'^(\s*)(/*)(\s*)(#define\s+{})\s+(.*?)\s*(//.*)?$'.format(re.escape(define_name)), content[i]) if match: - new_line = f"{match[1]}{match[3]}{match[4]} {value} // {match[5]}\n" - content[i] = new_line modified = True + comm = '' if match[6] is None else ' ' + match[6] + oldval = '' if match[5] is None else match[5] + if match[2] or value != oldval: + content[i] = f"{match[1]}{match[3]}{match[4]} {value} // {match[5]}{comm}\n" # Write the modified content back to the file only if changes were made if modified: with open(file_path, 'w') as f: f.writelines(content) - return True + return True return False def add(file_path, define_name, value=""): ''' Insert a define on the first blank line in a file. - Returns True if the define was found and replaced, False otherwise. ''' with open(file_path, 'r') as f: content = f.readlines() @@ -66,7 +72,7 @@ def enable(file_path, define_name, enable=True): content = f.readlines() # Prepare the regex - regex = re.compile(r'^(\s*)(/*)(\s*)(#define\s+{}\b.*?)( *//.*)?$'.format(re.escape(define_name))) + regex = re.compile(r'^(\s*)(/*)(\s*)(#define\s+{}\b.*?)(\s*//.*)?$'.format(re.escape(define_name))) # Find the define in the file and uncomment or comment it found = False diff --git a/buildroot/share/PlatformIO/scripts/config.py b/buildroot/share/PlatformIO/scripts/config.py new file mode 100755 index 0000000000..980c6ecc65 --- /dev/null +++ b/buildroot/share/PlatformIO/scripts/config.py @@ -0,0 +1,102 @@ +''' +config.py - Helper functions for config manipulation + +Make sure both copies always match: + - buildroot/bin/config.py + - buildroot/share/PlatformIO/scripts/config.py + +''' +import re + +FILES = ('Marlin/Configuration.h', 'Marlin/Configuration_adv.h') + +def set(file_path, define_name, value): + ''' + Replaces a define in a file with a new value. + Returns True if the define was found and replaced, False otherwise. + ''' + # Read the contents of the file + with open(file_path, 'r') as f: + content = f.readlines() + + modified = False + for i in range(len(content)): + # Regex to match the desired pattern + match = re.match(r'^(\s*)(/*)(\s*)(#define\s+{})\s+(.*?)\s*(//.*)?$'.format(re.escape(define_name)), content[i]) + if match: + modified = True + comm = '' if match[6] is None else ' ' + match[6] + oldval = '' if match[5] is None else match[5] + if match[2] or value != oldval: + content[i] = f"{match[1]}{match[3]}{match[4]} {value} // {match[5]}{comm}\n" + + # Write the modified content back to the file only if changes were made + if modified: + with open(file_path, 'w') as f: + f.writelines(content) + return True + + return False + +def add(file_path, define_name, value=""): + ''' + Insert a define on the first blank line in a file. + ''' + with open(file_path, 'r') as f: + content = f.readlines() + + # Prepend a space to the value if it's not empty + if value != "": + value = " " + value + + # Find the first blank line to insert the new define + for i in range(len(content)): + if content[i].strip() == '': + # Insert the define at the first blank line + content.insert(i, f"#define {define_name}{value}\n") + break + else: + # If no blank line is found, append to the end + content.append(f"#define {define_name}{value}\n") + + with open(file_path, 'w') as f: + f.writelines(content) + +def enable(file_path, define_name, enable=True): + ''' + Uncomment or comment the named defines in the given file path. + Returns True if the define was found, False otherwise. + ''' + # Read the contents of the file + with open(file_path, 'r') as f: + content = f.readlines() + + # Prepare the regex + regex = re.compile(r'^(\s*)(/*)(\s*)(#define\s+{}\b.*?)(\s*//.*)?$'.format(re.escape(define_name))) + + # Find the define in the file and uncomment or comment it + found = False + modified = False + for i in range(len(content)): + match = regex.match(content[i]) + if not match: continue + found = True + if enable: + if match[2]: + modified = True + comment = '' if match[5] is None else ' ' + match[5] + content[i] = f"{match[1]}{match[3]}{match[4]}{comment}\n" + else: + if not match[2]: + modified = True + comment = '' if match[5] is None else match[5] + if comment.startswith(' '): comment = comment[2:] + content[i] = f"{match[1]}//{match[3]}{match[4]}{comment}\n" + break + + # Write the modified content back to the file only if changes were made + if modified: + with open(file_path, 'w') as f: + f.writelines(content) + + return found diff --git a/buildroot/share/PlatformIO/scripts/mc-apply.py b/buildroot/share/PlatformIO/scripts/mc-apply.py index 0cfabab0f5..52d2ad6387 100755 --- a/buildroot/share/PlatformIO/scripts/mc-apply.py +++ b/buildroot/share/PlatformIO/scripts/mc-apply.py @@ -1,66 +1,100 @@ #!/usr/bin/env python # -# Create a Configuration from marlin_config.json +# mc-apply.py # -import json, sys, shutil +# Apply firmware configuration from a JSON file (marlin_config.json). +# +# usage: mc-apply.py [-h] [--opt] [config_file] +# +# Process Marlin firmware configuration. +# +# positional arguments: +# config_file Path to the configuration file. +# +# optional arguments: +# -h, --help show this help message and exit +# --opt Output as an option setting script. +# +import json, sys, os +import config +import argparse -opt_output = '--opt' in sys.argv -output_suffix = '.sh' if opt_output else '' if '--bare-output' in sys.argv else '.gen' +def report_version(conf): + if 'VERSION' in conf: + for k, v in sorted(conf['VERSION'].items()): + print(k + ': ' + v) -try: - with open('marlin_config.json', 'r') as infile: - conf = json.load(infile) - for key in conf: - # We don't care about the hash when restoring here - if key == '__INITIAL_HASH': +def write_opt_file(conf, outpath='Marlin/apply_config.sh'): + with open(outpath, 'w') as outfile: + for key, val in conf.items(): + if key in ('__INITIAL_HASH', 'VERSION'): continue + + # Other keys are assumed to be configs + if not type(val) is dict: continue - if key == 'VERSION': - for k, v in sorted(conf[key].items()): - print(k + ': ' + v) - continue - # The key is the file name, so let's build it now - outfile = open('Marlin/' + key + output_suffix, 'w') - for k, v in sorted(conf[key].items()): - # Make define line now - if opt_output: - if v != '': - if '"' in v: - v = "'%s'" % v - elif ' ' in v: - v = '"%s"' % v - define = 'opt_set ' + k + ' ' + v + '\n' - else: - define = 'opt_enable ' + k + '\n' + + # Write config commands to the script file + lines = [] + for k, v in sorted(val.items()): + if v != '': + v.replace('"', '\\"').replace("'", "\\'").replace(' ', '\\ ') + lines += [f'opt_set {k} {v}'] else: - define = '#define ' + k + ' ' + v + '\n' - outfile.write(define) - outfile.close() + lines += [f'opt_enable {k}'] - # Try to apply changes to the actual configuration file (in order to keep useful comments) - if output_suffix != '': - # Move the existing configuration so it doesn't interfere - shutil.move('Marlin/' + key, 'Marlin/' + key + '.orig') - infile_lines = open('Marlin/' + key + '.orig', 'r').read().split('\n') - outfile = open('Marlin/' + key, 'w') - for line in infile_lines: - sline = line.strip(" \t\n\r") - if sline[:7] == "#define": - # Extract the key here (we don't care about the value) - kv = sline[8:].strip().split(' ') - if kv[0] in conf[key]: - outfile.write('#define ' + kv[0] + ' ' + conf[key][kv[0]] + '\n') - # Remove the key from the dict, so we can still write all missing keys at the end of the file - del conf[key][kv[0]] - else: - outfile.write(line + '\n') - else: - outfile.write(line + '\n') - # Process any remaining defines here - for k, v in sorted(conf[key].items()): - define = '#define ' + k + ' ' + v + '\n' - outfile.write(define) - outfile.close() + outfile.write('\n'.join(lines)) - print('Output configuration written to: ' + 'Marlin/' + key + output_suffix) -except: - print('No marlin_config.json found.') + print('Config script written to: ' + outpath) + +def back_up_config(name): + # Back up the existing file before modifying it + conf_path = 'Marlin/' + name + with open(conf_path, 'r') as f: + # Write a filename.bak#.ext retaining the original extension + parts = conf_path.split('.') + nr = '' + while True: + bak_path = '.'.join(parts[:-1]) + f'.bak{nr}.' + parts[-1] + if os.path.exists(bak_path): + nr = 1 if nr == '' else nr + 1 + continue + + with open(bak_path, 'w') as b: + b.writelines(f.readlines()) + break + +def apply_config(conf): + for key in conf: + if key in ('__INITIAL_HASH', 'VERSION'): continue + + back_up_config(key) + + for k, v in conf[key].items(): + if v: + config.set('Marlin/' + key, k, v) + else: + config.enable('Marlin/' + key, k) + +def main(): + parser = argparse.ArgumentParser(description='Process Marlin firmware configuration.') + parser.add_argument('--opt', action='store_true', help='Output as an option setting script.') + parser.add_argument('config_file', nargs='?', default='marlin_config.json', help='Path to the configuration file.') + + args = parser.parse_args() + + try: + infile = open(args.config_file, 'r') + except: + print(f'No {args.config_file} found.') + sys.exit(1) + + conf = json.load(infile) + report_version(conf) + + if args.opt: + write_opt_file(conf) + else: + apply_config(conf) + +if __name__ == '__main__': + main() diff --git a/buildroot/share/PlatformIO/scripts/signature.py b/buildroot/share/PlatformIO/scripts/signature.py index f47d509bab..a5c92cff17 100755 --- a/buildroot/share/PlatformIO/scripts/signature.py +++ b/buildroot/share/PlatformIO/scripts/signature.py @@ -75,8 +75,8 @@ def get_file_sha256sum(filepath): # import zipfile def compress_file(filepath, storedname, outpath): - with zipfile.ZipFile(outpath, 'w', compression=zipfile.ZIP_BZIP2, compresslevel=9) as zipf: - zipf.write(filepath, arcname=storedname, compress_type=zipfile.ZIP_BZIP2, compresslevel=9) + with zipfile.ZipFile(outpath, 'w', compression=zipfile.ZIP_DEFLATED, allowZip64=False, compresslevel=9) as zipf: + zipf.write(filepath, arcname=storedname) ignore = ('CONFIGURATION_H_VERSION', 'CONFIGURATION_ADV_H_VERSION', 'CONFIG_EXAMPLES_DIR', 'CONFIG_EXPORT') @@ -161,7 +161,8 @@ def compute_build_signature(env): # # Continue to gather data for CONFIGURATION_EMBEDDING or CONFIG_EXPORT # - if not ('CONFIGURATION_EMBEDDING' in build_defines or 'CONFIG_EXPORT' in build_defines): + is_embed = 'CONFIGURATION_EMBEDDING' in build_defines + if not (is_embed or 'CONFIG_EXPORT' in build_defines): return # Filter out useless macros from the output @@ -450,7 +451,7 @@ f'''# # Produce a JSON file for CONFIGURATION_EMBEDDING or CONFIG_EXPORT == 1 or 101 # Skip if an identical JSON file was already present. # - if not same_hash and (config_dump == 1 or 'CONFIGURATION_EMBEDDING' in build_defines): + if not same_hash and (config_dump == 1 or is_embed): with marlin_json.open('w') as outfile: json_data = {} @@ -460,16 +461,19 @@ f'''# confs = real_config[header] json_data[header] = {} for name in confs: + if name in ignore: continue c = confs[name] s = c['section'] if s not in json_data[header]: json_data[header][s] = {} json_data[header][s][name] = c['value'] else: for header in real_config: + json_data[header] = {} conf = real_config[header] #print(f"real_config[{header}]", conf) for name in conf: - json_data[name] = conf[name]['value'] + if name in ignore: continue + json_data[header][name] = conf[name]['value'] json_data['__INITIAL_HASH'] = hashes @@ -489,7 +493,7 @@ f'''# # # The rest only applies to CONFIGURATION_EMBEDDING # - if not 'CONFIGURATION_EMBEDDING' in build_defines: + if not is_embed: (build_path / 'mc.zip').unlink(missing_ok=True) return From d57feeadaf161543ee26b9c4dab3d62afaaaacb8 Mon Sep 17 00:00:00 2001 From: Erik van Luijk Date: Wed, 8 Jan 2025 23:48:32 +0100 Subject: [PATCH 019/787] =?UTF-8?q?=F0=9F=90=9B=20Fix=20JG=20Aurora=20A1?= =?UTF-8?q?=20implementation=20(#27622)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/pins/stm32f1/pins_JGAURORA_A5S_A1.h | 2 +- .../PlatformIO/variants/MARLIN_F103Zx/start.S | 104 ++++++++++++++++++ ini/stm32f1.ini | 2 + 3 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 buildroot/share/PlatformIO/variants/MARLIN_F103Zx/start.S diff --git a/Marlin/src/pins/stm32f1/pins_JGAURORA_A5S_A1.h b/Marlin/src/pins/stm32f1/pins_JGAURORA_A5S_A1.h index 507372771e..497af7a8bd 100644 --- a/Marlin/src/pins/stm32f1/pins_JGAURORA_A5S_A1.h +++ b/Marlin/src/pins/stm32f1/pins_JGAURORA_A5S_A1.h @@ -49,7 +49,7 @@ // Enable EEPROM Emulation for this board, so that we don't overwrite factory data #if NO_EEPROM_SELECTED //#define I2C_EEPROM // AT24C64 - //#define FLASH_EEPROM_EMULATION + #define FLASH_EEPROM_EMULATION #endif #if ENABLED(I2C_EEPROM) diff --git a/buildroot/share/PlatformIO/variants/MARLIN_F103Zx/start.S b/buildroot/share/PlatformIO/variants/MARLIN_F103Zx/start.S new file mode 100644 index 0000000000..9a887e4ea2 --- /dev/null +++ b/buildroot/share/PlatformIO/variants/MARLIN_F103Zx/start.S @@ -0,0 +1,104 @@ +/** + *************** (C) COPYRIGHT 2017 STMicroelectronics ************************ + * @file startup_stm32f101xe.s + * @author MCD Application Team + * @brief STM32F101xE Value Line Devices vector table for Atollic toolchain. + * This module performs: + * - Set the initial SP + * - Set the initial PC == Reset_Handler, + * - Set the vector table entries with the exceptions ISR address + * - Configure the clock system + * - Branches to main in the C library (which eventually + * calls main()). + * After Reset the Cortex-M3 processor is in Thread mode, + * priority is Privileged, and the Stack is set to Main. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2017 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + + .syntax unified + .cpu cortex-m3 + .fpu softvfp + .thumb + +.global g_pfnVectors +.global Default_Handler + +/* start address for the initialization values of the .data section. +defined in linker script */ +.word _sidata +/* start address for the .data section. defined in linker script */ +.word _sdata +/* end address for the .data section. defined in linker script */ +.word _edata +/* start address for the .bss section. defined in linker script */ +.word _sbss +/* end address for the .bss section. defined in linker script */ +.word _ebss + +.equ BootRAM, 0xF1E0F85F +/** + * @brief This is the code that gets called when the processor first + * starts execution following a reset event. Only the absolutely + * necessary set is performed, after which the application + * supplied main() routine is called. + * @param None + * @retval : None +*/ + + .section .text.Reset_Handler + .weak Reset_Handler + .type Reset_Handler, %function +Reset_Handler: + + /* Disable SysTick interrupt (was enabled by jg aurora bootloader) */ + ldr r2,SysTick + movs r1, #0 + str r1, [r2] + /* Copy the data segment initializers from flash to SRAM */ + b LoopCopyDataInit +SysTick: + .word 0xE000E010 +CopyDataInit: + ldr r3, =_sidata + ldr r3, [r3, r1] + str r3, [r0, r1] + adds r1, r1, #4 + +LoopCopyDataInit: + ldr r0, =_sdata + ldr r3, =_edata + adds r2, r0, r1 + cmp r2, r3 + bcc CopyDataInit + ldr r2, =_sbss + b LoopFillZerobss +/* Zero fill the bss segment. */ +FillZerobss: + movs r3, #0 + str r3, [r2], #4 + +LoopFillZerobss: + ldr r3, = _ebss + cmp r2, r3 + bcc FillZerobss + +/* Call the clock system intitialization function.*/ + bl SystemInit +/* Call static constructors */ + bl __libc_init_array +/* Call the application's entry point.*/ + bl main + bx lr + +.size Reset_Handler, .-Reset_Handler diff --git a/ini/stm32f1.ini b/ini/stm32f1.ini index ef117eb269..86aeacdecd 100644 --- a/ini/stm32f1.ini +++ b/ini/stm32f1.ini @@ -364,6 +364,8 @@ board_build.offset = 0xA000 board_upload.offset_address = 0x0800A000 build_flags = ${stm32_variant.build_flags} -DSTM32F1xx -DSTM32_XL_DENSITY +build_unflags = ${stm32_variant.build_unflags} + -DUSBCON -DUSBD_USE_CDC extra_scripts = ${stm32_variant.extra_scripts} buildroot/share/PlatformIO/scripts/jgaurora_a5s_a1_with_bootloader.py From de76f2f21a7795123b2ac2c92b3f19aa3c0c4506 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Thu, 9 Jan 2025 00:27:38 +0000 Subject: [PATCH 020/787] [cron] Bump distribution date (2025-01-09) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index a524fbe07d..a1baf0b75e 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2024-12-18" +//#define STRING_DISTRIBUTION_DATE "2025-01-09" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 00da505168..e916f53b43 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2024-12-18" + #define STRING_DISTRIBUTION_DATE "2025-01-09" #endif /** From 22977c885baaf5af82208663a95b621ea1222c25 Mon Sep 17 00:00:00 2001 From: Chris <52449218+shadow578@users.noreply.github.com> Date: Thu, 9 Jan 2025 01:53:15 +0100 Subject: [PATCH 021/787] =?UTF-8?q?=E2=9C=A8=20Games=20for=20E3V2=20+=20Ma?= =?UTF-8?q?rlinUI=20(#27620)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/Configuration_adv.h | 12 +- Marlin/src/lcd/dogm/game.cpp | 80 ++++++ Marlin/src/lcd/dogm/game.h | 33 +++ Marlin/src/lcd/e3v2/common/dwin_api.cpp | 63 ++++- Marlin/src/lcd/e3v2/common/dwin_api.h | 18 ++ Marlin/src/lcd/e3v2/marlinui/game.cpp | 254 ++++++++++++++++++ Marlin/src/lcd/e3v2/marlinui/game.h | 85 ++++++ .../src/lcd/e3v2/marlinui/lcdprint_dwin.cpp | 4 +- Marlin/src/lcd/menu/game/brickout.cpp | 66 +++-- Marlin/src/lcd/menu/game/game.cpp | 16 +- Marlin/src/lcd/menu/game/game.h | 3 +- Marlin/src/lcd/menu/game/invaders.cpp | 86 ++++-- Marlin/src/lcd/menu/game/snake.cpp | 49 ++-- Marlin/src/lcd/menu/game/types.h | 128 ++++++++- buildroot/tests/STM32F103RE_creality | 5 +- 15 files changed, 808 insertions(+), 94 deletions(-) create mode 100644 Marlin/src/lcd/dogm/game.cpp create mode 100644 Marlin/src/lcd/dogm/game.h create mode 100644 Marlin/src/lcd/e3v2/marlinui/game.cpp create mode 100644 Marlin/src/lcd/e3v2/marlinui/game.h diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 806bafa2d0..c159add506 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -2035,17 +2035,17 @@ //#define STATUS_HEAT_PERCENT // Show heating in a progress bar //#define STATUS_HEAT_POWER // Show heater output power as a vertical bar - // Frivolous Game Options - //#define MARLIN_BRICKOUT - //#define MARLIN_INVADERS - //#define MARLIN_SNAKE - //#define GAMES_EASTER_EGG // Add extra blank lines above the "Games" sub-menu - #endif // HAS_MARLINUI_U8GLIB #if HAS_MARLINUI_U8GLIB || IS_DWIN_MARLINUI #define MENU_HOLLOW_FRAME // Enable to save many cycles by drawing a hollow frame on Menu Screens //#define OVERLAY_GFX_REVERSE // Swap the CW/CCW indicators in the graphics overlay + + // Frivolous Game Options + //#define MARLIN_BRICKOUT + //#define MARLIN_INVADERS + //#define MARLIN_SNAKE + //#define GAMES_EASTER_EGG // Add extra blank lines above the "Games" sub-menu #endif // diff --git a/Marlin/src/lcd/dogm/game.cpp b/Marlin/src/lcd/dogm/game.cpp new file mode 100644 index 0000000000..70e8783b49 --- /dev/null +++ b/Marlin/src/lcd/dogm/game.cpp @@ -0,0 +1,80 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#include "../../inc/MarlinConfigPre.h" + +#if HAS_MARLINUI_U8GLIB && HAS_GAMES + +#include "../menu/game/types.h" // includes dogm/game.h + +void MarlinGame::frame_start() { + set_color(color::WHITE); +} + +void MarlinGame::frame_end() {} + +void MarlinGame::set_color(const color color) { + switch (color) { + default: + case color::WHITE: u8g.setColorIndex(1); break; + case color::BLACK: u8g.setColorIndex(0); break; + } +} + +void MarlinGame::draw_hline(const game_dim_t x, const game_dim_t y, const game_dim_t w) { + u8g.drawHLine(x, y, w); +} + +void MarlinGame::draw_vline(const game_dim_t x, const game_dim_t y, const game_dim_t h) { + u8g.drawVLine(x, y, h); +} + +void MarlinGame::draw_frame(const game_dim_t x, const game_dim_t y, const game_dim_t w, const game_dim_t h) { + u8g.drawFrame(x, y, w, h); +} + +void MarlinGame::draw_box(const game_dim_t x, const game_dim_t y, const game_dim_t w, const game_dim_t h) { + u8g.drawBox(x, y, w, h); +} + +void MarlinGame::draw_pixel(const game_dim_t x, const game_dim_t y) { + u8g.drawPixel(x, y); +} + +void MarlinGame::draw_bitmap(const game_dim_t x, const game_dim_t y, const game_dim_t bytes_per_row, const game_dim_t rows, const pgm_bitmap_t bitmap) { + u8g.drawBitmapP(x, y, bytes_per_row, rows, bitmap); +} + +int MarlinGame::draw_string(const game_dim_t x, const game_dim_t y, const char* str) { + lcd_moveto(x, y); + return lcd_put_u8str_P(str); +} + +int MarlinGame::draw_string(const game_dim_t x, const game_dim_t y, FSTR_P const fstr) { + lcd_moveto(x, y); + return lcd_put_u8str(fstr); +} + +void MarlinGame::draw_int(const game_dim_t x, const game_dim_t y, const int value) { + lcd_put_int(x, y, value); +} + +#endif // HAS_MARLINUI_U8GLIB && HAS_GAMES diff --git a/Marlin/src/lcd/dogm/game.h b/Marlin/src/lcd/dogm/game.h new file mode 100644 index 0000000000..f577eac3d2 --- /dev/null +++ b/Marlin/src/lcd/dogm/game.h @@ -0,0 +1,33 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +#include "marlinui_DOGM.h" +#include "../lcdprint.h" + +typedef uint8_t game_dim_t; +typedef const u8g_pgm_uint8_t* pgm_bitmap_t; + +constexpr game_dim_t GAME_WIDTH = LCD_PIXEL_WIDTH; +constexpr game_dim_t GAME_HEIGHT = LCD_PIXEL_HEIGHT; +constexpr game_dim_t GAME_FONT_WIDTH = MENU_FONT_WIDTH; +constexpr game_dim_t GAME_FONT_ASCENT = MENU_FONT_ASCENT; diff --git a/Marlin/src/lcd/e3v2/common/dwin_api.cpp b/Marlin/src/lcd/e3v2/common/dwin_api.cpp index 4a93d304ca..132e8bbb76 100644 --- a/Marlin/src/lcd/e3v2/common/dwin_api.cpp +++ b/Marlin/src/lcd/e3v2/common/dwin_api.cpp @@ -158,6 +158,7 @@ void dwinFrameClear(const uint16_t color) { } #if DISABLED(TJC_DISPLAY) + // Draw a point // color: point color // width: point width 0x01-0x0F @@ -173,7 +174,67 @@ void dwinFrameClear(const uint16_t color) { dwinWord(i, y); dwinSend(i); } -#endif + + // Draw a map of multiple points using minimal amount of point drawing commands + // color: point color + // point_width: point width 0x01-0x0F + // point_height: point height 0x01-0x0F + // x,y: upper left point + // map_columns: columns in theh point map. each column is a byte in the map and contains 8 points + // map_rows: rows in the point map + // map: point bitmap. 2D array of points, 1 bit per point + // Note: somewhat similar to U8G's drawBitmap() function, see https://github.com/olikraus/u8glib/wiki/userreference#drawbitmap + void dwinDrawPointMap( + const uint16_t color, + const uint8_t point_width, const uint8_t point_height, + const uint16_t x, const uint16_t y, + const uint16_t map_columns, const uint16_t map_rows, + const uint8_t *map_data + ) { + // At how many bytes should we flush the send buffer? + // One byte is used (hidden) for F_HONE, and we need 4 bytes when appending a point. + // So we should flush the send buffer when we have less than 5 bytes left. + constexpr size_t flush_send_buffer_at = (COUNT(dwinSendBuf) - 1 - 4); + + // How long is the header of each draw command? + // => 1B CMD, 2B COLOR, 1B WIDTH, 1B HEIGHT + constexpr size_t command_header_size = 5; + + size_t i = 0; + for (uint16_t row = 0; row < map_rows; row++) { + for (uint16_t col = 0; col < map_columns; col++) { + const uint8_t map_byte = map_data[(row * map_columns) + col]; + for (uint8_t bit = 0; bit < 8; bit++) { + // Draw a point at this position? + if (TEST(map_byte, bit)) { + // Flush the send buffer and prepare next draw if either + // a) The buffer reached the 'should flush' state, or + // b) This is the first point to draw + if (i >= flush_send_buffer_at || i == 0) { + // Dispatch the current draw command + if (i > command_header_size) dwinSend(i); + + // Prepare the next draw command + i = 0; + dwinByte(i, 0x02); // cmd: draw point(s) + dwinWord(i, color); + dwinByte(i, point_width); + dwinByte(i, point_height); + } + + // Append point coordinates to draw command + dwinWord(i, x + (point_width * ((8 * col) + (7 - bit)))); // x + dwinWord(i, y + (point_height * (row))); // y + } + } + } + } + + // Dispatch final draw command if the buffer contains any points + if (i > command_header_size) dwinSend(i); + } + +#endif // !TJC_DISPLAY // Draw a line // color: Line segment color diff --git a/Marlin/src/lcd/e3v2/common/dwin_api.h b/Marlin/src/lcd/e3v2/common/dwin_api.h index 4878515032..bf50a78e2f 100644 --- a/Marlin/src/lcd/e3v2/common/dwin_api.h +++ b/Marlin/src/lcd/e3v2/common/dwin_api.h @@ -164,6 +164,24 @@ inline void dwinDrawBox(uint8_t mode, uint16_t color, uint16_t xStart, uint16_t void dwinDrawPoint(uint16_t color, uint8_t width, uint8_t height, uint16_t x, uint16_t y); #endif +// Draw a map of multiple points using minimal amount of point drawing commands +// color: point color +// point_width: point width 0x01-0x0F +// point_height: point height 0x01-0x0F +// x,y: upper left point +// map_columns: columns in theh point map. each column is a byte in the map and contains 8 points +// map_rows: rows in the point map +// map: point bitmap. 2D array of points, 1 bit per point +#if DISABLED(TJC_DISPLAY) + void dwinDrawPointMap( + const uint16_t color, + const uint8_t point_width, const uint8_t point_height, + const uint16_t x, const uint16_t y, + const uint16_t map_columns, const uint16_t map_rows, + const uint8_t *map_data + ); +#endif + // Move a screen area // mode: 0, circle shift; 1, translation // dir: 0=left, 1=right, 2=up, 3=down diff --git a/Marlin/src/lcd/e3v2/marlinui/game.cpp b/Marlin/src/lcd/e3v2/marlinui/game.cpp new file mode 100644 index 0000000000..eb15bd8108 --- /dev/null +++ b/Marlin/src/lcd/e3v2/marlinui/game.cpp @@ -0,0 +1,254 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#include "../../../inc/MarlinConfigPre.h" + +#if IS_DWIN_MARLINUI && HAS_GAMES + +// Enable performance counters (draw call count, frame timing) for debugging +//#define GAME_PERFORMANCE_COUNTERS + +#include "../../menu/game/types.h" // includes e3v2/marlinui/game.h +#include "../../lcdprint.h" +#include "lcdprint_dwin.h" +#include "marlinui_dwin.h" + +#if ENABLED(GAME_PERFORMANCE_COUNTERS) + + typedef struct { + /** + * Number of draw calls sent to the LCD + */ + uint32_t draw_calls; + + /** + * millis() value at the start of the current frame + */ + millis_t frame_draw_millis; + + /** + * millis() value at the end of the previous frame (in frame_start) + * or time spend waiting for the next frame (in frame_end) + */ + millis_t frame_wait_millis; + } dwin_game_perf_t; + + static dwin_game_perf_t dwin_game_perf; + + #define COUNT_DRAW_CALLS(n) dwin_game_perf.draw_calls += n + +#else // !GAME_PERFORMANCE_COUNTERS + + #define COUNT_DRAW_CALLS(...) NOOP + +#endif // !GAME_PERFORMANCE_COUNTERS + +void MarlinGame::frame_start() { + // Clear the screen before each frame + //dwinFrameClear(CLEAR_COLOR); + + // Instead of using dwinFrameClear, fill the play area with the background color + // This tends to be faster than clearing the whole screen + const uint16_t fg = dwin_font.fg; + dwin_font.fg = COLOR_BG_BLACK; + draw_box(0, 0, GAME_WIDTH, GAME_HEIGHT); + dwin_font.fg = fg; + + // Ensure the correct font is selected + dwin_font.index = DWIN_FONT_MENU; + + #if ENABLED(GAME_PERFORMANCE_COUNTERS) + // Reset draw call counters + dwin_game_perf.draw_calls = 0; + + // Update timing information + const millis_t now = millis(); + dwin_game_perf.frame_draw_millis = now; + dwin_game_perf.frame_wait_millis = now - dwin_game_perf.frame_wait_millis; + #endif +} + +void MarlinGame::frame_end() { + #if ENABLED(GAME_PERFORMANCE_COUNTERS) + const millis_t now = millis(); + const millis_t frame_wait_millis = dwin_game_perf.frame_wait_millis; + const millis_t frame_draw_millis = now - dwin_game_perf.frame_draw_millis; + + dwin_game_perf.frame_wait_millis = now; + + // Save previous font settings and set new ones + const uint16_t fg = dwin_font.fg; + const bool solid = dwin_font.solid; + set_color(color::YELLOW); + dwin_font.solid = true; + + // Draw performance counters information + char perf_str[32]; + sprintf_P( + perf_str, + PSTR("d%04lu w%04lu c%04lu"), + frame_draw_millis, + frame_wait_millis, + dwin_game_perf.draw_calls + ); + lcd_moveto_xy(0, 0); + lcd_put_u8str(perf_str); + + // Restore previous font settings + dwin_font.fg = fg; + dwin_font.solid = solid; + #endif // GAME_PERFORMANCE_COUNTERS +} + +void MarlinGame::set_color(const color color) { + switch (color) { + default: + case color::WHITE: dwin_font.fg = COLOR_WHITE; break; + case color::BLACK: dwin_font.fg = COLOR_BG_BLACK; break; + + // https://rgbcolorpicker.com/565/table + case color::RED: dwin_font.fg = RGB(0x1F, 0x00, 0x00); break; + case color::GREEN: dwin_font.fg = RGB(0x00, 0x3F, 0x00); break; + case color::BLUE: dwin_font.fg = RGB(0x00, 0x00, 0x1F); break; + case color::YELLOW: dwin_font.fg = RGB(0x1F, 0x3F, 0x00); break; + case color::CYAN: dwin_font.fg = RGB(0x00, 0x3F, 0x1F); break; + case color::MAGENTA:dwin_font.fg = RGB(0x1F, 0x00, 0x1F); break; + } +} + +void MarlinGame::draw_hline(const game_dim_t x, const game_dim_t y, const game_dim_t w) { + // Draw lines as boxes, since DWIN lines are always 1px wide but we want to scale them + draw_box(x, y, w, 1); + + COUNT_DRAW_CALLS(1); +} + +void MarlinGame::draw_vline(const game_dim_t x, const game_dim_t y, const game_dim_t h) { + // Draw lines as boxes, since DWIN lines are always 1px wide but we want to scale them + draw_box(x, y, 1, h); + + COUNT_DRAW_CALLS(1); +} + +void MarlinGame::draw_frame(const game_dim_t x, const game_dim_t y, const game_dim_t w, const game_dim_t h) { + dwinDrawBox( + 0, // mode = frame + dwin_font.fg, // color + dwin_game::game_to_screen(x) + dwin_game::x_offset, + dwin_game::game_to_screen(y) + dwin_game::y_offset, + dwin_game::game_to_screen(w), + dwin_game::game_to_screen(h) + ); + + COUNT_DRAW_CALLS(1); +} + +void MarlinGame::draw_box(const game_dim_t x, const game_dim_t y, const game_dim_t w, const game_dim_t h) { + dwinDrawBox( + 1, // mode = fill + dwin_font.fg, // color + dwin_game::game_to_screen(x) + dwin_game::x_offset, + dwin_game::game_to_screen(y) + dwin_game::y_offset, + dwin_game::game_to_screen(w), + dwin_game::game_to_screen(h) + ); + + COUNT_DRAW_CALLS(1); +} + +void MarlinGame::draw_pixel(const game_dim_t x, const game_dim_t y) { + // Draw pixels using boxes. + // While DWIN protocol supports drawing points with different sizes, the + // 0x02 'draw point' command is slower per pixel than 0x05 'fill rectangle' + // (0.4 us vs 0.14 us per pixel) + draw_box(x, y, 1, 1); +} + +void MarlinGame::draw_bitmap(const game_dim_t x, const game_dim_t y, const game_dim_t bytes_per_row, const game_dim_t rows, const pgm_bitmap_t bitmap) { + // DWIN theorethically supports bitmaps since kernel 2.1, but most screens don't support it + // (either because they use an older kernel version, or because they just (badly) emulate the DWIN protocol). + // So instead, we have to fall back to drawing points manually. + + #if DISABLED(TJC_DISPLAY) + + // DWIN T5UI actually supports drawing multiple points in one go using the 0x02 'draw point' command, ever since kernel 1.2. + // So we use that to draw the bitmap as a series of points, which is faster than drawing rectangles using draw_pixel. + dwinDrawPointMap( + dwin_font.fg, + dwin_game::game_to_screen(1), + dwin_game::game_to_screen(1), + dwin_game::game_to_screen(x) + dwin_game::x_offset, + dwin_game::game_to_screen(y) + dwin_game::y_offset, + bytes_per_row, + rows, + bitmap + ); + + COUNT_DRAW_CALLS(1); + + #else // TJC_DISPLAY + + // TJC displays don't seem to support the 0x02 'draw point' command, so instead we have to draw the bitmap + // as a series of rectangles using draw_pixel. + // This will absolutely suck for performance, but it's the best we can do on these screens. + for (game_dim_t row = 0; row < rows; row++) { + for (game_dim_t col = 0; col < bytes_per_row; col++) { + const uint8_t byte = bitmap[(row * bytes_per_row) + col]; + for (uint8_t bit = 0; bit < 8; bit++) { + // Assuming that the drawing area was cleared before drawing + if (byte & (1 << bit)) { + draw_pixel(x + (col * 8) + (7 - bit + 1), y + row); + COUNT_DRAW_CALLS(1); + } + } + } + } + + #endif // TJC_DISPLAY +} + +int MarlinGame::draw_string(const game_dim_t x, const game_dim_t y, const char* str) { + COUNT_DRAW_CALLS(1); + + lcd_moveto_xy( + dwin_game::game_to_screen(x) + dwin_game::x_offset, + dwin_game::game_to_screen(y) + dwin_game::y_offset + ); + + return lcd_put_u8str_max_P(str, PIXEL_LEN_NOLIMIT); +} + +int MarlinGame::draw_string(const game_dim_t x, const game_dim_t y, FSTR_P const str) { + return draw_string(x, y, FTOP(str)); +} + +void MarlinGame::draw_int(const game_dim_t x, const game_dim_t y, const int value) { + COUNT_DRAW_CALLS(1); + + lcd_moveto_xy( + dwin_game::game_to_screen(x) + dwin_game::x_offset, + dwin_game::game_to_screen(y) + dwin_game::y_offset + ); + + lcd_put_int(value); +} + +#endif // IS_DWIN_MARLINUI && HAS_GAMES diff --git a/Marlin/src/lcd/e3v2/marlinui/game.h b/Marlin/src/lcd/e3v2/marlinui/game.h new file mode 100644 index 0000000000..edc0fc3ea9 --- /dev/null +++ b/Marlin/src/lcd/e3v2/marlinui/game.h @@ -0,0 +1,85 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +#include "../marlinui/marlinui_dwin.h" + +typedef uint8_t game_dim_t; +typedef uint16_t screen_dim_t; +typedef const uint8_t* pgm_bitmap_t; + +namespace dwin_game { + /** + * @brief Target the renderer at 128x64 pixels to match U8G screens + */ + constexpr screen_dim_t TARGET_WIDTH = 128; + constexpr screen_dim_t TARGET_HEIGHT = 64; + + constexpr int calculate_scale() { + // Use whichever is smaller: the width or height scaling factor + float scaling_factor = _MIN( + static_cast(DWIN_WIDTH) / static_cast(TARGET_WIDTH), + static_cast(DWIN_HEIGHT) / static_cast(TARGET_HEIGHT) + ); + + // Round DOWN to closest integer + return static_cast(scaling_factor); + } + + /** + * @brief Game render scale. + */ + constexpr int scale = calculate_scale(); + + /** + * @brief Scale a game dimension to screen dimensions + */ + constexpr game_dim_t screen_to_game(const screen_dim_t x) { + return x / scale; + } + + /** + * @brief Scale a screen dimension to game dimensions + */ + constexpr screen_dim_t game_to_screen(const game_dim_t x) { + return x * scale; + } + + /** + * @brief Offset of the game window on the screen. Applied after scaling. + */ + constexpr screen_dim_t x_offset = (DWIN_WIDTH - game_to_screen(TARGET_WIDTH)) / 2; + constexpr screen_dim_t y_offset = (DWIN_HEIGHT - game_to_screen(TARGET_HEIGHT)) / 2; + + static_assert(game_to_screen(TARGET_WIDTH) + (x_offset * 2) <= DWIN_WIDTH, "DWIN game renderer failed to auto-scale, is too wide"); + static_assert(game_to_screen(TARGET_HEIGHT) + (y_offset * 2) <= DWIN_HEIGHT, "DWIN game renderer failed to auto-scale, is too high"); +} // namespace dwin_game + +constexpr game_dim_t GAME_WIDTH = dwin_game::screen_to_game(DWIN_WIDTH - (dwin_game::x_offset * 2)); +constexpr game_dim_t GAME_HEIGHT = dwin_game::screen_to_game(DWIN_HEIGHT - (dwin_game::y_offset * 2)); +constexpr game_dim_t GAME_FONT_WIDTH = dwin_game::screen_to_game(MENU_FONT_WIDTH); +constexpr game_dim_t GAME_FONT_ASCENT = dwin_game::screen_to_game(MENU_FONT_ASCENT); + +// DWIN screens don't page, so these macros are always true +#define PAGE_OVER(ya) true +#define PAGE_UNDER(yb) true +#define PAGE_CONTAINS(ya, yb) true diff --git a/Marlin/src/lcd/e3v2/marlinui/lcdprint_dwin.cpp b/Marlin/src/lcd/e3v2/marlinui/lcdprint_dwin.cpp index f689a6ff69..9fa75a700b 100644 --- a/Marlin/src/lcd/e3v2/marlinui/lcdprint_dwin.cpp +++ b/Marlin/src/lcd/e3v2/marlinui/lcdprint_dwin.cpp @@ -52,7 +52,9 @@ void lcd_moveto(const lcd_uint_t col, const lcd_uint_t row) { inline void lcd_advance_cursor(const uint8_t len=1) { cursor.x += len * dwin_font.width; } void lcd_put_int(const int i) { - // TODO: Draw an int at the cursor position, advance the cursor + char buf[12]; // 10 digits + sign + null + itoa(i, buf, 10); + lcd_put_u8str_max(buf, PIXEL_LEN_NOLIMIT); } int lcd_put_dwin_string() { diff --git a/Marlin/src/lcd/menu/game/brickout.cpp b/Marlin/src/lcd/menu/game/brickout.cpp index 078cbbccee..061e4e89c8 100644 --- a/Marlin/src/lcd/menu/game/brickout.cpp +++ b/Marlin/src/lcd/menu/game/brickout.cpp @@ -27,14 +27,14 @@ #include "game.h" #define BRICK_H 5 -#define BRICK_TOP MENU_FONT_ASCENT +#define BRICK_TOP GAME_FONT_ASCENT #define PADDLE_H 2 #define PADDLE_VEL 3 -#define PADDLE_W ((LCD_PIXEL_WIDTH) / 8) -#define PADDLE_Y (LCD_PIXEL_HEIGHT - 1 - PADDLE_H) +#define PADDLE_W ((GAME_WIDTH) / 8) +#define PADDLE_Y (GAME_HEIGHT - 1 - PADDLE_H) -#define BRICK_W ((LCD_PIXEL_WIDTH) / (BRICK_COLS)) +#define BRICK_W ((GAME_WIDTH) / (BRICK_COLS)) #define BRICK_BOT (BRICK_TOP + BRICK_H * BRICK_ROWS - 1) #define BRICK_COL(X) ((X) / (BRICK_W)) @@ -53,7 +53,7 @@ void reset_ball() { bdat.ballv = FTOF(1.3f); bdat.ballh = -FTOF(1.25f); uint8_t bx = bdat.paddle_x + (PADDLE_W) / 2 + ball_dist; - if (bx >= LCD_PIXEL_WIDTH - 10) { bx -= ball_dist * 2; bdat.ballh = -bdat.ballh; } + if (bx >= GAME_WIDTH - 10) { bx -= ball_dist * 2; bdat.ballh = -bdat.ballh; } bdat.ballx = BTOF(bx); bdat.hit_dir = -1; } @@ -61,7 +61,7 @@ void reset_ball() { void BrickoutGame::game_screen() { if (game_frame()) { // Run logic twice for finer resolution // Update Paddle Position - bdat.paddle_x = constrain(int8_t(ui.encoderPosition), 0, (LCD_PIXEL_WIDTH - (PADDLE_W)) / (PADDLE_VEL)); + bdat.paddle_x = constrain(int8_t(ui.encoderPosition), 0, (GAME_WIDTH - (PADDLE_W)) / (PADDLE_VEL)); ui.encoderPosition = bdat.paddle_x; bdat.paddle_x *= (PADDLE_VEL); @@ -70,7 +70,7 @@ void BrickoutGame::game_screen() { // Provisionally update the ball position const fixed_t newx = bdat.ballx + bdat.ballh, newy = bdat.bally + bdat.ballv; // current next position - if (!WITHIN(newx, 0, BTOF(LCD_PIXEL_WIDTH - 1))) { // out in x? + if (!WITHIN(newx, 0, BTOF(GAME_WIDTH - 1))) { // out in x? bdat.ballh = -bdat.ballh; _BUZZ(5, 220); // bounce x } if (newy < 0) { // out in y? @@ -78,7 +78,7 @@ void BrickoutGame::game_screen() { bdat.hit_dir = 1; } // Did the ball go below the bottom? - else if (newy > BTOF(LCD_PIXEL_HEIGHT)) { + else if (newy > BTOF(GAME_HEIGHT)) { _BUZZ(500, 75); if (--bdat.balls_left) reset_ball(); else game_state = 0; break; // done @@ -134,32 +134,51 @@ void BrickoutGame::game_screen() { } while (false); } - u8g.setColorIndex(1); + frame_start(); - // Draw bricks + // Draw bricks, cycling through colors for each brick + #if IS_DWIN_MARLINUI + const color brick_colors[] = { color::RED, color::CYAN, color::GREEN, color::YELLOW, color::MAGENTA, color::BLUE }; + int color_index = 0; + #endif if (PAGE_CONTAINS(BRICK_TOP, BRICK_BOT)) { for (uint8_t y = 0; y < BRICK_ROWS; ++y) { const uint8_t yy = y * BRICK_H + BRICK_TOP; if (PAGE_CONTAINS(yy, yy + BRICK_H - 1)) { for (uint8_t x = 0; x < BRICK_COLS; ++x) { + #if IS_DWIN_MARLINUI + // Cycle through colors, even if the brick is gone. + // Otherwise, bricks would change color if their neighbor is hit + set_color(brick_colors[color_index++ % COUNT(brick_colors)]); + #endif + + // Draw brick if it's still there if (TEST(bdat.bricks[y], x)) { const uint8_t xx = x * BRICK_W; - for (uint8_t v = 0; v < BRICK_H - 1; ++v) - if (PAGE_CONTAINS(yy + v, yy + v)) - u8g.drawHLine(xx, yy + v, BRICK_W - 1); + #if IS_DWIN_MARLINUI + if (PAGE_CONTAINS(yy, yy + BRICK_H - 1)) + draw_box(xx, yy, BRICK_W - 1, BRICK_H - 1); + #else + for (uint8_t v = 0; v < BRICK_H - 1; ++v) + if (PAGE_CONTAINS(yy + v, yy + v)) + u8g.drawHLine(xx, yy + v, BRICK_W - 1); + #endif } } } } } + // Everything else is white + TERN_(IS_DWIN_MARLINUI, set_color(color::WHITE)); + // Draw paddle if (PAGE_CONTAINS(PADDLE_Y-1, PADDLE_Y)) { - u8g.drawHLine(bdat.paddle_x, PADDLE_Y, PADDLE_W); + draw_hline(bdat.paddle_x, PADDLE_Y, PADDLE_W); #if PADDLE_H > 1 - u8g.drawHLine(bdat.paddle_x, PADDLE_Y-1, PADDLE_W); + draw_hline(bdat.paddle_x, PADDLE_Y-1, PADDLE_W); #if PADDLE_H > 2 - u8g.drawHLine(bdat.paddle_x, PADDLE_Y-2, PADDLE_W); + draw_hline(bdat.paddle_x, PADDLE_Y-2, PADDLE_W); #endif #endif } @@ -168,29 +187,30 @@ void BrickoutGame::game_screen() { if (game_state) { const uint8_t by = FTOB(bdat.bally); if (PAGE_CONTAINS(by, by+1)) - u8g.drawFrame(FTOB(bdat.ballx), by, 2, 2); + draw_frame(FTOB(bdat.ballx), by, 2, 2); } // Or draw GAME OVER else draw_game_over(); - if (PAGE_UNDER(MENU_FONT_ASCENT)) { + if (PAGE_UNDER(GAME_FONT_ASCENT)) { // Score Digits - //const uint8_t sx = (LCD_PIXEL_WIDTH - (score >= 10 ? score >= 100 ? score >= 1000 ? 4 : 3 : 2 : 1) * MENU_FONT_WIDTH) / 2; + //const uint8_t sx = (GAME_WIDTH - (score >= 10 ? score >= 100 ? score >= 1000 ? 4 : 3 : 2 : 1) * GAME_FONT_WIDTH) / 2; constexpr uint8_t sx = 0; - lcd_put_int(sx, MENU_FONT_ASCENT - 1, score); + draw_int(sx, GAME_FONT_ASCENT - 1, score); // Balls Left - lcd_moveto(LCD_PIXEL_WIDTH - MENU_FONT_WIDTH * 3, MENU_FONT_ASCENT - 1); PGM_P const ohs = PSTR("ooo\0\0"); - lcd_put_u8str_P(ohs + 3 - bdat.balls_left); + draw_string(GAME_WIDTH - GAME_FONT_WIDTH * 3, GAME_FONT_ASCENT - 1, ohs + 3 - bdat.balls_left); } + frame_end(); + // A click always exits this game if (ui.use_click()) exit_game(); } -#define SCREEN_M ((LCD_PIXEL_WIDTH) / 2) +#define SCREEN_M ((GAME_WIDTH) / 2) void BrickoutGame::enter_game() { init_game(2, game_screen); // 2 = reset bricks on paddle hit diff --git a/Marlin/src/lcd/menu/game/game.cpp b/Marlin/src/lcd/menu/game/game.cpp index d465b00388..933e2e8e66 100644 --- a/Marlin/src/lcd/menu/game/game.cpp +++ b/Marlin/src/lcd/menu/game/game.cpp @@ -40,15 +40,15 @@ bool MarlinGame::game_frame() { } void MarlinGame::draw_game_over() { - constexpr int8_t gowide = (MENU_FONT_WIDTH) * 9, - gohigh = MENU_FONT_ASCENT - 3, - lx = (LCD_PIXEL_WIDTH - gowide) / 2, - ly = (LCD_PIXEL_HEIGHT + gohigh) / 2; + constexpr int8_t gowide = (GAME_FONT_WIDTH) * 9, + gohigh = GAME_FONT_ASCENT - 3, + lx = (GAME_WIDTH - gowide) / 2, + ly = (GAME_HEIGHT + gohigh) / 2; if (PAGE_CONTAINS(ly - gohigh - 1, ly + 1)) { - u8g.setColorIndex(0); - u8g.drawBox(lx - 1, ly - gohigh - 1, gowide + 2, gohigh + 2); - u8g.setColorIndex(1); - if (ui.get_blink()) lcd_put_u8str(lx, ly, F("GAME OVER")); + set_color(color::BLACK); + draw_box(lx - 1, ly - gohigh - 1, gowide + 2, gohigh + 2); + set_color(color::WHITE); + if (ui.get_blink()) draw_string(lx, ly, F("GAME OVER")); } } diff --git a/Marlin/src/lcd/menu/game/game.h b/Marlin/src/lcd/menu/game/game.h index ba123cb98b..2e9d55b1a5 100644 --- a/Marlin/src/lcd/menu/game/game.h +++ b/Marlin/src/lcd/menu/game/game.h @@ -22,9 +22,8 @@ #pragma once #include "../../../inc/MarlinConfigPre.h" -#include "../../dogm/marlinui_DOGM.h" -#include "../../lcdprint.h" #include "../../marlinui.h" +#include "types.h" //#define MUTE_GAMES diff --git a/Marlin/src/lcd/menu/game/invaders.cpp b/Marlin/src/lcd/menu/game/invaders.cpp index 588523854f..330ead081e 100644 --- a/Marlin/src/lcd/menu/game/invaders.cpp +++ b/Marlin/src/lcd/menu/game/invaders.cpp @@ -29,11 +29,11 @@ #define CANNON_W 11 #define CANNON_H 8 #define CANNON_VEL 4 -#define CANNON_Y (LCD_PIXEL_HEIGHT - 1 - CANNON_H) +#define CANNON_Y (GAME_HEIGHT - 1 - CANNON_H) #define INVADER_VEL 3 -#define INVADER_TOP MENU_FONT_ASCENT +#define INVADER_TOP GAME_FONT_ASCENT #define INVADERS_WIDE ((INVADER_COL_W) * (INVADER_COLS)) #define INVADERS_HIGH ((INVADER_ROW_H) * (INVADER_ROWS)) @@ -48,6 +48,16 @@ #define INVADER_RIGHT ((INVADER_COLS) * (INVADER_COL_W)) +#if IS_DWIN_MARLINUI + #define INVADER_COLOR { MarlinGame::color::GREEN, MarlinGame::color::CYAN, MarlinGame::color::YELLOW } + #define CANNON_COLOR MarlinGame::color::WHITE + #define LASER_COLOR MarlinGame::color::WHITE // Shot by player + #define BULLET_COLOR LASER_COLOR // Shot by invader + #define LIFE_COLOR CANNON_COLOR + #define UFO_COLOR MarlinGame::color::MAGENTA + #define EXPLOSION_COLOR MarlinGame::color::RED +#endif + // 11x8 const unsigned char invader[3][2][16] PROGMEM = { { { B00000110,B00000000, @@ -175,7 +185,7 @@ inline void update_invader_data() { } idat.leftmost = 0; for (uint8_t i = 0; i < INVADER_COLS; ++i) { if (TEST(inv_mask, i)) break; idat.leftmost -= INVADER_COL_W; } - idat.rightmost = LCD_PIXEL_WIDTH - (INVADERS_WIDE); + idat.rightmost = GAME_WIDTH - (INVADERS_WIDE); for (uint8_t i = INVADER_COLS; i--;) { if (TEST(inv_mask, i)) break; idat.rightmost += INVADER_COL_W; } if (idat.count == 2) idat.dir = idat.dir > 0 ? INVADER_VEL + 1 : -(INVADER_VEL + 1); } @@ -195,7 +205,7 @@ inline void reset_invaders() { inline void spawn_ufo() { idat.ufov = random(0, 2) ? 1 : -1; - idat.ufox = idat.ufov > 0 ? -(UFO_W) : LCD_PIXEL_WIDTH - 1; + idat.ufox = idat.ufov > 0 ? -(UFO_W) : GAME_WIDTH - 1; } inline void reset_player() { @@ -205,7 +215,7 @@ inline void reset_player() { inline void fire_cannon() { idat.laser.x = idat.cannon_x + CANNON_W / 2; - idat.laser.y = LCD_PIXEL_HEIGHT - CANNON_H - (LASER_H); + idat.laser.y = GAME_HEIGHT - CANNON_H - (LASER_H); idat.laser.v = -(LASER_H); } @@ -235,7 +245,7 @@ void InvadersGame::game_screen() { if (ui.first_page) { // Update Cannon Position - int16_t ep = constrain(int16_t(ui.encoderPosition), 0, (LCD_PIXEL_WIDTH - (CANNON_W)) / (CANNON_VEL)); + int16_t ep = constrain(int16_t(ui.encoderPosition), 0, (GAME_WIDTH - (CANNON_W)) / (CANNON_VEL)); ui.encoderPosition = ep; ep *= (CANNON_VEL); @@ -246,7 +256,7 @@ void InvadersGame::game_screen() { if (game_state) do { // Move the UFO, if any - if (idat.ufov) { idat.ufox += idat.ufov; if (!WITHIN(idat.ufox, -(UFO_W), LCD_PIXEL_WIDTH - 1)) idat.ufov = 0; } + if (idat.ufov) { idat.ufox += idat.ufov; if (!WITHIN(idat.ufox, -(UFO_W), GAME_WIDTH - 1)) idat.ufov = 0; } if (game_state > 1) { if (--game_state == 2) { reset_invaders(); } else if (game_state == 100) { game_state = 1; } break; } @@ -326,7 +336,7 @@ void InvadersGame::game_screen() { if (b->v) { // Update alien bullet position b->y += b->v; - if (b->y >= LCD_PIXEL_HEIGHT) + if (b->y >= GAME_HEIGHT) b->v = 0; // Offscreen else if (b->y >= CANNON_Y && WITHIN(b->x, idat.cannon_x, idat.cannon_x + CANNON_W - 1)) kill_cannon(game_state, 120); // Hit the cannon @@ -365,7 +375,7 @@ void InvadersGame::game_screen() { if (!idat.quit_count) exit_game(); - u8g.setColorIndex(1); + frame_start(); // Draw invaders if (PAGE_CONTAINS(idat.pos.y, idat.pos.y + idat.botmost * (INVADER_ROW_H) - 2 - 1)) { @@ -375,8 +385,13 @@ void InvadersGame::game_screen() { if (PAGE_CONTAINS(yy, yy + INVADER_H - 1)) { int8_t xx = idat.pos.x; for (uint8_t x = 0; x < INVADER_COLS; ++x) { - if (TEST(idat.bugs[y], x)) - u8g.drawBitmapP(xx, yy, 2, INVADER_H, invader[type][idat.game_blink]); + if (TEST(idat.bugs[y], x)) { + #if IS_DWIN_MARLINUI + constexpr color invader_color[] = INVADER_COLOR; + set_color(invader_color[type]); + #endif + draw_bitmap(xx, yy, 2, INVADER_H, invader[type][idat.game_blink]); + } xx += INVADER_COL_W; } } @@ -385,44 +400,59 @@ void InvadersGame::game_screen() { } // Draw UFO - if (idat.ufov && PAGE_UNDER(UFO_H + 2)) - u8g.drawBitmapP(idat.ufox, 2, 2, UFO_H, ufo); + if (idat.ufov && PAGE_UNDER(UFO_H + 2)) { + TERN_(IS_DWIN_MARLINUI, set_color(UFO_COLOR)); + draw_bitmap(idat.ufox, 2, 2, UFO_H, ufo); + } // Draw cannon - if (game_state && PAGE_CONTAINS(CANNON_Y, CANNON_Y + CANNON_H - 1) && (game_state < 2 || (game_state & 0x02))) - u8g.drawBitmapP(idat.cannon_x, CANNON_Y, 2, CANNON_H, cannon); + if (game_state && PAGE_CONTAINS(CANNON_Y, CANNON_Y + CANNON_H - 1) && (game_state < 2 || (game_state & 0x02))) { + TERN_(IS_DWIN_MARLINUI, set_color(CANNON_COLOR)); + draw_bitmap(idat.cannon_x, CANNON_Y, 2, CANNON_H, cannon); + } // Draw laser - if (idat.laser.v && PAGE_CONTAINS(idat.laser.y, idat.laser.y + LASER_H - 1)) - u8g.drawVLine(idat.laser.x, idat.laser.y, LASER_H); + if (idat.laser.v && PAGE_CONTAINS(idat.laser.y, idat.laser.y + LASER_H - 1)) { + TERN_(IS_DWIN_MARLINUI, set_color(LASER_COLOR)); + draw_vline(idat.laser.x, idat.laser.y, LASER_H); + } // Draw invader bullets for (uint8_t i = 0; i < COUNT(idat.bullet); ++i) { - if (idat.bullet[i].v && PAGE_CONTAINS(idat.bullet[i].y - (SHOT_H - 1), idat.bullet[i].y)) - u8g.drawVLine(idat.bullet[i].x, idat.bullet[i].y - (SHOT_H - 1), SHOT_H); + if (idat.bullet[i].v && PAGE_CONTAINS(idat.bullet[i].y - (SHOT_H - 1), idat.bullet[i].y)) { + TERN_(IS_DWIN_MARLINUI, set_color(BULLET_COLOR)); + draw_vline(idat.bullet[i].x, idat.bullet[i].y - (SHOT_H - 1), SHOT_H); + } } // Draw explosion if (idat.explod.v && PAGE_CONTAINS(idat.explod.y, idat.explod.y + 7 - 1)) { - u8g.drawBitmapP(idat.explod.x, idat.explod.y, 2, 7, explosion); + TERN_(IS_DWIN_MARLINUI, set_color(EXPLOSION_COLOR)); + draw_bitmap(idat.explod.x, idat.explod.y, 2, 7, explosion); --idat.explod.v; } + // Everything else is white + TERN_(IS_DWIN_MARLINUI, set_color(color::WHITE)); + // Blink GAME OVER when game is over if (!game_state) draw_game_over(); - if (PAGE_UNDER(MENU_FONT_ASCENT - 1)) { - // Draw Score - //const uint8_t sx = (LCD_PIXEL_WIDTH - (score >= 10 ? score >= 100 ? score >= 1000 ? 4 : 3 : 2 : 1) * MENU_FONT_WIDTH) / 2; - constexpr uint8_t sx = 0; - lcd_put_int(sx, MENU_FONT_ASCENT - 1, score); - + if (PAGE_UNDER(GAME_FONT_ASCENT - 1)) { // Draw lives if (idat.cannons_left) - for (uint8_t i = 1; i <= idat.cannons_left; ++i) - u8g.drawBitmapP(LCD_PIXEL_WIDTH - i * (LIFE_W), 6 - (LIFE_H), 1, LIFE_H, life); + for (uint8_t i = 1; i <= idat.cannons_left; ++i) { + TERN_(IS_DWIN_MARLINUI, set_color(LIFE_COLOR)); + draw_bitmap(GAME_WIDTH - i * (LIFE_W), 6 - (LIFE_H), 1, LIFE_H, life); + } + + // Draw Score + //const uint8_t sx = (GAME_WIDTH - (score >= 10 ? score >= 100 ? score >= 1000 ? 4 : 3 : 2 : 1) * GAME_FONT_WIDTH) / 2; + constexpr uint8_t sx = 0; + draw_int(sx, GAME_FONT_ASCENT - 1, score); } + frame_end(); } void InvadersGame::enter_game() { diff --git a/Marlin/src/lcd/menu/game/snake.cpp b/Marlin/src/lcd/menu/game/snake.cpp index 2a78c089cf..80d833a1cf 100644 --- a/Marlin/src/lcd/menu/game/snake.cpp +++ b/Marlin/src/lcd/menu/game/snake.cpp @@ -28,13 +28,13 @@ #define SNAKE_BOX 4 -#define HEADER_H (MENU_FONT_ASCENT - 2) +#define HEADER_H (GAME_FONT_ASCENT - 2) #define SNAKE_WH (SNAKE_BOX + 1) #define IDEAL_L 2 -#define IDEAL_R (LCD_PIXEL_WIDTH - 1 - 2) +#define IDEAL_R (GAME_WIDTH - 1 - 2) #define IDEAL_T (HEADER_H + 2) -#define IDEAL_B (LCD_PIXEL_HEIGHT - 1 - 2) +#define IDEAL_B (GAME_HEIGHT - 1 - 2) #define IDEAL_W (IDEAL_R - (IDEAL_L) + 1) #define IDEAL_H (IDEAL_B - (IDEAL_T) + 1) @@ -43,9 +43,9 @@ #define BOARD_W ((SNAKE_WH) * (GAME_W) + 1) #define BOARD_H ((SNAKE_WH) * (GAME_H) + 1) -#define BOARD_L ((LCD_PIXEL_WIDTH - (BOARD_W) + 1) / 2) +#define BOARD_L ((GAME_WIDTH - (BOARD_W) + 1) / 2) #define BOARD_R (BOARD_L + BOARD_W - 1) -#define BOARD_T (((LCD_PIXEL_HEIGHT + IDEAL_T) - (BOARD_H)) / 2) +#define BOARD_T (((GAME_HEIGHT + IDEAL_T) - (BOARD_H)) / 2) #define BOARD_B (BOARD_T + BOARD_H - 1) #define GAMEX(X) (BOARD_L + ((X) * (SNAKE_WH))) @@ -228,15 +228,10 @@ void SnakeGame::game_screen() { } while(0); - u8g.setColorIndex(1); + frame_start(); - // Draw Score - if (PAGE_UNDER(HEADER_H)) lcd_put_int(0, HEADER_H - 1, score); - - // DRAW THE PLAYFIELD BORDER - u8g.drawFrame(BOARD_L - 2, BOARD_T - 2, BOARD_R - BOARD_L + 4, BOARD_B - BOARD_T + 4); - - // Draw the snake (tail) + // Draw the snake (tail) in green + TERN_(IS_DWIN_MARLINUI, set_color(color::GREEN)); #if SNAKE_WH < 2 // At this scale just draw a line @@ -245,11 +240,11 @@ void SnakeGame::game_screen() { if (p.x == q.x) { const int8_t y1 = GAMEY(_MIN(p.y, q.y)), y2 = GAMEY(_MAX(p.y, q.y)); if (PAGE_CONTAINS(y1, y2)) - u8g.drawVLine(GAMEX(p.x), y1, y2 - y1 + 1); + draw_vline(GAMEX(p.x), y1, y2 - y1 + 1); } else if (PAGE_CONTAINS(GAMEY(p.y), GAMEY(p.y))) { const int8_t x1 = GAMEX(_MIN(p.x, q.x)), x2 = GAMEX(_MAX(p.x, q.x)); - u8g.drawHLine(x1, GAMEY(p.y), x2 - x1 + 1); + draw_hline(x1, GAMEY(p.y), x2 - x1 + 1); } } @@ -261,13 +256,13 @@ void SnakeGame::game_screen() { if (p.x == q.x) { const int8_t y1 = GAMEY(_MIN(p.y, q.y)), y2 = GAMEY(_MAX(p.y, q.y)); if (PAGE_CONTAINS(y1, y2 + 1)) - u8g.drawFrame(GAMEX(p.x), y1, 2, y2 - y1 + 1 + 1); + draw_frame(GAMEX(p.x), y1, 2, y2 - y1 + 1 + 1); } else { const int8_t py = GAMEY(p.y); if (PAGE_CONTAINS(py, py + 1)) { const int8_t x1 = GAMEX(_MIN(p.x, q.x)), x2 = GAMEX(_MAX(p.x, q.x)); - u8g.drawFrame(x1, py, x2 - x1 + 1 + 1, 2); + draw_frame(x1, py, x2 - x1 + 1 + 1, 2); } } } @@ -283,7 +278,7 @@ void SnakeGame::game_screen() { for (int8_t i = y1; i <= y2; ++i) { const int8_t y = GAMEY(i); if (PAGE_CONTAINS(y, y + SNAKE_SIZ - 1)) - u8g.drawBox(GAMEX(p.x), y, SNAKE_SIZ, SNAKE_SIZ); + draw_box(GAMEX(p.x), y, SNAKE_SIZ, SNAKE_SIZ); } } } @@ -292,26 +287,36 @@ void SnakeGame::game_screen() { if (PAGE_CONTAINS(py, py + SNAKE_SIZ - 1)) { const int8_t x1 = _MIN(p.x, q.x), x2 = _MAX(p.x, q.x); for (int8_t i = x1; i <= x2; ++i) - u8g.drawBox(GAMEX(i), py, SNAKE_SIZ, SNAKE_SIZ); + draw_box(GAMEX(i), py, SNAKE_SIZ, SNAKE_SIZ); } } } #endif - // Draw food + // Draw food in red + TERN_(IS_DWIN_MARLINUI, set_color(color::RED)); const int8_t fy = GAMEY(sdat.foody); if (PAGE_CONTAINS(fy, fy + FOOD_WH - 1)) { const int8_t fx = GAMEX(sdat.foodx); - u8g.drawFrame(fx, fy, FOOD_WH, FOOD_WH); - if (FOOD_WH == 5) u8g.drawPixel(fx + 2, fy + 2); + draw_frame(fx, fy, FOOD_WH, FOOD_WH); + if (FOOD_WH == 5) draw_pixel(fx + 2, fy + 2); } + // Draw the playfield border + TERN_(IS_DWIN_MARLINUI, set_color(color::WHITE)); + draw_frame(BOARD_L - 2, BOARD_T - 2, BOARD_R - BOARD_L + 4, BOARD_B - BOARD_T + 4); + + // Draw Score + if (PAGE_UNDER(HEADER_H)) draw_int(0, HEADER_H - 1, score); + // Draw GAME OVER if (!game_state) draw_game_over(); // A click always exits this game if (ui.use_click()) exit_game(); + + frame_end(); } void SnakeGame::enter_game() { diff --git a/Marlin/src/lcd/menu/game/types.h b/Marlin/src/lcd/menu/game/types.h index 6e0a2051d7..a12d134d38 100644 --- a/Marlin/src/lcd/menu/game/types.h +++ b/Marlin/src/lcd/menu/game/types.h @@ -21,7 +21,14 @@ */ #pragma once -#include +#include "../../../inc/MarlinConfigPre.h" +#include "../../marlinui.h" + +#if HAS_MARLINUI_U8GLIB + #include "../../dogm/game.h" +#elif IS_DWIN_MARLINUI + #include "../../e3v2/marlinui/game.h" +#endif typedef struct { int8_t x, y; } pos_t; @@ -41,6 +48,125 @@ protected: static bool game_frame(); static void draw_game_over(); static void exit_game(); + public: static void init_game(const uint8_t init_state, const screenFunc_t screen); + + // Game rendering API, based on U8glib's API. + // See the @see comments for the U8glib API documentation corresponding to each function. + + /** + * @brief The colors available for drawing games. + * @note Renderer implementations will map these colors to the closest + * available color on the screen, as long as that color is not black. + * Thus, black is guranteed to be black on all screens, but other colors may differ. + * On black-and-white screens, all colors but black will be white. + */ + enum class color { + BLACK, WHITE + #if IS_DWIN_MARLINUI + , RED, GREEN, BLUE, YELLOW, CYAN, MAGENTA + #endif + }; + +protected: + /** + * @brief Called before any draw calls in the current frame. + */ + static void frame_start(); + + /** + * @brief Called after all draw calls in the current frame. + */ + static void frame_end(); + + /** + * @brief Set the color for subsequent draw calls. + * @param color The color to use for subsequent draw calls. + */ + static void set_color(const color color); + + /** + * @brief Draw a horizontal line. + * @param x The x-coordinate of the start of the line. + * @param y The y-coordinate of the line. + * @param l The length of the line. + * @see https://github.com/olikraus/u8glib/wiki/userreference#drawhline + */ + static void draw_hline(const game_dim_t x, const game_dim_t y, const game_dim_t l); + + /** + * @brief Draw a vertical line. + * @param x The x-coordinate of the line. + * @param y The y-coordinate of the start of the line. + * @param l The length of the line. + * @see https://github.com/olikraus/u8glib/wiki/userreference#drawvline + */ + static void draw_vline(const game_dim_t x, const game_dim_t y, const game_dim_t l); + + /** + * @brief Draw a outlined rectangle (frame). + * @param x The x-coordinate of the top-left corner of the frame. + * @param y The y-coordinate of the top-left corner of the frame. + * @param w The width of the frame. + * @param h The height of the frame. + * @see https://github.com/olikraus/u8glib/wiki/userreference#drawframe + */ + static void draw_frame(const game_dim_t x, const game_dim_t y, const game_dim_t w, const game_dim_t h); + + /** + * @brief Draw a filled rectangle (box). + * @param x The x-coordinate of the top-left corner of the box. + * @param y The y-coordinate of the top-left corner of the box. + * @param w The width of the box. + * @param h The height of the box. + * @see https://github.com/olikraus/u8glib/wiki/userreference#drawbox + */ + static void draw_box(const game_dim_t x, const game_dim_t y, const game_dim_t w, const game_dim_t h); + + /** + * @brief Draw a pixel. + * @param x The x-coordinate of the pixel. + * @param y The y-coordinate of the pixel. + * @see https://github.com/olikraus/u8glib/wiki/userreference#drawpixel + */ + static void draw_pixel(const game_dim_t x, const game_dim_t y); + + /** + * @brief Draw a bitmap. + * @param x The x-coordinate of the top-left corner of the bitmap. + * @param y The y-coordinate of the top-left corner of the bitmap. + * @param bytes_per_row The number of bytes per row in the bitmap (Width = bytes_per_row * 8). + * @param rows The number of rows in the bitmap (= Height). + * @param bitmap The bitmap to draw. + * @see https://github.com/olikraus/u8glib/wiki/userreference#drawbitmap + */ + static void draw_bitmap(const game_dim_t x, const game_dim_t y, const game_dim_t bytes_per_row, const game_dim_t rows, const pgm_bitmap_t bitmap); + + /** + * @brief Draw a string. + * @param x The x-coordinate of the string. + * @param y The y-coordinate of the string. + * @param str The string to draw. + * @see lcd_moveto + lcd_put_u8str + * @note The font size is available using the GAME_FONT_WIDTH and GAME_FONT_ASCENT constants. + * + * @note On the DWIN renderer, strings may flush the screen, which may cause flickering. + * Consider drawing strings after all other elements have been drawn. + */ + static int draw_string(const game_dim_t x, const game_dim_t y, const char *str); + static int draw_string(const game_dim_t x, const game_dim_t y, FSTR_P const str); + + /** + * @brief Draw an integer. + * @param x The x-coordinate of the integer. + * @param y The y-coordinate of the integer. + * @param value The integer to draw. + * @see lcd_put_int + * @note The font size is available using the GAME_FONT_WIDTH and GAME_FONT_ASCENT constants. + * + * @note On the DWIN renderer, strings may flush the screen, which may cause flickering. + * Consider drawing strings after all other elements have been drawn. + */ + static void draw_int(const game_dim_t x, const game_dim_t y, const int value); }; diff --git a/buildroot/tests/STM32F103RE_creality b/buildroot/tests/STM32F103RE_creality index d08b82f7bd..0a1b1bc79d 100755 --- a/buildroot/tests/STM32F103RE_creality +++ b/buildroot/tests/STM32F103RE_creality @@ -20,8 +20,9 @@ exec_test $1 $2 "Ender-3 V2 - JyersUI (ABL Bilinear/Manual)" "$3" use_example_configs "Creality/Ender-3 V2/CrealityV422/CrealityUI" opt_disable DWIN_CREALITY_LCD PIDTEMP -opt_enable DWIN_MARLINUI_LANDSCAPE LCD_ENDSTOP_TEST AUTO_BED_LEVELING_UBL BLTOUCH Z_SAFE_HOMING MPCTEMP MPC_AUTOTUNE -exec_test $1 $2 "Ender-3 V2 - MarlinUI (UBL+BLTOUCH, MPCTEMP, LCD_ENDSTOP_TEST)" "$3" +opt_enable DWIN_MARLINUI_LANDSCAPE LCD_ENDSTOP_TEST AUTO_BED_LEVELING_UBL BLTOUCH Z_SAFE_HOMING MPCTEMP MPC_AUTOTUNE \ + MARLIN_BRICKOUT MARLIN_INVADERS MARLIN_SNAKE GAMES_EASTER_EGG +exec_test $1 $2 "Ender-3 V2 - MarlinUI (Games, UBL+BLTOUCH, MPCTEMP, LCD_ENDSTOP_TEST)" "$3" use_example_configs "Creality/Ender-3 S1/STM32F1" opt_disable DWIN_CREALITY_LCD Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN AUTO_BED_LEVELING_BILINEAR CANCEL_OBJECTS FWRETRACT EVENT_GCODE_SD_ABORT From 63bc413da806888039262f9e4db0863b2950bc88 Mon Sep 17 00:00:00 2001 From: Red Echidna UK <64329845+RedEchidnaUK@users.noreply.github.com> Date: Thu, 9 Jan 2025 04:30:53 +0000 Subject: [PATCH 022/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Add?= =?UTF-8?q?=20STM32/STM32F1=20Open=20Drain=20(OD)=20pin=20mode=20(#27616)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/HAL/STM32/fastio.h | 1 + Marlin/src/HAL/STM32F1/fastio.h | 1 + 2 files changed, 2 insertions(+) diff --git a/Marlin/src/HAL/STM32/fastio.h b/Marlin/src/HAL/STM32/fastio.h index af2941c49c..a92bbc492e 100644 --- a/Marlin/src/HAL/STM32/fastio.h +++ b/Marlin/src/HAL/STM32/fastio.h @@ -77,6 +77,7 @@ void FastIO_init(); // Must be called before using fast io macros #define SET_INPUT_PULLUP(IO) _SET_MODE(IO, INPUT_PULLUP) //!< Input with Pull-up activation #define SET_INPUT_PULLDOWN(IO) _SET_MODE(IO, INPUT_PULLDOWN) //!< Input with Pull-down activation #define SET_OUTPUT(IO) OUT_WRITE(IO, LOW) +#define SET_OUTPUT_OD(IO) OUT_WRITE_OD(IO, LOW) #define SET_PWM(IO) _SET_MODE(IO, PWM) #define IS_INPUT(IO) diff --git a/Marlin/src/HAL/STM32F1/fastio.h b/Marlin/src/HAL/STM32F1/fastio.h index 5b3ebaa52c..8bb986b466 100644 --- a/Marlin/src/HAL/STM32F1/fastio.h +++ b/Marlin/src/HAL/STM32F1/fastio.h @@ -44,6 +44,7 @@ #define SET_INPUT_PULLUP(IO) _SET_MODE(IO, GPIO_INPUT_PU) #define SET_INPUT_PULLDOWN(IO) _SET_MODE(IO, GPIO_INPUT_PD) #define SET_OUTPUT(IO) OUT_WRITE(IO, LOW) +#define SET_OUTPUT_OD(IO) OUT_WRITE_OD(IO, LOW) #define SET_PWM(IO) pinMode(IO, PWM) // do{ gpio_set_mode(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_bit, GPIO_AF_OUTPUT_PP); timer_set_mode(PIN_MAP[pin].timer_device, PIN_MAP[pin].timer_channel, TIMER_PWM); }while(0) #define SET_PWM_OD(IO) pinMode(IO, PWM_OPEN_DRAIN) From 7eee772f6079ae3ce3bd147986c0556078acf0cd Mon Sep 17 00:00:00 2001 From: ellensp <530024+ellensp@users.noreply.github.com> Date: Thu, 9 Jan 2025 17:41:03 +1300 Subject: [PATCH 023/787] =?UTF-8?q?=E2=9C=A8=20MAX31865=20Bed=20settings?= =?UTF-8?q?=20(#27611)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/Configuration.h | 4 ++++ Marlin/Configuration_adv.h | 8 +++++--- Marlin/src/HAL/shared/Delay.h | 3 +++ Marlin/src/inc/SanityCheck.h | 7 +++++++ 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 6d5ae49de8..8e03a2391d 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -599,6 +599,10 @@ #define MAX31865_SENSOR_OHMS_2 100 #define MAX31865_CALIBRATION_OHMS_2 430 #endif +#if TEMP_SENSOR_IS_MAX_TC(BED) + #define MAX31865_SENSOR_OHMS_BED 100 + #define MAX31865_CALIBRATION_OHMS_BED 430 +#endif #if HAS_E_TEMP_SENSOR #define TEMP_RESIDENCY_TIME 10 // (seconds) Time to wait for hotend to "settle" in M109 diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index c159add506..417bea4718 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -174,9 +174,10 @@ * Thermocouple Options — for MAX6675 (-2), MAX31855 (-3), and MAX31865 (-5). */ //#define TEMP_SENSOR_FORCE_HW_SPI // Ignore SCK/MOSI/MISO pins; use CS and the default SPI bus. -//#define MAX31865_SENSOR_WIRES_0 2 // (2-4) Number of wires for the probe connected to a MAX31865 board. -//#define MAX31865_SENSOR_WIRES_1 2 -//#define MAX31865_SENSOR_WIRES_2 2 +//#define MAX31865_SENSOR_WIRES_0 2 // (2-4) Number of wires for the probe connected to a MAX31865 board. +//#define MAX31865_SENSOR_WIRES_1 2 +//#define MAX31865_SENSOR_WIRES_2 2 +//#define MAX31865_SENSOR_WIRES_BED 2 //#define MAX31865_50HZ_FILTER // Use a 50Hz filter instead of the default 60Hz. //#define MAX31865_USE_READ_ERROR_DETECTION // Treat value spikes (20°C delta in under 1s) as read errors. @@ -188,6 +189,7 @@ //#define MAX31865_WIRE_OHMS_0 0.95f // For 2-wire, set the wire resistances for more accurate readings. //#define MAX31865_WIRE_OHMS_1 0.0f //#define MAX31865_WIRE_OHMS_2 0.0f +//#define MAX31865_WIRE_OHMS_BED 0.0f /** * Hephestos 2 24V heated bed upgrade kit. diff --git a/Marlin/src/HAL/shared/Delay.h b/Marlin/src/HAL/shared/Delay.h index a6795a78ea..4751d7a5e2 100644 --- a/Marlin/src/HAL/shared/Delay.h +++ b/Marlin/src/HAL/shared/Delay.h @@ -174,6 +174,9 @@ void calibrate_delay_loop(); // Delay in microseconds #define DELAY_US(x) DELAY_CYCLES((x) * ((F_CPU) / 1000000UL)) + + #define DELAY_CYCLES_VAR DELAY_CYCLES + #else #error "Unsupported MCU architecture" diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index 9c21c4fd29..b7edc34ade 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -2121,6 +2121,13 @@ static_assert(NUM_SERVOS <= NUM_SERVO_PLUGS, "NUM_SERVOS (or some servo index) i #error "MAX31865_SENSOR_OHMS_2 and MAX31865_CALIBRATION_OHMS_2 must be set if TEMP_SENSOR_2/TEMP_SENSOR_REDUNDANT is MAX31865." #endif #endif +#if TEMP_SENSOR_BED_IS_MAX31865 + #if !defined(MAX31865_SENSOR_WIRES_BED) || !WITHIN(MAX31865_SENSOR_WIRES_BED, 2, 4) + #error "MAX31865_SENSOR_WIRES_BED must be defined as an integer between 2 and 4." + #elif !defined(MAX31865_SENSOR_OHMS_BED) || !defined(MAX31865_CALIBRATION_OHMS_BED) + #error "MAX31865_SENSOR_OHMS_BED and MAX31865_CALIBRATION_OHMS_BED must be set if TEMP_SENSOR_BED is MAX31865." + #endif +#endif /** * Redundant temperature sensor config From acd825972c94faa22688907c828dde39fabf3b7c Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Wed, 8 Jan 2025 23:03:41 -0600 Subject: [PATCH 024/787] =?UTF-8?q?=E2=9C=A8=20EVENT=5FGCODE=5FBEFORE=5FG2?= =?UTF-8?q?9=20(#27566)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/Configuration.h | 6 ++++++ Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp | 23 ++++++++++++++------- Marlin/src/gcode/bedlevel/abl/G29.cpp | 7 ++++++- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 8e03a2391d..6a4087529d 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -2108,6 +2108,12 @@ //#define AUTO_BED_LEVELING_UBL //#define MESH_BED_LEVELING +/** + * Commands to execute at the start of G29 probing, + * after switching to the PROBING_TOOL. + */ +//#define EVENT_GCODE_BEFORE_G29 "M300 P440 S200" + /** * Commands to execute at the end of G29 probing. * Useful to retract or move the Z probe out of the way. diff --git a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp index 4637bf87e8..2cea4968b7 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp +++ b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp @@ -297,7 +297,13 @@ G29_parameters_t unified_bed_leveling::param; void unified_bed_leveling::G29() { - bool probe_deployed = false; + #ifdef EVENT_GCODE_AFTER_G29 + bool probe_deployed = false; + #define SET_PROBE_DEPLOYED(N) probe_deployed = N + #else + #define SET_PROBE_DEPLOYED(N) + #endif + if (G29_parse_parameters()) return; // Abort on parameter error const uint8_t p_val = parser.byteval('P'); @@ -316,6 +322,11 @@ void unified_bed_leveling::G29() { #endif probe.use_probing_tool(); + #ifdef EVENT_GCODE_BEFORE_G29 + if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Before G29 G-code: ", EVENT_GCODE_BEFORE_G29); + gcode.process_subcommands_now(F(EVENT_GCODE_BEFORE_G29)); + #endif + // Position bed horizontally and Z probe vertically. #if HAS_SAFE_BED_LEVELING xyze_pos_t safe_position = current_position; @@ -430,7 +441,7 @@ void unified_bed_leveling::G29() { do_blocking_move_to_xy(0.5f * ((MESH_MIN_X) + (MESH_MAX_X)), 0.5f * ((MESH_MIN_Y) + (MESH_MAX_Y))); #endif report_current_position(); - probe_deployed = true; + SET_PROBE_DEPLOYED(true); } #endif // HAS_BED_PROBE @@ -465,7 +476,7 @@ void unified_bed_leveling::G29() { probe_entire_mesh(param.XY_pos, parser.seen_test('T'), parser.seen_test('E'), parser.seen_test('U')); report_current_position(); - probe_deployed = true; + SET_PROBE_DEPLOYED(true); } break; #endif // HAS_BED_PROBE @@ -503,7 +514,7 @@ void unified_bed_leveling::G29() { SERIAL_ECHOLNPGM("?Error in Business Card measurement."); return; } - probe_deployed = true; + SET_PROBE_DEPLOYED(true); } if (!position_is_reachable(param.XY_pos)) { @@ -681,13 +692,11 @@ void unified_bed_leveling::G29() { #endif #ifdef EVENT_GCODE_AFTER_G29 - if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Z Probe End Script: ", EVENT_GCODE_AFTER_G29); + if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("After G29 G-code: ", EVENT_GCODE_AFTER_G29); if (probe_deployed) { planner.synchronize(); gcode.process_subcommands_now(F(EVENT_GCODE_AFTER_G29)); } - #else - UNUSED(probe_deployed); #endif probe.use_probing_tool(false); diff --git a/Marlin/src/gcode/bedlevel/abl/G29.cpp b/Marlin/src/gcode/bedlevel/abl/G29.cpp index 3b922dd54f..386b805b6d 100644 --- a/Marlin/src/gcode/bedlevel/abl/G29.cpp +++ b/Marlin/src/gcode/bedlevel/abl/G29.cpp @@ -287,6 +287,11 @@ G29_TYPE GcodeSuite::G29() { probe.use_probing_tool(); + #ifdef EVENT_GCODE_BEFORE_G29 + if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Before G29 G-code: ", EVENT_GCODE_BEFORE_G29); + gcode.process_subcommands_now(F(EVENT_GCODE_BEFORE_G29)); + #endif + #if ANY(PROBE_MANUALLY, AUTO_BED_LEVELING_LINEAR) abl.abl_probe_index = -1; #endif @@ -1007,7 +1012,7 @@ G29_TYPE GcodeSuite::G29() { TERN_(HAS_BED_PROBE, probe.move_z_after_probing()); #ifdef EVENT_GCODE_AFTER_G29 - if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Z Probe End Script: ", EVENT_GCODE_AFTER_G29); + if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("After G29 G-code: ", EVENT_GCODE_AFTER_G29); planner.synchronize(); process_subcommands_now(F(EVENT_GCODE_AFTER_G29)); #endif From a7d79618b98f5fb44ada6ed4305f170623a21be2 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Fri, 10 Jan 2025 00:28:20 +0000 Subject: [PATCH 025/787] [cron] Bump distribution date (2025-01-10) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index a1baf0b75e..b6c613131b 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-01-09" +//#define STRING_DISTRIBUTION_DATE "2025-01-10" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index e916f53b43..12a73f99fe 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-01-09" + #define STRING_DISTRIBUTION_DATE "2025-01-10" #endif /** From 8d7ecad5317eadd853eade895877a4aa801b0b24 Mon Sep 17 00:00:00 2001 From: Andrew <18502096+classicrocker883@users.noreply.github.com> Date: Sat, 11 Jan 2025 16:09:49 -0500 Subject: [PATCH 026/787] =?UTF-8?q?=F0=9F=94=A8=20Fix=20cmake=20build=20on?= =?UTF-8?q?=20Linux=20(#27605)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- buildroot/share/cmake/CMakeLists.txt | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/buildroot/share/cmake/CMakeLists.txt b/buildroot/share/cmake/CMakeLists.txt index 5f15d26680..3e44dcf0fe 100644 --- a/buildroot/share/cmake/CMakeLists.txt +++ b/buildroot/share/cmake/CMakeLists.txt @@ -1,15 +1,17 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION 3.10) #====================================================================# # Usage under Linux: # # # -# From Marlin/buildroot/share/cmake folder: # +# From the project folder: # +# cd buildroot/share/cmake # # mkdir -p build && cd build # # cmake .. # # make # # # # Usage under Windows: # # # -# From Marlin/buildroot/share/cmake folder: # +# From the project folder: # +# cd buildroot/share/cmake # # mkdir build && cd build # # cmake -G"Unix Makefiles" .. # # make # @@ -82,10 +84,21 @@ message("-- Running CMake version: " ${CMAKE_VERSION}) # Replace the CMake Ver. in the Arduino.cmake file(READ "${CMAKE_CURRENT_LIST_DIR}/marlin-cmake/Platform/Arduino.cmake" ORIGINAL_FILE_CONTENTS) -string(REGEX REPLACE "cmake_minimum_required\\(VERSION[^\n]*\n" "cmake_minimum_required(VERSION 3.5)\n" NEW_FILE_CONTENTS "${ORIGINAL_FILE_CONTENTS}") +string(REGEX REPLACE "cmake_minimum_required\\(VERSION[^\n]*\n" "cmake_minimum_required(VERSION 3.10)\n" NEW_FILE_CONTENTS "${ORIGINAL_FILE_CONTENTS}") file(WRITE "${CMAKE_CURRENT_LIST_DIR}/marlin-cmake/Platform/Arduino.cmake" "${NEW_FILE_CONTENTS}") -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_LIST_DIR}/marlin-cmake/modules) +# Fix "CMake Error... avr-gcc / avr-g++ is not a full path..." +if(UNIX) + set(ORIGINAL_FILE_CONTENTS "") + set(NEW_FILE_CONTENTS "") + file(READ "${CMAKE_CURRENT_LIST_DIR}/marlin-cmake/toolchain/ArduinoToolchain.cmake" ORIGINAL_FILE_CONTENTS) + string(REPLACE "set(CMAKE_C_COMPILER avr-gcc)\nset(CMAKE_CXX_COMPILER avr-g++)" + "set(CMAKE_C_COMPILER /usr/bin/gcc)\nset(CMAKE_CXX_COMPILER /usr/bin/gcc)" + NEW_FILE_CONTENTS "${ORIGINAL_FILE_CONTENTS}") + file(WRITE "${CMAKE_CURRENT_LIST_DIR}/marlin-cmake/toolchain/ArduinoToolchain.cmake" "${NEW_FILE_CONTENTS}") +endif(UNIX) + +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_LIST_DIR}/marlin-cmake/modules) #====================================================================# # Custom path to Arduino SDK can be set here # @@ -116,6 +129,7 @@ set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_LIST_DIR}/marlin-cmake/toolchain/Arduin # Go to the file in your CMake directory # # # # For Windows: cmake\Modules\Platform\WindowsPaths.cmake # +# For macOS: cmake/Modules/Platform/UnixPaths.cmake # # For Linux: cmake/Modules/Platform/UnixPaths.cmake # # # # Comment out "_cmake_record_install_prefix()" # From 55add905cba7db7113fe20a9bf38cafef0f41f45 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Sun, 12 Jan 2025 00:36:21 +0000 Subject: [PATCH 027/787] [cron] Bump distribution date (2025-01-12) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index b6c613131b..68dfc21722 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-01-10" +//#define STRING_DISTRIBUTION_DATE "2025-01-12" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 12a73f99fe..2b090530a2 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-01-10" + #define STRING_DISTRIBUTION_DATE "2025-01-12" #endif /** From 28c591309fae16c0266ec072ffa401aa8296110f Mon Sep 17 00:00:00 2001 From: rondlh <77279634+rondlh@users.noreply.github.com> Date: Sun, 12 Jan 2025 10:58:26 +0800 Subject: [PATCH 028/787] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20STM32H7=20Flash=20?= =?UTF-8?q?Wear=20Leveling=20(#27634)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/HAL/STM32/eeprom_flash.cpp | 59 ++++++++++++++++++-------- Marlin/src/HAL/STM32/inc/SanityCheck.h | 4 +- 2 files changed, 43 insertions(+), 20 deletions(-) diff --git a/Marlin/src/HAL/STM32/eeprom_flash.cpp b/Marlin/src/HAL/STM32/eeprom_flash.cpp index 37963ad501..48f3f402a7 100644 --- a/Marlin/src/HAL/STM32/eeprom_flash.cpp +++ b/Marlin/src/HAL/STM32/eeprom_flash.cpp @@ -74,13 +74,13 @@ #define EEPROM_SLOTS ((FLASH_UNIT_SIZE) / (MARLIN_EEPROM_SIZE)) #define SLOT_ADDRESS(slot) (FLASH_ADDRESS_START + (slot * (MARLIN_EEPROM_SIZE))) - #define UNLOCK_FLASH() if (!flash_unlocked) { \ - HAL_FLASH_Unlock(); \ - __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | \ - FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR); \ - flash_unlocked = true; \ - } - #define LOCK_FLASH() if (flash_unlocked) { HAL_FLASH_Lock(); flash_unlocked = false; } + #ifdef STM32H7xx + #define FLASHWORD_SIZE 32U // STM32H7xx a FLASHWORD is 32 bytes (256 bits) + #define FLASH_FLAGS_TO_CLEAR (FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGSERR) + #else + #define FLASHWORD_SIZE 4U // STM32F4xx a FLASHWORD is 4 bytes sizeof(uint32_t) + #define FLASH_FLAGS_TO_CLEAR (FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR) + #endif #define EMPTY_UINT32 ((uint32_t)-1) #define EMPTY_UINT8 ((uint8_t)-1) @@ -88,7 +88,7 @@ static uint8_t ram_eeprom[MARLIN_EEPROM_SIZE] __attribute__((aligned(4))) = {0}; static int current_slot = -1; - static_assert(0 == MARLIN_EEPROM_SIZE % 4, "MARLIN_EEPROM_SIZE must be a multiple of 4"); // Ensure copying as uint32_t is safe + static_assert(0 == MARLIN_EEPROM_SIZE % FLASHWORD_SIZE, "MARLIN_EEPROM_SIZE must be a multiple of the FLASHWORD size"); // Ensure copying as uint32_t is safe static_assert(0 == FLASH_UNIT_SIZE % MARLIN_EEPROM_SIZE, "MARLIN_EEPROM_SIZE must divide evenly into your FLASH_UNIT_SIZE"); static_assert(FLASH_UNIT_SIZE >= MARLIN_EEPROM_SIZE, "FLASH_UNIT_SIZE must be greater than or equal to your MARLIN_EEPROM_SIZE"); static_assert(IS_FLASH_SECTOR(FLASH_SECTOR), "FLASH_SECTOR is invalid"); @@ -147,11 +147,15 @@ bool PersistentStore::access_start() { bool PersistentStore::access_finish() { if (eeprom_data_written) { + #ifdef STM32F4xx // MCU may come up with flash error bits which prevent some flash operations. // Clear flags prior to flash operations to prevent errors. __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR); #endif + #ifdef STM32H7xx + __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGSERR); + #endif #if ENABLED(FLASH_EEPROM_LEVELING) @@ -170,7 +174,12 @@ bool PersistentStore::access_finish() { EraseInitStruct.NbSectors = 1; current_slot = EEPROM_SLOTS - 1; - UNLOCK_FLASH(); + + if (!flash_unlocked) { + HAL_FLASH_Unlock(); + __HAL_FLASH_CLEAR_FLAG(FLASH_FLAGS_TO_CLEAR); + flash_unlocked = true; + } TERN_(HAS_PAUSE_SERVO_OUTPUT, PAUSE_SERVO_OUTPUT()); hal.isr_off(); @@ -181,26 +190,37 @@ bool PersistentStore::access_finish() { DEBUG_ECHOLNPGM("HAL_FLASHEx_Erase=", status); DEBUG_ECHOLNPGM("GetError=", HAL_FLASH_GetError()); DEBUG_ECHOLNPGM("SectorError=", SectorError); - LOCK_FLASH(); + if (flash_unlocked) { + HAL_FLASH_Lock(); + flash_unlocked = false; + } return false; } } - UNLOCK_FLASH(); + if (!flash_unlocked) { + HAL_FLASH_Unlock(); + __HAL_FLASH_CLEAR_FLAG(FLASH_FLAGS_TO_CLEAR); + flash_unlocked = true; + } uint32_t offset = 0, address = SLOT_ADDRESS(current_slot), - address_end = address + MARLIN_EEPROM_SIZE, - data = 0; + address_end = address + MARLIN_EEPROM_SIZE; bool success = true; while (address < address_end) { - memcpy(&data, ram_eeprom + offset, sizeof(data)); - status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, address, data); + #ifdef STM32H7xx + status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD, address, uint32_t(ram_eeprom + offset)); + #else + //memcpy(&data, ram_eeprom + offset, sizeof(data)); // IRON, IMPROVED + //status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, address, data); + status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, address, *(uint32_t*)(ram_eeprom + offset)); // IRON, OPTIMIZED + #endif if (status == HAL_OK) { - address += sizeof(uint32_t); - offset += sizeof(uint32_t); + address += FLASHWORD_SIZE; + offset += FLASHWORD_SIZE; } else { DEBUG_ECHOLNPGM("HAL_FLASH_Program=", status); @@ -211,7 +231,10 @@ bool PersistentStore::access_finish() { } } - LOCK_FLASH(); + if (flash_unlocked) { + HAL_FLASH_Lock(); + flash_unlocked = false; + } if (success) { eeprom_data_written = false; diff --git a/Marlin/src/HAL/STM32/inc/SanityCheck.h b/Marlin/src/HAL/STM32/inc/SanityCheck.h index e35b4e59cf..bdcc6ab9f0 100644 --- a/Marlin/src/HAL/STM32/inc/SanityCheck.h +++ b/Marlin/src/HAL/STM32/inc/SanityCheck.h @@ -36,8 +36,8 @@ #error "SDCARD_EEPROM_EMULATION requires SDSUPPORT. Enable SDSUPPORT or choose another EEPROM emulation." #endif -#if !defined(STM32F4xx) && ENABLED(FLASH_EEPROM_LEVELING) - #error "FLASH_EEPROM_LEVELING is currently only supported on STM32F4 hardware." +#if NONE(STM32F4xx, STM32H7xx) && ENABLED(FLASH_EEPROM_LEVELING) + #error "FLASH_EEPROM_LEVELING is currently only supported on STM32F4/H7 hardware." // IRON #endif #if ENABLED(SERIAL_STATS_MAX_RX_QUEUED) From de7ac7f594bc10d80b4153b716ed3bf8b5de29b2 Mon Sep 17 00:00:00 2001 From: Giuliano Zaro <3684609+GMagician@users.noreply.github.com> Date: Sun, 12 Jan 2025 04:00:10 +0100 Subject: [PATCH 029/787] =?UTF-8?q?=F0=9F=90=9B=20Fix=20M119=20filament=20?= =?UTF-8?q?sensor=20part=20(#27596)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix from #27576 --- Marlin/src/module/endstops.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/src/module/endstops.cpp b/Marlin/src/module/endstops.cpp index 57d6e0989d..f3515ad928 100644 --- a/Marlin/src/module/endstops.cpp +++ b/Marlin/src/module/endstops.cpp @@ -533,7 +533,7 @@ void __O2 Endstops::report_states() { } #undef _CASE_RUNOUT #elif HAS_FILAMENT_SENSOR - print_es_state(!FILAMENT_IS_OUT()); + print_es_state(!FILAMENT_IS_OUT(), F(STR_FILAMENT)); #endif TERN_(BLTOUCH, bltouch._reset_SW_mode()); From 6eca4bbab12448d1c2b10881e5bd39211a008c20 Mon Sep 17 00:00:00 2001 From: ellensp <530024+ellensp@users.noreply.github.com> Date: Sun, 12 Jan 2025 16:06:24 +1300 Subject: [PATCH 030/787] =?UTF-8?q?=F0=9F=94=A8=20Migrate=20use=5Fexample?= =?UTF-8?q?=5Fconfigs=20to=20Python=20(#27632)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- buildroot/bin/restore_configs | 41 +++++++++---- buildroot/bin/use_example_configs | 97 +++++++++++++++++++++---------- 2 files changed, 97 insertions(+), 41 deletions(-) diff --git a/buildroot/bin/restore_configs b/buildroot/bin/restore_configs index e1a601679b..0bbd36fd1c 100755 --- a/buildroot/bin/restore_configs +++ b/buildroot/bin/restore_configs @@ -1,12 +1,33 @@ -#!/usr/bin/env bash +#!/usr/bin/env python3 -rm -f Marlin/_Bootscreen.h Marlin/_Statusscreen.h marlin_config.json .pio/build/mc.zip +import os, sys, subprocess -if [[ $1 == '-d' || $1 == '--default' ]]; then - use_example_configs -else - git checkout Marlin/Configuration.h 2>/dev/null - git checkout Marlin/Configuration_adv.h 2>/dev/null - git checkout Marlin/config.ini 2>/dev/null - git checkout Marlin/src/pins/*/pins_*.h 2>/dev/null -fi +files_to_remove = [ + "Marlin/_Bootscreen.h", + "Marlin/_Statusscreen.h", + "marlin_config.json", + ".pio/build/mc.zip" +] + +for file in files_to_remove: + if os.path.exists(file): + os.remove(file) + +def use_example_configs(): + try: + subprocess.run(['use_example_configs'], check=True) + except FileNotFoundError: + print("use_example_configs not found, skipping.") + pass + +if len(sys.argv) > 1 and sys.argv[1] in ['-d', '--default']: + use_example_configs() +else: + files_to_checkout = [ + "Marlin/Configuration.h", + "Marlin/Configuration_adv.h", + "Marlin/config.ini", + "Marlin/src/pins/*/pins_*.h" + ] + for file in files_to_checkout: + subprocess.run(["git", "checkout", file], stderr=subprocess.DEVNULL) diff --git a/buildroot/bin/use_example_configs b/buildroot/bin/use_example_configs index 282e057dde..193da74901 100755 --- a/buildroot/bin/use_example_configs +++ b/buildroot/bin/use_example_configs @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/usr/bin/env python # # use_example_configs [repo:]configpath # @@ -14,40 +14,75 @@ # The fallback branch is bugfix-2.1.x. # -which curl >/dev/null && TOOL='curl -L -s -S -f -o wgot' -which wget >/dev/null && TOOL='wget -q -O wgot' +import os, subprocess, sys, urllib.request -CURR=$(git branch 2>/dev/null | grep ^* | sed 's/\* //g') -case "$CURR" in - bugfix-2.*.x ) BRANCH=$CURR ;; - *-2.1.x|2.1.x ) BRANCH=latest-2.1.x ;; - *-2.0.x|2.0.x ) BRANCH=latest-2.0.x ;; - *-1.1.x|1.1.x ) BRANCH=latest-1.1.x ;; - *-1.0.x|1.0.x ) BRANCH=latest-1.0.x ;; - * ) BRANCH=bugfix-2.1.x ;; -esac +def get_current_branch(): + try: + result = subprocess.run(['git', 'branch'], capture_output=True, text=True, check=True) + for line in result.stdout.splitlines(): + if line.startswith('*'): + return line[2:] + except subprocess.CalledProcessError: + return None -if [[ $# > 0 ]]; then - IFS=: read -r PART1 PART2 <<< "$@" - [[ -n $PART2 ]] && { UDIR="$PART2" ; BRANCH="$PART1" ; } \ - || { UDIR="$PART1" ; } - RDIR="${UDIR// /%20}" - echo "Fetching $UDIR configurations from $BRANCH..." - EXAMPLES="examples/$RDIR" -else - EXAMPLES="default" -fi +def fetch_configs(branch, config_path): + print(f"Fetching {config_path} configurations from {branch}...") + base_url = f"https://raw.githubusercontent.com/MarlinFirmware/Configurations/{branch}/config/{config_path}" + files = ["Configuration.h", "Configuration_adv.h", "_Bootscreen.h", "_Statusscreen.h"] + marlin_dir = os.path.join(os.getcwd(), "Marlin") + if not os.path.exists(marlin_dir): + print(f"Directory {marlin_dir} does not exist.") + sys.exit(1) + for file in files: + url = f"{base_url}/{file}" + dest_file = os.path.join(marlin_dir, file) + if os.getenv('DEBUG', '0') == '1': + print(f"Fetching {file} from {url} to {dest_file}") + try: + urllib.request.urlretrieve(url, dest_file) + except urllib.error.HTTPError as e: + if e.code == 404: + if os.getenv('DEBUG', '0') == '1': + print(f"File {file} not found (404), skipping.") + else: + raise -CONFIGS="https://raw.githubusercontent.com/MarlinFirmware/Configurations/$BRANCH/config/${EXAMPLES}" +def main(): + branch = get_current_branch() + if not branch: + print("Not a git repository or no branch found.") + sys.exit(1) -restore_configs + if branch.startswith("bugfix-2."): + branch = branch + elif branch.endswith("-2.1.x") or branch == "2.1.x": + branch = "latest-2.1.x" + elif branch.endswith("-2.0.x") or branch == "2.0.x": + branch = "latest-2.0.x" + elif branch.endswith("-1.1.x") or branch == "1.1.x": + branch = "latest-1.1.x" + elif branch.endswith("-1.0.x") or branch == "1.0.x": + branch = "latest-1.0.x" + else: + branch = "bugfix-2.1.x" -cd Marlin + if len(sys.argv) > 1: + arg = sys.argv[1] + if ':' in arg: + part1, part2 = arg.split(':', 1) + config_path = part2 + branch = part1 + else: + config_path = arg + config_path = 'examples/'+config_path.replace(' ', '%20') + else: + config_path = "default" -$TOOL "$CONFIGS/Configuration.h" >/dev/null 2>&1 && mv wgot Configuration.h -$TOOL "$CONFIGS/Configuration_adv.h" >/dev/null 2>&1 && mv wgot Configuration_adv.h -$TOOL "$CONFIGS/_Bootscreen.h" >/dev/null 2>&1 && mv wgot _Bootscreen.h -$TOOL "$CONFIGS/_Statusscreen.h" >/dev/null 2>&1 && mv wgot _Statusscreen.h + try: + subprocess.run(['restore_configs'], check=True) + except FileNotFoundError: + print("restore_configs not found, skipping.") + fetch_configs(branch, config_path) -rm -f wgot -cd - >/dev/null +if __name__ == "__main__": + main() From 2e142725a68ec49e990e5bc30dd3aac4f2f8f762 Mon Sep 17 00:00:00 2001 From: RomanFaktor Date: Sun, 12 Jan 2025 04:16:34 +0100 Subject: [PATCH 031/787] =?UTF-8?q?=F0=9F=90=9B=20Fix=20ERYONE=20Ery32=20m?= =?UTF-8?q?ini=20SPI=20for=20SD=20(#27600)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/pins/stm32f1/pins_ERYONE_ERY32_MINI.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Marlin/src/pins/stm32f1/pins_ERYONE_ERY32_MINI.h b/Marlin/src/pins/stm32f1/pins_ERYONE_ERY32_MINI.h index 1a43f2e414..30f3f939d8 100644 --- a/Marlin/src/pins/stm32f1/pins_ERYONE_ERY32_MINI.h +++ b/Marlin/src/pins/stm32f1/pins_ERYONE_ERY32_MINI.h @@ -200,7 +200,7 @@ // #define ENABLE_SPI1 #define SD_DETECT_PIN PA4 -#define SCK_PIN PA5 -#define MISO_PIN PA6 -#define MOSI_PIN PA7 -#define SS_PIN PC4 +#define SD_SCK_PIN PA5 +#define SD_MISO_PIN PA6 +#define SD_MOSI_PIN PA7 +#define SD_SS_PIN PC4 From f54ec92ba8ed5aad202bb4af4cf136ca86681b22 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Mon, 13 Jan 2025 00:30:03 +0000 Subject: [PATCH 032/787] [cron] Bump distribution date (2025-01-13) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 68dfc21722..35807cab41 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-01-12" +//#define STRING_DISTRIBUTION_DATE "2025-01-13" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 2b090530a2..b798c042fe 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-01-12" + #define STRING_DISTRIBUTION_DATE "2025-01-13" #endif /** From b7f628ce2f12c6b450b5cb70a727e79747381b17 Mon Sep 17 00:00:00 2001 From: ellensp <530024+ellensp@users.noreply.github.com> Date: Tue, 14 Jan 2025 08:12:09 +1300 Subject: [PATCH 033/787] =?UTF-8?q?=F0=9F=A9=B9=20Fix=20EEPROM=20CRC=20dis?= =?UTF-8?q?play=20(#27631)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/module/settings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/src/module/settings.cpp b/Marlin/src/module/settings.cpp index 51677fdec6..c156bfeaca 100644 --- a/Marlin/src/module/settings.cpp +++ b/Marlin/src/module/settings.cpp @@ -2993,7 +2993,7 @@ void MarlinSettings::postprocess() { } else if (!validating) { DEBUG_ECHO_START(); - DEBUG_ECHOLN(version_str, F(" stored settings retrieved ("), eeprom_total, F(" bytes; crc "), working_crc, ')'); + DEBUG_ECHOLN(version_str, F(" stored settings retrieved ("), eeprom_total, F(" bytes; crc "), working_crc, C(')')); TERN_(HOST_EEPROM_CHITCHAT, hostui.notify(F("Stored settings retrieved"))); } From 854cfc016d26fc69d3fe1cbbb02b18e6c9c12aa3 Mon Sep 17 00:00:00 2001 From: phizev <1267833+phizev@users.noreply.github.com> Date: Tue, 14 Jan 2025 00:14:16 +0200 Subject: [PATCH 034/787] =?UTF-8?q?=E2=9C=A8=20Teensy=204=20hardware=20PWM?= =?UTF-8?q?=20for=20laser/spindle/fan=20(#27608)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/HAL/TEENSY40_41/HAL.cpp | 13 ++--- Marlin/src/HAL/TEENSY40_41/HAL.h | 16 ++++-- Marlin/src/HAL/TEENSY40_41/fast_pwm.cpp | 54 ++++++++++++++++++++ Marlin/src/HAL/TEENSY40_41/inc/SanityCheck.h | 20 ++++++-- Marlin/src/gcode/calibrate/M100.cpp | 2 +- 5 files changed, 86 insertions(+), 19 deletions(-) create mode 100644 Marlin/src/HAL/TEENSY40_41/fast_pwm.cpp diff --git a/Marlin/src/HAL/TEENSY40_41/HAL.cpp b/Marlin/src/HAL/TEENSY40_41/HAL.cpp index 4dd5c3678d..d40f620c81 100644 --- a/Marlin/src/HAL/TEENSY40_41/HAL.cpp +++ b/Marlin/src/HAL/TEENSY40_41/HAL.cpp @@ -202,18 +202,13 @@ uint16_t MarlinHAL::adc_value() { // Free Memory Accessor // ------------------------ -#define __bss_end _ebss - extern "C" { - extern char __bss_end; - extern char __heap_start; - extern void* __brkval; + // Reference for Teensy 4.x: https://forum.pjrc.com/index.php?threads/how-to-display-free-ram.33443/#post-275013 + extern unsigned long _heap_end; + extern char *__brkval; - // Doesn't work on Teensy 4.x uint32_t freeMemory() { - uint32_t free_memory; - free_memory = ((uint32_t)&free_memory) - (((uint32_t)__brkval) ?: ((uint32_t)&__bss_end)); - return free_memory; + return (char *)&_heap_end - __brkval; } } diff --git a/Marlin/src/HAL/TEENSY40_41/HAL.h b/Marlin/src/HAL/TEENSY40_41/HAL.h index 355d1d75ac..7fa285ae62 100644 --- a/Marlin/src/HAL/TEENSY40_41/HAL.h +++ b/Marlin/src/HAL/TEENSY40_41/HAL.h @@ -61,6 +61,8 @@ #undef PSTR #define PSTR(str) ({static const char *data = (str); &data[0];}) +#define HAL_CAN_SET_PWM_FREQ + // ------------------------ // Serial ports // ------------------------ @@ -221,11 +223,15 @@ public: /** * Set the PWM duty cycle for the pin to the given value. - * No option to invert the duty cycle [default = false] - * No option to change the scale of the provided value to enable finer PWM duty control [default = 255] + * Optionally invert the duty cycle [default = false] + * Optionally change the scale of the provided value to enable finer PWM duty control [default = 255] */ - static void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t=255, const bool=false) { - analogWrite(pin, v); - } + static void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size=255, const bool invert=false); + /** + * Set the PWM output frequency. This may affect multiple pins, though + * Teensy 4.x provides many timers affecting only a single pin. + * See: https://www.pjrc.com/teensy/td_pulse.html + */ + static void set_pwm_frequency(const pin_t pin, const uint16_t f_desired); }; diff --git a/Marlin/src/HAL/TEENSY40_41/fast_pwm.cpp b/Marlin/src/HAL/TEENSY40_41/fast_pwm.cpp new file mode 100644 index 0000000000..21531d115d --- /dev/null +++ b/Marlin/src/HAL/TEENSY40_41/fast_pwm.cpp @@ -0,0 +1,54 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifdef __IMXRT1062__ + +#include "../../inc/MarlinConfig.h" + +#include "HAL.h" + +void MarlinHAL::set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size /*=255*/, const bool invert) { + + uint32_t bits = 1; + uint16_t value = _MIN(v, v_size); + + if (invert) value = v_size - value; + + // Choose scale as smallest power of 2 which holds v_size. + uint32_t scale = 1; + while (scale < v_size) { + bits++; + scale *= 2; + } + + uint32_t scaled_val = scale * value / v_size; + + uint32_t prior = analogWriteResolution(bits); + analogWrite(pin, scaled_val); + analogWriteResolution(prior); +} + +void MarlinHAL::set_pwm_frequency(const pin_t pin, const uint16_t f_desired) { + analogWriteFrequency(pin, f_desired); +} + +#endif // __IMXRT1062__ diff --git a/Marlin/src/HAL/TEENSY40_41/inc/SanityCheck.h b/Marlin/src/HAL/TEENSY40_41/inc/SanityCheck.h index 731658b4a3..7b1c466f23 100644 --- a/Marlin/src/HAL/TEENSY40_41/inc/SanityCheck.h +++ b/Marlin/src/HAL/TEENSY40_41/inc/SanityCheck.h @@ -33,10 +33,6 @@ #error "EMERGENCY_PARSER is not yet implemented for Teensy 4.0/4.1. Disable EMERGENCY_PARSER to continue." #endif -#if ENABLED(FAST_PWM_FAN) || SPINDLE_LASER_FREQUENCY - #error "Features requiring Hardware PWM (FAST_PWM_FAN, SPINDLE_LASER_FREQUENCY) are not yet supported for Teensy 4.0/4.1." -#endif - #if HAS_TMC_SW_SERIAL #error "TMC220x Software Serial is not supported for Teensy 4.0/4.1." #endif @@ -44,3 +40,19 @@ #if ENABLED(POSTMORTEM_DEBUGGING) #error "POSTMORTEM_DEBUGGING is not yet supported for Teensy 4.0/4.1." #endif + +#if ENABLED(SERIAL_STATS_MAX_RX_QUEUED) || ENABLED(SERIAL_STATS_DROPPED_RX) || ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS) || ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS) + #error "SERIAL_STATS_* features not supported on Teensy 4.0/4.1." +#endif + +#if ENABLED(BAUD_RATE_GCODE) && SERIAL_PORT_2 == -2 + #error "BAUD_RATE_GCODE cannot be enabled when using the Ethernet serial port." +#endif + +#if ENABLED(SPINDLE_LASER_USE_PWM) && !ENABLED(SILENCE_TEENSY_SPINDLE_LASER_WARNING) + #warning "SPINDLE_LASER_USE_PWM is untested on Teensy 4.0/4.1, see https://www.pjrc.com/teensy/td_pulse.html for details on frequencies, and resolution. #define SILENCE_TEENSY_SPINDLE_LASER_WARNING to silence warning." +#endif + +#if ENABLED(FAST_PWM_FAN) && FAST_PWM_FAN_FREQUENCY == 1000U + #warning "FAST_PWM_FAN_FREQUENCY has been left as default, see https://www.pjrc.com/teensy/td_pulse.html and consider raising it to reduce noise." +#endif diff --git a/Marlin/src/gcode/calibrate/M100.cpp b/Marlin/src/gcode/calibrate/M100.cpp index c05fe12fc3..93045e955c 100644 --- a/Marlin/src/gcode/calibrate/M100.cpp +++ b/Marlin/src/gcode/calibrate/M100.cpp @@ -60,7 +60,7 @@ #define TEST_BYTE ((char) 0xE5) -#if ANY(__AVR__, IS_32BIT_TEENSY) +#if ANY(__AVR__, IS_32BIT_TEENSY) && !IS_TEENSY_40_41 extern char __bss_end; char *end_bss = &__bss_end, From ef34fd1a3f535a1bcaed6f189db265a6dbc0998a Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Tue, 14 Jan 2025 00:26:31 +0000 Subject: [PATCH 035/787] [cron] Bump distribution date (2025-01-14) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 35807cab41..2ac491e71b 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-01-13" +//#define STRING_DISTRIBUTION_DATE "2025-01-14" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index b798c042fe..47a83f82b4 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-01-13" + #define STRING_DISTRIBUTION_DATE "2025-01-14" #endif /** From 5dc55150bd77eb93966b796ce702313835720a21 Mon Sep 17 00:00:00 2001 From: Keith Bennett <13375512+thisiskeithb@users.noreply.github.com> Date: Tue, 14 Jan 2025 10:42:06 -0800 Subject: [PATCH 036/787] =?UTF-8?q?=F0=9F=94=A7=20BTT=20SKRat=20UART=20dri?= =?UTF-8?q?ver=20support=20pending=20(#27639)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/pins/stm32g0/pins_BTT_SKRAT_V1_0.h | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/Marlin/src/pins/stm32g0/pins_BTT_SKRAT_V1_0.h b/Marlin/src/pins/stm32g0/pins_BTT_SKRAT_V1_0.h index cbdb8ed896..7d3c249b90 100644 --- a/Marlin/src/pins/stm32g0/pins_BTT_SKRAT_V1_0.h +++ b/Marlin/src/pins/stm32g0/pins_BTT_SKRAT_V1_0.h @@ -309,16 +309,18 @@ // // Software serial // - #define X_SERIAL_TX_PIN PF10 - #define Y_SERIAL_TX_PIN PD4 - #define Z_SERIAL_TX_PIN PC8 - #define E0_SERIAL_TX_PIN PD8 - #define E1_SERIAL_TX_PIN PB11 + //#define X_SERIAL_TX_PIN PF10 + //#define Y_SERIAL_TX_PIN PD4 + //#define Z_SERIAL_TX_PIN PC8 + //#define E0_SERIAL_TX_PIN PD8 + //#define E1_SERIAL_TX_PIN PB11 // Reduce baud rate to improve software serial reliability - #ifndef TMC_BAUD_RATE - #define TMC_BAUD_RATE 19200 - #endif + //#ifndef TMC_BAUD_RATE + // #define TMC_BAUD_RATE 19200 + //#endif + + #error "UART-based drivers are not supported on this board." #endif From 70cdfbe8fc2ca4ee9833147cef9d3fe4d38022e6 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 14 Jan 2025 12:46:32 -0600 Subject: [PATCH 037/787] =?UTF-8?q?=F0=9F=93=9D=20Add'l=20homeaxis=20comme?= =?UTF-8?q?nts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/module/motion.cpp | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/Marlin/src/module/motion.cpp b/Marlin/src/module/motion.cpp index 820089d7ee..fe9038a6b8 100644 --- a/Marlin/src/module/motion.cpp +++ b/Marlin/src/module/motion.cpp @@ -1314,7 +1314,7 @@ void do_blocking_move_to(const xyze_pos_t &raw, const_feedRate_t fr_mm_s/*=0.0f* probe.move_z_after_probing(); #endif } -#endif +#endif // HAS_Z_AXIS #if HAS_I_AXIS void do_blocking_move_to_xyz_i(const xyze_pos_t &raw, const_float_t i, const_feedRate_t fr_mm_s/*=0.0f*/) { @@ -2681,12 +2681,10 @@ void prepare_line_to_destination() { // // Homing Z with a probe? Raise Z (maybe) and deploy the Z probe. + // Return early if probe deployment fails. // #if HOMING_Z_WITH_PROBE - if (axis == Z_AXIS && probe.deploy()) { - probe.stow(); - return; - } + if (axis == Z_AXIS && probe.deploy()) { probe.stow(); return; } #endif // Set flags for X, Y, Z motor locking @@ -2705,16 +2703,17 @@ void prepare_line_to_destination() { // #if HOMING_Z_WITH_PROBE if (axis == Z_AXIS) { + #if ENABLED(BLTOUCH) - if (bltouch.deploy()) { // BLTouch was deployed above, but get the alarm state. - bltouch.stow(); - return; - } + // BLTouch was deployed above, but get the alarm state. + // Stow and return early if there is a deploy alarm. + if (bltouch.deploy()) { bltouch.stow(); return; } #endif - if (TERN0(PROBE_TARE, probe.tare())) { - probe.stow(); - return; - } + + // Tare the probe. Stow and return early if it fails + if (TERN0(PROBE_TARE, probe.tare())) { probe.stow(); return; } + + // Tell the Bed Distance Sensor we're Z homing TERN_(BD_SENSOR, bdl.config_state = BDS_HOMING_Z); } #endif @@ -2987,7 +2986,7 @@ void prepare_line_to_destination() { if (axis == Z_AXIS) bdl.config_state = BDS_IDLE; #endif - // Put away the Z probe + // Put away the Z probe. Return early if it fails. if (TERN0(HOMING_Z_WITH_PROBE, axis == Z_AXIS && probe.stow())) return; #if DISABLED(DELTA) && defined(HOMING_BACKOFF_POST_MM) From 85ebd170a9c4f5aec328d96961e33070c0de8197 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 14 Jan 2025 13:13:29 -0600 Subject: [PATCH 038/787] =?UTF-8?q?=F0=9F=94=A7=20Standard=20filament=20ru?= =?UTF-8?q?nout=20pins=20for=20MKS=5FUI=20/=20MKS=20TFT=20(#27640)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/feature/pause.cpp | 2 +- Marlin/src/feature/runout.h | 2 +- Marlin/src/inc/SanityCheck.h | 2 + .../src/lcd/extui/dgus/mks/DGUSDisplayDef.h | 6 -- .../lcd/extui/dgus/mks/DGUSScreenHandler.cpp | 14 +-- Marlin/src/lcd/extui/mks_ui/mks_hardware.cpp | 88 +++++++++++-------- .../lcd/extui/mks_ui/printer_operation.cpp | 49 ++++++----- Marlin/src/lcd/menu/menu_configuration.cpp | 2 +- Marlin/src/module/endstops.cpp | 18 ++-- Marlin/src/pins/stm32f1/pins_FLSUN_HISPEED.h | 16 ++-- Marlin/src/pins/stm32f1/pins_MKS_ROBIN_E3P.h | 10 ++- Marlin/src/pins/stm32f1/pins_MKS_ROBIN_MINI.h | 8 +- .../src/pins/stm32f1/pins_MKS_ROBIN_NANO_V2.h | 12 ++- .../pins/stm32f1/pins_MKS_ROBIN_NANO_common.h | 12 ++- .../src/pins/stm32f4/pins_MKS_MONSTER8_V1.h | 6 +- .../src/pins/stm32f4/pins_MKS_MONSTER8_V2.h | 6 +- .../pins/stm32f4/pins_MKS_MONSTER8_common.h | 10 +++ .../stm32f4/pins_MKS_ROBIN_NANO_V3_common.h | 19 ++-- 18 files changed, 155 insertions(+), 127 deletions(-) diff --git a/Marlin/src/feature/pause.cpp b/Marlin/src/feature/pause.cpp index 3589847761..fbb78ccbf9 100644 --- a/Marlin/src/feature/pause.cpp +++ b/Marlin/src/feature/pause.cpp @@ -221,7 +221,7 @@ bool load_filament(const_float_t slow_load_length/*=0*/, const_float_t fast_load impatient_beep(max_beep_count); #if ALL(HAS_FILAMENT_SENSOR, FILAMENT_CHANGE_RESUME_ON_INSERT) #if MULTI_FILAMENT_SENSOR - #define _CASE_INSERTED(N) case N-1: if (READ(FIL_RUNOUT##N##_PIN) != FIL_RUNOUT##N##_STATE) wait_for_user = false; break; + #define _CASE_INSERTED(N) case N-1: if (!FILAMENT_IS_OUT(N)) wait_for_user = false; break; switch (active_extruder) { REPEAT_1(NUM_RUNOUT_SENSORS, _CASE_INSERTED) } diff --git a/Marlin/src/feature/runout.h b/Marlin/src/feature/runout.h index 52a9020830..d7c41907ed 100644 --- a/Marlin/src/feature/runout.h +++ b/Marlin/src/feature/runout.h @@ -51,7 +51,7 @@ #define HAS_FILAMENT_SWITCH 1 #endif -#define FILAMENT_IS_OUT() (READ(FIL_RUNOUT_PIN) == FIL_RUNOUT_STATE) +#define FILAMENT_IS_OUT(N...) (READ(FIL_RUNOUT##N##_PIN) == FIL_RUNOUT##N##_STATE) typedef Flags< #if NUM_MOTION_SENSORS > NUM_RUNOUT_SENSORS diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index b7edc34ade..034878db66 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -553,6 +553,8 @@ static_assert(COUNT(arm) == LOGICAL_AXES, "AXIS_RELATIVE_MODES must contain " _L #error "FILAMENT_RUNOUT_DISTANCE_MM must be greater than or equal to zero." #elif DISABLED(ADVANCED_PAUSE_FEATURE) && defined(FILAMENT_RUNOUT_SCRIPT) static_assert(nullptr == strstr(FILAMENT_RUNOUT_SCRIPT, "M600"), "FILAMENT_RUNOUT_SCRIPT cannot make use of M600 unless ADVANCED_PAUSE_FEATURE is enabled"); + #elif DGUS_LCD_UI_MKS + #error "MKS UI is not currently compatible with FILAMENT_RUNOUT_SENSOR. Define DGUS_MKS_RUNOUT_SENSOR instead." #endif #endif diff --git a/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.h b/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.h index ee2e7ffb6b..95bee17229 100644 --- a/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.h +++ b/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.h @@ -27,12 +27,6 @@ #define LOGO_TIME_DELAY TERN(USE_MKS_GREEN_UI, 8000, 1500) -#if ENABLED(DGUS_MKS_RUNOUT_SENSOR) - #define MT_DET_1_PIN 1 - #define MT_DET_2_PIN 2 - #define MT_DET_PIN_STATE LOW -#endif - #define MKS_FINSH extern uint16_t manualMoveStep; diff --git a/Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.cpp b/Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.cpp index edaff3b845..1999518607 100644 --- a/Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.cpp +++ b/Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.cpp @@ -47,6 +47,10 @@ #include "../../../../feature/powerloss.h" #endif +#if ENABLED(DGUS_MKS_RUNOUT_SENSOR) + #define FILAMENT_IS_OUT(N...) (READ(FIL_RUNOUT##N##_PIN) == FIL_RUNOUT##N##_STATE) +#endif + #if HAS_MEDIA extern ExtUI::FileList filelist; #endif @@ -1374,8 +1378,8 @@ void DGUSScreenHandlerMKS::extrudeLoadInit() { } void DGUSScreenHandlerMKS::runoutInit() { - #if PIN_EXISTS(MT_DET_1) - SET_INPUT_PULLUP(MT_DET_1_PIN); + #if ENABLED(DGUS_MKS_RUNOUT_SENSOR) && PIN_EXISTS(FIL_RUNOUT) + SET_INPUT_PULLUP(FIL_RUNOUT_PIN); #endif runout_mks.de_count = 0; runout_mks.de_times = 10; @@ -1399,17 +1403,17 @@ void DGUSScreenHandlerMKS::runoutIdle() { break; case UNRUNOUT_STATUS: - if (READ(MT_DET_1_PIN) == MT_DET_PIN_STATE) + if (FILAMENT_IS_OUT()) runout_mks.runout_status = RUNOUT_STATUS; break; case RUNOUT_BEGIN_STATUS: - if (READ(MT_DET_1_PIN) != MT_DET_PIN_STATE) + if (!FILAMENT_IS_OUT()) runout_mks.runout_status = RUNOUT_WAITING_STATUS; break; case RUNOUT_WAITING_STATUS: - if (READ(MT_DET_1_PIN) == MT_DET_PIN_STATE) + if (FILAMENT_IS_OUT()) runout_mks.runout_status = RUNOUT_BEGIN_STATUS; break; diff --git a/Marlin/src/lcd/extui/mks_ui/mks_hardware.cpp b/Marlin/src/lcd/extui/mks_ui/mks_hardware.cpp index f06ffcd89d..c216eb7e63 100644 --- a/Marlin/src/lcd/extui/mks_ui/mks_hardware.cpp +++ b/Marlin/src/lcd/extui/mks_ui/mks_hardware.cpp @@ -41,8 +41,11 @@ #include "mks_hardware.h" #include "../../../module/endstops.h" - bool pw_det_sta, pw_off_sta, mt_det_sta; - #if PIN_EXISTS(MT_DET_2) + bool pw_det_sta, pw_off_sta; + #if PIN_EXISTS(FIL_RUNOUT) + bool mt_det1_sta; + #endif + #if PIN_EXISTS(FIL_RUNOUT2) bool mt_det2_sta; #endif #if USE_X_MIN @@ -96,40 +99,42 @@ constexpr static bool endstopz4_sta = true; #endif - #define ESTATE(S) (READ(S##_PIN) == S##_ENDSTOP_HIT_STATE) + #define LOWSTATE(S) (READ(S##_PIN) == LOW) void test_gpio_readlevel_L() { #if PIN_EXISTS(WIFI_IO0) WRITE(WIFI_IO0_PIN, HIGH); #endif delay(10); - pw_det_sta = (READ(MKS_TEST_POWER_LOSS_PIN) == LOW); - pw_off_sta = (READ(MKS_TEST_PS_ON_PIN) == LOW); - mt_det_sta = (READ(MT_DET_1_PIN) == LOW); - #if PIN_EXISTS(MT_DET_2) - mt_det2_sta = (READ(MT_DET_2_PIN) == LOW); + pw_det_sta = LOWSTATE(MKS_TEST_POWER_LOSS); + pw_off_sta = LOWSTATE(MKS_TEST_PS_ON); + #if PIN_EXISTS(FIL_RUNOUT) + mt_det1_sta = LOWSTATE(FIL_RUNOUT); #endif - TERN_(USE_X_MIN, endstopx1_min = ESTATE(X_MIN)); - TERN_(USE_X_MAX, endstopx1_max = ESTATE(X_MAX)); + #if PIN_EXISTS(FIL_RUNOUT2) + mt_det2_sta = LOWSTATE(FIL_RUNOUT2); + #endif + TERN_(USE_X_MIN, endstopx1_min = LOWSTATE(X_MIN)); + TERN_(USE_X_MAX, endstopx1_max = LOWSTATE(X_MAX)); #if USE_X2_MIN || USE_X2_MAX - endstopx2_sta = ESTATE(TERN(USE_X2_MIN, X2_MIN, X2_MAX)); + endstopx2_sta = LOWSTATE(TERN(USE_X2_MIN, X2_MIN, X2_MAX)); #endif #if USE_Y_MIN || USE_Y_MAX - endstopy1_sta = ESTATE(TERN(USE_Y_MIN, Y_MIN, Y_MAX)); + endstopy1_sta = LOWSTATE(TERN(USE_Y_MIN, Y_MIN, Y_MAX)); #endif #if USE_Y2_MIN || USE_Y2_MAX - endstopy2_sta = ESTATE(TERN(USE_Y2_MIN, Y2_MIN, Y2_MAX)); + endstopy2_sta = LOWSTATE(TERN(USE_Y2_MIN, Y2_MIN, Y2_MAX)); #endif - TERN_(USE_Z_MIN, endstopz1_min = ESTATE(Z_MIN)); - TERN_(USE_Z_MAX, endstopz1_max = ESTATE(Z_MAX)); + TERN_(USE_Z_MIN, endstopz1_min = LOWSTATE(Z_MIN)); + TERN_(USE_Z_MAX, endstopz1_max = LOWSTATE(Z_MAX)); #if USE_Z2_MIN || USE_Z2_MAX - endstopz2_sta = ESTATE(TERN(USE_Z2_MIN, Z2_MIN, Z2_MAX)); + endstopz2_sta = LOWSTATE(TERN(USE_Z2_MIN, Z2_MIN, Z2_MAX)); #endif #if USE_Z3_MIN || USE_Z3_MAX - endstopz3_sta = ESTATE(TERN(USE_Z3_MIN, Z3_MIN, Z3_MAX)); + endstopz3_sta = LOWSTATE(TERN(USE_Z3_MIN, Z3_MIN, Z3_MAX)); #endif #if USE_Z4_MIN || USE_Z4_MAX - endstopz4_sta = ESTATE(TERN(USE_Z4_MIN, Z4_MIN, Z4_MAX)); + endstopz4_sta = LOWSTATE(TERN(USE_Z4_MIN, Z4_MIN, Z4_MAX)); #endif } @@ -138,33 +143,35 @@ WRITE(WIFI_IO0_PIN, LOW); #endif delay(10); - pw_det_sta = (READ(MKS_TEST_POWER_LOSS_PIN) == HIGH); - pw_off_sta = (READ(MKS_TEST_PS_ON_PIN) == HIGH); - mt_det_sta = (READ(MT_DET_1_PIN) == HIGH); - #if PIN_EXISTS(MT_DET_2) - mt_det2_sta = (READ(MT_DET_2_PIN) == HIGH); + pw_det_sta = !LOWSTATE(MKS_TEST_POWER_LOSS); + pw_off_sta = !LOWSTATE(MKS_TEST_PS_ON); + #if PIN_EXISTS(FIL_RUNOUT) + mt_det1_sta = !LOWSTATE(FIL_RUNOUT); #endif - TERN_(USE_X_MIN, endstopx1_min = !ESTATE(X_MIN)); - TERN_(USE_X_MAX, endstopx1_max = !ESTATE(X_MAX)); + #if PIN_EXISTS(FIL_RUNOUT2) + mt_det2_sta = !LOWSTATE(FIL_RUNOUT2); + #endif + TERN_(USE_X_MIN, endstopx1_min = !LOWSTATE(X_MIN)); + TERN_(USE_X_MAX, endstopx1_max = !LOWSTATE(X_MAX)); #if USE_X2_MIN || USE_X2_MAX - endstopx2_sta = !ESTATE(TERN(USE_X2_MIN, X2_MIN, X2_MAX)); + endstopx2_sta = !LOWSTATE(TERN(USE_X2_MIN, X2_MIN, X2_MAX)); #endif #if USE_Y_MIN || USE_Y_MAX - endstopy1_sta = !ESTATE(TERN(USE_Y_MIN, Y_MIN, Y_MAX)); + endstopy1_sta = !LOWSTATE(TERN(USE_Y_MIN, Y_MIN, Y_MAX)); #endif #if USE_Y2_MIN || USE_Y2_MAX - endstopy2_sta = !ESTATE(TERN(USE_Y2_MIN, Y2_MIN, Y2_MAX)); + endstopy2_sta = !LOWSTATE(TERN(USE_Y2_MIN, Y2_MIN, Y2_MAX)); #endif - TERN_(USE_Z_MIN, endstopz1_min = !ESTATE(Z_MIN)); - TERN_(USE_Z_MAX, endstopz1_max = !ESTATE(Z_MAX)); + TERN_(USE_Z_MIN, endstopz1_min = !LOWSTATE(Z_MIN)); + TERN_(USE_Z_MAX, endstopz1_max = !LOWSTATE(Z_MAX)); #if USE_Z2_MIN || USE_Z2_MAX - endstopz2_sta = !ESTATE(TERN(USE_Z2_MIN, Z2_MIN, Z2_MAX)); + endstopz2_sta = !LOWSTATE(TERN(USE_Z2_MIN, Z2_MIN, Z2_MAX)); #endif #if USE_Z3_MIN || USE_Z3_MAX - endstopz3_sta = !ESTATE(TERN(USE_Z3_MIN, Z3_MIN, Z3_MAX)); + endstopz3_sta = !LOWSTATE(TERN(USE_Z3_MIN, Z3_MIN, Z3_MAX)); #endif #if USE_Z4_MIN || USE_Z4_MAX - endstopz4_sta = !ESTATE(TERN(USE_Z4_MIN, Z4_MIN, Z4_MAX)); + endstopz4_sta = !LOWSTATE(TERN(USE_Z4_MIN, Z4_MIN, Z4_MAX)); #endif } @@ -177,11 +184,11 @@ SET_OUTPUT(WIFI_IO0_PIN); #endif - #if PIN_EXISTS(MT_DET_1) - SET_INPUT_PULLUP(MT_DET_1_PIN); + #if PIN_EXISTS(FIL_RUNOUT) + SET_INPUT_PULLUP(FIL_RUNOUT_PIN); #endif - #if PIN_EXISTS(MT_DET_2) - SET_INPUT_PULLUP(MT_DET_2_PIN); + #if PIN_EXISTS(FIL_RUNOUT2) + SET_INPUT_PULLUP(FIL_RUNOUT2_PIN); #endif SET_INPUT_PULLUP(MKS_TEST_POWER_LOSS_PIN); @@ -225,8 +232,11 @@ test_gpio_readlevel_L(); test_gpio_readlevel_H(); test_gpio_readlevel_L(); - if (pw_det_sta && pw_off_sta && mt_det_sta - #if PIN_EXISTS(MT_DET_2) + if (pw_det_sta && pw_off_sta + #if PIN_EXISTS(FIL_RUNOUT) + && mt_det1_sta + #endif + #if PIN_EXISTS(FIL_RUNOUT2) && mt_det2_sta #endif #if ENABLED(MKS_HARDWARE_TEST_ONLY_E0) diff --git a/Marlin/src/lcd/extui/mks_ui/printer_operation.cpp b/Marlin/src/lcd/extui/mks_ui/printer_operation.cpp index 26979af270..dc47cdb357 100644 --- a/Marlin/src/lcd/extui/mks_ui/printer_operation.cpp +++ b/Marlin/src/lcd/extui/mks_ui/printer_operation.cpp @@ -39,6 +39,11 @@ #include "../../../feature/powerloss.h" #endif +#define FILAMENT_IS_OUT(N...) (READ(FIL_RUNOUT##N##_PIN) == FIL_RUNOUT##N##_STATE) +#ifndef FILAMENT_RUNOUT_THRESHOLD + #define FILAMENT_RUNOUT_THRESHOLD 20 +#endif + extern uint32_t To_pre_view; extern bool flash_preview_begin, default_preview_flg, gcode_preview_over; @@ -101,6 +106,7 @@ void printer_state_polling() { update_spi_flash(); } } + #if ENABLED(POWER_LOSS_RECOVERY) if (uiCfg.print_state == REPRINTED) { #if HAS_HOTEND @@ -118,6 +124,7 @@ void printer_state_polling() { #endif recovery.resume(); + #if 0 // Move back to the saved XY char str_1[16], str_2[16]; @@ -140,61 +147,57 @@ void printer_state_polling() { } #endif - if (uiCfg.print_state == WORKING) - filament_check(); + if (uiCfg.print_state == WORKING) filament_check(); TERN_(MKS_WIFI_MODULE, wifi_looping()); } void filament_pin_setup() { - #if PIN_EXISTS(MT_DET_1) - SET_INPUT_PULLUP(MT_DET_1_PIN); + #if PIN_EXISTS(FIL_RUNOUT1) + SET_INPUT_PULLUP(FIL_RUNOUT1_PIN); #endif - #if PIN_EXISTS(MT_DET_2) - SET_INPUT_PULLUP(MT_DET_2_PIN); + #if PIN_EXISTS(FIL_RUNOUT2) + SET_INPUT_PULLUP(FIL_RUNOUT2_PIN); #endif - #if PIN_EXISTS(MT_DET_3) - SET_INPUT_PULLUP(MT_DET_3_PIN); + #if PIN_EXISTS(FIL_RUNOUT3) + SET_INPUT_PULLUP(FIL_RUNOUT3_PIN); #endif } void filament_check() { - #if ANY_PIN(MT_DET_1, MT_DET_2, MT_DET_3) - const int FIL_DELAY = 20; - #endif - #if PIN_EXISTS(MT_DET_1) + #if PIN_EXISTS(FIL_RUNOUT1) static int fil_det_count_1 = 0; - if (READ(MT_DET_1_PIN) == MT_DET_PIN_STATE) + if (FILAMENT_IS_OUT(1)) fil_det_count_1++; else if (fil_det_count_1 > 0) fil_det_count_1--; #endif - #if PIN_EXISTS(MT_DET_2) + #if PIN_EXISTS(FIL_RUNOUT2) static int fil_det_count_2 = 0; - if (READ(MT_DET_2_PIN) == MT_DET_PIN_STATE) + if (FILAMENT_IS_OUT(2)) fil_det_count_2++; else if (fil_det_count_2 > 0) fil_det_count_2--; #endif - #if PIN_EXISTS(MT_DET_3) + #if PIN_EXISTS(FIL_RUNOUT3) static int fil_det_count_3 = 0; - if (READ(MT_DET_3_PIN) == MT_DET_PIN_STATE) + if (FILAMENT_IS_OUT(3)) fil_det_count_3++; else if (fil_det_count_3 > 0) fil_det_count_3--; #endif if (false - #if PIN_EXISTS(MT_DET_1) - || fil_det_count_1 >= FIL_DELAY + #if PIN_EXISTS(FIL_RUNOUT1) + || fil_det_count_1 >= FILAMENT_RUNOUT_THRESHOLD #endif - #if PIN_EXISTS(MT_DET_2) - || fil_det_count_2 >= FIL_DELAY + #if PIN_EXISTS(FIL_RUNOUT2) + || fil_det_count_2 >= FILAMENT_RUNOUT_THRESHOLD #endif - #if PIN_EXISTS(MT_DET_3) - || fil_det_count_3 >= FIL_DELAY + #if PIN_EXISTS(FIL_RUNOUT3) + || fil_det_count_3 >= FILAMENT_RUNOUT_THRESHOLD #endif ) { clear_cur_ui(); diff --git a/Marlin/src/lcd/menu/menu_configuration.cpp b/Marlin/src/lcd/menu/menu_configuration.cpp index e0e8ca4dd0..65a2f222ce 100644 --- a/Marlin/src/lcd/menu/menu_configuration.cpp +++ b/Marlin/src/lcd/menu/menu_configuration.cpp @@ -114,7 +114,7 @@ void menu_advanced_settings(); #endif #define STOP_ITEM(A,I,M,L) TERN(HAS_##A##I##_##M##_STATE, _STOP_ITEM, _IF_1_ELSE)(STRINGIFY(A) STRINGIFY(I) S1_SPACE(I) " " L, A##I##_##M) #define STOP_MINMAX(A,I) STOP_ITEM(A,I,MIN,"Min") STOP_ITEM(A,I,MAX,"Max") - #define FIL_ITEM(N) PSTRING_ITEM_N_P(N-1, MSG_FILAMENT_EN, (READ(FIL_RUNOUT##N##_PIN) != FIL_RUNOUT##N##_STATE) ? PSTR("PRESENT") : PSTR("out"), SS_FULL); + #define FIL_ITEM(N) PSTRING_ITEM_N_P(N-1, MSG_FILAMENT_EN, FILAMENT_IS_OUT(N) ? PSTR("out") : PSTR("PRESENT"), SS_FULL); static void screen_endstop_test() { if (ui.use_click()) { diff --git a/Marlin/src/module/endstops.cpp b/Marlin/src/module/endstops.cpp index f3515ad928..6894b13f07 100644 --- a/Marlin/src/module/endstops.cpp +++ b/Marlin/src/module/endstops.cpp @@ -519,18 +519,12 @@ void __O2 Endstops::report_states() { print_es_state(READ(CALIBRATION_PIN) != CALIBRATION_PIN_INVERTING, F(STR_CALIBRATION)); #endif #if MULTI_FILAMENT_SENSOR - #define _CASE_RUNOUT(N) case N: pin = FIL_RUNOUT##N##_PIN; state = FIL_RUNOUT##N##_STATE; break; - for (uint8_t i = 1; i <= NUM_RUNOUT_SENSORS; ++i) { - pin_t pin; - uint8_t state; - switch (i) { - default: continue; - REPEAT_1(NUM_RUNOUT_SENSORS, _CASE_RUNOUT) - } - SERIAL_ECHOPGM(STR_FILAMENT); - if (i > 1) SERIAL_CHAR(' ', '0' + i); - print_es_state(extDigitalRead(pin) != state); - } + #define _CASE_RUNOUT(N) do{ \ + SERIAL_ECHO(F(STR_FILAMENT)); \ + if ((N) > 1) SERIAL_CHAR(' ', '0' + char(N)); \ + print_es_state(!FILAMENT_IS_OUT(N)); \ + }while(0); + REPEAT_1(NUM_RUNOUT_SENSORS, _CASE_RUNOUT) #undef _CASE_RUNOUT #elif HAS_FILAMENT_SENSOR print_es_state(!FILAMENT_IS_OUT(), F(STR_FILAMENT)); diff --git a/Marlin/src/pins/stm32f1/pins_FLSUN_HISPEED.h b/Marlin/src/pins/stm32f1/pins_FLSUN_HISPEED.h index fa757d2d52..caac738bb9 100644 --- a/Marlin/src/pins/stm32f1/pins_FLSUN_HISPEED.h +++ b/Marlin/src/pins/stm32f1/pins_FLSUN_HISPEED.h @@ -95,10 +95,6 @@ #define Z_MIN_PIN PA11 // -Z #define Z_MAX_PIN PC4 // +Z -#ifndef FIL_RUNOUT_PIN - #define FIL_RUNOUT_PIN PA4 // MT_DET -#endif - // // Steppers // @@ -225,9 +221,15 @@ #endif #if HAS_TFT_LVGL_UI - #define MT_DET_1_PIN PA4 // MT_DET - #define MT_DET_2_PIN PE6 - #define MT_DET_PIN_STATE LOW + #ifndef FIL_RUNOUT_PIN + #define FIL_RUNOUT_PIN PA4 // MT_DET_1 + #endif + #ifndef FIL_RUNOUT2_PIN + #define FIL_RUNOUT2_PIN PE6 // MT_DET_2 + #endif + #ifndef FIL_RUNOUT_STATE + #define FIL_RUNOUT_STATE LOW + #endif #endif // diff --git a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_E3P.h b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_E3P.h index 01be779b13..087a064c05 100644 --- a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_E3P.h +++ b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_E3P.h @@ -80,6 +80,10 @@ #define Z_MIN_PIN PA11 #define Z_MAX_PIN PC4 +#ifndef FIL_RUNOUT_PIN + #define FIL_RUNOUT_PIN PA4 // MT_DET +#endif + // // Probe enable // @@ -187,8 +191,9 @@ #define KILL_PIN_STATE HIGH #endif - #define MT_DET_1_PIN PA4 - #define MT_DET_PIN_STATE LOW + #ifndef FIL_RUNOUT_STATE + #define FIL_RUNOUT_STATE LOW + #endif #define WIFI_IO0_PIN PC13 #define WIFI_IO1_PIN PC7 @@ -205,7 +210,6 @@ #else //#define POWER_LOSS_PIN PA2 // PW_DET //#define PS_ON_PIN PB2 // PW_OFF - #define FIL_RUNOUT_PIN PA4 #endif //#define LED_PIN PB2 diff --git a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_MINI.h b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_MINI.h index 6b563e9607..e21760940c 100644 --- a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_MINI.h +++ b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_MINI.h @@ -70,6 +70,9 @@ #ifndef FIL_RUNOUT_PIN #define FIL_RUNOUT_PIN PA4 // MT_DET #endif +#ifndef FIL_RUNOUT_STATE + #define FIL_RUNOUT_STATE LOW +#endif // // Probe enable @@ -126,11 +129,6 @@ #define POWER_LOSS_PIN PA2 // PW_DET #define PS_ON_PIN PA3 // PW_OFF -#if HAS_TFT_LVGL_UI - #define MT_DET_1_PIN PA4 // MT_DET - #define MT_DET_PIN_STATE LOW -#endif - #define WIFI_IO0_PIN PC13 // diff --git a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_NANO_V2.h b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_NANO_V2.h index 67d60a97ed..5c09d8e807 100644 --- a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_NANO_V2.h +++ b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_NANO_V2.h @@ -211,9 +211,15 @@ // Misc. Functions // #if HAS_TFT_LVGL_UI - #define MT_DET_1_PIN PA4 - #define MT_DET_2_PIN PE6 - #define MT_DET_PIN_STATE LOW + #ifndef FIL_RUNOUT_PIN + #define FIL_RUNOUT_PIN PA4 // MT_DET_1 + #endif + #ifndef FIL_RUNOUT2_PIN + #define FIL_RUNOUT2_PIN PE6 // MT_DET_2 + #endif + #ifndef FIL_RUNOUT_STATE + #define FIL_RUNOUT_STATE LOW + #endif #define WIFI_IO0_PIN PC13 #define WIFI_IO1_PIN PC7 diff --git a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_NANO_common.h b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_NANO_common.h index 6d644ed086..808b0c190c 100644 --- a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_NANO_common.h +++ b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_NANO_common.h @@ -149,9 +149,15 @@ // Misc. Functions // #if HAS_TFT_LVGL_UI - #define MT_DET_1_PIN PA4 - #define MT_DET_2_PIN PE6 - #define MT_DET_PIN_STATE LOW + #ifndef FIL_RUNOUT_PIN + #define FIL_RUNOUT_PIN PA4 // MT_DET_1 + #endif + #ifndef FIL_RUNOUT2_PIN + #define FIL_RUNOUT2_PIN PE6 // MT_DET_2 + #endif + #ifndef FIL_RUNOUT_STATE + #define FIL_RUNOUT_STATE LOW + #endif #define WIFI_IO0_PIN PC13 #define WIFI_IO1_PIN PC7 diff --git a/Marlin/src/pins/stm32f4/pins_MKS_MONSTER8_V1.h b/Marlin/src/pins/stm32f4/pins_MKS_MONSTER8_V1.h index 7d6ea8e039..a8d0be3ca6 100644 --- a/Marlin/src/pins/stm32f4/pins_MKS_MONSTER8_V1.h +++ b/Marlin/src/pins/stm32f4/pins_MKS_MONSTER8_V1.h @@ -41,13 +41,11 @@ // #define PW_DET PC5 // Y+ #define PW_OFF PB12 // Z+ -#define MT_DET_1_PIN PW_DET -#define MT_DET_2_PIN PW_OFF #ifndef FIL_RUNOUT_PIN - #define FIL_RUNOUT_PIN MT_DET_1_PIN + #define FIL_RUNOUT_PIN PC5 // Y+ #endif #ifndef FIL_RUNOUT2_PIN - #define FIL_RUNOUT2_PIN MT_DET_2_PIN + #define FIL_RUNOUT2_PIN PB12 // Z+ #endif #include "pins_MKS_MONSTER8_common.h" diff --git a/Marlin/src/pins/stm32f4/pins_MKS_MONSTER8_V2.h b/Marlin/src/pins/stm32f4/pins_MKS_MONSTER8_V2.h index 12d3947b99..3312a576b0 100644 --- a/Marlin/src/pins/stm32f4/pins_MKS_MONSTER8_V2.h +++ b/Marlin/src/pins/stm32f4/pins_MKS_MONSTER8_V2.h @@ -39,13 +39,11 @@ // #define PW_DET PA13 // MT_DET #define PW_OFF PB12 // Z+ -#define MT_DET_1_PIN PW_DET -#define MT_DET_2_PIN PW_OFF #ifndef FIL_RUNOUT_PIN - #define FIL_RUNOUT_PIN MT_DET_1_PIN + #define FIL_RUNOUT_PIN PA13 // MT_DET #endif #ifndef FIL_RUNOUT2_PIN - #define FIL_RUNOUT2_PIN MT_DET_2_PIN + #define FIL_RUNOUT2_PIN PB12 // Z+ #endif // diff --git a/Marlin/src/pins/stm32f4/pins_MKS_MONSTER8_common.h b/Marlin/src/pins/stm32f4/pins_MKS_MONSTER8_common.h index b15c7d7288..9c81eb1c85 100644 --- a/Marlin/src/pins/stm32f4/pins_MKS_MONSTER8_common.h +++ b/Marlin/src/pins/stm32f4/pins_MKS_MONSTER8_common.h @@ -74,6 +74,16 @@ #define PROBE_ENABLE_PIN SERVO0_PIN #endif +// +// Filament Runout Sensor +// +#ifndef FIL_RUNOUT_PIN + #define FIL_RUNOUT_PIN PC5 // Y+ +#endif +#ifndef FIL_RUNOUT2_PIN + #define FIL_RUNOUT2_PIN PB12 // Z+ +#endif + // // Steppers // diff --git a/Marlin/src/pins/stm32f4/pins_MKS_ROBIN_NANO_V3_common.h b/Marlin/src/pins/stm32f4/pins_MKS_ROBIN_NANO_V3_common.h index a3f6571271..8f4e5ff6b8 100644 --- a/Marlin/src/pins/stm32f4/pins_MKS_ROBIN_NANO_V3_common.h +++ b/Marlin/src/pins/stm32f4/pins_MKS_ROBIN_NANO_V3_common.h @@ -147,16 +147,15 @@ // Misc. Functions // #if HAS_TFT_LVGL_UI - #define MT_DET_1_PIN PA4 // MT_DET - #define MT_DET_2_PIN PE6 - #define MT_DET_PIN_STATE LOW -#endif - -#ifndef FIL_RUNOUT_PIN - #define FIL_RUNOUT_PIN PA4 -#endif -#ifndef FIL_RUNOUT2_PIN - #define FIL_RUNOUT2_PIN PE6 + #ifndef FIL_RUNOUT_PIN + #define FIL_RUNOUT_PIN PA4 // MT_DET_1 + #endif + #ifndef FIL_RUNOUT2_PIN + #define FIL_RUNOUT2_PIN PE6 // MT_DET_2 + #endif + #ifndef FIL_RUNOUT_STATE + #define FIL_RUNOUT_STATE LOW + #endif #endif #ifndef POWER_LOSS_PIN From b7358449e0786c8d7230a19f4ded4ec3f9bdb3e9 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 14 Jan 2025 13:37:48 -0600 Subject: [PATCH 039/787] =?UTF-8?q?=F0=9F=9A=B8=20Enabled=20probe=20cleara?= =?UTF-8?q?nce=20in=20do=5Fmove=5Fafter=5Fz=5Fhoming=20(#27593)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/module/motion.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Marlin/src/module/motion.cpp b/Marlin/src/module/motion.cpp index fe9038a6b8..dc218290a0 100644 --- a/Marlin/src/module/motion.cpp +++ b/Marlin/src/module/motion.cpp @@ -1309,7 +1309,11 @@ void do_blocking_move_to(const xyze_pos_t &raw, const_feedRate_t fr_mm_s/*=0.0f* void do_move_after_z_homing() { DEBUG_SECTION(mzah, "do_move_after_z_homing", DEBUGGING(LEVELING)); #ifdef Z_POST_CLEARANCE - do_z_clearance(Z_POST_CLEARANCE, true, true); + do_z_clearance( + Z_POST_CLEARANCE, + ALL(HOMING_Z_WITH_PROBE, HAS_STOWABLE_PROBE) && TERN0(HAS_BED_PROBE, endstops.z_probe_enabled), + true + ); #elif ENABLED(USE_PROBE_FOR_Z_HOMING) probe.move_z_after_probing(); #endif From e0c60a83a26957117726a0a104b10fc0f4922168 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 14 Jan 2025 15:18:58 -0600 Subject: [PATCH 040/787] =?UTF-8?q?=F0=9F=A9=B9=20Fix=20VALIDATE=5FHOMING?= =?UTF-8?q?=5FENDSTOPS=20missing=20header?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/module/endstops.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/src/module/endstops.cpp b/Marlin/src/module/endstops.cpp index 6894b13f07..7b8cb41505 100644 --- a/Marlin/src/module/endstops.cpp +++ b/Marlin/src/module/endstops.cpp @@ -27,7 +27,7 @@ #include "endstops.h" #include "stepper.h" -#if HAS_STATUS_MESSAGE +#if ANY(HAS_STATUS_MESSAGE, VALIDATE_HOMING_ENDSTOPS) #include "../lcd/marlinui.h" #endif From b4688346ab2cf2df2baeb40adbcb6e1f923ae2e1 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Wed, 15 Jan 2025 00:27:11 +0000 Subject: [PATCH 041/787] [cron] Bump distribution date (2025-01-15) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 2ac491e71b..03a2b55615 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-01-14" +//#define STRING_DISTRIBUTION_DATE "2025-01-15" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 47a83f82b4..03fa2fcbca 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-01-14" + #define STRING_DISTRIBUTION_DATE "2025-01-15" #endif /** From 8f35e9a7978788a05237afedc331e27e1e44a7e4 Mon Sep 17 00:00:00 2001 From: Andrew <18502096+classicrocker883@users.noreply.github.com> Date: Wed, 15 Jan 2025 15:30:00 -0500 Subject: [PATCH 042/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Upd?= =?UTF-8?q?ate=20types=20forward=20decl=20(#27637)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/core/types.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/src/core/types.h b/Marlin/src/core/types.h index 74570ced76..68adadc95d 100644 --- a/Marlin/src/core/types.h +++ b/Marlin/src/core/types.h @@ -180,6 +180,8 @@ template struct IF { typedef L type; }; #define uvalue_t(V) typename IF<((V)>65535), uint32_t, typename IF<((V)>255), uint16_t, uint8_t>::type>::type #define value_t(V) typename IF<((V)>32767), int32_t, typename IF<((V)>127), int16_t, int8_t>::type>::type +class BitProxy; + // Define a template for a bit field of N bits, using the smallest type that can hold N bits template 64)> struct Flags; @@ -1018,8 +1020,6 @@ struct XYZEarray { FI XYZEval operator[](const int n) const { return XYZval(LOGICAL_AXIS_ARRAY(e[n], x[n], y[n], z[n], i[n], j[n], k[n], u[n], v[n], w[n])); } }; -class AxisBits; - class AxisBits { public: typedef bits_t(NUM_AXIS_HEADS) el; From 45ca25a4abc70c8a730846eea5f9914facbb7185 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Thu, 16 Jan 2025 00:27:01 +0000 Subject: [PATCH 043/787] [cron] Bump distribution date (2025-01-16) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 03a2b55615..54ff582282 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-01-15" +//#define STRING_DISTRIBUTION_DATE "2025-01-16" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 03fa2fcbca..d6352b9e42 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-01-15" + #define STRING_DISTRIBUTION_DATE "2025-01-16" #endif /** From 8b8c862615013c0d60e419156e373d8b48894753 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Thu, 16 Jan 2025 15:40:03 -0600 Subject: [PATCH 044/787] =?UTF-8?q?=F0=9F=94=A8=20Skip=20=5Fxfer=20builds?= =?UTF-8?q?=20unless=20uploading?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- buildroot/bin/mftest | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/buildroot/bin/mftest b/buildroot/bin/mftest index 07601654aa..3dd54b2bf6 100755 --- a/buildroot/bin/mftest +++ b/buildroot/bin/mftest @@ -172,6 +172,14 @@ if ((AUTO_BUILD)); then BDESC=$( sed -E 's/^.+\/\/ *(.+)$/\1/' <<<"$BLINE" ) [[ -z $BNUM ]] && { echo "Error - Can't find BOARD_$MB in core/boards.h." ; exit 1 ; } ENVS=( $( grep -EA1 "MB\(.*\b$MB\b.*\)" Marlin/src/pins/pins.h | grep -E "#include.+//.+(env|$SYS):[^ ]+" | grep -oE "(env|$SYS):[^ ]+" | sed -E "s/(env|$SYS)://" ) ) + # If AUTO_BUILD is not 2 (upload), strip envs ending in '_xfer' from $ENVS + if [[ $AUTO_BUILD != 2 ]]; then + OENV=() + for env in "${ENVS[@]}"; do + [[ ! $env =~ _xfer$ ]] && OENV+=( "$env" ) + done + ENVS=( "${OENV[@]}" ) + fi [[ -z $ENVS ]] && { errout "Error - Can't find target(s) for $MB ($BNUM)." ; exit 1 ; } ECOUNT=${#ENVS[*]} From 4e72b17a88b877ab66bad400bc7caf652b0f89a3 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Fri, 17 Jan 2025 00:26:47 +0000 Subject: [PATCH 045/787] [cron] Bump distribution date (2025-01-17) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 54ff582282..b0ee513f7d 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-01-16" +//#define STRING_DISTRIBUTION_DATE "2025-01-17" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index d6352b9e42..3d6b6bfef2 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-01-16" + #define STRING_DISTRIBUTION_DATE "2025-01-17" #endif /** From 29635232d356175fee4a3383cafa7a967f786286 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 21 Jan 2025 18:04:52 -0600 Subject: [PATCH 046/787] =?UTF-8?q?=F0=9F=94=A8=20Prevent=20ESP32=20bad=20?= =?UTF-8?q?dependency?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ini/esp32.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ini/esp32.ini b/ini/esp32.ini index e60ab81563..4afaeaa030 100644 --- a/ini/esp32.ini +++ b/ini/esp32.ini @@ -19,7 +19,7 @@ board = esp32dev build_flags = ${common.build_flags} -DCORE_DEBUG_LEVEL=0 -std=gnu++17 build_unflags = -std=gnu11 -std=gnu++11 build_src_filter = ${common.default_src_filter} + -lib_ignore = NativeEthernet +lib_ignore = NativeEthernet, AsyncTCP_RP2040W upload_speed = 500000 monitor_speed = 250000 monitor_filters = colorize, time, send_on_enter, log2file, esp32_exception_decoder From 12d491c5f764c9d478dd840a9fa339c95ab09199 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 21 Jan 2025 21:08:26 -0600 Subject: [PATCH 047/787] =?UTF-8?q?=F0=9F=90=9B=20Don't=20reset=20axis=5Fd?= =?UTF-8?q?id=5Fmove=20in=20ftmotion.reset?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: narno2202 <130909513+narno2202@users.noreply.github.com> --- Marlin/src/module/ft_motion.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/Marlin/src/module/ft_motion.cpp b/Marlin/src/module/ft_motion.cpp index 8cfc8f2731..5044814373 100644 --- a/Marlin/src/module/ft_motion.cpp +++ b/Marlin/src/module/ft_motion.cpp @@ -382,8 +382,6 @@ void FTMotion::reset() { steps.reset(); interpIdx = 0; - stepper.axis_did_move.reset(); - #if HAS_FTM_SHAPING TERN_(HAS_X_AXIS, ZERO(shaping.x.d_zi)); TERN_(HAS_Y_AXIS, ZERO(shaping.y.d_zi)); From 7e0208940b97faacad63b7fe02242c9afed867ac Mon Sep 17 00:00:00 2001 From: narno2202 <130909513+narno2202@users.noreply.github.com> Date: Wed, 22 Jan 2025 04:10:52 +0100 Subject: [PATCH 048/787] =?UTF-8?q?=F0=9F=9A=B8=20Disable=20FT=20Motion=20?= =?UTF-8?q?during=20Biqu=20Microprobe=20use=20(#27368)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Scott Lahteine --- Marlin/Configuration.h | 1 - Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp | 8 ++++++++ Marlin/src/gcode/bedlevel/abl/G29.cpp | 8 ++++++++ Marlin/src/gcode/bedlevel/mbl/G29.cpp | 8 ++++++++ Marlin/src/gcode/calibrate/G28.cpp | 13 +++++++++++++ Marlin/src/gcode/probe/G30.cpp | 8 ++++++++ Marlin/src/inc/Conditionals-4-adv.h | 3 +++ Marlin/src/inc/SanityCheck.h | 4 ---- Marlin/src/module/ft_motion.h | 13 ++++++++++++- buildroot/tests/STM32F103RC_btt | 4 +++- 10 files changed, 63 insertions(+), 7 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 6a4087529d..f73ad0560d 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -1511,7 +1511,6 @@ * For information about this sensor https://github.com/bigtreetech/MicroProbe * * Also requires PROBE_ENABLE_DISABLE - * With FT_MOTION requires ENDSTOP_INTERRUPTS_FEATURE */ //#define BIQU_MICROPROBE_V1 // Triggers HIGH //#define BIQU_MICROPROBE_V2 // Triggers LOW diff --git a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp index 2cea4968b7..1d765988ed 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp +++ b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp @@ -48,6 +48,10 @@ #include "../hilbert_curve.h" #endif +#if FT_MOTION_DISABLE_FOR_PROBING + #include "../../../module/ft_motion.h" +#endif + #include #define UBL_G29_P31 @@ -309,6 +313,10 @@ void unified_bed_leveling::G29() { const uint8_t p_val = parser.byteval('P'); const bool may_move = p_val == 1 || p_val == 2 || p_val == 4 || parser.seen_test('J'); + #if FT_MOTION_DISABLE_FOR_PROBING + FTMotionDisableInScope FT_Disabler; // Disable Fixed-Time Motion for probing + #endif + // Check for commands that require the printer to be homed if (may_move) { planner.synchronize(); diff --git a/Marlin/src/gcode/bedlevel/abl/G29.cpp b/Marlin/src/gcode/bedlevel/abl/G29.cpp index 386b805b6d..6225c24360 100644 --- a/Marlin/src/gcode/bedlevel/abl/G29.cpp +++ b/Marlin/src/gcode/bedlevel/abl/G29.cpp @@ -59,6 +59,10 @@ #define DEBUG_OUT ENABLED(DEBUG_LEVELING_FEATURE) #include "../../../core/debug_out.h" +#if DISABLED(PROBE_MANUALLY) && FT_MOTION_DISABLE_FOR_PROBING + #include "../../../module/ft_motion.h" +#endif + #if ABL_USES_GRID #if ENABLED(PROBE_Y_FIRST) #define PR_OUTER_VAR abl.meshCount.x @@ -280,6 +284,10 @@ G29_TYPE GcodeSuite::G29() { // Set and report "probing" state to host TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(M_PROBE, false)); + #if DISABLED(PROBE_MANUALLY) && FT_MOTION_DISABLE_FOR_PROBING + FTMotionDisableInScope FT_Disabler; // Disable Fixed-Time Motion for probing + #endif + /** * On the initial G29 fetch command parameters. */ diff --git a/Marlin/src/gcode/bedlevel/mbl/G29.cpp b/Marlin/src/gcode/bedlevel/mbl/G29.cpp index 6d23de4f77..be0e5d7f18 100644 --- a/Marlin/src/gcode/bedlevel/mbl/G29.cpp +++ b/Marlin/src/gcode/bedlevel/mbl/G29.cpp @@ -45,6 +45,10 @@ #define DEBUG_OUT ENABLED(DEBUG_LEVELING_FEATURE) #include "../../../core/debug_out.h" +#if FT_MOTION_DISABLE_FOR_PROBING + #include "../../module/ft_motion.h" +#endif + // Save 130 bytes with non-duplication of PSTR inline void echo_not_entered(const char c) { SERIAL_CHAR(c); SERIAL_ECHOLNPGM(" not entered."); } @@ -63,6 +67,10 @@ inline void echo_not_entered(const char c) { SERIAL_CHAR(c); SERIAL_ECHOLNPGM(" */ void GcodeSuite::G29() { + #if FT_MOTION_DISABLE_FOR_PROBING + FTMotionDisableInScope FT_Disabler; // Disable Fixed-Time Motion for probing + #endif + DEBUG_SECTION(log_G29, "G29", true); // G29 Q is also available if debugging diff --git a/Marlin/src/gcode/calibrate/G28.cpp b/Marlin/src/gcode/calibrate/G28.cpp index ac90756ded..85d27e14e8 100644 --- a/Marlin/src/gcode/calibrate/G28.cpp +++ b/Marlin/src/gcode/calibrate/G28.cpp @@ -52,6 +52,10 @@ #include "../../feature/bltouch.h" #endif +#if FT_MOTION_DISABLE_FOR_PROBING + #include "../../module/ft_motion.h" +#endif + #include "../../lcd/marlinui.h" #if ENABLED(EXTENSIBLE_UI) @@ -129,6 +133,11 @@ #if ENABLED(Z_SAFE_HOMING) inline void home_z_safely() { + + #if FT_MOTION_DISABLE_FOR_PROBING + FTMotionDisableInScope FT_Disabler; // Disable Fixed-Time Motion for homing + #endif + DEBUG_SECTION(log_G28, "home_z_safely", DEBUGGING(LEVELING)); // Disallow Z homing if X or Y homing is needed @@ -284,6 +293,10 @@ void GcodeSuite::G28() { motion_state_t saved_motion_state = begin_slow_homing(); #endif + #if FT_MOTION_DISABLE_FOR_PROBING + FTMotionDisableInScope FT_Disabler; // Disable Fixed-Time Motion for homing + #endif + // Always home with tool 0 active #if HAS_MULTI_HOTEND #if DISABLED(DELTA) || ENABLED(DELTA_HOME_TO_SAFE_ZONE) diff --git a/Marlin/src/gcode/probe/G30.cpp b/Marlin/src/gcode/probe/G30.cpp index 29d6c1ad2b..aa116f1881 100644 --- a/Marlin/src/gcode/probe/G30.cpp +++ b/Marlin/src/gcode/probe/G30.cpp @@ -34,6 +34,10 @@ #include "../../feature/probe_temp_comp.h" #endif +#if FT_MOTION_DISABLE_FOR_PROBING + #include "../../module/ft_motion.h" +#endif + #if ANY(DWIN_CREALITY_LCD_JYERSUI, EXTENSIBLE_UI) #define VERBOSE_SINGLE_PROBE #endif @@ -76,6 +80,10 @@ void GcodeSuite::G30() { // Use 'C' to set Probe Temperature Compensation ON/OFF (on by default) TERN_(HAS_PTC, ptc.set_enabled(parser.boolval('C', true))); + #if FT_MOTION_DISABLE_FOR_PROBING + FTMotionDisableInScope FT_Disabler; // Disable Fixed-Time Motion for probing + #endif + // Probe the bed, optionally raise, and return the measured height const float measured_z = probe.probe_at_point(probepos, raise_after); diff --git a/Marlin/src/inc/Conditionals-4-adv.h b/Marlin/src/inc/Conditionals-4-adv.h index be65120642..671c3590f4 100644 --- a/Marlin/src/inc/Conditionals-4-adv.h +++ b/Marlin/src/inc/Conditionals-4-adv.h @@ -1423,6 +1423,9 @@ #define FTM_WINDOW_SIZE FTM_BW_SIZE #define FTM_BATCH_SIZE FTM_BW_SIZE #endif + #if ANY(BIQU_MICROPROBE_V1, BIQU_MICROPROBE_V2) + #define FT_MOTION_DISABLE_FOR_PROBING 1 + #endif #endif // Multi-Stepping Limit diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index 034878db66..be1ab0db50 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -1452,10 +1452,6 @@ static_assert(NUM_SERVOS <= NUM_SERVO_PLUGS, "NUM_SERVOS (or some servo index) i #error "BIQU MicroProbe requires a PROBE_ENABLE_PIN." #endif - #if ENABLED(FT_MOTION) && DISABLED(ENDSTOP_INTERRUPTS_FEATURE) - #error "BIQU Microprobe requires ENDSTOP_INTERRUPTS_FEATURE with FT_MOTION." - #endif - #if ENABLED(BIQU_MICROPROBE_V1) #if ENABLED(INVERTED_PROBE_STATE) #if Z_MIN_PROBE_ENDSTOP_HIT_STATE != LOW diff --git a/Marlin/src/module/ft_motion.h b/Marlin/src/module/ft_motion.h index bff3ba1fd4..f6ce81af12 100644 --- a/Marlin/src/module/ft_motion.h +++ b/Marlin/src/module/ft_motion.h @@ -213,7 +213,18 @@ class FTMotion { FORCE_INLINE static int32_t num_samples_shaper_settle() { return ( shaping.x.ena || shaping.y.ena ) ? FTM_ZMAX : 0; } - }; // class FTMotion extern FTMotion ftMotion; + +typedef struct FTMotionDisableInScope { + bool isactive; + FTMotionDisableInScope() { + isactive = ftMotion.cfg.active; + ftMotion.cfg.active = false; + } + ~FTMotionDisableInScope() { + ftMotion.cfg.active = isactive; + if (isactive) ftMotion.init(); + } +} FTMotionDisableInScope_t; diff --git a/buildroot/tests/STM32F103RC_btt b/buildroot/tests/STM32F103RC_btt index 62ef7d96e5..178170455f 100755 --- a/buildroot/tests/STM32F103RC_btt +++ b/buildroot/tests/STM32F103RC_btt @@ -12,5 +12,7 @@ set -e restore_configs opt_set MOTHERBOARD BOARD_BTT_SKR_MINI_E3_V1_0 SERIAL_PORT 1 SERIAL_PORT_2 -1 \ X_DRIVER_TYPE TMC2209 Y_DRIVER_TYPE TMC2209 Z_DRIVER_TYPE TMC2209 E0_DRIVER_TYPE TMC2209 -opt_enable CR10_STOCKDISPLAY PINS_DEBUGGING Z_IDLE_HEIGHT FT_MOTION FT_MOTION_MENU ADAPTIVE_STEP_SMOOTHING NONLINEAR_EXTRUSION +opt_enable CR10_STOCKDISPLAY PINS_DEBUGGING Z_IDLE_HEIGHT \ + FT_MOTION FT_MOTION_MENU BIQU_MICROPROBE_V1 PROBE_ENABLE_DISABLE Z_SAFE_HOMING AUTO_BED_LEVELING_BILINEAR \ + ADAPTIVE_STEP_SMOOTHING NONLINEAR_EXTRUSION exec_test $1 $2 "BigTreeTech SKR Mini E3 1.0 - TMC2209 HW Serial, FT_MOTION" "$3" From 88829bd92db001ee20400d1c66bf8bbcf76b9add Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Wed, 22 Jan 2025 06:08:44 +0000 Subject: [PATCH 049/787] [cron] Bump distribution date (2025-01-22) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index b0ee513f7d..cbc35729a6 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-01-17" +//#define STRING_DISTRIBUTION_DATE "2025-01-22" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 3d6b6bfef2..1f45e01399 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-01-17" + #define STRING_DISTRIBUTION_DATE "2025-01-22" #endif /** From a1ba1667407c56b3cf700512683b4eaaf7925240 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Wed, 22 Jan 2025 14:46:04 -0600 Subject: [PATCH 050/787] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Common=20serial=20?= =?UTF-8?q?ports=20header=20(#27648)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/HAL/DUE/HAL.h | 64 +------- Marlin/src/HAL/DUE/MarlinSerial.h | 15 ++ Marlin/src/HAL/HC32/HAL.h | 50 +----- Marlin/src/HAL/HC32/MarlinSerial.h | 8 + Marlin/src/HAL/LPC1768/HAL.cpp | 2 - Marlin/src/HAL/LPC1768/HAL.h | 65 +------- Marlin/src/HAL/LPC1768/MarlinSerial.cpp | 2 + Marlin/src/HAL/LPC1768/MarlinSerial.h | 13 ++ Marlin/src/HAL/NATIVE_SIM/HAL.h | 33 +--- Marlin/src/HAL/RP2040/HAL.h | 65 +------- Marlin/src/HAL/RP2040/MarlinSerial.h | 24 ++- Marlin/src/HAL/SAMD21/HAL.h | 43 +---- Marlin/src/HAL/SAMD51/HAL.h | 67 +------- Marlin/src/HAL/SAMD51/MarlinSerial_AGCM4.h | 21 +++ Marlin/src/HAL/STM32/HAL.h | 85 +--------- Marlin/src/HAL/STM32/MarlinSerial.h | 15 ++ Marlin/src/HAL/STM32F1/HAL.h | 94 +---------- Marlin/src/HAL/STM32F1/MarlinSerial.h | 23 +++ Marlin/src/HAL/TEENSY31_32/HAL.h | 15 +- Marlin/src/HAL/TEENSY35_36/HAL.h | 15 +- Marlin/src/HAL/TEENSY40_41/HAL.h | 40 +---- Marlin/src/HAL/shared/serial_ports.h | 178 +++++++++++++++++++++ 22 files changed, 328 insertions(+), 609 deletions(-) create mode 100644 Marlin/src/HAL/shared/serial_ports.h diff --git a/Marlin/src/HAL/DUE/HAL.h b/Marlin/src/HAL/DUE/HAL.h index 9d00d9d11d..54a977c2d8 100644 --- a/Marlin/src/HAL/DUE/HAL.h +++ b/Marlin/src/HAL/DUE/HAL.h @@ -35,67 +35,9 @@ #include -#include "../../core/serial_hook.h" - -// ------------------------ -// Serial ports -// ------------------------ - -typedef ForwardSerial1Class< decltype(Serial) > DefaultSerial1; -typedef ForwardSerial1Class< decltype(Serial1) > DefaultSerial2; -typedef ForwardSerial1Class< decltype(Serial2) > DefaultSerial3; -typedef ForwardSerial1Class< decltype(Serial3) > DefaultSerial4; -extern DefaultSerial1 MSerial0; -extern DefaultSerial2 MSerial1; -extern DefaultSerial3 MSerial2; -extern DefaultSerial4 MSerial3; - -#define _MSERIAL(X) MSerial##X -#define MSERIAL(X) _MSERIAL(X) - -#if SERIAL_PORT == -1 || ENABLED(EMERGENCY_PARSER) - #define MYSERIAL1 customizedSerial1 -#elif WITHIN(SERIAL_PORT, 0, 3) - #define MYSERIAL1 MSERIAL(SERIAL_PORT) -#else - #error "The required SERIAL_PORT must be from 0 to 3, or -1 for USB Serial." -#endif - -#ifdef SERIAL_PORT_2 - #if SERIAL_PORT_2 == -1 || ENABLED(EMERGENCY_PARSER) - #define MYSERIAL2 customizedSerial2 - #elif WITHIN(SERIAL_PORT_2, 0, 3) - #define MYSERIAL2 MSERIAL(SERIAL_PORT_2) - #else - #error "SERIAL_PORT_2 must be from 0 to 3, or -1 for USB Serial." - #endif -#endif - -#ifdef SERIAL_PORT_3 - #if SERIAL_PORT_3 == -1 || ENABLED(EMERGENCY_PARSER) - #define MYSERIAL3 customizedSerial3 - #elif WITHIN(SERIAL_PORT_3, 0, 3) - #define MYSERIAL3 MSERIAL(SERIAL_PORT_3) - #else - #error "SERIAL_PORT_3 must be from 0 to 3, or -1 for USB Serial." - #endif -#endif - -#ifdef MMU_SERIAL_PORT - #if WITHIN(MMU_SERIAL_PORT, 0, 3) - #define MMU_SERIAL MSERIAL(MMU_SERIAL_PORT) - #else - #error "MMU_SERIAL_PORT must be from 0 to 3." - #endif -#endif - -#ifdef LCD_SERIAL_PORT - #if WITHIN(LCD_SERIAL_PORT, 0, 3) - #define LCD_SERIAL MSERIAL(LCD_SERIAL_PORT) - #else - #error "LCD_SERIAL_PORT must be from 0 to 3." - #endif -#endif +// +// Serial Ports +// #include "MarlinSerial.h" #include "MarlinSerialUSB.h" diff --git a/Marlin/src/HAL/DUE/MarlinSerial.h b/Marlin/src/HAL/DUE/MarlinSerial.h index b80ae21823..cee0857d2b 100644 --- a/Marlin/src/HAL/DUE/MarlinSerial.h +++ b/Marlin/src/HAL/DUE/MarlinSerial.h @@ -33,6 +33,21 @@ #include "../../core/types.h" #include "../../core/serial_hook.h" +typedef ForwardSerial1Class< decltype(Serial) > DefaultSerial1; +typedef ForwardSerial1Class< decltype(Serial1) > DefaultSerial2; +typedef ForwardSerial1Class< decltype(Serial2) > DefaultSerial3; +typedef ForwardSerial1Class< decltype(Serial3) > DefaultSerial4; +extern DefaultSerial1 MSerial0; +extern DefaultSerial2 MSerial1; +extern DefaultSerial3 MSerial2; +extern DefaultSerial4 MSerial3; + +#define SERIAL_INDEX_MIN 0 +#define SERIAL_INDEX_MAX 3 +#define EP_SERIAL_PORT(N) customizedSerial##N +#define USB_SERIAL_PORT(N) customizedSerial##N +#include "../shared/serial_ports.h" + // Define constants and variables for buffering incoming serial data. We're // using a ring buffer (I think), in which rx_buffer_head is the index of the // location to which to write the next incoming character and rx_buffer_tail diff --git a/Marlin/src/HAL/HC32/HAL.h b/Marlin/src/HAL/HC32/HAL.h index 3f4ba14615..f751dea091 100644 --- a/Marlin/src/HAL/HC32/HAL.h +++ b/Marlin/src/HAL/HC32/HAL.h @@ -36,60 +36,12 @@ #include "fastio.h" #include "timers.h" -#include "MarlinSerial.h" // // Serial Ports // -#define _MSERIAL(X) MSerial##X -#define MSERIAL(X) _MSERIAL(X) -#define NUM_UARTS 4 -#if SERIAL_PORT == -1 - #error "USB Serial is not supported on HC32F460" -#elif WITHIN(SERIAL_PORT, 1, NUM_UARTS) - #define MYSERIAL1 MSERIAL(SERIAL_PORT) -#else - #define MYSERIAL1 MSERIAL(1) // Dummy port - static_assert(false, "SERIAL_PORT must be from 1 to " STRINGIFY(NUM_UARTS) ".") -#endif - -#ifdef SERIAL_PORT_2 - #if SERIAL_PORT_2 == -1 - #error "USB Serial is not supported on HC32F460" - #elif WITHIN(SERIAL_PORT_2, 1, NUM_UARTS) - #define MYSERIAL2 MSERIAL(SERIAL_PORT_2) - #else - #define MYSERIAL2 MSERIAL(1) // Dummy port - static_assert(false, "SERIAL_PORT_2 must be from 1 to " STRINGIFY(NUM_UARTS) ".") - #endif -#endif - -#ifdef SERIAL_PORT_3 - #if SERIAL_PORT_3 == -1 - #error "USB Serial is not supported on HC32F460" - #elif WITHIN(SERIAL_PORT_3, 1, NUM_UARTS) - #define MYSERIAL3 MSERIAL(SERIAL_PORT_3) - #else - #define MYSERIAL3 MSERIAL(1) // Dummy port - static_assert(false, "SERIAL_PORT_3 must be from 1 to " STRINGIFY(NUM_UARTS) ".") - #endif -#endif - -#ifdef LCD_SERIAL_PORT - #if LCD_SERIAL_PORT == -1 - #error "USB Serial is not supported on HC32F460" - #elif WITHIN(LCD_SERIAL_PORT, 1, NUM_UARTS) - #define LCD_SERIAL MSERIAL(LCD_SERIAL_PORT) - #else - #define LCD_SERIAL MSERIAL(1) // Dummy port - static_assert(false, "LCD_SERIAL_PORT must be from 1 to " STRINGIFY(NUM_UARTS) ".") - #endif - - #if HAS_DGUS_LCD - #define LCD_SERIAL_TX_BUFFER_FREE() LCD_SERIAL.availableForWrite() - #endif -#endif +#include "MarlinSerial.h" // // Emergency Parser diff --git a/Marlin/src/HAL/HC32/MarlinSerial.h b/Marlin/src/HAL/HC32/MarlinSerial.h index bb4630eb1d..1a97805a51 100644 --- a/Marlin/src/HAL/HC32/MarlinSerial.h +++ b/Marlin/src/HAL/HC32/MarlinSerial.h @@ -24,6 +24,14 @@ #include "../../core/serial_hook.h" #include +#define SERIAL_INDEX_MIN 1 +#define SERIAL_INDEX_MAX 4 +#include "../shared/serial_ports.h" + +#if defined(LCD_SERIAL_PORT) && ANY(HAS_DGUS_LCD, EXTENSIBLE_UI) + #define LCD_SERIAL_TX_BUFFER_FREE() LCD_SERIAL.availableForWrite() +#endif + // Optionally set uart IRQ priority to reduce overflow errors //#define UART_RX_IRQ_PRIO 1 //#define UART_TX_IRQ_PRIO 1 diff --git a/Marlin/src/HAL/LPC1768/HAL.cpp b/Marlin/src/HAL/LPC1768/HAL.cpp index db9881cdd4..55658acb76 100644 --- a/Marlin/src/HAL/LPC1768/HAL.cpp +++ b/Marlin/src/HAL/LPC1768/HAL.cpp @@ -35,8 +35,6 @@ #include #include -DefaultSerial1 USBSerial(false, UsbSerial); - uint32_t MarlinHAL::adc_result = 0; pin_t MarlinHAL::adc_pin = 0; diff --git a/Marlin/src/HAL/LPC1768/HAL.h b/Marlin/src/HAL/LPC1768/HAL.h index 6e0c9cff2f..9a68cdf748 100644 --- a/Marlin/src/HAL/LPC1768/HAL.h +++ b/Marlin/src/HAL/LPC1768/HAL.h @@ -38,72 +38,15 @@ extern "C" volatile uint32_t _millis; #include "../shared/math_32bit.h" #include "../shared/HAL_SPI.h" #include "fastio.h" -#include "MarlinSerial.h" #include #include -#include -// ------------------------ -// Serial ports -// ------------------------ +// +// Serial Ports +// -typedef ForwardSerial1Class< decltype(UsbSerial) > DefaultSerial1; -extern DefaultSerial1 USBSerial; - -#define _MSERIAL(X) MSerial##X -#define MSERIAL(X) _MSERIAL(X) - -#if SERIAL_PORT == -1 - #define MYSERIAL1 USBSerial -#elif WITHIN(SERIAL_PORT, 0, 3) - #define MYSERIAL1 MSERIAL(SERIAL_PORT) -#else - #error "SERIAL_PORT must be from 0 to 3. You can also use -1 if the board supports Native USB." -#endif - -#ifdef SERIAL_PORT_2 - #if SERIAL_PORT_2 == -1 - #define MYSERIAL2 USBSerial - #elif WITHIN(SERIAL_PORT_2, 0, 3) - #define MYSERIAL2 MSERIAL(SERIAL_PORT_2) - #else - #error "SERIAL_PORT_2 must be from 0 to 3. You can also use -1 if the board supports Native USB." - #endif -#endif - -#ifdef SERIAL_PORT_3 - #if SERIAL_PORT_3 == -1 - #define MYSERIAL3 USBSerial - #elif WITHIN(SERIAL_PORT_3, 0, 3) - #define MYSERIAL3 MSERIAL(SERIAL_PORT_3) - #else - #error "SERIAL_PORT_3 must be from 0 to 3. You can also use -1 if the board supports Native USB." - #endif -#endif - -#ifdef MMU_SERIAL_PORT - #if MMU_SERIAL_PORT == -1 - #define MMU_SERIAL USBSerial - #elif WITHIN(MMU_SERIAL_PORT, 0, 3) - #define MMU_SERIAL MSERIAL(MMU_SERIAL_PORT) - #else - #error "MMU_SERIAL_PORT must be from 0 to 3. You can also use -1 if the board supports Native USB." - #endif -#endif - -#ifdef LCD_SERIAL_PORT - #if LCD_SERIAL_PORT == -1 - #define LCD_SERIAL USBSerial - #elif WITHIN(LCD_SERIAL_PORT, 0, 3) - #define LCD_SERIAL MSERIAL(LCD_SERIAL_PORT) - #else - #error "LCD_SERIAL_PORT must be from 0 to 3. You can also use -1 if the board supports Native USB." - #endif - #if ANY(HAS_DGUS_LCD, EXTENSIBLE_UI) - #define LCD_SERIAL_TX_BUFFER_FREE() LCD_SERIAL.available() - #endif -#endif +#include "MarlinSerial.h" // // Interrupts diff --git a/Marlin/src/HAL/LPC1768/MarlinSerial.cpp b/Marlin/src/HAL/LPC1768/MarlinSerial.cpp index f2aecf54a0..291eba68a7 100644 --- a/Marlin/src/HAL/LPC1768/MarlinSerial.cpp +++ b/Marlin/src/HAL/LPC1768/MarlinSerial.cpp @@ -25,6 +25,8 @@ #include "../../inc/MarlinConfig.h" +DefaultSerial1 USBSerial(false, UsbSerial); + #if USING_HW_SERIAL0 MarlinSerial _MSerial0(LPC_UART0); MSerialT MSerial0(true, _MSerial0); diff --git a/Marlin/src/HAL/LPC1768/MarlinSerial.h b/Marlin/src/HAL/LPC1768/MarlinSerial.h index 2fadd8209b..04110e4aff 100644 --- a/Marlin/src/HAL/LPC1768/MarlinSerial.h +++ b/Marlin/src/HAL/LPC1768/MarlinSerial.h @@ -21,6 +21,7 @@ */ #pragma once +#include #include #include @@ -30,6 +31,18 @@ #endif #include "../../core/serial_hook.h" +typedef ForwardSerial1Class< decltype(UsbSerial) > DefaultSerial1; +extern DefaultSerial1 USBSerial; + +#define SERIAL_INDEX_MIN 0 +#define SERIAL_INDEX_MAX 3 +#define USB_SERIAL_PORT(...) USBSerial +#include "../shared/serial_ports.h" + +#if defined(LCD_SERIAL_PORT) && ANY(HAS_DGUS_LCD, EXTENSIBLE_UI) + #define LCD_SERIAL_TX_BUFFER_FREE() LCD_SERIAL.available() +#endif + class MarlinSerial : public HardwareSerial { public: MarlinSerial(LPC_UART_TypeDef *UARTx) : HardwareSerial(UARTx) { } diff --git a/Marlin/src/HAL/NATIVE_SIM/HAL.h b/Marlin/src/HAL/NATIVE_SIM/HAL.h index 020299fa5d..f741d0b246 100644 --- a/Marlin/src/HAL/NATIVE_SIM/HAL.h +++ b/Marlin/src/HAL/NATIVE_SIM/HAL.h @@ -71,37 +71,10 @@ extern MSerialT serial_stream_2; extern MSerialT serial_stream_3; #define _MSERIAL(X) serial_stream_##X -#define MSERIAL(X) _MSERIAL(X) -#if WITHIN(SERIAL_PORT, 0, 3) - #define MYSERIAL1 MSERIAL(SERIAL_PORT) -#else - #error "SERIAL_PORT must be from 0 to 3. Please update your configuration." -#endif - -#ifdef SERIAL_PORT_2 - #if WITHIN(SERIAL_PORT_2, 0, 3) - #define MYSERIAL2 MSERIAL(SERIAL_PORT_2) - #else - #error "SERIAL_PORT_2 must be from 0 to 3. Please update your configuration." - #endif -#endif - -#ifdef MMU_SERIAL_PORT - #if WITHIN(MMU_SERIAL_PORT, 0, 3) - #define MMU_SERIAL MSERIAL(MMU_SERIAL_PORT) - #else - #error "MMU_SERIAL_PORT must be from 0 to 3. Please update your configuration." - #endif -#endif - -#ifdef LCD_SERIAL_PORT - #if WITHIN(LCD_SERIAL_PORT, 0, 3) - #define LCD_SERIAL MSERIAL(LCD_SERIAL_PORT) - #else - #error "LCD_SERIAL_PORT must be from 0 to 3. Please update your configuration." - #endif -#endif +#define SERIAL_INDEX_MIN 0 +#define SERIAL_INDEX_MAX 3 +#include "../shared/serial_ports.h" // ------------------------ // Interrupts diff --git a/Marlin/src/HAL/RP2040/HAL.h b/Marlin/src/HAL/RP2040/HAL.h index fa1a35683e..fbd3b61e1c 100644 --- a/Marlin/src/HAL/RP2040/HAL.h +++ b/Marlin/src/HAL/RP2040/HAL.h @@ -35,73 +35,16 @@ #include "fastio.h" //#include "Servo.h" #include "watchdog.h" -#include "MarlinSerial.h" #include "../../inc/MarlinConfigPre.h" #include -// ------------------------ -// Serial ports -// ------------------------ +// +// Serial Ports +// -#include "../../core/serial_hook.h" -typedef ForwardSerial1Class< decltype(Serial) > DefaultSerial1; -extern DefaultSerial1 MSerial0; - -#define _MSERIAL(X) MSerial##X -#define MSERIAL(X) _MSERIAL(X) - -#if SERIAL_PORT == -1 - #define MYSERIAL1 MSerial0 -#elif WITHIN(SERIAL_PORT, 0, 6) - #define MYSERIAL1 MSERIAL(SERIAL_PORT) -#else - #error "SERIAL_PORT must be from 0 to 6. You can also use -1 if the board supports Native USB." -#endif - -#ifdef SERIAL_PORT_2 - #if SERIAL_PORT_2 == -1 - #define MYSERIAL2 MSerial0 - #elif WITHIN(SERIAL_PORT_2, 0, 6) - #define MYSERIAL2 MSERIAL(SERIAL_PORT_2) - #else - #error "SERIAL_PORT_2 must be from 0 to 6. You can also use -1 if the board supports Native USB." - #endif -#endif - -#ifdef SERIAL_PORT_3 - #if SERIAL_PORT_3 == -1 - #define MYSERIAL3 MSerial0 - #elif WITHIN(SERIAL_PORT_3, 0, 6) - #define MYSERIAL3 MSERIAL(SERIAL_PORT_3) - #else - #error "SERIAL_PORT_3 must be from 0 to 6. You can also use -1 if the board supports Native USB." - #endif -#endif - -#ifdef MMU2_SERIAL_PORT - #if MMU2_SERIAL_PORT == -1 - #define MMU2_SERIAL MSerial0 - #elif WITHIN(MMU2_SERIAL_PORT, 0, 6) - #define MMU2_SERIAL MSERIAL(MMU2_SERIAL_PORT) - #else - #error "MMU2_SERIAL_PORT must be from 0 to 6. You can also use -1 if the board supports Native USB." - #endif -#endif - -#ifdef LCD_SERIAL_PORT - #if LCD_SERIAL_PORT == -1 - #define LCD_SERIAL MSerial0 - #elif WITHIN(LCD_SERIAL_PORT, 0, 6) - #define LCD_SERIAL MSERIAL(LCD_SERIAL_PORT) - #else - #error "LCD_SERIAL_PORT must be from 0 to 6. You can also use -1 if the board supports Native USB." - #endif - #if HAS_DGUS_LCD - #define SERIAL_GET_TX_BUFFER_FREE() LCD_SERIAL.availableForWrite() - #endif -#endif +#include "MarlinSerial.h" // ------------------------ // Defines diff --git a/Marlin/src/HAL/RP2040/MarlinSerial.h b/Marlin/src/HAL/RP2040/MarlinSerial.h index c5924c9062..b0db3167fa 100644 --- a/Marlin/src/HAL/RP2040/MarlinSerial.h +++ b/Marlin/src/HAL/RP2040/MarlinSerial.h @@ -29,24 +29,22 @@ #include "../../core/serial_hook.h" +typedef ForwardSerial1Class< decltype(Serial) > DefaultSerial1; +extern DefaultSerial1 MSerial0; +typedef ForwardSerial1Class USBSerialType; +extern USBSerialType USBSerial; + #define Serial0 Serial #define _DECLARE_SERIAL(X) \ typedef ForwardSerial1Class DefaultSerial##X; \ extern DefaultSerial##X MSerial##X #define DECLARE_SERIAL(X) _DECLARE_SERIAL(X) -typedef ForwardSerial1Class USBSerialType; -extern USBSerialType USBSerial; +#define SERIAL_INDEX_MIN 0 +#define SERIAL_INDEX_MAX 6 +#define USB_SERIAL_PORT(...) MSerial0 +#include "../shared/serial_ports.h" -#define _MSERIAL(X) MSerial##X -#define MSERIAL(X) _MSERIAL(X) - -#if SERIAL_PORT == -1 - // #define MYSERIAL1 USBSerial this is already done in the HAL -#elif WITHIN(SERIAL_PORT, 0, 3) - #define MYSERIAL1 MSERIAL(SERIAL_PORT) - DECLARE_SERIAL(SERIAL_PORT); -#else - #error "SERIAL_PORT must be from 0 to 3, or -1 for Native USB." +#if defined(LCD_SERIAL_PORT) && ANY(HAS_DGUS_LCD, EXTENSIBLE_UI) + #define SERIAL_GET_TX_BUFFER_FREE() LCD_SERIAL.availableForWrite() #endif - diff --git a/Marlin/src/HAL/SAMD21/HAL.h b/Marlin/src/HAL/SAMD21/HAL.h index 63beb29cf1..e95f0e6f70 100644 --- a/Marlin/src/HAL/SAMD21/HAL.h +++ b/Marlin/src/HAL/SAMD21/HAL.h @@ -36,11 +36,11 @@ // ------------------------ // Serial ports // ------------------------ + #include "../../core/serial_hook.h" typedef ForwardSerial1Class< decltype(SerialUSB) > DefaultSerial1; extern DefaultSerial1 MSerialUSB; -// Serial ports typedef ForwardSerial1Class< decltype(Serial1) > DefaultSerial2; typedef ForwardSerial1Class< decltype(Serial2) > DefaultSerial3; @@ -51,43 +51,10 @@ extern DefaultSerial3 MSerial1; #define _MSERIAL(X) __MSERIAL(X) #define MSERIAL(X) _MSERIAL(INCREMENT(X)) -#if WITHIN(SERIAL_PORT, 0, 1) - #define MYSERIAL1 MSERIAL(SERIAL_PORT) -#elif SERIAL_PORT == -1 - #define MYSERIAL1 MSerialUSB -#else - #error "SERIAL_PORT must be -1 (Native USB only)." -#endif - -#ifdef SERIAL_PORT_2 - #if WITHIN(SERIAL_PORT_2, 0, 1) - #define MYSERIAL2 MSERIAL(SERIAL_PORT) - #elif SERIAL_PORT_2 == -1 - #define MYSERIAL2 MSerialUSB - #else - #error "SERIAL_PORT_2 must be -1 (Native USB only)." - #endif -#endif - -#ifdef MMU_SERIAL_PORT - #if WITHIN(MMU_SERIAL_PORT, 0, 1) - #define MMU_SERIAL MSERIAL(SERIAL_PORT) - #elif MMU_SERIAL_PORT == -1 - #define MMU_SERIAL MSerialUSB - #else - #error "MMU_SERIAL_PORT must be -1 (Native USB only)." - #endif -#endif - -#ifdef LCD_SERIAL_PORT - #if WITHIN(LCD_SERIAL_PORT, 0, 1) - #define LCD_SERIAL MSERIAL(SERIAL_PORT) - #elif LCD_SERIAL_PORT == -1 - #define LCD_SERIAL MSerialUSB - #else - #error "LCD_SERIAL_PORT must be -1 (Native USB only)." - #endif -#endif +#define SERIAL_INDEX_MIN 0 +#define SERIAL_INDEX_MAX 1 +#define USB_SERIAL_PORT(...) MSerialUSB +#include "../shared/serial_ports.h" typedef int8_t pin_t; diff --git a/Marlin/src/HAL/SAMD51/HAL.h b/Marlin/src/HAL/SAMD51/HAL.h index 7655f82da1..51fed64e35 100644 --- a/Marlin/src/HAL/SAMD51/HAL.h +++ b/Marlin/src/HAL/SAMD51/HAL.h @@ -34,72 +34,7 @@ #ifdef ADAFRUIT_GRAND_CENTRAL_M4 #include "MarlinSerial_AGCM4.h" - - // Serial ports - typedef ForwardSerial1Class< decltype(Serial) > DefaultSerial1; - typedef ForwardSerial1Class< decltype(Serial1) > DefaultSerial2; - typedef ForwardSerial1Class< decltype(Serial2) > DefaultSerial3; - typedef ForwardSerial1Class< decltype(Serial3) > DefaultSerial4; - typedef ForwardSerial1Class< decltype(Serial4) > DefaultSerial5; - extern DefaultSerial1 MSerial0; - extern DefaultSerial2 MSerial1; - extern DefaultSerial3 MSerial2; - extern DefaultSerial4 MSerial3; - extern DefaultSerial5 MSerial4; - - #define __MSERIAL(X) MSerial##X - #define _MSERIAL(X) __MSERIAL(X) - #define MSERIAL(X) _MSERIAL(INCREMENT(X)) - - #if SERIAL_PORT == -1 - #define MYSERIAL1 MSerial0 - #elif WITHIN(SERIAL_PORT, 0, 3) - #define MYSERIAL1 MSERIAL(SERIAL_PORT) - #else - #error "SERIAL_PORT must be from 0 to 3. You can also use -1 if the board supports Native USB." - #endif - - #ifdef SERIAL_PORT_2 - #if SERIAL_PORT_2 == -1 - #define MYSERIAL2 MSerial0 - #elif WITHIN(SERIAL_PORT_2, 0, 3) - #define MYSERIAL2 MSERIAL(SERIAL_PORT_2) - #else - #error "SERIAL_PORT_2 must be from 0 to 3. You can also use -1 if the board supports Native USB." - #endif - #endif - - #ifdef SERIAL_PORT_3 - #if SERIAL_PORT_3 == -1 - #define MYSERIAL3 MSerial0 - #elif WITHIN(SERIAL_PORT_3, 0, 3) - #define MYSERIAL3 MSERIAL(SERIAL_PORT_3) - #else - #error "SERIAL_PORT_3 must be from 0 to 3. You can also use -1 if the board supports Native USB." - #endif - #endif - - #ifdef MMU_SERIAL_PORT - #if MMU_SERIAL_PORT == -1 - #define MMU_SERIAL MSerial0 - #elif WITHIN(MMU_SERIAL_PORT, 0, 3) - #define MMU_SERIAL MSERIAL(MMU_SERIAL_PORT) - #else - #error "MMU_SERIAL_PORT must be from 0 to 3. You can also use -1 if the board supports Native USB." - #endif - #endif - - #ifdef LCD_SERIAL_PORT - #if LCD_SERIAL_PORT == -1 - #define LCD_SERIAL MSerial0 - #elif WITHIN(LCD_SERIAL_PORT, 0, 3) - #define LCD_SERIAL MSERIAL(LCD_SERIAL_PORT) - #else - #error "LCD_SERIAL_PORT must be from 0 to 3. You can also use -1 if the board supports Native USB." - #endif - #endif - -#endif // ADAFRUIT_GRAND_CENTRAL_M4 +#endif typedef int8_t pin_t; diff --git a/Marlin/src/HAL/SAMD51/MarlinSerial_AGCM4.h b/Marlin/src/HAL/SAMD51/MarlinSerial_AGCM4.h index 1044d9fcd0..7827c1f958 100644 --- a/Marlin/src/HAL/SAMD51/MarlinSerial_AGCM4.h +++ b/Marlin/src/HAL/SAMD51/MarlinSerial_AGCM4.h @@ -32,3 +32,24 @@ typedef Serial1Class UartT; extern UartT Serial2; extern UartT Serial3; extern UartT Serial4; + +typedef ForwardSerial1Class< decltype(Serial) > DefaultSerial1; +typedef ForwardSerial1Class< decltype(Serial1) > DefaultSerial2; +typedef ForwardSerial1Class< decltype(Serial2) > DefaultSerial3; +typedef ForwardSerial1Class< decltype(Serial3) > DefaultSerial4; +typedef ForwardSerial1Class< decltype(Serial4) > DefaultSerial5; + +extern DefaultSerial1 MSerial0; +extern DefaultSerial2 MSerial1; +extern DefaultSerial3 MSerial2; +extern DefaultSerial4 MSerial3; +extern DefaultSerial5 MSerial4; + +#define __MSERIAL(X) MSerial##X +#define _MSERIAL(X) __MSERIAL(X) +#define MSERIAL(X) _MSERIAL(INCREMENT(X)) + +#define SERIAL_INDEX_MIN 0 +#define SERIAL_INDEX_MAX 3 +#define USB_SERIAL_PORT(...) MSerial0 +#include "../shared/serial_ports.h" diff --git a/Marlin/src/HAL/STM32/HAL.h b/Marlin/src/HAL/STM32/HAL.h index eab31be265..f43413fcd9 100644 --- a/Marlin/src/HAL/STM32/HAL.h +++ b/Marlin/src/HAL/STM32/HAL.h @@ -30,7 +30,6 @@ #include "temp_soc.h" #include "fastio.h" #include "Servo.h" -#include "MarlinSerial.h" #include "../../inc/MarlinConfigPre.h" @@ -43,87 +42,11 @@ #define CPU_ST7920_DELAY_2 40 #define CPU_ST7920_DELAY_3 340 -// ------------------------ -// Serial ports -// ------------------------ -#ifdef USBCON - #include - #include "../../core/serial_hook.h" - typedef ForwardSerial1Class< decltype(SerialUSB) > DefaultSerial1; - extern DefaultSerial1 MSerialUSB; -#endif +// +// Serial Ports +// -#define _MSERIAL(X) MSerial##X -#define MSERIAL(X) _MSERIAL(X) - -#if WITHIN(SERIAL_PORT, 1, 9) - #define MYSERIAL1 MSERIAL(SERIAL_PORT) -#elif !defined(USBCON) - #error "SERIAL_PORT must be from 1 to 9." -#elif SERIAL_PORT == -1 - #define MYSERIAL1 MSerialUSB -#else - #error "SERIAL_PORT must be from 1 to 9, or -1 for Native USB." -#endif - -#ifdef SERIAL_PORT_2 - #if WITHIN(SERIAL_PORT_2, 1, 9) - #define MYSERIAL2 MSERIAL(SERIAL_PORT_2) - #elif !defined(USBCON) - #error "SERIAL_PORT_2 must be from 1 to 9." - #elif SERIAL_PORT_2 == -1 - #define MYSERIAL2 MSerialUSB - #else - #error "SERIAL_PORT_2 must be from 1 to 9, or -1 for Native USB." - #endif -#endif - -#ifdef SERIAL_PORT_3 - #if WITHIN(SERIAL_PORT_3, 1, 9) - #define MYSERIAL3 MSERIAL(SERIAL_PORT_3) - #elif !defined(USBCON) - #error "SERIAL_PORT_3 must be from 1 to 9." - #elif SERIAL_PORT_3 == -1 - #define MYSERIAL3 MSerialUSB - #else - #error "SERIAL_PORT_3 must be from 1 to 9, or -1 for Native USB." - #endif -#endif - -#ifdef MMU_SERIAL_PORT - #if WITHIN(MMU_SERIAL_PORT, 1, 9) - #define MMU_SERIAL MSERIAL(MMU_SERIAL_PORT) - #elif !defined(USBCON) - #error "MMU_SERIAL_PORT must be from 1 to 9." - #elif MMU_SERIAL_PORT == -1 - #define MMU_SERIAL MSerialUSB - #else - #error "MMU_SERIAL_PORT must be from 1 to 9, or -1 for Native USB." - #endif -#endif - -#ifdef LCD_SERIAL_PORT - #if WITHIN(LCD_SERIAL_PORT, 1, 9) - #define LCD_SERIAL MSERIAL(LCD_SERIAL_PORT) - #elif !defined(USBCON) - #error "LCD_SERIAL_PORT must be from 1 to 9." - #elif LCD_SERIAL_PORT == -1 - #define LCD_SERIAL MSerialUSB - #else - #error "LCD_SERIAL_PORT must be from 1 to 9, or -1 for Native USB." - #endif - #if ANY(HAS_DGUS_LCD, EXTENSIBLE_UI) - #define LCD_SERIAL_TX_BUFFER_FREE() LCD_SERIAL.availableForWrite() - #endif -#endif - -#ifdef RS485_SERIAL_PORT - #if WITHIN(RS485_SERIAL_PORT, 1, 9) - #define RS485_SERIAL MSERIAL(RS485_SERIAL_PORT) - #else - #error "RS485_SERIAL_PORT must be from 1 to 9." - #endif -#endif +#include "MarlinSerial.h" /** * TODO: review this to return 1 for pins that are not analog input diff --git a/Marlin/src/HAL/STM32/MarlinSerial.h b/Marlin/src/HAL/STM32/MarlinSerial.h index d9311a98da..73ab77d8d4 100644 --- a/Marlin/src/HAL/STM32/MarlinSerial.h +++ b/Marlin/src/HAL/STM32/MarlinSerial.h @@ -33,6 +33,21 @@ #include "../../core/serial_hook.h" +#ifdef USBCON + #include + typedef ForwardSerial1Class< decltype(SerialUSB) > DefaultSerial1; + extern DefaultSerial1 MSerialUSB; + #define USB_SERIAL_PORT(...) MSerialUSB +#endif + +#define SERIAL_INDEX_MIN 1 +#define SERIAL_INDEX_MAX 9 +#include "../shared/serial_ports.h" + +#if defined(LCD_SERIAL_PORT) && ANY(HAS_DGUS_LCD, EXTENSIBLE_UI) + #define LCD_SERIAL_TX_BUFFER_FREE() LCD_SERIAL.availableForWrite() +#endif + #if ENABLED(SERIAL_DMA) struct MarlinSerial : public HAL_HardwareSerial { diff --git a/Marlin/src/HAL/STM32F1/HAL.h b/Marlin/src/HAL/STM32F1/HAL.h index e80ced866d..daf94dceb5 100644 --- a/Marlin/src/HAL/STM32F1/HAL.h +++ b/Marlin/src/HAL/STM32F1/HAL.h @@ -43,8 +43,6 @@ #include "msc_sd.h" #endif -#include "MarlinSerial.h" - // ------------------------ // Defines // ------------------------ @@ -64,95 +62,11 @@ #endif #endif -// ------------------------ -// Serial ports -// ------------------------ +// +// Serial Ports +// -#ifdef SERIAL_USB - typedef ForwardSerial1Class< USBSerial > DefaultSerial1; - extern DefaultSerial1 MSerial0; - #if HAS_SD_HOST_DRIVE - #define UsbSerial MarlinCompositeSerial - #else - #define UsbSerial MSerial0 - #endif -#endif - -#define _MSERIAL(X) MSerial##X -#define MSERIAL(X) _MSERIAL(X) - -#if ANY(STM32_HIGH_DENSITY, STM32_XL_DENSITY) - #define NUM_UARTS 5 -#else - #define NUM_UARTS 3 -#endif - -#if SERIAL_PORT == -1 - #define MYSERIAL1 UsbSerial -#elif WITHIN(SERIAL_PORT, 1, NUM_UARTS) - #define MYSERIAL1 MSERIAL(SERIAL_PORT) -#else - #define MYSERIAL1 MSERIAL(1) // dummy port - static_assert(false, "SERIAL_PORT must be from 1 to " STRINGIFY(NUM_UARTS) ". You can also use -1 if the board supports Native USB.") -#endif - -#ifdef SERIAL_PORT_2 - #if SERIAL_PORT_2 == -1 - #define MYSERIAL2 UsbSerial - #elif WITHIN(SERIAL_PORT_2, 1, NUM_UARTS) - #define MYSERIAL2 MSERIAL(SERIAL_PORT_2) - #else - #define MYSERIAL2 MSERIAL(1) // dummy port - static_assert(false, "SERIAL_PORT_2 must be from 1 to " STRINGIFY(NUM_UARTS) ". You can also use -1 if the board supports Native USB.") - #endif -#endif - -#ifdef SERIAL_PORT_3 - #if SERIAL_PORT_3 == -1 - #define MYSERIAL3 UsbSerial - #elif WITHIN(SERIAL_PORT_3, 1, NUM_UARTS) - #define MYSERIAL3 MSERIAL(SERIAL_PORT_3) - #else - #define MYSERIAL3 MSERIAL(1) // dummy port - static_assert(false, "SERIAL_PORT_3 must be from 1 to " STRINGIFY(NUM_UARTS) ". You can also use -1 if the board supports Native USB.") - #endif -#endif - -#ifdef MMU_SERIAL_PORT - #if MMU_SERIAL_PORT == -1 - #define MMU_SERIAL UsbSerial - #elif WITHIN(MMU_SERIAL_PORT, 1, NUM_UARTS) - #define MMU_SERIAL MSERIAL(MMU_SERIAL_PORT) - #else - #define MMU_SERIAL MSERIAL(1) // dummy port - static_assert(false, "MMU_SERIAL_PORT must be from 1 to " STRINGIFY(NUM_UARTS) ". You can also use -1 if the board supports Native USB.") - #endif -#endif - -#ifdef LCD_SERIAL_PORT - #if LCD_SERIAL_PORT == -1 - #define LCD_SERIAL UsbSerial - #elif WITHIN(LCD_SERIAL_PORT, 1, NUM_UARTS) - #define LCD_SERIAL MSERIAL(LCD_SERIAL_PORT) - #else - #define LCD_SERIAL MSERIAL(1) // dummy port - static_assert(false, "LCD_SERIAL_PORT must be from 1 to " STRINGIFY(NUM_UARTS) ". You can also use -1 if the board supports Native USB.") - #endif - #if ANY(HAS_DGUS_LCD, EXTENSIBLE_UI) - #define LCD_SERIAL_TX_BUFFER_FREE() LCD_SERIAL.availableForWrite() - #endif -#endif - -#ifdef RS485_SERIAL_PORT - #if RS485_SERIAL_PORT == -1 - #define RS485_SERIAL UsbSerial - #elif WITHIN(RS485_SERIAL_PORT, 1, NUM_UARTS) - #define RS485_SERIAL MSERIAL(RS485_SERIAL_PORT) - #else - #define RS485_SERIAL MSERIAL(1) // dummy port - static_assert(false, "RS485_SERIAL_PORT must be from 1 to " STRINGIFY(NUM_UARTS) ".") - #endif -#endif +#include "MarlinSerial.h" /** * TODO: review this to return 1 for pins that are not analog input diff --git a/Marlin/src/HAL/STM32F1/MarlinSerial.h b/Marlin/src/HAL/STM32F1/MarlinSerial.h index 53bcd48476..c2dc5bd571 100644 --- a/Marlin/src/HAL/STM32F1/MarlinSerial.h +++ b/Marlin/src/HAL/STM32F1/MarlinSerial.h @@ -28,6 +28,29 @@ #include "../../inc/MarlinConfigPre.h" #include "../../core/serial_hook.h" +#ifdef SERIAL_USB + typedef ForwardSerial1Class< USBSerial > DefaultSerial1; + extern DefaultSerial1 MSerial0; + #if HAS_SD_HOST_DRIVE + #define UsbSerial MarlinCompositeSerial + #else + #define UsbSerial MSerial0 + #endif +#endif + +#define SERIAL_INDEX_MIN 1 +#if ANY(STM32_HIGH_DENSITY, STM32_XL_DENSITY) + #define SERIAL_INDEX_MAX 5 +#else + #define SERIAL_INDEX_MAX 3 +#endif +#define USB_SERIAL_PORT(...) UsbSerial +#include "../shared/serial_ports.h" + +#if defined(LCD_SERIAL_PORT) && ANY(HAS_DGUS_LCD, EXTENSIBLE_UI) + #define LCD_SERIAL_TX_BUFFER_FREE() LCD_SERIAL.availableForWrite() +#endif + // Increase priority of serial interrupts, to reduce overflow errors #define UART_IRQ_PRIO 1 diff --git a/Marlin/src/HAL/TEENSY31_32/HAL.h b/Marlin/src/HAL/TEENSY31_32/HAL.h index 659fcb72e5..03610c65f8 100644 --- a/Marlin/src/HAL/TEENSY31_32/HAL.h +++ b/Marlin/src/HAL/TEENSY31_32/HAL.h @@ -64,17 +64,10 @@ typedef ForwardSerial1Class USBSerialType; extern USBSerialType USBSerial; -#define _MSERIAL(X) MSerial##X -#define MSERIAL(X) _MSERIAL(X) - -#if SERIAL_PORT == -1 - #define MYSERIAL1 USBSerial -#elif WITHIN(SERIAL_PORT, 0, 3) - DECLARE_SERIAL(SERIAL_PORT); - #define MYSERIAL1 MSERIAL(SERIAL_PORT) -#else - #error "The required SERIAL_PORT must be from 0 to 3, or -1 for Native USB." -#endif +#define SERIAL_INDEX_MIN 0 +#define SERIAL_INDEX_MAX 3 +#define USB_SERIAL_PORT(...) USBSerial +#include "../shared/serial_ports.h" // ------------------------ // Types diff --git a/Marlin/src/HAL/TEENSY35_36/HAL.h b/Marlin/src/HAL/TEENSY35_36/HAL.h index 44eafe5e6d..0f229000d4 100644 --- a/Marlin/src/HAL/TEENSY35_36/HAL.h +++ b/Marlin/src/HAL/TEENSY35_36/HAL.h @@ -70,17 +70,10 @@ typedef ForwardSerial1Class USBSerialType; extern USBSerialType USBSerial; -#define _MSERIAL(X) MSerial##X -#define MSERIAL(X) _MSERIAL(X) - -#if SERIAL_PORT == -1 - #define MYSERIAL1 USBSerial -#elif WITHIN(SERIAL_PORT, 0, 3) - #define MYSERIAL1 MSERIAL(SERIAL_PORT) - DECLARE_SERIAL(SERIAL_PORT); -#else - #error "SERIAL_PORT must be from 0 to 3, or -1 for Native USB." -#endif +#define SERIAL_INDEX_MIN 0 +#define SERIAL_INDEX_MAX 3 +#define USB_SERIAL_PORT(...) USBSerial +#include "../shared/serial_ports.h" // ------------------------ // Types diff --git a/Marlin/src/HAL/TEENSY40_41/HAL.h b/Marlin/src/HAL/TEENSY40_41/HAL.h index 7fa285ae62..f884db6684 100644 --- a/Marlin/src/HAL/TEENSY40_41/HAL.h +++ b/Marlin/src/HAL/TEENSY40_41/HAL.h @@ -78,41 +78,11 @@ typedef ForwardSerial1Class USBSerialType; extern USBSerialType USBSerial; -#define _MSERIAL(X) MSerial##X -#define MSERIAL(X) _MSERIAL(X) - -#if SERIAL_PORT == -1 - #define MYSERIAL1 USBSerial -#elif WITHIN(SERIAL_PORT, 0, 8) - DECLARE_SERIAL(SERIAL_PORT); - #define MYSERIAL1 MSERIAL(SERIAL_PORT) -#else - #error "The required SERIAL_PORT must be from 0 to 8, or -1 for Native USB." -#endif - -#ifdef SERIAL_PORT_2 - #if SERIAL_PORT_2 == -1 - #define MYSERIAL2 USBSerial - #elif SERIAL_PORT_2 == -2 - #define MYSERIAL2 ethernet.telnetClient - #elif WITHIN(SERIAL_PORT_2, 0, 8) - DECLARE_SERIAL(SERIAL_PORT_2); - #define MYSERIAL2 MSERIAL(SERIAL_PORT_2) - #else - #error "SERIAL_PORT_2 must be from 0 to 8, or -1 for Native USB, or -2 for Ethernet." - #endif -#endif - -#ifdef SERIAL_PORT_3 - #if SERIAL_PORT_3 == -1 - #define MYSERIAL3 USBSerial - #elif WITHIN(SERIAL_PORT_3, 0, 8) - DECLARE_SERIAL(SERIAL_PORT_3); - #define MYSERIAL3 MSERIAL(SERIAL_PORT_3) - #else - #error "SERIAL_PORT_3 must be from 0 to 8, or -1 for Native USB." - #endif -#endif +#define SERIAL_INDEX_MIN 0 +#define SERIAL_INDEX_MAX 8 +#define USB_SERIAL_PORT(...) USBSerial +#define ETH_SERIAL_PORT(...) ethernet.telnetClient +#include "../shared/serial_ports.h" // ------------------------ // Types diff --git a/Marlin/src/HAL/shared/serial_ports.h b/Marlin/src/HAL/shared/serial_ports.h new file mode 100644 index 0000000000..2daeea34e3 --- /dev/null +++ b/Marlin/src/HAL/shared/serial_ports.h @@ -0,0 +1,178 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +/** + * serial_ports.h - Define Marlin serial port macros and optionally declare ports + * + * This header defines one or more of the serial ports... + * - MYSERIAL1/2/3 ..... for host devices + * - MMU_SERIAL ........ for Multi-Material color changers + * - LCD_SERIAL ........ for serial LCDs + * - RS485_SERIAL ...... for CAN bus devices + * + * Before including this header define the following macros: + * - SERIAL_INDEX_MIN, SERIAL_INDEX_MAX to provide the valid range of serial port indexes. + * - _MSERIAL(X) and MSERIAL(X) to provide the instance name of Serial Port X. (Default: MSerial##X) + * - EP_SERIAL_PORT(X) to provide the instance name of Emergency Parser serial port X (if it is special). + * - USB_SERIAL_PORT(X) to provide the instance name of the USB serial port (if any). + * - ETH_SERIAL_PORT(X) to provide the instance name of the Ethernet serial port (if any). + * - DECLARE_SERIAL(X) to declare standard a serial port with the given index. + */ + +#ifndef _MSERIAL + #define _MSERIAL(X) MSerial##X +#endif +#ifndef MSERIAL + #define MSERIAL(X) _MSERIAL(X) +#endif + +#define INDEX_RANGE_MSG " must be from " STRINGIFY(SERIAL_INDEX_MIN) " to " STRINGIFY(SERIAL_INDEX_MAX) +#if defined(USB_SERIAL_PORT) && defined(ETH_SERIAL_PORT) + #define MORE_INDEXES_MSG ", -1 for Native USB, or -2 for Ethernet" +#elif defined(USB_SERIAL_PORT) + #define MORE_INDEXES_MSG ", or -1 for Native USB" +#elif defined(ETH_SERIAL_PORT) + #define MORE_INDEXES_MSG ", or -2 for Ethernet" +#else + #define MORE_INDEXES_MSG +#endif + +// +// SERIAL_PORT => MYSERIAL1 +// + +#if defined(EP_SERIAL_PORT) && ENABLED(EMERGENCY_PARSER) + #define MYSERIAL1 EP_SERIAL_PORT(1) +#elif WITHIN(SERIAL_PORT, SERIAL_INDEX_MIN, SERIAL_INDEX_MAX) + #define MYSERIAL1 MSERIAL(SERIAL_PORT) + #ifdef DECLARE_SERIAL + DECLARE_SERIAL(SERIAL_PORT); + #endif +#elif SERIAL_PORT == -1 && defined(USB_SERIAL_PORT) + #define MYSERIAL1 USB_SERIAL_PORT(1) +#elif SERIAL_PORT == -2 && defined(ETH_SERIAL_PORT) + #define MYSERIAL1 ETH_SERIAL_PORT(1) +#endif +#ifndef MYSERIAL1 + static_assert(false, "SERIAL_PORT" INDEX_RANGE_MSG MORE_INDEXES_MSG "."); + #define MYSERIAL1 _MSERIAL(1) // Dummy port +#endif + +// +// SERIAL_PORT_2 => MYSERIAL2 +// + +#ifdef SERIAL_PORT_2 + #if defined(EP_SERIAL_PORT) && ENABLED(EMERGENCY_PARSER) + #define MYSERIAL2 EP_SERIAL_PORT(2) + #elif WITHIN(SERIAL_PORT_2, SERIAL_INDEX_MIN, SERIAL_INDEX_MAX) + #define MYSERIAL2 MSERIAL(SERIAL_PORT_2) + #ifdef DECLARE_SERIAL + DECLARE_SERIAL(SERIAL_PORT_2); + #endif + #elif SERIAL_PORT_2 == -1 && defined(USB_SERIAL_PORT) + #define MYSERIAL2 USB_SERIAL_PORT(2) + #elif SERIAL_PORT_2 == -2 && defined(ETH_SERIAL_PORT) + #define MYSERIAL2 ETH_SERIAL_PORT(2) + #endif + #ifndef MYSERIAL2 + static_assert(false, "SERIAL_PORT_2" INDEX_RANGE_MSG MORE_INDEXES_MSG "."); + #define MYSERIAL2 _MSERIAL(1) // Dummy port + #endif +#endif + +// +// SERIAL_PORT_3 => MYSERIAL3 +// + +#ifdef SERIAL_PORT_3 + #if defined(EP_SERIAL_PORT) && ENABLED(EMERGENCY_PARSER) + #define MYSERIAL3 EP_SERIAL_PORT(3) + #elif WITHIN(SERIAL_PORT_3, SERIAL_INDEX_MIN, SERIAL_INDEX_MAX) + #define MYSERIAL3 MSERIAL(SERIAL_PORT_3) + #ifdef DECLARE_SERIAL + DECLARE_SERIAL(SERIAL_PORT_3); + #endif + #elif SERIAL_PORT_3 == -1 && defined(USB_SERIAL_PORT) + #define MYSERIAL3 USB_SERIAL_PORT(3) + #elif SERIAL_PORT_3 == -2 && defined(ETH_SERIAL_PORT) + #define MYSERIAL3 ETH_SERIAL_PORT(3) + #endif + #ifndef MYSERIAL3 + static_assert(false, "SERIAL_PORT_3" INDEX_RANGE_MSG MORE_INDEXES_MSG "."); + #define MYSERIAL3 _MSERIAL(1) // Dummy port + #endif +#endif + +// +// MMU_SERIAL_PORT => MMU_SERIAL +// + +#ifdef MMU_SERIAL_PORT + #if WITHIN(MMU_SERIAL_PORT, SERIAL_INDEX_MIN, SERIAL_INDEX_MAX) + #define MMU_SERIAL MSERIAL(MMU_SERIAL_PORT) + #ifdef DECLARE_SERIAL + DECLARE_SERIAL(MMU_SERIAL_PORT); + #endif + #else + static_assert(false, "MMU_SERIAL_PORT" INDEX_RANGE_MSG "."); + #define MMU_SERIAL _MSERIAL(1) // Dummy port + #endif +#endif + +// +// LCD_SERIAL_PORT => LCD_SERIAL +// + +#ifdef LCD_SERIAL_PORT + #if WITHIN(LCD_SERIAL_PORT, SERIAL_INDEX_MIN, SERIAL_INDEX_MAX) + #define LCD_SERIAL MSERIAL(LCD_SERIAL_PORT) + #ifdef DECLARE_SERIAL + DECLARE_SERIAL(LCD_SERIAL_PORT); + #endif + #else + static_assert(false, "LCD_SERIAL_PORT" INDEX_RANGE_MSG "."); + #define LCD_SERIAL _MSERIAL(1) // Dummy port + #endif +#endif + +// +// RS485_SERIAL_PORT => RS485_SERIAL +// + +#ifdef RS485_SERIAL_PORT + #if WITHIN(RS485_SERIAL_PORT, SERIAL_INDEX_MIN, SERIAL_INDEX_MAX) + #define RS485_SERIAL MSERIAL(RS485_SERIAL_PORT) + #ifdef DECLARE_SERIAL + DECLARE_SERIAL(RS485_SERIAL_PORT); + #endif + #else + static_assert(false, "RS485_SERIAL_PORT" INDEX_RANGE_MSG "."); + #define RS485_SERIAL _MSERIAL(1) // Dummy port + #endif +#endif + +#undef DECLARE_SERIAL +#undef SERIAL_INDEX_MIN +#undef SERIAL_INDEX_MAX +#undef INDEX_RANGE_MSG From 31bc23b6e3161cd15767314796e83d7a9bbf0b12 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Thu, 23 Jan 2025 00:26:51 +0000 Subject: [PATCH 051/787] [cron] Bump distribution date (2025-01-23) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index cbc35729a6..01e082eeaa 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-01-22" +//#define STRING_DISTRIBUTION_DATE "2025-01-23" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 1f45e01399..30210ab983 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-01-22" + #define STRING_DISTRIBUTION_DATE "2025-01-23" #endif /** From 428f721cbfc040ca9e57abd590c3798ed719fd8d Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Wed, 22 Jan 2025 18:06:54 -0600 Subject: [PATCH 052/787] =?UTF-8?q?=F0=9F=94=A7=20Sequential=20Opulo=20boa?= =?UTF-8?q?rds?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/core/boards.h | 12 ++++++------ Marlin/src/pins/pins.h | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Marlin/src/core/boards.h b/Marlin/src/core/boards.h index f08d69e3e5..e56e2177e5 100644 --- a/Marlin/src/core/boards.h +++ b/Marlin/src/core/boards.h @@ -457,12 +457,12 @@ #define BOARD_FYSETC_CHEETAH_V30 5235 // FYSETC Cheetah V3.0 (STM32F446RC) #define BOARD_TH3D_EZBOARD_V2 5236 // TH3D EZBoard v2.0 (STM32F405RG) #define BOARD_OPULO_LUMEN_REV3 5237 // Opulo Lumen PnP Controller REV3 (STM32F407VE / STM32F407VG) -#define BOARD_MKS_ROBIN_NANO_V1_3_F4 5238 // MKS Robin Nano V1.3 and MKS Robin Nano-S V1.3 (STM32F407VE) -#define BOARD_MKS_EAGLE 5239 // MKS Eagle (STM32F407VE) -#define BOARD_ARTILLERY_RUBY 5240 // Artillery Ruby (STM32F401RC) -#define BOARD_CREALITY_V24S1_301F4 5241 // Creality v2.4.S1_301F4 (STM32F401RC) as found in the Ender-3 S1 F4 -#define BOARD_CREALITY_CR4NTXXC10 5242 // Creality E3 Free-runs Silent Motherboard (STM32F401RET6) -#define BOARD_OPULO_LUMEN_REV4 5243 // Opulo Lumen PnP Controller REV4 (STM32F407VE / STM32F407VG) +#define BOARD_OPULO_LUMEN_REV4 5238 // Opulo Lumen PnP Controller REV4 (STM32F407VE / STM32F407VG) +#define BOARD_MKS_ROBIN_NANO_V1_3_F4 5239 // MKS Robin Nano V1.3 and MKS Robin Nano-S V1.3 (STM32F407VE) +#define BOARD_MKS_EAGLE 5240 // MKS Eagle (STM32F407VE) +#define BOARD_ARTILLERY_RUBY 5241 // Artillery Ruby (STM32F401RC) +#define BOARD_CREALITY_V24S1_301F4 5242 // Creality v2.4.S1_301F4 (STM32F401RC) as found in the Ender-3 S1 F4 +#define BOARD_CREALITY_CR4NTXXC10 5243 // Creality E3 Free-runs Silent Motherboard (STM32F401RET6) #define BOARD_FYSETC_SPIDER_KING407 5244 // FYSETC Spider King407 (STM32F407ZG) #define BOARD_MKS_SKIPR_V1 5245 // MKS SKIPR v1.0 all-in-one board (STM32F407VE) #define BOARD_TRONXY_CXY_446_V10 5246 // TRONXY CXY-446-V10-220413/CXY-V6-191121 (STM32F446ZE) diff --git a/Marlin/src/pins/pins.h b/Marlin/src/pins/pins.h index aee437c245..11b8f32c92 100644 --- a/Marlin/src/pins/pins.h +++ b/Marlin/src/pins/pins.h @@ -813,6 +813,8 @@ #include "stm32f4/pins_TH3D_EZBOARD_V2.h" // STM32F4 env:TH3D_EZBoard_V2_no_bootloader env:TH3D_EZBoard_V2_OpenBLT #elif MB(OPULO_LUMEN_REV3) #include "stm32f4/pins_OPULO_LUMEN_REV3.h" // STM32F4 env:Opulo_Lumen_REV3 +#elif MB(OPULO_LUMEN_REV4) + #include "stm32f4/pins_OPULO_LUMEN_REV4.h" // STM32F4 env:Opulo_Lumen_REV4 #elif MB(MKS_ROBIN_NANO_V1_3_F4) #include "stm32f4/pins_MKS_ROBIN_NANO_V1_3_F4.h" // STM32F4 env:mks_robin_nano_v1_3_f4 env:mks_robin_nano_v1_3_f4_usbmod #elif MB(MKS_EAGLE) @@ -823,8 +825,6 @@ #include "stm32f4/pins_CREALITY_V24S1_301F4.h" // STM32F4 env:STM32F401RC_creality env:STM32F401RC_creality_nobootloader env:STM32F401RC_creality_jlink env:STM32F401RC_creality_stlink #elif MB(CREALITY_CR4NTXXC10) #include "stm32f4/pins_CREALITY_CR4NTXXC10.h" // STM32F4 env:STM32F401RE_freeruns env:STM32F401RE_freeruns_jlink env:STM32F401RE_freeruns_stlink -#elif MB(OPULO_LUMEN_REV4) - #include "stm32f4/pins_OPULO_LUMEN_REV4.h" // STM32F4 env:Opulo_Lumen_REV4 #elif MB(FYSETC_SPIDER_KING407) #include "stm32f4/pins_FYSETC_SPIDER_KING407.h" // STM32F4 env:FYSETC_SPIDER_KING407 #elif MB(MKS_SKIPR_V1) From 0f7fb5d88df2ff450b6f7426c55ac0a979a5ed55 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Wed, 22 Jan 2025 15:48:29 -0600 Subject: [PATCH 053/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Med?= =?UTF-8?q?ia=20conditionals?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/HAL/RP2040/inc/SanityCheck.h | 2 +- Marlin/src/HAL/RP2040/msc_sd.cpp | 2 +- Marlin/src/HAL/STM32/inc/SanityCheck.h | 2 +- Marlin/src/HAL/STM32/msc_sd.cpp | 2 +- Marlin/src/MarlinCore.cpp | 2 +- Marlin/src/gcode/host/M115.cpp | 2 +- Marlin/src/gcode/parser.cpp | 2 +- Marlin/src/gcode/sd/M21_M22.cpp | 2 +- Marlin/src/inc/Conditionals-2-LCD.h | 6 ++++++ Marlin/src/inc/Conditionals-4-adv.h | 2 +- Marlin/src/inc/Conditionals-5-post.h | 2 +- Marlin/src/inc/SanityCheck.h | 10 ++++------ Marlin/src/lcd/extui/mks_ui/draw_media_select.cpp | 2 +- Marlin/src/lcd/extui/mks_ui/draw_print_file.cpp | 2 +- Marlin/src/lcd/extui/mks_ui/draw_ready_print.cpp | 2 +- Marlin/src/lcd/extui/mks_ui/draw_ui.cpp | 2 +- Marlin/src/lcd/extui/mks_ui/pic_manager.cpp | 2 +- .../src/lcd/extui/mks_ui/tft_lvgl_configuration.cpp | 4 ++-- Marlin/src/lcd/menu/menu_main.cpp | 12 ++++++------ Marlin/src/lcd/menu/menu_media.cpp | 6 +++--- Marlin/src/lcd/sovol_rts/sovol_rts.cpp | 4 ++-- Marlin/src/pins/rp2040/pins_RP2040.h | 2 +- Marlin/src/pins/sam/pins_ARCHIM2.h | 4 ++-- Marlin/src/sd/SdFatConfig.h | 2 +- Marlin/src/sd/SdVolume.h | 2 +- Marlin/src/sd/cardreader.cpp | 2 +- Marlin/src/sd/cardreader.h | 8 ++++---- Marlin/src/sd/usb_flashdrive/Sd2Card_FlashDrive.cpp | 6 +++--- Marlin/src/sd/usb_flashdrive/lib-uhs2/Usb.cpp | 4 ++-- Marlin/src/sd/usb_flashdrive/lib-uhs2/masstorage.cpp | 4 ++-- Marlin/src/sd/usb_flashdrive/lib-uhs2/message.cpp | 4 ++-- Marlin/src/sd/usb_flashdrive/lib-uhs2/parsetools.cpp | 4 ++-- Marlin/src/sd/usb_flashdrive/lib-uhs2/settings.h | 4 ++-- Marlin/src/sd/usb_flashdrive/lib-uhs2/usbhost.cpp | 6 +++--- ini/features.ini | 2 +- 35 files changed, 65 insertions(+), 61 deletions(-) diff --git a/Marlin/src/HAL/RP2040/inc/SanityCheck.h b/Marlin/src/HAL/RP2040/inc/SanityCheck.h index 29175f8bbb..e4b1d7ee8d 100644 --- a/Marlin/src/HAL/RP2040/inc/SanityCheck.h +++ b/Marlin/src/HAL/RP2040/inc/SanityCheck.h @@ -28,7 +28,7 @@ // #error "SPINDLE_LASER_PWM_PIN must use SERVO0, SERVO1 or SERVO3 connector" //#endif -#if ENABLED(SDCARD_EEPROM_EMULATION) && DISABLED(SDSUPPORT) +#if ENABLED(SDCARD_EEPROM_EMULATION) && !HAS_MEDIA #undef SDCARD_EEPROM_EMULATION // Avoid additional error noise #if USE_FALLBACK_EEPROM #warning "EEPROM type not specified. Fallback is SDCARD_EEPROM_EMULATION." diff --git a/Marlin/src/HAL/RP2040/msc_sd.cpp b/Marlin/src/HAL/RP2040/msc_sd.cpp index bc945c1999..58c900302d 100644 --- a/Marlin/src/HAL/RP2040/msc_sd.cpp +++ b/Marlin/src/HAL/RP2040/msc_sd.cpp @@ -42,7 +42,7 @@ class Sd2CardUSBMscHandler : public USBMscHandler { public: DiskIODriver* diskIODriver() { - #if ENABLED(MULTI_VOLUME) + #if HAS_MULTI_VOLUME #if SHARED_VOLUME_IS(SD_ONBOARD) return &card.media_driver_sdcard; #elif SHARED_VOLUME_IS(USB_FLASH_DRIVE) diff --git a/Marlin/src/HAL/STM32/inc/SanityCheck.h b/Marlin/src/HAL/STM32/inc/SanityCheck.h index bdcc6ab9f0..616f96eba0 100644 --- a/Marlin/src/HAL/STM32/inc/SanityCheck.h +++ b/Marlin/src/HAL/STM32/inc/SanityCheck.h @@ -58,7 +58,7 @@ * Check for common serial pin conflicts */ #define _CHECK_SERIAL_PIN(N) (( \ - BTN_EN1 == N || BTN_EN2 == N ||DOGLCD_CS == N || HEATER_BED_PIN == N || FAN0_PIN == N || \ + BTN_EN1 == N || BTN_EN2 == N || DOGLCD_CS == N || HEATER_BED_PIN == N || FAN0_PIN == N || \ SDIO_D2_PIN == N || SDIO_D3_PIN == N || SDIO_CK_PIN == N || SDIO_CMD_PIN == N || \ Y_STEP_PIN == N || Y_ENABLE_PIN == N || E0_ENABLE_PIN == N || POWER_LOSS_PIN == N \ )) diff --git a/Marlin/src/HAL/STM32/msc_sd.cpp b/Marlin/src/HAL/STM32/msc_sd.cpp index 5c8bee9c62..d4afc5990a 100644 --- a/Marlin/src/HAL/STM32/msc_sd.cpp +++ b/Marlin/src/HAL/STM32/msc_sd.cpp @@ -49,7 +49,7 @@ class Sd2CardUSBMscHandler : public USBMscHandler { public: DiskIODriver* diskIODriver() { - #if ENABLED(MULTI_VOLUME) + #if HAS_MULTI_VOLUME #if SHARED_VOLUME_IS(SD_ONBOARD) return &card.media_driver_sdcard; #elif SHARED_VOLUME_IS(USB_FLASH_DRIVE) diff --git a/Marlin/src/MarlinCore.cpp b/Marlin/src/MarlinCore.cpp index 140423f25c..bdcabca980 100644 --- a/Marlin/src/MarlinCore.cpp +++ b/Marlin/src/MarlinCore.cpp @@ -815,7 +815,7 @@ void idle(const bool no_stepper_sleep/*=false*/) { TERN_(HAS_MEDIA, card.manage_media()); // Handle USB Flash Drive insert / remove - TERN_(USB_FLASH_DRIVE_SUPPORT, card.diskIODriver()->idle()); + TERN_(HAS_USB_FLASH_DRIVE, card.diskIODriver()->idle()); // Announce Host Keepalive state (if any) TERN_(HOST_KEEPALIVE_FEATURE, gcode.host_keepalive()); diff --git a/Marlin/src/gcode/host/M115.cpp b/Marlin/src/gcode/host/M115.cpp index a4a2ac405f..6f38a65ae6 100644 --- a/Marlin/src/gcode/host/M115.cpp +++ b/Marlin/src/gcode/host/M115.cpp @@ -194,7 +194,7 @@ void GcodeSuite::M115() { // MULTI_VOLUME (M21 S/M21 U) #if HAS_MEDIA - cap_line(F("MULTI_VOLUME"), ENABLED(MULTI_VOLUME)); + cap_line(F("MULTI_VOLUME"), ENABLED(HAS_MULTI_VOLUME)); #endif // REPEAT (M808) diff --git a/Marlin/src/gcode/parser.cpp b/Marlin/src/gcode/parser.cpp index 54ae802863..6892d78b4a 100644 --- a/Marlin/src/gcode/parser.cpp +++ b/Marlin/src/gcode/parser.cpp @@ -273,7 +273,7 @@ void GCodeParser::parse(char *p) { // Only use string_arg for these M codes if (letter == 'M') switch (codenum) { TERN_(EXPECTED_PRINTER_CHECK, case 16:) - TERN_(SDSUPPORT, case 23: case 28: case 30: case 928:) + TERN_(HAS_MEDIA, case 23: case 28: case 30: case 928:) TERN_(HAS_STATUS_MESSAGE, case 117:) TERN_(HAS_RS485_SERIAL, case 485:) TERN_(GCODE_MACROS, case 810 ... 819:) diff --git a/Marlin/src/gcode/sd/M21_M22.cpp b/Marlin/src/gcode/sd/M21_M22.cpp index 3347168151..f561229b17 100644 --- a/Marlin/src/gcode/sd/M21_M22.cpp +++ b/Marlin/src/gcode/sd/M21_M22.cpp @@ -35,7 +35,7 @@ * P1 or U - Change to the USB Drive and mount it */ void GcodeSuite::M21() { - #if ENABLED(MULTI_VOLUME) + #if HAS_MULTI_VOLUME const int8_t vol = parser.intval('P', -1); if (vol == 0 || parser.seen_test('S')) // "S" for SD Card card.changeMedia(&card.media_driver_sdcard); diff --git a/Marlin/src/inc/Conditionals-2-LCD.h b/Marlin/src/inc/Conditionals-2-LCD.h index 0108fad02c..97f1cbd9c5 100644 --- a/Marlin/src/inc/Conditionals-2-LCD.h +++ b/Marlin/src/inc/Conditionals-2-LCD.h @@ -36,6 +36,12 @@ #if ENABLED(SDSUPPORT) #define HAS_MEDIA 1 #endif +#if ENABLED(MULTI_VOLUME) + #define HAS_MULTI_VOLUME 1 +#endif +#if ENABLED(USB_FLASH_DRIVE_SUPPORT) + #define HAS_USB_FLASH_DRIVE 1 +#endif // // Serial Port Info diff --git a/Marlin/src/inc/Conditionals-4-adv.h b/Marlin/src/inc/Conditionals-4-adv.h index 671c3590f4..103de78865 100644 --- a/Marlin/src/inc/Conditionals-4-adv.h +++ b/Marlin/src/inc/Conditionals-4-adv.h @@ -1234,7 +1234,7 @@ #define HOMING_BUMP_MM { 0, 0, 0 } #endif -#if ENABLED(USB_FLASH_DRIVE_SUPPORT) && NONE(USE_OTG_USB_HOST, USE_UHS3_USB) +#if HAS_USB_FLASH_DRIVE && NONE(USE_OTG_USB_HOST, USE_UHS3_USB) #define USE_UHS2_USB #endif diff --git a/Marlin/src/inc/Conditionals-5-post.h b/Marlin/src/inc/Conditionals-5-post.h index 55d91c4b81..d07a5914cd 100644 --- a/Marlin/src/inc/Conditionals-5-post.h +++ b/Marlin/src/inc/Conditionals-5-post.h @@ -550,7 +550,7 @@ #endif #endif - #if DISABLED(USB_FLASH_DRIVE_SUPPORT) || ALL(MULTI_VOLUME, VOLUME_SD_ONBOARD) + #if !HAS_USB_FLASH_DRIVE || ALL(HAS_MULTI_VOLUME, VOLUME_SD_ONBOARD) #if ENABLED(ONBOARD_SDIO) #define NEED_SD2CARD_SDIO 1 #else diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index be1ab0db50..83159f2638 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -3850,11 +3850,9 @@ static_assert(_PLUS_TEST(3), "DEFAULT_MAX_ACCELERATION values must be positive." #error "PRINTCOUNTER requires EEPROM_SETTINGS." #endif -#if ENABLED(USB_FLASH_DRIVE_SUPPORT) && !PINS_EXIST(USB_CS, USB_INTR) && DISABLED(USE_OTG_USB_HOST) - #error "USB_CS_PIN and USB_INTR_PIN are required for USB_FLASH_DRIVE_SUPPORT." -#endif - -#if ENABLED(USE_OTG_USB_HOST) && !defined(HAS_OTG_USB_HOST_SUPPORT) +#if HAS_USB_FLASH_DRIVE && DISABLED(USE_OTG_USB_HOST) && !PINS_EXIST(USB_CS, USB_INTR) + #error "USB_CS_PIN and USB_INTR_PIN (or USE_OTG_USB_HOST) are required for USB_FLASH_DRIVE_SUPPORT." +#elif ENABLED(USE_OTG_USB_HOST) && !defined(HAS_OTG_USB_HOST_SUPPORT) #error "The current board does not support USE_OTG_USB_HOST." #endif @@ -4075,7 +4073,7 @@ static_assert(_PLUS_TEST(3), "DEFAULT_MAX_ACCELERATION values must be positive." * Check to make sure MONITOR_DRIVER_STATUS isn't enabled * on boards where TMC drivers share the SPI bus with SD. */ -#if HAS_TMC_SPI && ALL(MONITOR_DRIVER_STATUS, HAS_MEDIA, USES_SHARED_SPI) +#if HAS_TMC_SPI && ALL(HAS_MEDIA, MONITOR_DRIVER_STATUS, USES_SHARED_SPI) #error "MONITOR_DRIVER_STATUS and SDSUPPORT cannot be used together on boards with shared SPI." #endif diff --git a/Marlin/src/lcd/extui/mks_ui/draw_media_select.cpp b/Marlin/src/lcd/extui/mks_ui/draw_media_select.cpp index 085a008acd..25a9238705 100644 --- a/Marlin/src/lcd/extui/mks_ui/draw_media_select.cpp +++ b/Marlin/src/lcd/extui/mks_ui/draw_media_select.cpp @@ -21,7 +21,7 @@ */ #include "../../../inc/MarlinConfigPre.h" -#if ALL(HAS_TFT_LVGL_UI, MULTI_VOLUME) +#if ALL(HAS_TFT_LVGL_UI, HAS_MULTI_VOLUME) #include "draw_ui.h" #include diff --git a/Marlin/src/lcd/extui/mks_ui/draw_print_file.cpp b/Marlin/src/lcd/extui/mks_ui/draw_print_file.cpp index 7732d5d2a4..69300ee9c9 100644 --- a/Marlin/src/lcd/extui/mks_ui/draw_print_file.cpp +++ b/Marlin/src/lcd/extui/mks_ui/draw_print_file.cpp @@ -168,7 +168,7 @@ static void event_handler(lv_obj_t *obj, lv_event_t event) { } else { lv_clear_print_file(); - TERN(MULTI_VOLUME, lv_draw_media_select(), lv_draw_ready_print()); + TERN(HAS_MULTI_VOLUME, lv_draw_media_select(), lv_draw_ready_print()); } } else { diff --git a/Marlin/src/lcd/extui/mks_ui/draw_ready_print.cpp b/Marlin/src/lcd/extui/mks_ui/draw_ready_print.cpp index 39f270840b..a3b31e33b5 100644 --- a/Marlin/src/lcd/extui/mks_ui/draw_ready_print.cpp +++ b/Marlin/src/lcd/extui/mks_ui/draw_ready_print.cpp @@ -76,7 +76,7 @@ static void event_handler(lv_obj_t *obj, lv_event_t event) { case ID_INFO_EXT: uiCfg.curTempType = 0; lv_draw_preHeat(); break; case ID_INFO_BED: uiCfg.curTempType = 1; lv_draw_preHeat(); break; case ID_INFO_FAN: lv_draw_fan(); break; - case ID_PRINT: TERN(MULTI_VOLUME, lv_draw_media_select(), lv_draw_print_file()); break; + case ID_PRINT: TERN(HAS_MULTI_VOLUME, lv_draw_media_select(), lv_draw_print_file()); break; } } diff --git a/Marlin/src/lcd/extui/mks_ui/draw_ui.cpp b/Marlin/src/lcd/extui/mks_ui/draw_ui.cpp index 2a906ff80f..92cc17f8cc 100644 --- a/Marlin/src/lcd/extui/mks_ui/draw_ui.cpp +++ b/Marlin/src/lcd/extui/mks_ui/draw_ui.cpp @@ -966,7 +966,7 @@ void clear_cur_ui() { #if ENABLED(TOUCH_SCREEN_CALIBRATION) case TOUCH_CALIBRATION_UI: lv_clear_touch_calibration_screen(); break; #endif - #if ENABLED(MULTI_VOLUME) + #if HAS_MULTI_VOLUME case MEDIA_SELECT_UI: lv_clear_media_select(); break; #endif default: break; diff --git a/Marlin/src/lcd/extui/mks_ui/pic_manager.cpp b/Marlin/src/lcd/extui/mks_ui/pic_manager.cpp index 06d47d949b..04ea827236 100644 --- a/Marlin/src/lcd/extui/mks_ui/pic_manager.cpp +++ b/Marlin/src/lcd/extui/mks_ui/pic_manager.cpp @@ -197,7 +197,7 @@ static FSTR_P const assets[] = { F("bmp_cloud.bin"), #endif - #if ENABLED(MULTI_VOLUME) + #if HAS_MULTI_VOLUME F("bmp_usb_disk.bin"), //F("bmp_usb_disk_sel.bin"), F("bmp_sd.bin"), diff --git a/Marlin/src/lcd/extui/mks_ui/tft_lvgl_configuration.cpp b/Marlin/src/lcd/extui/mks_ui/tft_lvgl_configuration.cpp index f8dda5bd7b..7a56cf371f 100644 --- a/Marlin/src/lcd/extui/mks_ui/tft_lvgl_configuration.cpp +++ b/Marlin/src/lcd/extui/mks_ui/tft_lvgl_configuration.cpp @@ -134,9 +134,9 @@ void tft_lvgl_init() { hal.watchdog_refresh(); // LVGL init takes time - #if ENABLED(USB_FLASH_DRIVE_SUPPORT) + #if HAS_USB_FLASH_DRIVE uint16_t usb_flash_loop = 1000; - #if ENABLED(MULTI_VOLUME) && !HAS_SD_HOST_DRIVE + #if HAS_MULTI_VOLUME && !HAS_SD_HOST_DRIVE if (IS_SD_INSERTED()) card.changeMedia(&card.media_driver_sdcard); else diff --git a/Marlin/src/lcd/menu/menu_main.cpp b/Marlin/src/lcd/menu/menu_main.cpp index 4da92d5e49..c74d6b2a1d 100644 --- a/Marlin/src/lcd/menu/menu_main.cpp +++ b/Marlin/src/lcd/menu/menu_main.cpp @@ -293,8 +293,8 @@ void menu_main() { #endif #if HAS_SD_DETECT - GCODES_ITEM(MSG_CHANGE_MEDIA, F("M21" TERN_(MULTI_VOLUME, "S"))); // M21 Change Media - #if ENABLED(MULTI_VOLUME) + GCODES_ITEM(MSG_CHANGE_MEDIA, F("M21" TERN_(HAS_MULTI_VOLUME, "S"))); // M21 Change Media + #if HAS_MULTI_VOLUME GCODES_ITEM(MSG_ATTACH_USB_MEDIA, F("M21U")); // M21 Attach USB Media #endif #else // - or - @@ -314,7 +314,7 @@ void menu_main() { #if HAS_SD_DETECT ACTION_ITEM(MSG_NO_MEDIA, nullptr); // "No Media" #else - #if ENABLED(MULTI_VOLUME) + #if HAS_MULTI_VOLUME GCODES_ITEM(MSG_ATTACH_SD_MEDIA, F("M21S")); // M21S Attach SD Card GCODES_ITEM(MSG_ATTACH_USB_MEDIA, F("M21U")); // M21U Attach USB Media #else @@ -420,8 +420,8 @@ void menu_main() { #endif #if HAS_SD_DETECT - GCODES_ITEM(MSG_CHANGE_MEDIA, F("M21" TERN_(MULTI_VOLUME, "S"))); // M21 Change Media - #if ENABLED(MULTI_VOLUME) + GCODES_ITEM(MSG_CHANGE_MEDIA, F("M21" TERN_(HAS_MULTI_VOLUME, "S"))); // M21 Change Media + #if HAS_MULTI_VOLUME GCODES_ITEM(MSG_ATTACH_USB_MEDIA, F("M21U")); // M21 Attach USB Media #endif #else // - or - @@ -441,7 +441,7 @@ void menu_main() { #if HAS_SD_DETECT ACTION_ITEM(MSG_NO_MEDIA, nullptr); // "No Media" #else - #if ENABLED(MULTI_VOLUME) + #if HAS_MULTI_VOLUME GCODES_ITEM(MSG_ATTACH_SD_MEDIA, F("M21S")); // M21S Attach SD Card GCODES_ITEM(MSG_ATTACH_USB_MEDIA, F("M21U")); // M21U Attach USB Media #else diff --git a/Marlin/src/lcd/menu/menu_media.cpp b/Marlin/src/lcd/menu/menu_media.cpp index f28c0900f0..fe00bf3710 100644 --- a/Marlin/src/lcd/menu/menu_media.cpp +++ b/Marlin/src/lcd/menu/menu_media.cpp @@ -112,7 +112,7 @@ void menu_media_filelist() { #endif START_MENU(); - #if ENABLED(MULTI_VOLUME) + #if HAS_MULTI_VOLUME ACTION_ITEM(MSG_BACK, []{ ui.goto_screen(menu_media); }); #else BACK_ITEM_F(TERN1(BROWSE_MEDIA_ON_INSERT, screen_history_depth) ? GET_TEXT_F(MSG_MAIN_MENU) : GET_TEXT_F(MSG_BACK)); @@ -141,7 +141,7 @@ void menu_media_filelist() { END_MENU(); } -#if ENABLED(MULTI_VOLUME) +#if HAS_MULTI_VOLUME void menu_media_select() { START_MENU(); BACK_ITEM_F(TERN1(BROWSE_MEDIA_ON_INSERT, screen_history_depth) ? GET_TEXT_F(MSG_MAIN_MENU) : GET_TEXT_F(MSG_BACK)); @@ -156,7 +156,7 @@ void menu_media_filelist() { #endif void menu_media() { - TERN(MULTI_VOLUME, menu_media_select, menu_media_filelist)(); + TERN(HAS_MULTI_VOLUME, menu_media_select, menu_media_filelist)(); } #endif // HAS_MARLINUI_MENU && HAS_MEDIA diff --git a/Marlin/src/lcd/sovol_rts/sovol_rts.cpp b/Marlin/src/lcd/sovol_rts/sovol_rts.cpp index cdffca409b..b0cb2001fa 100644 --- a/Marlin/src/lcd/sovol_rts/sovol_rts.cpp +++ b/Marlin/src/lcd/sovol_rts/sovol_rts.cpp @@ -521,7 +521,7 @@ void RTS::sdCardStop() { thermalManager.zero_fan_speeds(); wait_for_heatup = wait_for_user = false; poweroff_continue = false; - #if ALL(SDSUPPORT, POWER_LOSS_RECOVERY) + #if ALL(HAS_MEDIA, POWER_LOSS_RECOVERY) if (card.flag.mounted) card.removeJobRecoveryFile(); #endif #ifdef EVENT_GCODE_SD_STOP @@ -1094,7 +1094,7 @@ void RTS::handleData() { thermalManager.disable_all_heaters(); print_job_timer.reset(); - #if ALL(SDSUPPORT, POWER_LOSS_RECOVERY) + #if ALL(HAS_MEDIA, POWER_LOSS_RECOVERY) if (card.flag.mounted) { card.removeJobRecoveryFile(); recovery.info.valid_head = 0; diff --git a/Marlin/src/pins/rp2040/pins_RP2040.h b/Marlin/src/pins/rp2040/pins_RP2040.h index 2f4e3796a6..ce1c5160ae 100644 --- a/Marlin/src/pins/rp2040/pins_RP2040.h +++ b/Marlin/src/pins/rp2040/pins_RP2040.h @@ -95,7 +95,7 @@ #define TEMP_BOARD_PIN TEMP_MCU // SPI for MAX Thermocouple -#if DISABLED(SDSUPPORT) +#if !HAS_MEDIA #define TEMP_0_CS_PIN 17 // Don't use 53 if using Display/SD card #else #define TEMP_0_CS_PIN 17 // Don't use 49 (SD_DETECT_PIN) diff --git a/Marlin/src/pins/sam/pins_ARCHIM2.h b/Marlin/src/pins/sam/pins_ARCHIM2.h index cd8527c727..a0488d64dc 100644 --- a/Marlin/src/pins/sam/pins_ARCHIM2.h +++ b/Marlin/src/pins/sam/pins_ARCHIM2.h @@ -253,9 +253,9 @@ #define BTN_ENC 16 // D16 PA13_TXD1 // the click #endif -#if ANY(HAS_WIRED_LCD, TOUCH_UI_ULTIPANEL, TOUCH_UI_FTDI_EVE, USB_FLASH_DRIVE_SUPPORT) +#if ANY(HAS_WIRED_LCD, TOUCH_UI_ULTIPANEL, TOUCH_UI_FTDI_EVE, HAS_USB_FLASH_DRIVE) #define SD_DETECT_PIN 2 // D2 PB25_TIOA0 - #if ENABLED(USB_FLASH_DRIVE_SUPPORT) + #if HAS_USB_FLASH_DRIVE #define DISABLE_DUE_SD_MMC #endif #endif diff --git a/Marlin/src/sd/SdFatConfig.h b/Marlin/src/sd/SdFatConfig.h index 674737c102..cc47a71443 100644 --- a/Marlin/src/sd/SdFatConfig.h +++ b/Marlin/src/sd/SdFatConfig.h @@ -39,7 +39,7 @@ * * Each card requires about 550 bytes of SRAM so use of a Mega is recommended. */ -#define USE_MULTIPLE_CARDS 0 //TODO? ENABLED(MULTI_VOLUME) +#define USE_MULTIPLE_CARDS 0 // TODO? HAS_MULTI_VOLUME /** * Call flush for endl if ENDL_CALLS_FLUSH is nonzero diff --git a/Marlin/src/sd/SdVolume.h b/Marlin/src/sd/SdVolume.h index ccf595a593..2d08c66e27 100644 --- a/Marlin/src/sd/SdVolume.h +++ b/Marlin/src/sd/SdVolume.h @@ -34,7 +34,7 @@ #include "../inc/MarlinConfigPre.h" -#if ENABLED(USB_FLASH_DRIVE_SUPPORT) +#if HAS_USB_FLASH_DRIVE #include "usb_flashdrive/Sd2Card_FlashDrive.h" #endif diff --git a/Marlin/src/sd/cardreader.cpp b/Marlin/src/sd/cardreader.cpp index facd2d811a..1f4b9695ac 100644 --- a/Marlin/src/sd/cardreader.cpp +++ b/Marlin/src/sd/cardreader.cpp @@ -504,7 +504,7 @@ void CardReader::mount() { if (flag.mounted) cdroot(); else { - #if ANY(HAS_SD_DETECT, USB_FLASH_DRIVE_SUPPORT) + #if ANY(HAS_SD_DETECT, HAS_USB_FLASH_DRIVE) if (marlin_state != MarlinState::MF_INITIALIZING) LCD_ALERTMESSAGE(MSG_MEDIA_INIT_FAIL); #endif } diff --git a/Marlin/src/sd/cardreader.h b/Marlin/src/sd/cardreader.h index 1d2ba3ae6f..eeead4e490 100644 --- a/Marlin/src/sd/cardreader.h +++ b/Marlin/src/sd/cardreader.h @@ -50,7 +50,7 @@ extern const char M23_STR[], M24_STR[]; #include "SdFile.h" #include "disk_io_driver.h" -#if ENABLED(USB_FLASH_DRIVE_SUPPORT) +#if HAS_USB_FLASH_DRIVE #include "usb_flashdrive/Sd2Card_FlashDrive.h" #endif @@ -60,7 +60,7 @@ extern const char M23_STR[], M24_STR[]; #include "Sd2Card.h" #endif -#if ENABLED(MULTI_VOLUME) +#if HAS_MULTI_VOLUME #define SV_SD_ONBOARD 1 #define SV_USB_FLASH_DRIVE 2 #define _VOLUME_ID(N) _CAT(SV_, N) @@ -257,7 +257,7 @@ public: static AutoReporter auto_reporter; #endif - #if SHARED_VOLUME_IS(USB_FLASH_DRIVE) || ENABLED(USB_FLASH_DRIVE_SUPPORT) + #if SHARED_VOLUME_IS(USB_FLASH_DRIVE) || HAS_USB_FLASH_DRIVE #define HAS_USB_FLASH_DRIVE 1 static DiskIODriver_USBFlash media_driver_usbFlash; #endif @@ -363,7 +363,7 @@ private: #endif }; -#if ENABLED(USB_FLASH_DRIVE_SUPPORT) +#if HAS_USB_FLASH_DRIVE #define IS_SD_INSERTED() DiskIODriver_USBFlash::isInserted() #elif HAS_SD_DETECT #define IS_SD_INSERTED() (READ(SD_DETECT_PIN) == SD_DETECT_STATE) diff --git a/Marlin/src/sd/usb_flashdrive/Sd2Card_FlashDrive.cpp b/Marlin/src/sd/usb_flashdrive/Sd2Card_FlashDrive.cpp index 76d69c789e..455ba6ba0a 100644 --- a/Marlin/src/sd/usb_flashdrive/Sd2Card_FlashDrive.cpp +++ b/Marlin/src/sd/usb_flashdrive/Sd2Card_FlashDrive.cpp @@ -38,14 +38,14 @@ //#define BS_HOST_DEBUG(...) {char s[255]; sprintf(s,__VA_ARGS__); SERIAL_ECHOLNPGM("UHS:",s);} //#define MAX_HOST_DEBUG(...) {char s[255]; sprintf(s,__VA_ARGS__); SERIAL_ECHOLNPGM("UHS:",s);} -#if ENABLED(USB_FLASH_DRIVE_SUPPORT) +#if HAS_USB_FLASH_DRIVE #include "../../MarlinCore.h" #include "../../core/serial.h" #include "../../module/temperature.h" #if DISABLED(USE_OTG_USB_HOST) && !PINS_EXIST(USB_CS, USB_INTR) - #error "USB_FLASH_DRIVE_SUPPORT requires USB_CS_PIN and USB_INTR_PIN to be defined." + #error "USB_FLASH_DRIVE_SUPPORT requires USB_CS_PIN and USB_INTR_PIN (or USE_OTG_USB_HOST) to be defined." #endif #if ENABLED(USE_UHS3_USB) @@ -325,4 +325,4 @@ bool DiskIODriver_USBFlash::writeBlock(uint32_t block, const uint8_t *src) { return bulk.Write(0, block, 512, 1, src) == 0; } -#endif // USB_FLASH_DRIVE_SUPPORT +#endif // HAS_USB_FLASH_DRIVE diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs2/Usb.cpp b/Marlin/src/sd/usb_flashdrive/lib-uhs2/Usb.cpp index 016500d2d6..aa102e228f 100644 --- a/Marlin/src/sd/usb_flashdrive/lib-uhs2/Usb.cpp +++ b/Marlin/src/sd/usb_flashdrive/lib-uhs2/Usb.cpp @@ -29,7 +29,7 @@ #include "../../../inc/MarlinConfigPre.h" -#if ENABLED(USB_FLASH_DRIVE_SUPPORT) && DISABLED(USE_UHS3_USB) +#if HAS_USB_FLASH_DRIVE && DISABLED(USE_UHS3_USB) #include "Usb.h" @@ -792,4 +792,4 @@ uint8_t USB::setConf(uint8_t addr, uint8_t ep, uint8_t conf_value) { return ctrlReq(addr, ep, bmREQ_SET, USB_REQUEST_SET_CONFIGURATION, conf_value, 0x00, 0x0000, 0x0000, 0x0000, nullptr, nullptr); } -#endif // USB_FLASH_DRIVE_SUPPORT +#endif // HAS_USB_FLASH_DRIVE && !USE_UHS3_USB diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs2/masstorage.cpp b/Marlin/src/sd/usb_flashdrive/lib-uhs2/masstorage.cpp index 551fb274d7..a6124ab0fe 100644 --- a/Marlin/src/sd/usb_flashdrive/lib-uhs2/masstorage.cpp +++ b/Marlin/src/sd/usb_flashdrive/lib-uhs2/masstorage.cpp @@ -25,7 +25,7 @@ #include "../../../inc/MarlinConfigPre.h" -#if ENABLED(USB_FLASH_DRIVE_SUPPORT) && DISABLED(USE_UHS3_USB) +#if HAS_USB_FLASH_DRIVE && DISABLED(USE_UHS3_USB) #include "masstorage.h" @@ -1204,4 +1204,4 @@ uint8_t BulkOnly::Read(uint8_t lun __attribute__((unused)), uint32_t addr __attr #endif } -#endif // USB_FLASH_DRIVE_SUPPORT +#endif // HAS_USB_FLASH_DRIVE && !USE_UHS3_USB diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs2/message.cpp b/Marlin/src/sd/usb_flashdrive/lib-uhs2/message.cpp index 1c1131cd3c..afe9e86e52 100644 --- a/Marlin/src/sd/usb_flashdrive/lib-uhs2/message.cpp +++ b/Marlin/src/sd/usb_flashdrive/lib-uhs2/message.cpp @@ -25,7 +25,7 @@ #include "../../../inc/MarlinConfigPre.h" -#if ENABLED(USB_FLASH_DRIVE_SUPPORT) && DISABLED(USE_UHS3_USB) +#if HAS_USB_FLASH_DRIVE && DISABLED(USE_UHS3_USB) #include "Usb.h" @@ -125,4 +125,4 @@ void E_Notify(double d, int lvl) { #endif // DEBUG_USB_HOST -#endif // USB_FLASH_DRIVE_SUPPORT +#endif // HAS_USB_FLASH_DRIVE && !USE_UHS3_USB diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs2/parsetools.cpp b/Marlin/src/sd/usb_flashdrive/lib-uhs2/parsetools.cpp index 5d25576c40..4b2ef4b1f9 100644 --- a/Marlin/src/sd/usb_flashdrive/lib-uhs2/parsetools.cpp +++ b/Marlin/src/sd/usb_flashdrive/lib-uhs2/parsetools.cpp @@ -25,7 +25,7 @@ #include "../../../inc/MarlinConfigPre.h" -#if ENABLED(USB_FLASH_DRIVE_SUPPORT) && DISABLED(USE_UHS3_USB) +#if HAS_USB_FLASH_DRIVE && DISABLED(USE_UHS3_USB) #include "Usb.h" @@ -74,4 +74,4 @@ bool PTPListParser::Parse(uint8_t **pp, uint16_t *pcntdn, PTP_ARRAY_EL_FUNC pf, return true; } -#endif // USB_FLASH_DRIVE_SUPPORT +#endif // HAS_USB_FLASH_DRIVE && !USE_UHS3_USB diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs2/settings.h b/Marlin/src/sd/usb_flashdrive/lib-uhs2/settings.h index 1d46dc69b3..c437e8b31f 100644 --- a/Marlin/src/sd/usb_flashdrive/lib-uhs2/settings.h +++ b/Marlin/src/sd/usb_flashdrive/lib-uhs2/settings.h @@ -28,7 +28,7 @@ #include "macros.h" -#if ENABLED(USB_FLASH_DRIVE_SUPPORT) +#if HAS_USB_FLASH_DRIVE //////////////////////////////////////////////////////////////////////////////// /* Added by Bill Greiman to speed up mass storage initialization with USB * flash drives and simple USB hard drives. @@ -65,7 +65,7 @@ * For example Serial3. */ #ifndef USB_HOST_SERIAL - #if ENABLED(USB_FLASH_DRIVE_SUPPORT) + #if HAS_USB_FLASH_DRIVE #define USB_HOST_SERIAL MYSERIAL1 #else #define USB_HOST_SERIAL Serial diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs2/usbhost.cpp b/Marlin/src/sd/usb_flashdrive/lib-uhs2/usbhost.cpp index 09fd57b154..fd3849d1ed 100644 --- a/Marlin/src/sd/usb_flashdrive/lib-uhs2/usbhost.cpp +++ b/Marlin/src/sd/usb_flashdrive/lib-uhs2/usbhost.cpp @@ -25,10 +25,10 @@ #include "../../../inc/MarlinConfigPre.h" -#if ENABLED(USB_FLASH_DRIVE_SUPPORT) && DISABLED(USE_UHS3_USB) +#if HAS_USB_FLASH_DRIVE && DISABLED(USE_UHS3_USB) #if !PINS_EXIST(USB_CS, USB_INTR) - #error "USB_FLASH_DRIVE_SUPPORT requires USB_CS_PIN and USB_INTR_PIN to be defined." + #error "USB_FLASH_DRIVE_SUPPORT requires USB_CS_PIN and USB_INTR_PIN (or USE_UHS3_USB) to be defined." #endif #include "Usb.h" @@ -203,4 +203,4 @@ uint8_t MAX3421e::IntHandler() { return HIRQ_sendback; } -#endif // USB_FLASH_DRIVE_SUPPORT +#endif // HAS_USB_FLASH_DRIVE && !USE_UHS3_USB diff --git a/ini/features.ini b/ini/features.ini index b2e9d6884e..a21c36b27e 100644 --- a/ini/features.ini +++ b/ini/features.ini @@ -208,7 +208,7 @@ MALYAN_LCD = build_src_filter=+ USE_UHS2_USB = build_src_filter=+ USE_UHS3_USB = build_src_filter=+ -USB_FLASH_DRIVE_SUPPORT = build_src_filter=+ +HAS_USB_FLASH_DRIVE = build_src_filter=+ HAS_MCP3426_ADC = build_src_filter=+ + AUTO_BED_LEVELING_BILINEAR = build_src_filter=+ AUTO_BED_LEVELING_(3POINT|(BI)?LINEAR) = build_src_filter=+ From ac14c656434083aebb0a0b1dbcfd36666a9da83e Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Thu, 23 Jan 2025 18:00:17 -0600 Subject: [PATCH 054/787] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20SD-=20and=20SPI-re?= =?UTF-8?q?lated=20pins=20cleanup=20(#27650)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/Configuration_adv.h | 4 +- Marlin/src/HAL/AVR/spi_pins.h | 50 +++++++------- Marlin/src/HAL/DUE/HAL.cpp | 2 +- Marlin/src/HAL/DUE/HAL_SPI.cpp | 7 +- Marlin/src/HAL/DUE/spi_pins.h | 65 +++++++++---------- Marlin/src/HAL/ESP32/spi_pins.h | 17 +++-- Marlin/src/HAL/LINUX/spi_pins.h | 6 -- Marlin/src/HAL/LPC1768/inc/SanityCheck.h | 6 +- Marlin/src/HAL/LPC1768/spi_pins.h | 8 --- Marlin/src/HAL/NATIVE_SIM/spi_pins.h | 7 -- Marlin/src/HAL/RP2040/HAL.cpp | 7 +- Marlin/src/HAL/RP2040/spi_pins.h | 5 +- Marlin/src/HAL/SAMD21/HAL.cpp | 2 +- Marlin/src/HAL/SAMD21/spi_pins.h | 7 -- Marlin/src/HAL/SAMD51/HAL.cpp | 2 +- Marlin/src/HAL/SAMD51/spi_pins.h | 5 -- Marlin/src/HAL/STM32/HAL.cpp | 4 +- Marlin/src/HAL/STM32/spi_pins.h | 3 - Marlin/src/HAL/STM32F1/spi_pins.h | 5 -- Marlin/src/HAL/TEENSY31_32/spi_pins.h | 1 - Marlin/src/HAL/TEENSY35_36/spi_pins.h | 1 - Marlin/src/HAL/TEENSY40_41/spi_pins.h | 1 - Marlin/src/inc/Changes.h | 10 +++ .../extui/ftdi_eve_touch_ui/pin_mappings.h | 2 +- Marlin/src/pins/esp32/pins_E4D.h | 2 +- Marlin/src/pins/esp32/pins_ENWI_ESPNP.h | 7 +- Marlin/src/pins/esp32/pins_ESP32.h | 2 +- Marlin/src/pins/esp32/pins_ESPA_common.h | 2 +- .../pins/esp32/pins_GODI_CONTROLLER_V1_0.h | 2 +- Marlin/src/pins/esp32/pins_MKS_TINYBEE.h | 2 +- Marlin/src/pins/esp32/pins_MM_JOKER.h | 2 +- Marlin/src/pins/esp32/pins_MRR_ESPE.h | 2 +- Marlin/src/pins/esp32/pins_PANDA_common.h | 2 +- Marlin/src/pins/gd32f1/pins_TRIGORILLA_V006.h | 17 ++--- Marlin/src/pins/lpc1768/pins_AZSMZ_MINI.h | 4 +- Marlin/src/pins/lpc1768/pins_BIQU_B300_V1.0.h | 1 - Marlin/src/pins/lpc1768/pins_BIQU_BQ111_A4.h | 5 +- Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_1.h | 8 +-- Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_3.h | 2 +- Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_4.h | 2 +- Marlin/src/pins/lpc1768/pins_MKS_SBASE.h | 2 +- Marlin/src/pins/lpc1768/pins_MKS_SGEN_L.h | 2 +- Marlin/src/pins/lpc1768/pins_RAMPS_RE_ARM.h | 2 +- Marlin/src/pins/lpc1769/pins_AZTEEG_X5_GT.h | 2 +- Marlin/src/pins/lpc1769/pins_AZTEEG_X5_MINI.h | 2 +- .../src/pins/lpc1769/pins_COHESION3D_MINI.h | 2 +- .../src/pins/lpc1769/pins_COHESION3D_REMIX.h | 2 +- Marlin/src/pins/lpc1769/pins_MKS_SGEN_L_V2.h | 2 +- Marlin/src/pins/lpc1769/pins_SMOOTHIEBOARD.h | 2 +- .../pins/lpc1769/pins_XTLW_CLIMBER_8TH_LPC.h | 2 +- Marlin/src/pins/mega/pins_CHEAPTRONICv2.h | 2 +- Marlin/src/pins/mega/pins_CNCONTROLS_11.h | 2 +- Marlin/src/pins/mega/pins_CNCONTROLS_12.h | 2 +- Marlin/src/pins/mega/pins_CNCONTROLS_15.h | 2 +- Marlin/src/pins/mega/pins_EINSTART-S.h | 2 +- Marlin/src/pins/mega/pins_ELEFU_3.h | 2 +- Marlin/src/pins/mega/pins_GT2560_REV_A.h | 2 +- Marlin/src/pins/mega/pins_GT2560_V3.h | 2 +- Marlin/src/pins/mega/pins_GT2560_V41b.h | 2 +- Marlin/src/pins/mega/pins_HJC2560C_REV2.h | 2 +- Marlin/src/pins/mega/pins_INTAMSYS40.h | 2 +- Marlin/src/pins/mega/pins_LEAPFROG.h | 2 +- Marlin/src/pins/mega/pins_MEGACONTROLLER.h | 2 +- Marlin/src/pins/mega/pins_MEGATRONICS.h | 2 +- Marlin/src/pins/mega/pins_MEGATRONICS_2.h | 2 +- Marlin/src/pins/mega/pins_MEGATRONICS_3.h | 2 +- Marlin/src/pins/mega/pins_MIGHTYBOARD_REVE.h | 2 +- Marlin/src/pins/mega/pins_MINITRONICS.h | 2 +- Marlin/src/pins/mega/pins_OVERLORD.h | 2 +- Marlin/src/pins/mega/pins_PICA.h | 4 +- Marlin/src/pins/mega/pins_SILVER_GATE.h | 2 +- Marlin/src/pins/mega/pins_WANHAO_ONEPLUS.h | 2 +- Marlin/src/pins/mega/pins_WEEDO_62A.h | 2 +- Marlin/src/pins/native/pins_RAMPS_NATIVE.h | 8 +-- Marlin/src/pins/pinsDebug_list.h | 8 +-- Marlin/src/pins/pins_postprocess.h | 4 +- Marlin/src/pins/rambo/pins_EINSY_RAMBO.h | 2 +- Marlin/src/pins/rambo/pins_EINSY_RETRO.h | 2 +- Marlin/src/pins/rambo/pins_MINIRAMBO.h | 2 +- Marlin/src/pins/rambo/pins_RAMBO.h | 2 +- Marlin/src/pins/rambo/pins_SCOOVO_X9H.h | 2 +- Marlin/src/pins/ramps/pins_3DRAG.h | 2 +- .../src/pins/ramps/pins_DUPLICATOR_I3_PLUS.h | 2 +- Marlin/src/pins/ramps/pins_FORMBOT_RAPTOR.h | 4 +- .../src/pins/ramps/pins_FORMBOT_TREX2PLUS.h | 2 +- Marlin/src/pins/ramps/pins_FORMBOT_TREX3.h | 2 +- Marlin/src/pins/ramps/pins_FYSETC_F6_13.h | 2 +- Marlin/src/pins/ramps/pins_K8600.h | 2 +- Marlin/src/pins/ramps/pins_K8800.h | 4 +- Marlin/src/pins/ramps/pins_MKS_GEN_13.h | 2 +- Marlin/src/pins/ramps/pins_ORTUR_4.h | 2 +- Marlin/src/pins/ramps/pins_RAMPS.h | 10 +-- Marlin/src/pins/ramps/pins_RAMPS_OLD.h | 2 +- Marlin/src/pins/ramps/pins_RAMPS_S_12.h | 2 +- Marlin/src/pins/ramps/pins_RUMBA.h | 2 +- Marlin/src/pins/ramps/pins_TENLOG_D3_HERO.h | 2 +- Marlin/src/pins/ramps/pins_TENLOG_MB1_V23.h | 2 +- Marlin/src/pins/ramps/pins_TT_OSCAR.h | 14 ++-- Marlin/src/pins/ramps/pins_ULTIMAIN_2.h | 2 +- Marlin/src/pins/ramps/pins_ULTIMAKER.h | 2 +- Marlin/src/pins/ramps/pins_ZRIB_V53.h | 8 +-- Marlin/src/pins/ramps/pins_Z_BOLT_X_SERIES.h | 2 +- Marlin/src/pins/rp2040/pins_RP2040.h | 8 +-- Marlin/src/pins/sam/pins_ADSK.h | 2 +- Marlin/src/pins/sam/pins_ALLIGATOR_R2.h | 2 +- Marlin/src/pins/sam/pins_ARCHIM1.h | 2 +- Marlin/src/pins/sam/pins_ARCHIM2.h | 2 +- Marlin/src/pins/sam/pins_CNCONTROLS_15D.h | 2 +- Marlin/src/pins/sam/pins_DUE3DOM.h | 4 +- Marlin/src/pins/sam/pins_DUE3DOM_MINI.h | 6 +- Marlin/src/pins/sam/pins_KRATOS32.h | 2 +- Marlin/src/pins/sam/pins_PRINTRBOARD_G2.h | 2 +- Marlin/src/pins/sam/pins_RADDS.h | 8 +-- Marlin/src/pins/sam/pins_RAMPS_FD_V1.h | 2 +- Marlin/src/pins/sam/pins_RURAMPS4D_11.h | 4 +- Marlin/src/pins/sam/pins_RURAMPS4D_13.h | 4 +- Marlin/src/pins/sam/pins_ULTRATRONICS_PRO.h | 2 +- .../src/pins/samd/pins_BRICOLEMON_LITE_V1_0.h | 11 ++-- Marlin/src/pins/samd/pins_BRICOLEMON_V1_0.h | 10 +-- Marlin/src/pins/samd/pins_MINITRONICS20.h | 8 +-- Marlin/src/pins/samd/pins_RAMPS_144.h | 10 +-- Marlin/src/pins/sanguino/pins_ANET_10.h | 4 +- Marlin/src/pins/sanguino/pins_GEN3_PLUS.h | 2 +- Marlin/src/pins/sanguino/pins_GEN6.h | 2 +- Marlin/src/pins/sanguino/pins_GEN7_CUSTOM.h | 2 +- .../src/pins/sanguino/pins_MELZI_CREALITY.h | 2 +- .../pins/sanguino/pins_MELZI_CREALITY_E2.h | 2 +- Marlin/src/pins/sanguino/pins_MELZI_TRONXY.h | 2 +- Marlin/src/pins/sanguino/pins_OMCA.h | 2 +- Marlin/src/pins/sanguino/pins_OMCA_A.h | 2 +- .../src/pins/sanguino/pins_SANGUINOLOLU_11.h | 12 ++-- Marlin/src/pins/sanguino/pins_ZMIB_V2.h | 4 +- Marlin/src/pins/stm32f0/pins_MALYAN_M300.h | 5 -- Marlin/src/pins/stm32f1/pins_BEAST.h | 2 +- Marlin/src/pins/stm32f1/pins_BTT_SKR_CR6.h | 2 +- Marlin/src/pins/stm32f1/pins_BTT_SKR_E3_DIP.h | 2 +- .../stm32f1/pins_BTT_SKR_MINI_E3_common.h | 2 +- .../src/pins/stm32f1/pins_BTT_SKR_MINI_V1_1.h | 1 - Marlin/src/pins/stm32f1/pins_CHITU3D.h | 11 ++-- Marlin/src/pins/stm32f1/pins_FLSUN_HISPEED.h | 1 - Marlin/src/pins/stm32f1/pins_FLY_MINI.h | 1 - Marlin/src/pins/stm32f1/pins_FYSETC_AIO_II.h | 2 +- Marlin/src/pins/stm32f1/pins_FYSETC_CHEETAH.h | 2 +- Marlin/src/pins/stm32f1/pins_GTM32_MINI.h | 2 - Marlin/src/pins/stm32f1/pins_GTM32_MINI_A30.h | 2 - Marlin/src/pins/stm32f1/pins_GTM32_PRO_VB.h | 2 - Marlin/src/pins/stm32f1/pins_GTM32_REV_B.h | 2 - Marlin/src/pins/stm32f1/pins_LONGER3D_LK.h | 1 - Marlin/src/pins/stm32f1/pins_MALYAN_M200.h | 2 - Marlin/src/pins/stm32f1/pins_MD_D301.h | 2 +- Marlin/src/pins/stm32f1/pins_MKS_ROBIN.h | 3 +- Marlin/src/pins/stm32f1/pins_MKS_ROBIN_E3P.h | 2 +- .../pins/stm32f1/pins_MKS_ROBIN_E3_common.h | 5 +- .../src/pins/stm32f1/pins_MKS_ROBIN_NANO_V2.h | 2 +- Marlin/src/pins/stm32f1/pins_MORPHEUS.h | 2 +- Marlin/src/pins/stm32f1/pins_PANDA_PI_V29.h | 2 +- Marlin/src/pins/stm32f1/pins_STM32F1R.h | 2 +- Marlin/src/pins/stm32f1/pins_STM3R_MINI.h | 2 +- Marlin/src/pins/stm32f1/pins_TRIGORILLA_PRO.h | 3 +- Marlin/src/pins/stm32f4/pins_ANET_ET4.h | 3 +- Marlin/src/pins/stm32f4/pins_ARMED.h | 2 +- Marlin/src/pins/stm32f4/pins_ARTILLERY_RUBY.h | 9 +-- Marlin/src/pins/stm32f4/pins_BLACKBEEZMINI.h | 2 +- .../src/pins/stm32f4/pins_BLACKPILL_CUSTOM.h | 5 +- .../src/pins/stm32f4/pins_BLACK_STM32F407VE.h | 2 +- .../src/pins/stm32f4/pins_BTT_BTT002_V1_0.h | 2 - Marlin/src/pins/stm32f4/pins_BTT_GTR_V1_0.h | 5 +- .../pins/stm32f4/pins_BTT_OCTOPUS_V1_common.h | 3 +- .../stm32f4/pins_BTT_SKR_MINI_E3_V3_0_1.h | 1 - .../pins/stm32f4/pins_BTT_SKR_PRO_common.h | 4 +- .../pins/stm32f4/pins_BTT_SKR_V2_0_common.h | 3 +- Marlin/src/pins/stm32f4/pins_FLYF407ZG.h | 4 +- .../pins/stm32f4/pins_FYSETC_CHEETAH_V20.h | 2 +- .../pins/stm32f4/pins_FYSETC_CHEETAH_V30.h | 4 +- .../src/pins/stm32f4/pins_FYSETC_S6_common.h | 4 +- .../pins/stm32f4/pins_FYSETC_SPIDER_KING407.h | 4 +- Marlin/src/pins/stm32f4/pins_I3DBEEZ9.h | 4 +- Marlin/src/pins/stm32f4/pins_LERDGE_K.h | 1 - Marlin/src/pins/stm32f4/pins_LERDGE_S.h | 1 - Marlin/src/pins/stm32f4/pins_LERDGE_X.h | 1 - .../src/pins/stm32f4/pins_MELLOW_FLY_E3_V2.h | 3 +- .../pins/stm32f4/pins_MKS_MONSTER8_common.h | 5 +- Marlin/src/pins/stm32f4/pins_MKS_ROBIN2.h | 2 - .../stm32f4/pins_MKS_ROBIN_NANO_V3_common.h | 5 +- .../src/pins/stm32f4/pins_MKS_ROBIN_PRO_V2.h | 5 +- Marlin/src/pins/stm32f4/pins_MKS_SKIPR_V1_0.h | 1 - .../src/pins/stm32f4/pins_OPULO_LUMEN_REV3.h | 10 +-- .../src/pins/stm32f4/pins_OPULO_LUMEN_REV4.h | 10 +-- Marlin/src/pins/stm32f4/pins_RUMBA32_common.h | 2 +- .../src/pins/stm32f4/pins_TH3D_EZBOARD_V2.h | 8 +-- .../src/pins/stm32f4/pins_XTLW_CLIMBER_8TH.h | 3 +- Marlin/src/pins/stm32f7/pins_NUCLEO_F767ZI.h | 1 - Marlin/src/pins/stm32f7/pins_REMRAM_V1.h | 4 +- .../pins/stm32g0/pins_BTT_MANTA_E3_EZ_V1_0.h | 1 - .../pins/stm32g0/pins_BTT_MANTA_M4P_V2_1.h | 3 +- .../pins/stm32g0/pins_BTT_MANTA_M5P_V1_0.h | 3 +- .../pins/stm32g0/pins_BTT_MANTA_M8P_common.h | 3 +- Marlin/src/pins/stm32g0/pins_BTT_SKRAT_V1_0.h | 1 - .../pins/stm32g0/pins_BTT_SKR_MINI_E3_V3_0.h | 1 - .../src/pins/stm32h7/pins_BTT_KRAKEN_V1_0.h | 6 +- .../pins/stm32h7/pins_BTT_MANTA_M8P_V2_0.h | 6 +- .../pins/stm32h7/pins_BTT_OCTOPUS_MAX_EZ.h | 6 +- .../stm32h7/pins_BTT_OCTOPUS_PRO_V1_common.h | 3 +- .../pins/stm32h7/pins_BTT_SKR_SE_BX_common.h | 3 +- .../pins/stm32h7/pins_BTT_SKR_V3_0_common.h | 3 +- Marlin/src/pins/teensy2/pins_5DPRINT.h | 2 +- Marlin/src/pins/teensy2/pins_BRAINWAVE_PRO.h | 2 +- Marlin/src/pins/teensy2/pins_PRINTRBOARD.h | 6 +- .../src/pins/teensy2/pins_PRINTRBOARD_REVF.h | 6 +- Marlin/src/pins/teensy2/pins_SAV_MKI.h | 2 +- Marlin/src/pins/teensy2/pins_TEENSY2.h | 2 +- Marlin/src/pins/teensy2/pins_TEENSYLU.h | 4 +- Marlin/src/pins/teensy3/pins_TEENSY31_32.h | 2 +- Marlin/src/pins/teensy3/pins_TEENSY35_36.h | 2 +- Marlin/src/sd/cardreader.cpp | 6 +- 215 files changed, 366 insertions(+), 485 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 417bea4718..a1e5443129 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -1869,7 +1869,7 @@ * * SCLK, MOSI, MISO --> SCLK, MOSI, MISO * INT --> SD_DETECT_PIN [1] - * SS --> SDSS + * SS --> SD_SS_PIN * * [1] On AVR an interrupt-capable pin is best for UHS3 compatibility. */ @@ -1896,7 +1896,7 @@ //#define USE_OTG_USB_HOST #if DISABLED(USE_OTG_USB_HOST) - #define USB_CS_PIN SDSS + #define USB_CS_PIN SD_SS_PIN #define USB_INTR_PIN SD_DETECT_PIN #endif #endif diff --git a/Marlin/src/HAL/AVR/spi_pins.h b/Marlin/src/HAL/AVR/spi_pins.h index 831972938a..934b6e3b14 100644 --- a/Marlin/src/HAL/AVR/spi_pins.h +++ b/Marlin/src/HAL/AVR/spi_pins.h @@ -23,43 +23,41 @@ /** * Define SPI Pins: SCK, MISO, MOSI, SS + * Platform pins have parentheses, e.g., "(53)", so we cannot use them. */ #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__) - #define AVR_SCK_PIN 13 - #define AVR_MISO_PIN 12 - #define AVR_MOSI_PIN 11 - #define AVR_SS_PIN 10 + #define _PIN_SPI_SCK 13 + #define _PIN_SPI_MISO 12 + #define _PIN_SPI_MOSI 11 + #define _PIN_SPI_SS 10 #elif defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__) || defined(__AVR_ATmega1284P__) - #define AVR_SCK_PIN 7 - #define AVR_MISO_PIN 6 - #define AVR_MOSI_PIN 5 - #define AVR_SS_PIN 4 + #define _PIN_SPI_SCK 7 + #define _PIN_SPI_MISO 6 + #define _PIN_SPI_MOSI 5 + #define _PIN_SPI_SS 4 #elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) - #define AVR_SCK_PIN 52 - #define AVR_MISO_PIN 50 - #define AVR_MOSI_PIN 51 - #define AVR_SS_PIN 53 + #define _PIN_SPI_SCK 52 + #define _PIN_SPI_MISO 50 + #define _PIN_SPI_MOSI 51 + #define _PIN_SPI_SS 53 #elif defined(__AVR_AT90USB1287__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) - #define AVR_SCK_PIN 21 - #define AVR_MISO_PIN 23 - #define AVR_MOSI_PIN 22 - #define AVR_SS_PIN 20 + #define _PIN_SPI_SCK 21 + #define _PIN_SPI_MISO 23 + #define _PIN_SPI_MOSI 22 + #define _PIN_SPI_SS 20 #elif defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2561__) - #define AVR_SCK_PIN 10 - #define AVR_MISO_PIN 12 - #define AVR_MOSI_PIN 11 - #define AVR_SS_PIN 16 + #define _PIN_SPI_SCK 10 + #define _PIN_SPI_MISO 12 + #define _PIN_SPI_MOSI 11 + #define _PIN_SPI_SS 16 #endif #ifndef SD_SCK_PIN - #define SD_SCK_PIN AVR_SCK_PIN + #define SD_SCK_PIN _PIN_SPI_SCK #endif #ifndef SD_MISO_PIN - #define SD_MISO_PIN AVR_MISO_PIN + #define SD_MISO_PIN _PIN_SPI_MISO #endif #ifndef SD_MOSI_PIN - #define SD_MOSI_PIN AVR_MOSI_PIN -#endif -#ifndef SD_SS_PIN - #define SD_SS_PIN AVR_SS_PIN + #define SD_MOSI_PIN _PIN_SPI_MOSI #endif diff --git a/Marlin/src/HAL/DUE/HAL.cpp b/Marlin/src/HAL/DUE/HAL.cpp index 763091cb00..d1db9148c4 100644 --- a/Marlin/src/HAL/DUE/HAL.cpp +++ b/Marlin/src/HAL/DUE/HAL.cpp @@ -48,7 +48,7 @@ uint16_t MarlinHAL::adc_result; void MarlinHAL::init() { #if HAS_MEDIA - OUT_WRITE(SDSS, HIGH); // Try to set SDSS inactive before any other SPI users start up + OUT_WRITE(SD_SS_PIN, HIGH); // Try to set SDSS inactive before any other SPI users start up #endif usb_task_init(); // Initialize the USB stack TERN_(POSTMORTEM_DEBUGGING, install_min_serial()); // Install the min serial handler diff --git a/Marlin/src/HAL/DUE/HAL_SPI.cpp b/Marlin/src/HAL/DUE/HAL_SPI.cpp index c2fabb0d49..5bbc4223bb 100644 --- a/Marlin/src/HAL/DUE/HAL_SPI.cpp +++ b/Marlin/src/HAL/DUE/HAL_SPI.cpp @@ -600,9 +600,8 @@ OUT_WRITE(SPI_EEPROM1_CS_PIN, HIGH); OUT_WRITE(SPI_EEPROM2_CS_PIN, HIGH); OUT_WRITE(SPI_FLASH_CS_PIN, HIGH); - WRITE(SD_SS_PIN, HIGH); - - OUT_WRITE(SDSS, LOW); + OUT_WRITE(SD_SS_PIN, HIGH); + WRITE(SD_SS_PIN, LOW); PIO_Configure( g_APinDescription[SPI_PIN].pPort, @@ -767,7 +766,7 @@ // Disable PIO on A26 and A27 REG_PIOA_PDR = 0x0C000000; - OUT_WRITE(SDSS, HIGH); + OUT_WRITE(SD_SS_PIN, HIGH); // Reset SPI0 (from sam lib) SPI0->SPI_CR = SPI_CR_SPIDIS; diff --git a/Marlin/src/HAL/DUE/spi_pins.h b/Marlin/src/HAL/DUE/spi_pins.h index 7f0b1290b1..e289c8ced2 100644 --- a/Marlin/src/HAL/DUE/spi_pins.h +++ b/Marlin/src/HAL/DUE/spi_pins.h @@ -26,39 +26,36 @@ * * Available chip select pins for HW SPI are 4 10 52 77 87 */ -#if SDSS == 4 || SDSS == 10 || SDSS == 52 || SDSS == 77 || SDSS == 87 - #if SDSS == 4 - #define SPI_PIN 87 - #define SPI_CHAN 1 - #elif SDSS == 10 - #define SPI_PIN 77 - #define SPI_CHAN 0 - #elif SDSS == 52 - #define SPI_PIN 86 - #define SPI_CHAN 2 - #elif SDSS == 77 - #define SPI_PIN 77 - #define SPI_CHAN 0 - #else - #define SPI_PIN 87 - #define SPI_CHAN 1 - #endif - #define SD_SCK_PIN 76 - #define SD_MISO_PIN 74 - #define SD_MOSI_PIN 75 -#else - // defaults - #define SOFTWARE_SPI - #ifndef SD_SCK_PIN - #define SD_SCK_PIN 52 - #endif - #ifndef SD_MISO_PIN - #define SD_MISO_PIN 50 - #endif - #ifndef SD_MOSI_PIN - #define SD_MOSI_PIN 51 - #endif +#if SD_SS_PIN == 4 || SD_SS_PIN == 10 || SD_SS_PIN == 52 || SD_SS_PIN == 77 || SD_SS_PIN == 87 + #define SD_SCK_PIN 76 + #define SD_MISO_PIN 74 + #define SD_MOSI_PIN 75 #endif -/* A.28, A.29, B.21, C.26, C.29 */ -#define SD_SS_PIN SDSS +#if SD_SS_PIN == 4 + #define SPI_PIN 87 + #define SPI_CHAN 1 +#elif SD_SS_PIN == 10 + #define SPI_PIN 77 + #define SPI_CHAN 0 +#elif SD_SS_PIN == 52 + #define SPI_PIN 86 + #define SPI_CHAN 2 +#elif SD_SS_PIN == 77 + #define SPI_PIN 77 + #define SPI_CHAN 0 +#elif SD_SS_PIN == 87 + #define SPI_PIN 87 + #define SPI_CHAN 1 +#else + #define SOFTWARE_SPI + #ifndef SD_SCK_PIN + #define SD_SCK_PIN 52 + #endif + #ifndef SD_MISO_PIN + #define SD_MISO_PIN 50 + #endif + #ifndef SD_MOSI_PIN + #define SD_MOSI_PIN 51 + #endif +#endif diff --git a/Marlin/src/HAL/ESP32/spi_pins.h b/Marlin/src/HAL/ESP32/spi_pins.h index 58881f0ea7..b50ea725ab 100644 --- a/Marlin/src/HAL/ESP32/spi_pins.h +++ b/Marlin/src/HAL/ESP32/spi_pins.h @@ -21,7 +21,16 @@ */ #pragma once -#define SD_SS_PIN SDSS -#define SD_SCK_PIN 18 -#define SD_MISO_PIN 19 -#define SD_MOSI_PIN 23 +#define PIN_SPI_SCK 18 +#define PIN_SPI_MISO 19 +#define PIN_SPI_MOSI 23 + +#ifndef SD_SCK_PIN + #define SD_SCK_PIN PIN_SPI_SCK +#endif +#ifndef SD_MISO_PIN + #define SD_MISO_PIN PIN_SPI_MISO +#endif +#ifndef SD_MOSI_PIN + #define SD_MOSI_PIN PIN_SPI_MOSI +#endif diff --git a/Marlin/src/HAL/LINUX/spi_pins.h b/Marlin/src/HAL/LINUX/spi_pins.h index 4139c8f898..221145e4b3 100644 --- a/Marlin/src/HAL/LINUX/spi_pins.h +++ b/Marlin/src/HAL/LINUX/spi_pins.h @@ -38,9 +38,3 @@ #ifndef SD_MOSI_PIN #define SD_MOSI_PIN 52 #endif -#ifndef SD_SS_PIN - #define SD_SS_PIN 53 -#endif -#ifndef SDSS - #define SDSS SD_SS_PIN -#endif diff --git a/Marlin/src/HAL/LPC1768/inc/SanityCheck.h b/Marlin/src/HAL/LPC1768/inc/SanityCheck.h index 2782f225b0..5a5617f4ac 100644 --- a/Marlin/src/HAL/LPC1768/inc/SanityCheck.h +++ b/Marlin/src/HAL/LPC1768/inc/SanityCheck.h @@ -121,7 +121,7 @@ static_assert(DISABLED(BAUD_RATE_GCODE), "BAUD_RATE_GCODE is not yet supported o #if IS_TX1(BTN_EN2) || IS_RX1(BTN_EN1) #error "Serial port pins (1) conflict with Encoder Buttons!" #elif ANY_TX(1, SD_SCK_PIN, LCD_PINS_D4, DOGLCD_SCK, LCD_RESET_PIN, LCD_PINS_RS, SHIFT_CLK_PIN) \ - || ANY_RX(1, LCD_SDSS, LCD_PINS_RS, SD_MISO_PIN, DOGLCD_A0, SD_SS_PIN, LCD_SDSS, DOGLCD_CS, LCD_RESET_PIN, LCD_BACKLIGHT_PIN) + || ANY_RX(1, LCD_SDSS_PIN, LCD_PINS_RS, SD_MISO_PIN, DOGLCD_A0, SD_SS_PIN, DOGLCD_CS, LCD_RESET_PIN, LCD_BACKLIGHT_PIN) #error "Serial port pins (1) conflict with LCD pins!" #endif #endif @@ -211,8 +211,8 @@ static_assert(DISABLED(BAUD_RATE_GCODE), "BAUD_RATE_GCODE is not yet supported o #error "SCL0 overlaps with Encoder Button!" #elif IS_SCL0(SD_SS_PIN) #error "SCL0 overlaps with SD_SS_PIN!" - #elif IS_SCL0(LCD_SDSS) - #error "SCL0 overlaps with LCD_SDSS!" + #elif IS_SCL0(LCD_SDSS_PIN) + #error "SCL0 overlaps with LCD_SDSS_PIN!" #endif #undef PIN_IS_SDA0 #undef IS_SCL0 diff --git a/Marlin/src/HAL/LPC1768/spi_pins.h b/Marlin/src/HAL/LPC1768/spi_pins.h index e52f78a7cb..036bf0e023 100644 --- a/Marlin/src/HAL/LPC1768/spi_pins.h +++ b/Marlin/src/HAL/LPC1768/spi_pins.h @@ -32,7 +32,6 @@ //#define SD_SCK_PIN P0_07 //#define SD_MISO_PIN P0_08 //#define SD_MOSI_PIN P0_09 -//#define SD_SS_PIN P0_06 // External SD #ifndef SD_SCK_PIN @@ -44,10 +43,3 @@ #ifndef SD_MOSI_PIN #define SD_MOSI_PIN P0_18 #endif -#ifndef SD_SS_PIN - #define SD_SS_PIN P1_23 -#endif -#if !defined(SDSS) || SDSS == P_NC // gets defaulted in pins.h - #undef SDSS - #define SDSS SD_SS_PIN -#endif diff --git a/Marlin/src/HAL/NATIVE_SIM/spi_pins.h b/Marlin/src/HAL/NATIVE_SIM/spi_pins.h index d9911bf56c..0e83e13692 100644 --- a/Marlin/src/HAL/NATIVE_SIM/spi_pins.h +++ b/Marlin/src/HAL/NATIVE_SIM/spi_pins.h @@ -32,7 +32,6 @@ //#define SD_SCK_PIN P0_07 //#define SD_MISO_PIN P0_08 //#define SD_MOSI_PIN P0_09 -//#define SD_SS_PIN P0_06 // External SD #ifndef SD_SCK_PIN @@ -44,9 +43,3 @@ #ifndef SD_MOSI_PIN #define SD_MOSI_PIN 52 #endif -#ifndef SD_SS_PIN - #define SD_SS_PIN 53 -#endif -#ifndef SDSS - #define SDSS SD_SS_PIN -#endif diff --git a/Marlin/src/HAL/RP2040/HAL.cpp b/Marlin/src/HAL/RP2040/HAL.cpp index d1af25a842..ceaf540452 100644 --- a/Marlin/src/HAL/RP2040/HAL.cpp +++ b/Marlin/src/HAL/RP2040/HAL.cpp @@ -59,11 +59,8 @@ void MarlinHAL::init() { constexpr int cpuFreq = F_CPU; UNUSED(cpuFreq); - #undef SDSS - #define SDSS 2 - #define PIN_EXISTS_(P1,P2) (defined(P1##P2) && P1##P2 >= 0) - #if HAS_MEDIA && DISABLED(SDIO_SUPPORT) && PIN_EXISTS_(SDSS,) - OUT_WRITE(SDSS, HIGH); // Try to set SDSS inactive before any other SPI users start up + #if HAS_MEDIA && DISABLED(SDIO_SUPPORT) && PIN_EXISTS(SD_SS) + OUT_WRITE(SD_SS_PIN, HIGH); // Try to set SD_SS_PIN inactive before any other SPI users start up #endif #if PIN_EXISTS(LED) diff --git a/Marlin/src/HAL/RP2040/spi_pins.h b/Marlin/src/HAL/RP2040/spi_pins.h index e6ee840b55..949fdff36f 100644 --- a/Marlin/src/HAL/RP2040/spi_pins.h +++ b/Marlin/src/HAL/RP2040/spi_pins.h @@ -24,6 +24,8 @@ /** * Define SPI Pins: SCK, MISO, MOSI, SS */ +#define PIN_SPI_SS 2 + #ifndef SD_SCK_PIN #define SD_SCK_PIN PIN_SPI_SCK #endif @@ -33,6 +35,3 @@ #ifndef SD_MOSI_PIN #define SD_MOSI_PIN PIN_SPI_MOSI #endif -#ifndef SD_SS_PIN - #define SD_SS_PIN PIN_SPI_SS -#endif diff --git a/Marlin/src/HAL/SAMD21/HAL.cpp b/Marlin/src/HAL/SAMD21/HAL.cpp index 3656d97190..0a95366cc4 100644 --- a/Marlin/src/HAL/SAMD21/HAL.cpp +++ b/Marlin/src/HAL/SAMD21/HAL.cpp @@ -107,7 +107,7 @@ void MarlinHAL::init() { #if HAS_SD_DETECT && SD_CONNECTION_IS(ONBOARD) SET_INPUT_PULLUP(SD_DETECT_PIN); #endif - OUT_WRITE(SDSS, HIGH); // Try to set SDSS inactive before any other SPI users start up + OUT_WRITE(SD_SS_PIN, HIGH); // Try to set SDSS inactive before any other SPI users start up #endif } diff --git a/Marlin/src/HAL/SAMD21/spi_pins.h b/Marlin/src/HAL/SAMD21/spi_pins.h index 8c25b84dc1..1186c3de48 100644 --- a/Marlin/src/HAL/SAMD21/spi_pins.h +++ b/Marlin/src/HAL/SAMD21/spi_pins.h @@ -45,10 +45,3 @@ #ifndef SD_MOSI_PIN #define SD_MOSI_PIN 37 #endif -#ifndef SDSS - #define SDSS 18 -#endif - -#ifndef SD_SS_PIN - #define SD_SS_PIN SDSS -#endif diff --git a/Marlin/src/HAL/SAMD51/HAL.cpp b/Marlin/src/HAL/SAMD51/HAL.cpp index a3c871ce51..cfc44e1360 100644 --- a/Marlin/src/HAL/SAMD51/HAL.cpp +++ b/Marlin/src/HAL/SAMD51/HAL.cpp @@ -669,7 +669,7 @@ void MarlinHAL::init() { #if HAS_SD_DETECT && SD_CONNECTION_IS(ONBOARD) SET_INPUT_PULLUP(SD_DETECT_PIN); #endif - OUT_WRITE(SDSS, HIGH); // Try to set SDSS inactive before any other SPI users start up + OUT_WRITE(SD_SS_PIN, HIGH); // Try to set SDSS inactive before any other SPI users start up #endif } diff --git a/Marlin/src/HAL/SAMD51/spi_pins.h b/Marlin/src/HAL/SAMD51/spi_pins.h index 2c7cbeb994..a2d5b72ec4 100644 --- a/Marlin/src/HAL/SAMD51/spi_pins.h +++ b/Marlin/src/HAL/SAMD51/spi_pins.h @@ -46,14 +46,9 @@ #ifndef SD_MOSI_PIN #define SD_MOSI_PIN 51 #endif - #ifndef SDSS - #define SDSS 53 - #endif #else #error "Unsupported board!" #endif - -#define SD_SS_PIN SDSS diff --git a/Marlin/src/HAL/STM32/HAL.cpp b/Marlin/src/HAL/STM32/HAL.cpp index 610bd0b243..6bebaa24f0 100644 --- a/Marlin/src/HAL/STM32/HAL.cpp +++ b/Marlin/src/HAL/STM32/HAL.cpp @@ -69,8 +69,8 @@ void MarlinHAL::init() { constexpr int cpuFreq = F_CPU; UNUSED(cpuFreq); - #if HAS_MEDIA && DISABLED(ONBOARD_SDIO) && (defined(SDSS) && SDSS != -1) - OUT_WRITE(SDSS, HIGH); // Try to set SDSS inactive before any other SPI users start up + #if HAS_MEDIA && DISABLED(ONBOARD_SDIO) && PIN_EXISTS(SD_SS) + OUT_WRITE(SD_SS_PIN, HIGH); // Try to set SDSS inactive before any other SPI users start up #endif #if PIN_EXISTS(LED) diff --git a/Marlin/src/HAL/STM32/spi_pins.h b/Marlin/src/HAL/STM32/spi_pins.h index 7f341a8c25..da6fa0d160 100644 --- a/Marlin/src/HAL/STM32/spi_pins.h +++ b/Marlin/src/HAL/STM32/spi_pins.h @@ -33,6 +33,3 @@ #ifndef SD_MOSI_PIN #define SD_MOSI_PIN PIN_SPI_MOSI #endif -#ifndef SD_SS_PIN - #define SD_SS_PIN PIN_SPI_SS -#endif diff --git a/Marlin/src/HAL/STM32F1/spi_pins.h b/Marlin/src/HAL/STM32F1/spi_pins.h index 3d3c8f8d2f..d9c5e1f8c6 100644 --- a/Marlin/src/HAL/STM32F1/spi_pins.h +++ b/Marlin/src/HAL/STM32F1/spi_pins.h @@ -46,11 +46,6 @@ #ifndef SD_MOSI_PIN #define SD_MOSI_PIN PA7 #endif -#ifndef SD_SS_PIN - #define SD_SS_PIN PA4 -#endif -#undef SDSS -#define SDSS SD_SS_PIN #ifndef SPI_DEVICE #define SPI_DEVICE 1 diff --git a/Marlin/src/HAL/TEENSY31_32/spi_pins.h b/Marlin/src/HAL/TEENSY31_32/spi_pins.h index 6d0d05f85a..dbd0bb9174 100644 --- a/Marlin/src/HAL/TEENSY31_32/spi_pins.h +++ b/Marlin/src/HAL/TEENSY31_32/spi_pins.h @@ -24,4 +24,3 @@ #define SD_SCK_PIN 13 #define SD_MISO_PIN 12 #define SD_MOSI_PIN 11 -#define SD_SS_PIN 20 // SDSS // A.28, A.29, B.21, C.26, C.29 diff --git a/Marlin/src/HAL/TEENSY35_36/spi_pins.h b/Marlin/src/HAL/TEENSY35_36/spi_pins.h index cfffdc9325..d898a923f5 100644 --- a/Marlin/src/HAL/TEENSY35_36/spi_pins.h +++ b/Marlin/src/HAL/TEENSY35_36/spi_pins.h @@ -28,4 +28,3 @@ #define SD_SCK_PIN 13 #define SD_MISO_PIN 12 #define SD_MOSI_PIN 11 -#define SD_SS_PIN 20 // SDSS // A.28, A.29, B.21, C.26, C.29 diff --git a/Marlin/src/HAL/TEENSY40_41/spi_pins.h b/Marlin/src/HAL/TEENSY40_41/spi_pins.h index ba4a2c700a..fc1c2a7fed 100644 --- a/Marlin/src/HAL/TEENSY40_41/spi_pins.h +++ b/Marlin/src/HAL/TEENSY40_41/spi_pins.h @@ -28,4 +28,3 @@ #define SD_SCK_PIN 13 #define SD_MISO_PIN 12 #define SD_MOSI_PIN 11 -#define SD_SS_PIN 20 // SDSS // A.28, A.29, B.21, C.26, C.29 diff --git a/Marlin/src/inc/Changes.h b/Marlin/src/inc/Changes.h index 8e7a71ecfc..abd7db8011 100644 --- a/Marlin/src/inc/Changes.h +++ b/Marlin/src/inc/Changes.h @@ -743,8 +743,18 @@ #error "MMU2_DEBUG is now MMU_DEBUG." #elif defined(FTM_SHAPING_DEFAULT_X_FREQ) || defined(FTM_SHAPING_DEFAULT_Y_FREQ) #error "FTM_SHAPING_DEFAULT_[XY]_FREQ is now FTM_SHAPING_DEFAULT_FREQ_[XY]." +#elif defined(SDSS) + #error "SDSS is now SD_SS_PIN." #endif +// SDSS renamed to SD_SS_PIN +#undef SDSS +#define SDSS 8675309 +#if USB_CS_PIN == SDSS + #error "SDSS is now SD_SS_PIN." +#endif +#undef SDSS + // Changes to Probe Temp Compensation (#17392) #if HAS_PTC && TEMP_SENSOR_PROBE && TEMP_SENSOR_BED #if defined(PTC_PARK_POS_X) || defined(PTC_PARK_POS_Y) || defined(PTC_PARK_POS_Z) diff --git a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/pin_mappings.h b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/pin_mappings.h index 3963493841..24e1d6ce5e 100644 --- a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/pin_mappings.h +++ b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/pin_mappings.h @@ -138,7 +138,7 @@ #define CLCD_SPI_CS BTN_EN1 #define CLCD_MOD_RESET BTN_EN2 #if MB(EINSY_RAMBO, EINSY_RETRO) && !HAS_MEDIA - #define CLCD_SPI_EXTRA_CS SDSS + #define CLCD_SPI_EXTRA_CS SD_SS_PIN #endif #endif diff --git a/Marlin/src/pins/esp32/pins_E4D.h b/Marlin/src/pins/esp32/pins_E4D.h index 06e46e3c4c..425d6a0dec 100644 --- a/Marlin/src/pins/esp32/pins_E4D.h +++ b/Marlin/src/pins/esp32/pins_E4D.h @@ -97,5 +97,5 @@ #define SD_MOSI_PIN 23 #define SD_MISO_PIN 19 #define SD_SCK_PIN 18 -#define SDSS 5 +#define SD_SS_PIN 5 #define USES_SHARED_SPI // SPI is shared by SD card with TMC SPI drivers diff --git a/Marlin/src/pins/esp32/pins_ENWI_ESPNP.h b/Marlin/src/pins/esp32/pins_ENWI_ESPNP.h index 578ccfa849..b239254346 100644 --- a/Marlin/src/pins/esp32/pins_ENWI_ESPNP.h +++ b/Marlin/src/pins/esp32/pins_ENWI_ESPNP.h @@ -112,11 +112,8 @@ // #define FAN_SOFT_PWM_REQUIRED // check if needed +// // NeoPixel Rings +// #define BOARD_NEOPIXEL_PIN 14 #define NEOPIXEL2_PIN 27 - -// SPI -#define MISO_PIN 19 -#define MOSI_PIN 23 -#define SCK_PIN 18 diff --git a/Marlin/src/pins/esp32/pins_ESP32.h b/Marlin/src/pins/esp32/pins_ESP32.h index 9c9b06ca64..6da77f55da 100644 --- a/Marlin/src/pins/esp32/pins_ESP32.h +++ b/Marlin/src/pins/esp32/pins_ESP32.h @@ -85,4 +85,4 @@ #define HEATER_BED_PIN 4 // SPI -#define SDSS 5 +#define SD_SS_PIN 5 diff --git a/Marlin/src/pins/esp32/pins_ESPA_common.h b/Marlin/src/pins/esp32/pins_ESPA_common.h index 36068150f7..0f1204878f 100644 --- a/Marlin/src/pins/esp32/pins_ESPA_common.h +++ b/Marlin/src/pins/esp32/pins_ESPA_common.h @@ -77,5 +77,5 @@ #define SD_MOSI_PIN 23 #define SD_MISO_PIN 19 #define SD_SCK_PIN 18 -#define SDSS 5 +#define SD_SS_PIN 5 #define USES_SHARED_SPI // SPI is shared by SD card with TMC SPI drivers diff --git a/Marlin/src/pins/esp32/pins_GODI_CONTROLLER_V1_0.h b/Marlin/src/pins/esp32/pins_GODI_CONTROLLER_V1_0.h index 3099b492e3..7cbaa96088 100644 --- a/Marlin/src/pins/esp32/pins_GODI_CONTROLLER_V1_0.h +++ b/Marlin/src/pins/esp32/pins_GODI_CONTROLLER_V1_0.h @@ -91,7 +91,7 @@ #define SD_MOSI_PIN 23 #define SD_MISO_PIN 19 #define SD_SCK_PIN 18 -#define SDSS 5 +#define SD_SS_PIN 5 #define USES_SHARED_SPI // SPI is shared by SD card with TMC SPI drivers #if HAS_TMC_UART diff --git a/Marlin/src/pins/esp32/pins_MKS_TINYBEE.h b/Marlin/src/pins/esp32/pins_MKS_TINYBEE.h index 4c043fd363..6b5411e09d 100644 --- a/Marlin/src/pins/esp32/pins_MKS_TINYBEE.h +++ b/Marlin/src/pins/esp32/pins_MKS_TINYBEE.h @@ -160,7 +160,7 @@ //#define SD_SCK_PIN EXP2_02_PIN // uses esp32 default 18 // TODO: Migrate external SD Card to pins/lcd -#define SDSS EXP2_04_PIN +#define SD_SS_PIN EXP2_04_PIN #define SD_DETECT_PIN EXP2_07_PIN // IO34 default is SD_DET signal (Jump to SDDET) #define USES_SHARED_SPI // SPI is shared by SD card with TMC SPI drivers diff --git a/Marlin/src/pins/esp32/pins_MM_JOKER.h b/Marlin/src/pins/esp32/pins_MM_JOKER.h index b74321dbfc..2ebeda6b60 100644 --- a/Marlin/src/pins/esp32/pins_MM_JOKER.h +++ b/Marlin/src/pins/esp32/pins_MM_JOKER.h @@ -213,7 +213,7 @@ #define SD_MOSI_PIN 23 #define SD_MISO_PIN 19 #define SD_SCK_PIN 18 -#define SDSS 5 +#define SD_SS_PIN 5 #define USES_SHARED_SPI // SPI is shared by SD card with TMC SPI drivers // diff --git a/Marlin/src/pins/esp32/pins_MRR_ESPE.h b/Marlin/src/pins/esp32/pins_MRR_ESPE.h index bcdb8c4faa..6bded9db9b 100644 --- a/Marlin/src/pins/esp32/pins_MRR_ESPE.h +++ b/Marlin/src/pins/esp32/pins_MRR_ESPE.h @@ -118,7 +118,7 @@ #define SD_MOSI_PIN 23 #define SD_MISO_PIN 19 #define SD_SCK_PIN 18 -#define SDSS 5 +#define SD_SS_PIN 5 #define USES_SHARED_SPI // SPI is shared by SD card with TMC SPI drivers // diff --git a/Marlin/src/pins/esp32/pins_PANDA_common.h b/Marlin/src/pins/esp32/pins_PANDA_common.h index 2cc954940e..b668245446 100644 --- a/Marlin/src/pins/esp32/pins_PANDA_common.h +++ b/Marlin/src/pins/esp32/pins_PANDA_common.h @@ -111,7 +111,7 @@ #define SD_MOSI_PIN EXP2_06_PIN #define SD_MISO_PIN EXP2_01_PIN #define SD_SCK_PIN EXP2_02_PIN - #define SDSS EXP2_04_PIN + #define SD_SS_PIN EXP2_04_PIN #define SD_DETECT_PIN EXP2_07_PIN #endif diff --git a/Marlin/src/pins/gd32f1/pins_TRIGORILLA_V006.h b/Marlin/src/pins/gd32f1/pins_TRIGORILLA_V006.h index a477308277..482d68616a 100644 --- a/Marlin/src/pins/gd32f1/pins_TRIGORILLA_V006.h +++ b/Marlin/src/pins/gd32f1/pins_TRIGORILLA_V006.h @@ -123,10 +123,9 @@ // SPI // #define SPI_DEVICE -1 // Maple - #define SCK_PIN -1 - #define MISO_PIN -1 - #define MOSI_PIN -1 - #define SS_PIN -1 + #define SD_SCK_PIN -1 + #define SD_MISO_PIN -1 + #define SD_MOSI_PIN -1 // // SDIO @@ -141,12 +140,10 @@ #else - #undef SDSS - #define SDSS PC11 // SDIO_D3_PIN - #define SS_PIN SDSS - #define SCK_PIN PC12 // SDIO_CK_PIN - #define MISO_PIN PC8 // SDIO_D0_PIN - #define MOSI_PIN PD2 // SDIO_CMD_PIN + #define SD_SS_PIN PC11 // SDIO_D3_PIN + #define SD_SCK_PIN PC12 // SDIO_CK_PIN + #define SD_MISO_PIN PC8 // SDIO_D0_PIN + #define SD_MOSI_PIN PD2 // SDIO_CMD_PIN #define SOFTWARE_SPI #endif diff --git a/Marlin/src/pins/lpc1768/pins_AZSMZ_MINI.h b/Marlin/src/pins/lpc1768/pins_AZSMZ_MINI.h index 6d5a3c70b5..8645baf2e4 100644 --- a/Marlin/src/pins/lpc1768/pins_AZSMZ_MINI.h +++ b/Marlin/src/pins/lpc1768/pins_AZSMZ_MINI.h @@ -86,7 +86,7 @@ #endif #define FAN1_PIN P0_26 -#define LCD_SDSS P0_16 // LCD SD chip select +#define LCD_SDSS_PIN P0_16 // LCD SD chip select #if ENABLED(AZSMZ_12864) #define BEEPER_PIN P1_30 @@ -104,7 +104,7 @@ #define SD_SCK_PIN P0_15 #define SD_MISO_PIN P0_17 #define SD_MOSI_PIN P0_18 - #define SD_SS_PIN LCD_SDSS + #define SD_SS_PIN LCD_SDSS_PIN #define SD_DETECT_PIN P3_25 #elif SD_CONNECTION_IS(ONBOARD) #define SD_SCK_PIN P0_07 diff --git a/Marlin/src/pins/lpc1768/pins_BIQU_B300_V1.0.h b/Marlin/src/pins/lpc1768/pins_BIQU_B300_V1.0.h index c498af3a64..63a8b8f4ea 100644 --- a/Marlin/src/pins/lpc1768/pins_BIQU_B300_V1.0.h +++ b/Marlin/src/pins/lpc1768/pins_BIQU_B300_V1.0.h @@ -151,7 +151,6 @@ #define SD_MISO_PIN P0_16 // EXP1-4 #define SD_MOSI_PIN P0_18 // EXP1-3 #define SD_SS_PIN P1_30 // EXP1-2 - #define SDSS SD_SS_PIN #endif /** diff --git a/Marlin/src/pins/lpc1768/pins_BIQU_BQ111_A4.h b/Marlin/src/pins/lpc1768/pins_BIQU_BQ111_A4.h index 3fb29b9092..83195aaaac 100644 --- a/Marlin/src/pins/lpc1768/pins_BIQU_BQ111_A4.h +++ b/Marlin/src/pins/lpc1768/pins_BIQU_BQ111_A4.h @@ -124,14 +124,11 @@ * Hardware SPI can't be used because P0_17 (MISO) is not brought out on this board. */ #if HAS_MEDIA - #define SD_SCK_PIN P0_15 // EXP1-5 #define SD_MISO_PIN P0_16 // EXP1-4 #define SD_MOSI_PIN P0_18 // EXP1-3 #define SD_SS_PIN P1_30 // EXP1-2 - #define SDSS SD_SS_PIN - -#endif // HAS_MEDIA +#endif /** * PWMS diff --git a/Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_1.h b/Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_1.h index be6da885df..b10b7fa414 100644 --- a/Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_1.h +++ b/Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_1.h @@ -109,7 +109,7 @@ #define BTN_EN2 EXP2_05_PIN #define BTN_ENC EXP1_02_PIN - #define LCD_SDSS EXP2_04_PIN + #define LCD_SDSS_PIN EXP2_04_PIN #define LCD_PINS_RS EXP1_04_PIN #define LCD_PINS_EN EXP2_06_PIN #define LCD_PINS_D4 EXP2_02_PIN @@ -229,9 +229,9 @@ // We use SD_DETECT_PIN for E0 #undef SD_DETECT_PIN #define E0_CS_PIN EXP2_07_PIN - // We use LCD_SDSS pin for E1 - #undef LCD_SDSS - #define LCD_SDSS -1 + // We use LCD_SDSS_PIN pin for E1 + #undef LCD_SDSS_PIN + #define LCD_SDSS_PIN -1 #define E1_CS_PIN EXP2_04_PIN #endif diff --git a/Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_3.h b/Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_3.h index 45b08b016a..e6b4baddaf 100644 --- a/Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_3.h +++ b/Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_3.h @@ -472,7 +472,7 @@ #define LCD_PINS_EN EXP1_03_PIN #define LCD_PINS_D4 EXP1_05_PIN - #define LCD_SDSS EXP2_04_PIN // (16) J3-7 & AUX-4 + #define LCD_SDSS_PIN EXP2_04_PIN // (16) J3-7 & AUX-4 #define SD_DETECT_PIN EXP2_07_PIN // (49) (NOT 5V tolerant) #if ENABLED(FYSETC_MINI_12864) diff --git a/Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_4.h b/Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_4.h index 2de1e459e1..5219540db3 100644 --- a/Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_4.h +++ b/Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_4.h @@ -519,7 +519,7 @@ #define LCD_PINS_EN EXP1_03_PIN #define LCD_PINS_D4 EXP1_05_PIN - #define LCD_SDSS EXP2_04_PIN // (16) J3-7 & AUX-4 + #define LCD_SDSS_PIN EXP2_04_PIN // (16) J3-7 & AUX-4 #if ENABLED(FYSETC_MINI_12864) #define DOGLCD_CS EXP1_03_PIN diff --git a/Marlin/src/pins/lpc1768/pins_MKS_SBASE.h b/Marlin/src/pins/lpc1768/pins_MKS_SBASE.h index b028d49098..065502e46a 100644 --- a/Marlin/src/pins/lpc1768/pins_MKS_SBASE.h +++ b/Marlin/src/pins/lpc1768/pins_MKS_SBASE.h @@ -246,7 +246,7 @@ #define BTN_EN1 EXP2_05_PIN #define BTN_EN2 EXP2_03_PIN #define LCD_PINS_RS EXP1_04_PIN - #define LCD_SDSS EXP2_04_PIN + #define LCD_SDSS_PIN EXP2_04_PIN #define LCD_PINS_EN EXP1_03_PIN #define LCD_PINS_D4 EXP1_05_PIN #if ANY(VIKI2, miniVIKI) diff --git a/Marlin/src/pins/lpc1768/pins_MKS_SGEN_L.h b/Marlin/src/pins/lpc1768/pins_MKS_SGEN_L.h index 38c7cac3d4..9b1258bec2 100644 --- a/Marlin/src/pins/lpc1768/pins_MKS_SGEN_L.h +++ b/Marlin/src/pins/lpc1768/pins_MKS_SGEN_L.h @@ -342,7 +342,7 @@ #define BTN_EN1 EXP2_03_PIN #define BTN_EN2 EXP2_05_PIN - #define LCD_SDSS EXP2_04_PIN + #define LCD_SDSS_PIN EXP2_04_PIN #if ENABLED(MKS_12864OLED_SSD1306) diff --git a/Marlin/src/pins/lpc1768/pins_RAMPS_RE_ARM.h b/Marlin/src/pins/lpc1768/pins_RAMPS_RE_ARM.h index 9ca1fb9555..c5bd72ef09 100644 --- a/Marlin/src/pins/lpc1768/pins_RAMPS_RE_ARM.h +++ b/Marlin/src/pins/lpc1768/pins_RAMPS_RE_ARM.h @@ -322,7 +322,7 @@ #define SD_DETECT_PIN P1_31 // (49) J3-1 & AUX-3 (NOT 5V tolerant) #define KILL_PIN P1_22 // (41) J5-4 & AUX-4 #define LCD_PINS_RS P0_16 // (16) J3-7 & AUX-4 - #define LCD_SDSS P1_23 // (53) J3-5 & AUX-3 + #define LCD_SDSS_PIN P1_23 // (53) J3-5 & AUX-3 #if IS_NEWPANEL #if IS_RRW_KEYPAD diff --git a/Marlin/src/pins/lpc1769/pins_AZTEEG_X5_GT.h b/Marlin/src/pins/lpc1769/pins_AZTEEG_X5_GT.h index 26f0ff39ce..26f2d960a4 100644 --- a/Marlin/src/pins/lpc1769/pins_AZTEEG_X5_GT.h +++ b/Marlin/src/pins/lpc1769/pins_AZTEEG_X5_GT.h @@ -117,7 +117,7 @@ #define BTN_ENC P2_11 #define SD_DETECT_PIN P1_18 - #define SDSS P1_21 + #define SD_SS_PIN P1_21 #define STAT_LED_RED_PIN P1_19 #define STAT_LED_BLUE_PIN P1_20 diff --git a/Marlin/src/pins/lpc1769/pins_AZTEEG_X5_MINI.h b/Marlin/src/pins/lpc1769/pins_AZTEEG_X5_MINI.h index 5256da2ef2..f276f9fb67 100644 --- a/Marlin/src/pins/lpc1769/pins_AZTEEG_X5_MINI.h +++ b/Marlin/src/pins/lpc1769/pins_AZTEEG_X5_MINI.h @@ -178,7 +178,7 @@ #define SD_DETECT_PIN _EXP2_01 #define KILL_PIN _EXP1_10 #define LCD_PINS_RS _EXP2_07 - #define LCD_SDSS _EXP2_07 + #define LCD_SDSS_PIN _EXP2_07 #define LCD_BACKLIGHT_PIN _EXP2_07 #define LCD_PINS_EN _EXP2_10 #define LCD_PINS_D4 _EXP2_09 diff --git a/Marlin/src/pins/lpc1769/pins_COHESION3D_MINI.h b/Marlin/src/pins/lpc1769/pins_COHESION3D_MINI.h index 485b3109ad..cae65592b4 100644 --- a/Marlin/src/pins/lpc1769/pins_COHESION3D_MINI.h +++ b/Marlin/src/pins/lpc1769/pins_COHESION3D_MINI.h @@ -147,7 +147,7 @@ #define BTN_ENC P1_30 // EXP1-2 #define LCD_PINS_RS P0_16 // EXP1-4 - #define LCD_SDSS P0_28 // EXP2-4 + #define LCD_SDSS_PIN P0_28 // EXP2-4 #define LCD_PINS_EN P0_18 // EXP1-3 #define LCD_PINS_D4 P0_15 // EXP1-5 diff --git a/Marlin/src/pins/lpc1769/pins_COHESION3D_REMIX.h b/Marlin/src/pins/lpc1769/pins_COHESION3D_REMIX.h index d1ecb0e7dd..2529f2cafb 100644 --- a/Marlin/src/pins/lpc1769/pins_COHESION3D_REMIX.h +++ b/Marlin/src/pins/lpc1769/pins_COHESION3D_REMIX.h @@ -244,7 +244,7 @@ #define BTN_ENC EXP1_02_PIN #define LCD_PINS_RS EXP1_04_PIN - #define LCD_SDSS EXP2_04_PIN + #define LCD_SDSS_PIN EXP2_04_PIN #define LCD_PINS_EN EXP1_03_PIN #define LCD_PINS_D4 EXP1_05_PIN diff --git a/Marlin/src/pins/lpc1769/pins_MKS_SGEN_L_V2.h b/Marlin/src/pins/lpc1769/pins_MKS_SGEN_L_V2.h index 5d7a703015..56e7ef53b3 100644 --- a/Marlin/src/pins/lpc1769/pins_MKS_SGEN_L_V2.h +++ b/Marlin/src/pins/lpc1769/pins_MKS_SGEN_L_V2.h @@ -324,7 +324,7 @@ #define BTN_EN1 EXP2_03_PIN #define BTN_EN2 EXP2_05_PIN - #define LCD_SDSS EXP2_04_PIN + #define LCD_SDSS_PIN EXP2_04_PIN #if ENABLED(MKS_12864OLED_SSD1306) diff --git a/Marlin/src/pins/lpc1769/pins_SMOOTHIEBOARD.h b/Marlin/src/pins/lpc1769/pins_SMOOTHIEBOARD.h index 062e572605..f762bdb6ca 100644 --- a/Marlin/src/pins/lpc1769/pins_SMOOTHIEBOARD.h +++ b/Marlin/src/pins/lpc1769/pins_SMOOTHIEBOARD.h @@ -105,7 +105,7 @@ #define BTN_ENC P1_30 #define SD_DETECT_PIN P1_18 - #define SDSS P1_21 + #define SD_SS_PIN P1_21 #define STAT_LED_RED_PIN P1_19 #define STAT_LED_BLUE_PIN P1_20 diff --git a/Marlin/src/pins/lpc1769/pins_XTLW_CLIMBER_8TH_LPC.h b/Marlin/src/pins/lpc1769/pins_XTLW_CLIMBER_8TH_LPC.h index f5a23ec5fb..bbdf16dc2b 100644 --- a/Marlin/src/pins/lpc1769/pins_XTLW_CLIMBER_8TH_LPC.h +++ b/Marlin/src/pins/lpc1769/pins_XTLW_CLIMBER_8TH_LPC.h @@ -196,7 +196,7 @@ #define BTN_EN1 P0_00 #define BTN_EN2 P0_01 - #define LCD_SDSS P0_16 + #define LCD_SDSS_PIN P0_16 #if ENABLED(MKS_12864OLED_SSD1306) diff --git a/Marlin/src/pins/mega/pins_CHEAPTRONICv2.h b/Marlin/src/pins/mega/pins_CHEAPTRONICv2.h index 2669210d57..8c34116037 100644 --- a/Marlin/src/pins/mega/pins_CHEAPTRONICv2.h +++ b/Marlin/src/pins/mega/pins_CHEAPTRONICv2.h @@ -129,7 +129,7 @@ #define BEEPER_PIN 44 #if HAS_MEDIA - #define SDSS 53 + #define SD_SS_PIN 53 #define SD_DETECT_PIN 49 #endif diff --git a/Marlin/src/pins/mega/pins_CNCONTROLS_11.h b/Marlin/src/pins/mega/pins_CNCONTROLS_11.h index 5c0c11033d..6a7eef5782 100644 --- a/Marlin/src/pins/mega/pins_CNCONTROLS_11.h +++ b/Marlin/src/pins/mega/pins_CNCONTROLS_11.h @@ -117,7 +117,7 @@ // // Misc. Functions // -#define SDSS 53 +#define SD_SS_PIN 53 #define SD_DETECT_PIN 13 // Tools diff --git a/Marlin/src/pins/mega/pins_CNCONTROLS_12.h b/Marlin/src/pins/mega/pins_CNCONTROLS_12.h index 37485ea790..05f2865ae4 100644 --- a/Marlin/src/pins/mega/pins_CNCONTROLS_12.h +++ b/Marlin/src/pins/mega/pins_CNCONTROLS_12.h @@ -117,7 +117,7 @@ // // Misc. Functions // -#define SDSS 53 +#define SD_SS_PIN 53 #define SD_DETECT_PIN 15 // Tools diff --git a/Marlin/src/pins/mega/pins_CNCONTROLS_15.h b/Marlin/src/pins/mega/pins_CNCONTROLS_15.h index bbb0385844..7b23aa0b73 100644 --- a/Marlin/src/pins/mega/pins_CNCONTROLS_15.h +++ b/Marlin/src/pins/mega/pins_CNCONTROLS_15.h @@ -112,7 +112,7 @@ // // Misc. Functions // -#define SDSS 53 +#define SD_SS_PIN 53 #define SD_DETECT_PIN 40 // Common I/O diff --git a/Marlin/src/pins/mega/pins_EINSTART-S.h b/Marlin/src/pins/mega/pins_EINSTART-S.h index 92c85c1211..27e5f8b075 100644 --- a/Marlin/src/pins/mega/pins_EINSTART-S.h +++ b/Marlin/src/pins/mega/pins_EINSTART-S.h @@ -75,7 +75,7 @@ // // Misc. Functions // -#define SDSS 53 +#define SD_SS_PIN 53 #define LED_PIN 4 // diff --git a/Marlin/src/pins/mega/pins_ELEFU_3.h b/Marlin/src/pins/mega/pins_ELEFU_3.h index 623b7a0d43..b041f1e64b 100644 --- a/Marlin/src/pins/mega/pins_ELEFU_3.h +++ b/Marlin/src/pins/mega/pins_ELEFU_3.h @@ -109,7 +109,7 @@ #if ENABLED(RA_CONTROL_PANEL) - #define SDSS 53 + #define SD_SS_PIN 53 #define SD_DETECT_PIN 28 #define BTN_EN1 14 diff --git a/Marlin/src/pins/mega/pins_GT2560_REV_A.h b/Marlin/src/pins/mega/pins_GT2560_REV_A.h index 96e3e5c36f..08bcf90385 100644 --- a/Marlin/src/pins/mega/pins_GT2560_REV_A.h +++ b/Marlin/src/pins/mega/pins_GT2560_REV_A.h @@ -138,7 +138,7 @@ #define EXP2_07_PIN 38 // SD_DET #define EXP2_08_PIN -1 // RESET -#define SDSS EXP2_04_PIN +#define SD_SS_PIN EXP2_04_PIN #define LED_PIN 13 #if HAS_WIRED_LCD diff --git a/Marlin/src/pins/mega/pins_GT2560_V3.h b/Marlin/src/pins/mega/pins_GT2560_V3.h index 1323ae3c8e..72bdc7bb4b 100644 --- a/Marlin/src/pins/mega/pins_GT2560_V3.h +++ b/Marlin/src/pins/mega/pins_GT2560_V3.h @@ -149,7 +149,7 @@ // Misc. Functions // #define SD_DETECT_PIN 38 -#define SDSS 53 +#define SD_SS_PIN 53 #define LED_PIN 13 // Use 6 (case light) for external LED. 13 is internal (yellow) LED. #define PS_ON_PIN 12 diff --git a/Marlin/src/pins/mega/pins_GT2560_V41b.h b/Marlin/src/pins/mega/pins_GT2560_V41b.h index 3ffaaabef4..daebc6526d 100644 --- a/Marlin/src/pins/mega/pins_GT2560_V41b.h +++ b/Marlin/src/pins/mega/pins_GT2560_V41b.h @@ -185,7 +185,7 @@ // Misc. Functions // #define SD_DETECT_PIN 38 -#define SDSS 53 +#define SD_SS_PIN 53 #define LED_PIN 13 // Use 6 (case light) for external LED. 13 is internal (yellow) LED. #define PS_ON_PIN 12 diff --git a/Marlin/src/pins/mega/pins_HJC2560C_REV2.h b/Marlin/src/pins/mega/pins_HJC2560C_REV2.h index 638465f3b9..38e6617f51 100644 --- a/Marlin/src/pins/mega/pins_HJC2560C_REV2.h +++ b/Marlin/src/pins/mega/pins_HJC2560C_REV2.h @@ -99,7 +99,7 @@ // // Misc. Functions // -#define SDSS 53 +#define SD_SS_PIN 53 #define SD_DETECT_PIN 39 //#define LED_PIN 8 diff --git a/Marlin/src/pins/mega/pins_INTAMSYS40.h b/Marlin/src/pins/mega/pins_INTAMSYS40.h index 6b82965065..83a77ec98c 100644 --- a/Marlin/src/pins/mega/pins_INTAMSYS40.h +++ b/Marlin/src/pins/mega/pins_INTAMSYS40.h @@ -104,7 +104,7 @@ // // Misc. Functions // -#define SDSS 53 +#define SD_SS_PIN 53 #define SD_DETECT_PIN 39 #if ENABLED(CASE_LIGHT_ENABLE) diff --git a/Marlin/src/pins/mega/pins_LEAPFROG.h b/Marlin/src/pins/mega/pins_LEAPFROG.h index d986728e72..de4831a36a 100644 --- a/Marlin/src/pins/mega/pins_LEAPFROG.h +++ b/Marlin/src/pins/mega/pins_LEAPFROG.h @@ -84,7 +84,7 @@ // // Misc. Functions // -#define SDSS 11 +#define SD_SS_PIN 11 #define LED_PIN 13 #define SOL1_PIN 16 #define SOL2_PIN 17 diff --git a/Marlin/src/pins/mega/pins_MEGACONTROLLER.h b/Marlin/src/pins/mega/pins_MEGACONTROLLER.h index 514f7b255e..4ee5df8c66 100644 --- a/Marlin/src/pins/mega/pins_MEGACONTROLLER.h +++ b/Marlin/src/pins/mega/pins_MEGACONTROLLER.h @@ -128,7 +128,7 @@ // // Misc. Functions // -#define SDSS MINI_06 +#define SD_SS_PIN MINI_06 #define LED_PIN 13 #ifndef CASE_LIGHT_PIN diff --git a/Marlin/src/pins/mega/pins_MEGATRONICS.h b/Marlin/src/pins/mega/pins_MEGATRONICS.h index 90d128c9fc..d5616c0026 100644 --- a/Marlin/src/pins/mega/pins_MEGATRONICS.h +++ b/Marlin/src/pins/mega/pins_MEGATRONICS.h @@ -95,7 +95,7 @@ // // Misc. Functions // -#define SDSS 53 +#define SD_SS_PIN 53 #define LED_PIN 13 #define PS_ON_PIN 12 diff --git a/Marlin/src/pins/mega/pins_MEGATRONICS_2.h b/Marlin/src/pins/mega/pins_MEGATRONICS_2.h index 285a77b636..9f7abd3fb8 100644 --- a/Marlin/src/pins/mega/pins_MEGATRONICS_2.h +++ b/Marlin/src/pins/mega/pins_MEGATRONICS_2.h @@ -110,7 +110,7 @@ // // Misc. Functions // -#define SDSS 53 +#define SD_SS_PIN 53 #define LED_PIN 13 #define PS_ON_PIN 12 diff --git a/Marlin/src/pins/mega/pins_MEGATRONICS_3.h b/Marlin/src/pins/mega/pins_MEGATRONICS_3.h index 5a71994063..4c60ef1a5b 100644 --- a/Marlin/src/pins/mega/pins_MEGATRONICS_3.h +++ b/Marlin/src/pins/mega/pins_MEGATRONICS_3.h @@ -135,7 +135,7 @@ // // Misc. Functions // -#define SDSS 53 +#define SD_SS_PIN 53 #define LED_PIN 13 #define PS_ON_PIN 12 diff --git a/Marlin/src/pins/mega/pins_MIGHTYBOARD_REVE.h b/Marlin/src/pins/mega/pins_MIGHTYBOARD_REVE.h index fb73660815..9dc0c5f7d8 100644 --- a/Marlin/src/pins/mega/pins_MIGHTYBOARD_REVE.h +++ b/Marlin/src/pins/mega/pins_MIGHTYBOARD_REVE.h @@ -239,7 +239,7 @@ // // SD Card // -#define SDSS 53 // B0 +#define SD_SS_PIN 53 // B0 #define SD_DETECT_PIN 9 // H6 #if HAS_TMC_UART diff --git a/Marlin/src/pins/mega/pins_MINITRONICS.h b/Marlin/src/pins/mega/pins_MINITRONICS.h index d3a012dd4b..967c04a181 100644 --- a/Marlin/src/pins/mega/pins_MINITRONICS.h +++ b/Marlin/src/pins/mega/pins_MINITRONICS.h @@ -92,7 +92,7 @@ // // Misc. Functions // -#define SDSS 16 +#define SD_SS_PIN 16 #define LED_PIN 46 // diff --git a/Marlin/src/pins/mega/pins_OVERLORD.h b/Marlin/src/pins/mega/pins_OVERLORD.h index 804aa38e59..a275802f27 100644 --- a/Marlin/src/pins/mega/pins_OVERLORD.h +++ b/Marlin/src/pins/mega/pins_OVERLORD.h @@ -99,7 +99,7 @@ // // SD Card // -#define SDSS 53 +#define SD_SS_PIN 53 #define SD_DETECT_PIN 38 // diff --git a/Marlin/src/pins/mega/pins_PICA.h b/Marlin/src/pins/mega/pins_PICA.h index 63e14d9bf2..ec7c32daca 100644 --- a/Marlin/src/pins/mega/pins_PICA.h +++ b/Marlin/src/pins/mega/pins_PICA.h @@ -127,7 +127,7 @@ // SD Support // #define SD_DETECT_PIN EXP2_07_PIN -#define SDSS EXP2_04_PIN +#define SD_SS_PIN EXP2_04_PIN /** PICA Expansion Headers * ------ ------ @@ -174,5 +174,5 @@ #define BTN_EN2 EXP2_05_PIN #define BTN_ENC EXP1_02_PIN - #define LCD_SDSS EXP2_04_PIN + #define LCD_SDSS_PIN EXP2_04_PIN #endif diff --git a/Marlin/src/pins/mega/pins_SILVER_GATE.h b/Marlin/src/pins/mega/pins_SILVER_GATE.h index d739157aaf..2d8419c50c 100644 --- a/Marlin/src/pins/mega/pins_SILVER_GATE.h +++ b/Marlin/src/pins/mega/pins_SILVER_GATE.h @@ -51,7 +51,7 @@ #define E0_DIR_PIN 37 #define E0_ENABLE_PIN 45 -#define SDSS 16 +#define SD_SS_PIN 16 #ifndef FIL_RUNOUT_PIN #define FIL_RUNOUT_PIN 34 // X_MAX unless overridden diff --git a/Marlin/src/pins/mega/pins_WANHAO_ONEPLUS.h b/Marlin/src/pins/mega/pins_WANHAO_ONEPLUS.h index e224e06178..8a350d34d0 100644 --- a/Marlin/src/pins/mega/pins_WANHAO_ONEPLUS.h +++ b/Marlin/src/pins/mega/pins_WANHAO_ONEPLUS.h @@ -82,7 +82,7 @@ // SD Card // #define SD_DETECT_PIN 83 -#define SDSS 53 +#define SD_SS_PIN 53 // // Misc. Functions diff --git a/Marlin/src/pins/mega/pins_WEEDO_62A.h b/Marlin/src/pins/mega/pins_WEEDO_62A.h index 436529cb35..b7143c7912 100644 --- a/Marlin/src/pins/mega/pins_WEEDO_62A.h +++ b/Marlin/src/pins/mega/pins_WEEDO_62A.h @@ -85,7 +85,7 @@ // SD Support // #if HAS_MEDIA - #define SDSS 53 + #define SD_SS_PIN 53 #define SD_DETECT_PIN 49 #endif diff --git a/Marlin/src/pins/native/pins_RAMPS_NATIVE.h b/Marlin/src/pins/native/pins_RAMPS_NATIVE.h index 42b33a0944..563ad9e5b3 100644 --- a/Marlin/src/pins/native/pins_RAMPS_NATIVE.h +++ b/Marlin/src/pins/native/pins_RAMPS_NATIVE.h @@ -193,7 +193,7 @@ // // Misc. Functions // -#define SDSS 53 +#define SD_SS_PIN 53 #define LED_PIN 13 #define BOARD_NEOPIXEL_PIN 71 @@ -602,7 +602,7 @@ #define BTN_EN1 47 #define BTN_EN2 43 #define BTN_ENC 32 - #define LCD_SDSS SDSS + #define LCD_SDSS_PIN SD_SS_PIN #define KILL_PIN 41 #undef LCD_PINS_EN // not used, causes false pin conflict report @@ -612,7 +612,7 @@ #define BTN_EN2 7 // 22/7 are unused on RAMPS_14. 22 is unused and 7 the SERVO0_PIN on RAMPS_13. #define BTN_ENC -1 - #define LCD_SDSS SDSS + #define LCD_SDSS_PIN SD_SS_PIN #define SD_DETECT_PIN 49 #elif ANY(VIKI2, miniVIKI) @@ -645,7 +645,7 @@ #define BTN_EN2 EXP1_01_PIN #define BTN_ENC EXP2_03_PIN - #define LCD_SDSS SDSS + #define LCD_SDSS_PIN SD_SS_PIN #define SD_DETECT_PIN EXP2_07_PIN #define KILL_PIN EXP2_08_PIN diff --git a/Marlin/src/pins/pinsDebug_list.h b/Marlin/src/pins/pinsDebug_list.h index 2372382a34..e93f232545 100644 --- a/Marlin/src/pins/pinsDebug_list.h +++ b/Marlin/src/pins/pinsDebug_list.h @@ -943,8 +943,8 @@ #if _EXISTS(LCD_PINS_RS) REPORT_NAME_DIGITAL(__LINE__, LCD_PINS_RS) #endif -#if _EXISTS(LCD_SDSS) - REPORT_NAME_DIGITAL(__LINE__, LCD_SDSS) +#if PIN_EXISTS(LCD_SDSS) + REPORT_NAME_DIGITAL(__LINE__, LCD_SDSS_PIN) #endif #if PIN_EXISTS(LCD_RESET) REPORT_NAME_DIGITAL(__LINE__, LCD_RESET_PIN) @@ -1092,8 +1092,8 @@ #if PIN_EXISTS(SD_SCK) REPORT_NAME_DIGITAL(__LINE__, SD_SCK_PIN) #endif -#if _EXISTS(SDSS) - REPORT_NAME_DIGITAL(__LINE__, SDSS) +#if PIN_EXISTS(SD_SS) + REPORT_NAME_DIGITAL(__LINE__, SD_SS_PIN) #endif #if PIN_EXISTS(SD_SS) REPORT_NAME_DIGITAL(__LINE__, SD_SS_PIN) diff --git a/Marlin/src/pins/pins_postprocess.h b/Marlin/src/pins/pins_postprocess.h index 1d3b0ebcce..9e82d854f9 100644 --- a/Marlin/src/pins/pins_postprocess.h +++ b/Marlin/src/pins/pins_postprocess.h @@ -564,8 +564,8 @@ #ifndef SDPOWER_PIN #define SDPOWER_PIN -1 #endif -#ifndef SDSS - #define SDSS -1 +#ifndef SD_SS_PIN + #define SD_SS_PIN -1 #endif #ifndef LED_PIN #define LED_PIN -1 diff --git a/Marlin/src/pins/rambo/pins_EINSY_RAMBO.h b/Marlin/src/pins/rambo/pins_EINSY_RAMBO.h index 8315de6ee3..98a16764af 100644 --- a/Marlin/src/pins/rambo/pins_EINSY_RAMBO.h +++ b/Marlin/src/pins/rambo/pins_EINSY_RAMBO.h @@ -178,7 +178,7 @@ // // Misc. Functions // -#define SDSS EXP2_04_PIN +#define SD_SS_PIN EXP2_04_PIN #define LED_PIN 13 #ifndef CASE_LIGHT_PIN diff --git a/Marlin/src/pins/rambo/pins_EINSY_RETRO.h b/Marlin/src/pins/rambo/pins_EINSY_RETRO.h index 1f5061d4ce..ca681b8174 100644 --- a/Marlin/src/pins/rambo/pins_EINSY_RETRO.h +++ b/Marlin/src/pins/rambo/pins_EINSY_RETRO.h @@ -141,7 +141,7 @@ // // Misc. Functions // -#define SDSS 53 +#define SD_SS_PIN 53 #define LED_PIN 13 #ifndef CASE_LIGHT_PIN diff --git a/Marlin/src/pins/rambo/pins_MINIRAMBO.h b/Marlin/src/pins/rambo/pins_MINIRAMBO.h index 18f73a81d5..1d56e749f2 100644 --- a/Marlin/src/pins/rambo/pins_MINIRAMBO.h +++ b/Marlin/src/pins/rambo/pins_MINIRAMBO.h @@ -121,7 +121,7 @@ // // Misc. Functions // -#define SDSS 53 +#define SD_SS_PIN 53 #define LED_PIN 13 #if !MB(MINIRAMBO_10A) #define CASE_LIGHT_PIN 9 diff --git a/Marlin/src/pins/rambo/pins_RAMBO.h b/Marlin/src/pins/rambo/pins_RAMBO.h index 7e46b17151..fdcb7958c3 100644 --- a/Marlin/src/pins/rambo/pins_RAMBO.h +++ b/Marlin/src/pins/rambo/pins_RAMBO.h @@ -152,7 +152,7 @@ // // Misc. Functions // -#define SDSS 53 +#define SD_SS_PIN 53 #define LED_PIN 13 #define PS_ON_PIN 4 diff --git a/Marlin/src/pins/rambo/pins_SCOOVO_X9H.h b/Marlin/src/pins/rambo/pins_SCOOVO_X9H.h index 0d212010e0..1f003440b0 100644 --- a/Marlin/src/pins/rambo/pins_SCOOVO_X9H.h +++ b/Marlin/src/pins/rambo/pins_SCOOVO_X9H.h @@ -114,7 +114,7 @@ // // Misc. Functions // -#define SDSS 53 +#define SD_SS_PIN 53 #define LED_PIN 13 #define PS_ON_PIN 4 diff --git a/Marlin/src/pins/ramps/pins_3DRAG.h b/Marlin/src/pins/ramps/pins_3DRAG.h index de4b3cfeb9..e5a2d05cb7 100644 --- a/Marlin/src/pins/ramps/pins_3DRAG.h +++ b/Marlin/src/pins/ramps/pins_3DRAG.h @@ -74,7 +74,7 @@ // // Misc. Functions // -#define SDSS 25 +#define SD_SS_PIN 25 #ifndef CASE_LIGHT_PIN #define CASE_LIGHT_PIN -1 // Hardware PWM but one is not available on expansion header diff --git a/Marlin/src/pins/ramps/pins_DUPLICATOR_I3_PLUS.h b/Marlin/src/pins/ramps/pins_DUPLICATOR_I3_PLUS.h index 83045bdfe0..40351d2bde 100644 --- a/Marlin/src/pins/ramps/pins_DUPLICATOR_I3_PLUS.h +++ b/Marlin/src/pins/ramps/pins_DUPLICATOR_I3_PLUS.h @@ -77,7 +77,7 @@ // // Misc. Functions // -#define SDSS 53 // PB0 / SS +#define SD_SS_PIN 53 // PB0 / SS #define LED_PIN 13 // PB7 / PWM13 #define SD_MISO_PIN 50 // PB3 diff --git a/Marlin/src/pins/ramps/pins_FORMBOT_RAPTOR.h b/Marlin/src/pins/ramps/pins_FORMBOT_RAPTOR.h index f6ee06846d..6ebda4638b 100644 --- a/Marlin/src/pins/ramps/pins_FORMBOT_RAPTOR.h +++ b/Marlin/src/pins/ramps/pins_FORMBOT_RAPTOR.h @@ -144,8 +144,8 @@ // // Misc. Functions // -#ifndef SDSS - #define SDSS 53 +#ifndef SD_SS_PIN + #define SD_SS_PIN 53 #endif #define LED_PIN 13 #define LED4_PIN 5 diff --git a/Marlin/src/pins/ramps/pins_FORMBOT_TREX2PLUS.h b/Marlin/src/pins/ramps/pins_FORMBOT_TREX2PLUS.h index fad3cc0f9d..76061633f3 100644 --- a/Marlin/src/pins/ramps/pins_FORMBOT_TREX2PLUS.h +++ b/Marlin/src/pins/ramps/pins_FORMBOT_TREX2PLUS.h @@ -139,7 +139,7 @@ // // Misc. Functions // -#define SDSS 53 +#define SD_SS_PIN 53 #ifndef LED_PIN #define LED_PIN 13 // The Formbot v 1 board has almost no unassigned pins. #endif // The Board's LED is a good place to connect the Max7219 Matrix. diff --git a/Marlin/src/pins/ramps/pins_FORMBOT_TREX3.h b/Marlin/src/pins/ramps/pins_FORMBOT_TREX3.h index fd799e0d49..c7cb34be7c 100644 --- a/Marlin/src/pins/ramps/pins_FORMBOT_TREX3.h +++ b/Marlin/src/pins/ramps/pins_FORMBOT_TREX3.h @@ -141,7 +141,7 @@ // // Misc. Functions // -#define SDSS 53 +#define SD_SS_PIN 53 #ifndef LED_PIN #define LED_PIN 13 diff --git a/Marlin/src/pins/ramps/pins_FYSETC_F6_13.h b/Marlin/src/pins/ramps/pins_FYSETC_F6_13.h index 59c4c79884..98117750f9 100644 --- a/Marlin/src/pins/ramps/pins_FYSETC_F6_13.h +++ b/Marlin/src/pins/ramps/pins_FYSETC_F6_13.h @@ -231,7 +231,7 @@ // SD Card // -#define SDSS EXP2_04_PIN +#define SD_SS_PIN EXP2_04_PIN #define SD_DETECT_PIN EXP2_07_PIN // diff --git a/Marlin/src/pins/ramps/pins_K8600.h b/Marlin/src/pins/ramps/pins_K8600.h index 170401bf1c..a1dbb85a77 100644 --- a/Marlin/src/pins/ramps/pins_K8600.h +++ b/Marlin/src/pins/ramps/pins_K8600.h @@ -54,7 +54,7 @@ // // Misc. Functions // -#define SDSS 25 +#define SD_SS_PIN 25 #define CASE_LIGHT_PIN 7 // diff --git a/Marlin/src/pins/ramps/pins_K8800.h b/Marlin/src/pins/ramps/pins_K8800.h index 6bd3e44ec8..a9cdd57059 100644 --- a/Marlin/src/pins/ramps/pins_K8800.h +++ b/Marlin/src/pins/ramps/pins_K8800.h @@ -85,7 +85,7 @@ // // SD Card // -#define SDSS 25 +#define SD_SS_PIN 25 #define SD_DETECT_PIN 21 // PD0 // @@ -95,7 +95,7 @@ #if HAS_WIRED_LCD - #define LCD_SDSS 53 + #define LCD_SDSS_PIN 53 #define DOGLCD_CS 29 #define DOGLCD_A0 27 diff --git a/Marlin/src/pins/ramps/pins_MKS_GEN_13.h b/Marlin/src/pins/ramps/pins_MKS_GEN_13.h index 5797424c66..c71749aa88 100644 --- a/Marlin/src/pins/ramps/pins_MKS_GEN_13.h +++ b/Marlin/src/pins/ramps/pins_MKS_GEN_13.h @@ -121,7 +121,7 @@ // EXP2_06_PIN yellow MOSI // EXP2_02_PIN orange SCK - //#define SDSS EXP2_04_PIN // SDCS blue + //#define SD_SS_PIN EXP2_04_PIN // SDCS blue // // VIKI2 4-wire lead diff --git a/Marlin/src/pins/ramps/pins_ORTUR_4.h b/Marlin/src/pins/ramps/pins_ORTUR_4.h index e8a87911d1..83daa93804 100644 --- a/Marlin/src/pins/ramps/pins_ORTUR_4.h +++ b/Marlin/src/pins/ramps/pins_ORTUR_4.h @@ -87,7 +87,7 @@ #define LCD_PINS_EN 23 #define LCD_PINS_D4 37 - #define LCD_SDSS 53 + #define LCD_SDSS_PIN 53 #define SD_DETECT_PIN 49 #define BTN_EN1 29 diff --git a/Marlin/src/pins/ramps/pins_RAMPS.h b/Marlin/src/pins/ramps/pins_RAMPS.h index 2d82b36f77..e40415c826 100644 --- a/Marlin/src/pins/ramps/pins_RAMPS.h +++ b/Marlin/src/pins/ramps/pins_RAMPS.h @@ -284,8 +284,8 @@ // // Misc. Functions // -#ifndef SDSS - #define SDSS AUX3_06 +#ifndef SD_SS_PIN + #define SD_SS_PIN AUX3_06 #endif #define LED_PIN 13 @@ -750,7 +750,7 @@ #define BTN_EN1 AUX4_04 #define BTN_EN2 AUX4_06 #define BTN_ENC AUX4_03 - #define LCD_SDSS SDSS + #define LCD_SDSS_PIN SD_SS_PIN #define KILL_PIN EXP2_08_PIN #undef LCD_PINS_EN // not used, causes false pin conflict report @@ -760,7 +760,7 @@ #define BTN_EN2 AUX2_08 #define BTN_ENC -1 - #define LCD_SDSS SDSS + #define LCD_SDSS_PIN SD_SS_PIN #ifndef SD_DETECT_PIN #define SD_DETECT_PIN EXP2_07_PIN #endif @@ -800,7 +800,7 @@ #define BTN_EN2 EXP1_01_PIN #define BTN_ENC EXP2_03_PIN - #define LCD_SDSS SDSS + #define LCD_SDSS_PIN SD_SS_PIN #ifndef SD_DETECT_PIN #define SD_DETECT_PIN EXP2_07_PIN #endif diff --git a/Marlin/src/pins/ramps/pins_RAMPS_OLD.h b/Marlin/src/pins/ramps/pins_RAMPS_OLD.h index fa24dd35b3..a5827569b5 100644 --- a/Marlin/src/pins/ramps/pins_RAMPS_OLD.h +++ b/Marlin/src/pins/ramps/pins_RAMPS_OLD.h @@ -103,7 +103,7 @@ // Misc. Functions // #define SDPOWER_PIN 48 -#define SDSS 53 +#define SD_SS_PIN 53 #define LED_PIN 13 #ifndef CASE_LIGHT_PIN diff --git a/Marlin/src/pins/ramps/pins_RAMPS_S_12.h b/Marlin/src/pins/ramps/pins_RAMPS_S_12.h index 9565adad2f..10a76e99c7 100644 --- a/Marlin/src/pins/ramps/pins_RAMPS_S_12.h +++ b/Marlin/src/pins/ramps/pins_RAMPS_S_12.h @@ -184,7 +184,7 @@ // // Misc. Functions // -#define SDSS 53 +#define SD_SS_PIN 53 #define LED_PIN 13 #ifndef KILL_PIN diff --git a/Marlin/src/pins/ramps/pins_RUMBA.h b/Marlin/src/pins/ramps/pins_RUMBA.h index 24cc2bada0..c62b68f6cc 100644 --- a/Marlin/src/pins/ramps/pins_RUMBA.h +++ b/Marlin/src/pins/ramps/pins_RUMBA.h @@ -239,7 +239,7 @@ #define BEEPER_PIN 44 #if HAS_MEDIA - #define SDSS 53 + #define SD_SS_PIN 53 #define SD_DETECT_PIN 49 #endif diff --git a/Marlin/src/pins/ramps/pins_TENLOG_D3_HERO.h b/Marlin/src/pins/ramps/pins_TENLOG_D3_HERO.h index f68b9ef8a6..8c015f9948 100644 --- a/Marlin/src/pins/ramps/pins_TENLOG_D3_HERO.h +++ b/Marlin/src/pins/ramps/pins_TENLOG_D3_HERO.h @@ -151,7 +151,7 @@ // //#define PS_ON_PIN 40 // The M80/M81 PSU pin for boards v2.1-2.3 //#define CASE_LIGHT_PIN 5 -#define SDSS 53 +#define SD_SS_PIN 53 //#ifndef LED_PIN //#define LED_PIN 13 //#endif diff --git a/Marlin/src/pins/ramps/pins_TENLOG_MB1_V23.h b/Marlin/src/pins/ramps/pins_TENLOG_MB1_V23.h index 1197874d71..3ef09f72d4 100644 --- a/Marlin/src/pins/ramps/pins_TENLOG_MB1_V23.h +++ b/Marlin/src/pins/ramps/pins_TENLOG_MB1_V23.h @@ -125,7 +125,7 @@ // Use the RAMPS 1.4 Analog input 5 on the AUX2 connector //#define FILWIDTH_PIN 5 // Analog Input -#define SDSS 53 +#define SD_SS_PIN 53 #define SD_DETECT_PIN 49 // diff --git a/Marlin/src/pins/ramps/pins_TT_OSCAR.h b/Marlin/src/pins/ramps/pins_TT_OSCAR.h index a4968eff3f..440f66298f 100644 --- a/Marlin/src/pins/ramps/pins_TT_OSCAR.h +++ b/Marlin/src/pins/ramps/pins_TT_OSCAR.h @@ -206,7 +206,7 @@ // // Misc. Functions // -#define SDSS 53 // EXP2-4 +#define SD_SS_PIN 53 // EXP2-4 #define LED_PIN 13 //#ifndef FILWIDTH_PIN @@ -421,7 +421,7 @@ #define BTN_EN1 47 #define BTN_EN2 43 #define BTN_ENC 32 - #define LCD_SDSS EXP2_04_PIN + #define LCD_SDSS_PIN EXP2_04_PIN //#define KILL_PIN 41 #undef LCD_PINS_EN // not used, causes false pin conflict report @@ -431,7 +431,7 @@ #define BTN_EN2 7 // 22/7 are unused on RAMPS_14. 22 is unused and 7 the SERVO0_PIN on RAMPS_13. #define BTN_ENC -1 - #define LCD_SDSS EXP2_04_PIN + #define LCD_SDSS_PIN EXP2_04_PIN #define SD_DETECT_PIN EXP2_07_PIN #elif ANY(VIKI2, miniVIKI) @@ -447,7 +447,7 @@ #define BTN_EN2 7 #define BTN_ENC 39 - #define SDSS EXP2_04_PIN + #define SD_SS_PIN EXP2_04_PIN #define SD_DETECT_PIN -1 // Pin 49 for display SD interface, 72 for easy adapter board //#define KILL_PIN 31 @@ -465,7 +465,7 @@ #define BTN_EN2 37 #define BTN_ENC 31 - #define LCD_SDSS EXP2_04_PIN + #define LCD_SDSS_PIN EXP2_04_PIN #define SD_DETECT_PIN EXP2_07_PIN //#define KILL_PIN 41 @@ -481,7 +481,7 @@ #define BTN_EN1 31 #define BTN_EN2 33 #define BTN_ENC 35 - //#define SDSS EXP2_04_PIN + //#define SD_SS_PIN EXP2_04_PIN #define SD_DETECT_PIN EXP2_07_PIN //#define KILL_PIN 64 @@ -501,7 +501,7 @@ #define BTN_EN2 63 #define BTN_ENC 59 - #define SDSS EXP2_04_PIN + #define SD_SS_PIN EXP2_04_PIN #define SD_DETECT_PIN EXP2_07_PIN //#define KILL_PIN 64 diff --git a/Marlin/src/pins/ramps/pins_ULTIMAIN_2.h b/Marlin/src/pins/ramps/pins_ULTIMAIN_2.h index e5998b3237..448c79a8d2 100644 --- a/Marlin/src/pins/ramps/pins_ULTIMAIN_2.h +++ b/Marlin/src/pins/ramps/pins_ULTIMAIN_2.h @@ -114,7 +114,7 @@ // // Misc. Functions // -#define SDSS 53 +#define SD_SS_PIN 53 #define SD_DETECT_PIN 39 #define LED_PIN 8 //#define SAFETY_TRIGGERED_PIN 28 // PIN to detect the safety circuit has triggered diff --git a/Marlin/src/pins/ramps/pins_ULTIMAKER.h b/Marlin/src/pins/ramps/pins_ULTIMAKER.h index b4eea9d488..baf4c234f6 100644 --- a/Marlin/src/pins/ramps/pins_ULTIMAKER.h +++ b/Marlin/src/pins/ramps/pins_ULTIMAKER.h @@ -106,7 +106,7 @@ // // Misc. Functions // -#define SDSS 53 +#define SD_SS_PIN 53 #define LED_PIN 13 #define PS_ON_PIN 12 #define SUICIDE_PIN 54 // PIN that has to be turned on right after start, to keep power flowing. diff --git a/Marlin/src/pins/ramps/pins_ZRIB_V53.h b/Marlin/src/pins/ramps/pins_ZRIB_V53.h index f2d3b83fc9..c8502fe3fd 100644 --- a/Marlin/src/pins/ramps/pins_ZRIB_V53.h +++ b/Marlin/src/pins/ramps/pins_ZRIB_V53.h @@ -171,8 +171,8 @@ // // Misc. Functions // -#ifndef SDSS - #define SDSS 53 +#ifndef SD_SS_PIN + #define SD_SS_PIN 53 #endif #define LED_PIN 13 @@ -335,7 +335,7 @@ #if ENABLED(ZONESTAR_12864LCD) #define LCDSCREEN_NAME "ZONESTAR LCD12864" - #define LCD_SDSS 16 + #define LCD_SDSS_PIN 16 #define LCD_PINS_RS 16 // ST7920 CS (LCD-4) #define LCD_PINS_EN 23 // ST7920 DAT LCD-R/W (LCD-5) #define LCD_PINS_D4 17 // ST7920 CLK LCD-ENA (LCD-6) @@ -363,7 +363,7 @@ #if ANY(ZONESTAR_12864OLED, ZONESTAR_12864OLED_SSD1306) #define LCDSCREEN_NAME "ZONESTAR 12864OLED" - #define LCD_SDSS 16 + #define LCD_SDSS_PIN 16 #define LCD_PINS_RS 23 // RESET Pull low for 1s to init #define LCD_PINS_DC 17 #define DOGLCD_CS 16 // CS diff --git a/Marlin/src/pins/ramps/pins_Z_BOLT_X_SERIES.h b/Marlin/src/pins/ramps/pins_Z_BOLT_X_SERIES.h index f63ca83723..57e4680508 100644 --- a/Marlin/src/pins/ramps/pins_Z_BOLT_X_SERIES.h +++ b/Marlin/src/pins/ramps/pins_Z_BOLT_X_SERIES.h @@ -141,7 +141,7 @@ // // Misc. Functions // -#define SDSS 53 +#define SD_SS_PIN 53 #define LED_PIN 13 #ifndef FILWIDTH_PIN diff --git a/Marlin/src/pins/rp2040/pins_RP2040.h b/Marlin/src/pins/rp2040/pins_RP2040.h index ce1c5160ae..aef5f5f9fd 100644 --- a/Marlin/src/pins/rp2040/pins_RP2040.h +++ b/Marlin/src/pins/rp2040/pins_RP2040.h @@ -123,7 +123,7 @@ // // Misc. Functions // -#define SDSS 20 +#define SD_SS_PIN 20 //#define LED_PIN 13 #define NEOPIXEL_PIN 15 @@ -427,7 +427,7 @@ #define BTN_EN1 47 #define BTN_EN2 43 #define BTN_ENC 32 - #define LCD_SDSS SDSS + #define LCD_SDSS_PIN SD_SS_PIN #define KILL_PIN 41 #elif ENABLED(LCD_I2C_VIKI) @@ -436,7 +436,7 @@ #define BTN_EN2 7 // 22/7 are unused on RAMPS_14. 22 is unused and 7 the SERVO0_PIN on RAMPS_13. #define BTN_ENC -1 - #define LCD_SDSS SDSS + #define LCD_SDSS_PIN SD_SS_PIN #define SD_DETECT_PIN 49 #elif ANY(VIKI2, miniVIKI) @@ -468,7 +468,7 @@ #define BTN_EN2 37 #define BTN_ENC 31 - #define LCD_SDSS SDSS + #define LCD_SDSS_PIN SD_SS_PIN #define SD_DETECT_PIN 49 #define KILL_PIN 41 diff --git a/Marlin/src/pins/sam/pins_ADSK.h b/Marlin/src/pins/sam/pins_ADSK.h index c264ffb50e..603565672f 100644 --- a/Marlin/src/pins/sam/pins_ADSK.h +++ b/Marlin/src/pins/sam/pins_ADSK.h @@ -129,7 +129,7 @@ A stepper for E0 extruder // // Misc. Functions // -#define SDSS 52 +#define SD_SS_PIN 52 #if ENABLED(ZONESTAR_LCD) diff --git a/Marlin/src/pins/sam/pins_ALLIGATOR_R2.h b/Marlin/src/pins/sam/pins_ALLIGATOR_R2.h index ceaeb8a587..6f6182a684 100644 --- a/Marlin/src/pins/sam/pins_ALLIGATOR_R2.h +++ b/Marlin/src/pins/sam/pins_ALLIGATOR_R2.h @@ -121,7 +121,7 @@ // // Misc. Functions // -#define SDSS 77 // PA28 +#define SD_SS_PIN 77 // PA28 #define SD_DETECT_PIN 87 // PA29 #define LED_RED_PIN 40 // PC8 #define LED_GREEN_PIN 41 // PC9 diff --git a/Marlin/src/pins/sam/pins_ARCHIM1.h b/Marlin/src/pins/sam/pins_ARCHIM1.h index 1d8a77ba36..1bbe86c41e 100644 --- a/Marlin/src/pins/sam/pins_ARCHIM1.h +++ b/Marlin/src/pins/sam/pins_ARCHIM1.h @@ -172,7 +172,7 @@ #define SD_SCK_PIN 76 // D76 PA27 #define SD_MISO_PIN 74 // D74 PA25 #define SD_MOSI_PIN 75 // D75 PA26 -#define SDSS 87 // D87 PA29 +#define SD_SS_PIN 87 // D87 PA29 // 2MB SPI Flash #define SPI_FLASH_SS 52 // D52 PB21 diff --git a/Marlin/src/pins/sam/pins_ARCHIM2.h b/Marlin/src/pins/sam/pins_ARCHIM2.h index a0488d64dc..2d0a42c03d 100644 --- a/Marlin/src/pins/sam/pins_ARCHIM2.h +++ b/Marlin/src/pins/sam/pins_ARCHIM2.h @@ -193,7 +193,7 @@ #define SD_SCK_PIN 76 // D76 PA27 #define SD_MISO_PIN 74 // D74 PA25 #define SD_MOSI_PIN 75 // D75 PA26 -#define SDSS 87 // D87 PA29 +#define SD_SS_PIN 87 // D87 PA29 // Unused Digital GPIO J20 Pins #define GPIO_PB1_J20_5 94 // D94 PB1 (Header J20 5) diff --git a/Marlin/src/pins/sam/pins_CNCONTROLS_15D.h b/Marlin/src/pins/sam/pins_CNCONTROLS_15D.h index 3d15f37e47..ee4890785b 100644 --- a/Marlin/src/pins/sam/pins_CNCONTROLS_15D.h +++ b/Marlin/src/pins/sam/pins_CNCONTROLS_15D.h @@ -119,7 +119,7 @@ #define SD_SCK_PIN 76 #define SD_MISO_PIN 74 #define SD_MOSI_PIN 75 -#define SDSS 53 +#define SD_SS_PIN 53 #define SD_DETECT_PIN 40 // Common I/O diff --git a/Marlin/src/pins/sam/pins_DUE3DOM.h b/Marlin/src/pins/sam/pins_DUE3DOM.h index 66aa581271..50705ac964 100644 --- a/Marlin/src/pins/sam/pins_DUE3DOM.h +++ b/Marlin/src/pins/sam/pins_DUE3DOM.h @@ -105,7 +105,7 @@ // // Misc. Functions // -#define SDSS 4 +#define SD_SS_PIN 4 #define PS_ON_PIN 40 // @@ -149,7 +149,7 @@ #define BTN_EN2 52 #define BTN_ENC 48 #define BEEPER_PIN 41 - #define LCD_SDSS 4 + #define LCD_SDSS_PIN 4 #define SD_DETECT_PIN 14 #elif ENABLED(SPARK_FULL_GRAPHICS) diff --git a/Marlin/src/pins/sam/pins_DUE3DOM_MINI.h b/Marlin/src/pins/sam/pins_DUE3DOM_MINI.h index b9f73adfe9..519a8232e9 100644 --- a/Marlin/src/pins/sam/pins_DUE3DOM_MINI.h +++ b/Marlin/src/pins/sam/pins_DUE3DOM_MINI.h @@ -97,7 +97,7 @@ // // Misc. Functions // -#define SDSS 4 +#define SD_SS_PIN 4 #define PS_ON_PIN 40 // @@ -145,7 +145,7 @@ #define BTN_EN2 52 #define BTN_ENC 48 #define BEEPER_PIN 41 - #define LCD_SDSS SDSS + #define LCD_SDSS_PIN SD_SS_PIN #define SD_DETECT_PIN 14 #elif ENABLED(SPARK_FULL_GRAPHICS) @@ -165,7 +165,7 @@ #define BTN_EN1 52 #define BTN_EN2 50 #define BTN_ENC 48 - #define LCD_SDSS SDSS + #define LCD_SDSS_PIN SD_SS_PIN #define SD_DETECT_PIN 14 #define BEEPER_PIN 41 #define DOGLCD_A0 46 diff --git a/Marlin/src/pins/sam/pins_KRATOS32.h b/Marlin/src/pins/sam/pins_KRATOS32.h index bebe2b82a3..ff715270d2 100644 --- a/Marlin/src/pins/sam/pins_KRATOS32.h +++ b/Marlin/src/pins/sam/pins_KRATOS32.h @@ -152,7 +152,7 @@ #define BTN_EN2 50 #define BTN_ENC 46 - #define SDSS 4 + #define SD_SS_PIN 4 #define SD_DETECT_PIN 14 #define BEEPER_PIN 41 diff --git a/Marlin/src/pins/sam/pins_PRINTRBOARD_G2.h b/Marlin/src/pins/sam/pins_PRINTRBOARD_G2.h index b85150f1ca..0f4db200a3 100644 --- a/Marlin/src/pins/sam/pins_PRINTRBOARD_G2.h +++ b/Marlin/src/pins/sam/pins_PRINTRBOARD_G2.h @@ -152,7 +152,7 @@ #define SD_MISO_PIN 68 // set to unused pins for now #define SD_MOSI_PIN 69 // set to unused pins for now #define SD_SCK_PIN 70 // set to unused pins for now -#define SDSS 71 // set to unused pins for now +#define SD_SS_PIN 71 // set to unused pins for now /** * G2 uses 8 pins that are not available in the DUE environment: diff --git a/Marlin/src/pins/sam/pins_RADDS.h b/Marlin/src/pins/sam/pins_RADDS.h index a490f9f89f..40f667eff4 100644 --- a/Marlin/src/pins/sam/pins_RADDS.h +++ b/Marlin/src/pins/sam/pins_RADDS.h @@ -244,7 +244,7 @@ #define BTN_BACK 71 - #define SDSS 10 + #define SD_SS_PIN 10 #define SD_DETECT_PIN 14 #elif IS_RRD_FG_SC @@ -262,7 +262,7 @@ #define BTN_EN2 52 #define BTN_ENC 48 - #define SDSS 10 + #define SD_SS_PIN 10 #define SD_DETECT_PIN 14 #elif HAS_U8GLIB_I2C_OLED @@ -271,7 +271,7 @@ #define BTN_EN2 52 #define BTN_ENC 48 #define BEEPER_PIN 41 - #define LCD_SDSS 10 + #define LCD_SDSS_PIN 10 #define SD_DETECT_PIN 14 #elif ENABLED(SPARK_FULL_GRAPHICS) @@ -293,5 +293,5 @@ #endif // HAS_WIRED_LCD #ifndef SDSS - #define SDSS 4 + #define SD_SS_PIN 4 #endif diff --git a/Marlin/src/pins/sam/pins_RAMPS_FD_V1.h b/Marlin/src/pins/sam/pins_RAMPS_FD_V1.h index 2b9c8fd7eb..a34a02839c 100644 --- a/Marlin/src/pins/sam/pins_RAMPS_FD_V1.h +++ b/Marlin/src/pins/sam/pins_RAMPS_FD_V1.h @@ -131,7 +131,7 @@ // // Misc. Functions // -#define SDSS 4 +#define SD_SS_PIN 4 #define LED_PIN 13 /** diff --git a/Marlin/src/pins/sam/pins_RURAMPS4D_11.h b/Marlin/src/pins/sam/pins_RURAMPS4D_11.h index 0ece2aeade..03ba77c077 100644 --- a/Marlin/src/pins/sam/pins_RURAMPS4D_11.h +++ b/Marlin/src/pins/sam/pins_RURAMPS4D_11.h @@ -155,7 +155,7 @@ // // Misc. Functions // -#define SDSS 4 // 4,10,52 if using HW SPI. +#define SD_SS_PIN 4 // 4,10,52 if using HW SPI. #define LED_PIN -1 // 13 - HEATER_0_PIN #define PS_ON_PIN -1 // 65 @@ -241,7 +241,7 @@ #elif HAS_U8GLIB_I2C_OLED #define BEEPER_PIN EXP1_01_PIN - #define LCD_SDSS EXP2_04_PIN + #define LCD_SDSS_PIN EXP2_04_PIN #define SD_DETECT_PIN EXP2_07_PIN #elif ENABLED(FYSETC_MINI_12864) diff --git a/Marlin/src/pins/sam/pins_RURAMPS4D_13.h b/Marlin/src/pins/sam/pins_RURAMPS4D_13.h index fa27868ff9..a4574cda54 100644 --- a/Marlin/src/pins/sam/pins_RURAMPS4D_13.h +++ b/Marlin/src/pins/sam/pins_RURAMPS4D_13.h @@ -145,7 +145,7 @@ // // Misc. Functions // -#define SDSS 4 // 4,10,52 if using HW SPI. +#define SD_SS_PIN 4 // 4,10,52 if using HW SPI. #define LED_PIN -1 // 13 - HEATER_0_PIN #define PS_ON_PIN -1 // 65 @@ -231,7 +231,7 @@ #elif HAS_U8GLIB_I2C_OLED #define BEEPER_PIN EXP1_01_PIN - #define LCD_SDSS EXP2_04_PIN + #define LCD_SDSS_PIN EXP2_04_PIN #define SD_DETECT_PIN EXP2_07_PIN #elif ENABLED(FYSETC_MINI_12864) diff --git a/Marlin/src/pins/sam/pins_ULTRATRONICS_PRO.h b/Marlin/src/pins/sam/pins_ULTRATRONICS_PRO.h index f3ec7806e6..bbd6189842 100644 --- a/Marlin/src/pins/sam/pins_ULTRATRONICS_PRO.h +++ b/Marlin/src/pins/sam/pins_ULTRATRONICS_PRO.h @@ -128,7 +128,7 @@ // // Misc. Functions // -#define SDSS 59 +#define SD_SS_PIN 59 #define SD_DETECT_PIN 60 #define LED_PIN 13 #define PS_ON_PIN 32 diff --git a/Marlin/src/pins/samd/pins_BRICOLEMON_LITE_V1_0.h b/Marlin/src/pins/samd/pins_BRICOLEMON_LITE_V1_0.h index 7f4344a364..7f8943ac46 100644 --- a/Marlin/src/pins/samd/pins_BRICOLEMON_LITE_V1_0.h +++ b/Marlin/src/pins/samd/pins_BRICOLEMON_LITE_V1_0.h @@ -359,7 +359,7 @@ //#define BTN_EN1 47 //#define BTN_EN2 EXP2_03_PIN //#define BTN_ENC 32 - //#define LCD_SDSS SDSS + //#define LCD_SDSS_PIN SD_SS_PIN //#define KILL_PIN EXP1_01_PIN //#undef LCD_PINS_EN // not used, causes false pin conflict report @@ -370,7 +370,7 @@ //#define BTN_EN2 EXP2_05_PIN //#define BTN_ENC -1 - //#define LCD_SDSS SDSS + //#define LCD_SDSS_PIN SD_SS_PIN //#define SD_DETECT_PIN EXP2_10_PIN #elif ANY(VIKI2, miniVIKI) @@ -404,7 +404,7 @@ //#define BTN_EN2 EXP1_06_PIN //#define BTN_ENC 31 - //#define LCD_SDSS SDSS + //#define LCD_SDSS_PIN SD_SS_PIN //#define SD_DETECT_PIN EXP2_10_PIN //#define KILL_PIN EXP1_01_PIN @@ -561,11 +561,10 @@ #endif #if SD_CONNECTION_IS(ONBOARD) - #define SDSS 83 - #undef SD_DETECT_PIN + #define SD_SS_PIN 83 #define SD_DETECT_PIN 95 #else - #define SDSS EXP2_04_PIN + #define SD_SS_PIN EXP2_04_PIN #endif #if HAS_TMC_UART diff --git a/Marlin/src/pins/samd/pins_BRICOLEMON_V1_0.h b/Marlin/src/pins/samd/pins_BRICOLEMON_V1_0.h index fd475ab222..e4766d33bb 100644 --- a/Marlin/src/pins/samd/pins_BRICOLEMON_V1_0.h +++ b/Marlin/src/pins/samd/pins_BRICOLEMON_V1_0.h @@ -411,7 +411,7 @@ //#define BTN_EN1 47 //#define BTN_EN2 EXP2_03_PIN //#define BTN_ENC 32 - //#define LCD_SDSS SDSS + //#define LCD_SDSS_PIN SD_SS_PIN //#define KILL_PIN EXP1_01_PIN //#undef LCD_PINS_EN // not used, causes false pin conflict report @@ -422,7 +422,7 @@ //#define BTN_EN2 EXP2_05_PIN //#define BTN_ENC -1 - //#define LCD_SDSS SDSS + //#define LCD_SDSS_PIN SD_SS_PIN //#define SD_DETECT_PIN EXP2_10_PIN #elif ANY(VIKI2, miniVIKI) @@ -456,7 +456,7 @@ //#define BTN_EN2 EXP1_06_PIN //#define BTN_ENC 31 - //#define LCD_SDSS SDSS + //#define LCD_SDSS_PIN SD_SS_PIN //#define SD_DETECT_PIN EXP2_10_PIN //#define KILL_PIN EXP1_01_PIN @@ -613,11 +613,11 @@ #endif #if SD_CONNECTION_IS(ONBOARD) - #define SDSS 83 + #define SD_SS_PIN 83 #undef SD_DETECT_PIN #define SD_DETECT_PIN 95 #else - #define SDSS EXP2_04_PIN + #define SD_SS_PIN EXP2_04_PIN #endif #if HAS_TMC_UART diff --git a/Marlin/src/pins/samd/pins_MINITRONICS20.h b/Marlin/src/pins/samd/pins_MINITRONICS20.h index 12cba80f00..3d625180ca 100644 --- a/Marlin/src/pins/samd/pins_MINITRONICS20.h +++ b/Marlin/src/pins/samd/pins_MINITRONICS20.h @@ -313,7 +313,7 @@ //#define BTN_EN1 47 //#define BTN_EN2 EXP2_03_PIN //#define BTN_ENC 32 - //#define LCD_SDSS SDSS + //#define LCD_SDSS_PIN SD_SS_PIN //#define KILL_PIN EXP1_01_PIN //#undef LCD_PINS_EN // not used, causes false pin conflict report @@ -324,7 +324,7 @@ //#define BTN_EN2 EXP2_05_PIN //#define BTN_ENC -1 - //#define LCD_SDSS SDSS + //#define LCD_SDSS_PIN SD_SS_PIN //#define SD_DETECT_PIN EXP2_10_PIN #elif ANY(VIKI2, miniVIKI) @@ -358,7 +358,7 @@ //#define BTN_EN2 EXP1_06_PIN //#define BTN_ENC 31 - //#define LCD_SDSS SDSS + //#define LCD_SDSS_PIN SD_SS_PIN //#define SD_DETECT_PIN EXP2_10_PIN //#define KILL_PIN EXP1_01_PIN @@ -500,7 +500,7 @@ // SD Support // -#define SDSS 2 +#define SD_SS_PIN 2 #undef SD_DETECT_PIN #define SD_DETECT_PIN 22 diff --git a/Marlin/src/pins/samd/pins_RAMPS_144.h b/Marlin/src/pins/samd/pins_RAMPS_144.h index 33a45fc9f4..97d662f8f2 100644 --- a/Marlin/src/pins/samd/pins_RAMPS_144.h +++ b/Marlin/src/pins/samd/pins_RAMPS_144.h @@ -244,11 +244,11 @@ #endif #if SD_CONNECTION_IS(ONBOARD) - #define SDSS 83 + #define SD_SS_PIN 83 #undef SD_DETECT_PIN #define SD_DETECT_PIN 95 #else - #define SDSS 53 + #define SD_SS_PIN 53 #endif // @@ -538,7 +538,7 @@ #define BTN_EN1 AUX4_04 #define BTN_EN2 AUX4_06 #define BTN_ENC AUX4_03 - #define LCD_SDSS SDSS + #define LCD_SDSS_PIN SD_SS_PIN #define KILL_PIN AUX4_07 #undef LCD_PINS_EN // not used, causes false pin conflict report @@ -548,7 +548,7 @@ #define BTN_EN2 AUX2_08 #define BTN_ENC -1 - #define LCD_SDSS SDSS + #define LCD_SDSS_PIN SD_SS_PIN #ifndef SD_DETECT_PIN #define SD_DETECT_PIN EXP2_07_PIN #endif @@ -584,7 +584,7 @@ #define BTN_EN2 EXP1_01_PIN #define BTN_ENC EXP2_03_PIN - #define LCD_SDSS SDSS + #define LCD_SDSS_PIN SD_SS_PIN #ifndef SD_DETECT_PIN #define SD_DETECT_PIN EXP2_07_PIN #endif diff --git a/Marlin/src/pins/sanguino/pins_ANET_10.h b/Marlin/src/pins/sanguino/pins_ANET_10.h index 708df22199..0d87e9ad0e 100644 --- a/Marlin/src/pins/sanguino/pins_ANET_10.h +++ b/Marlin/src/pins/sanguino/pins_ANET_10.h @@ -148,7 +148,7 @@ // // Misc. Functions // -#define SDSS 31 +#define SD_SS_PIN 31 #define LED_PIN -1 /** @@ -184,7 +184,7 @@ #if HAS_WIRED_LCD - #define LCD_SDSS EXP1_06_PIN + #define LCD_SDSS_PIN EXP1_06_PIN #if HAS_ADC_BUTTONS diff --git a/Marlin/src/pins/sanguino/pins_GEN3_PLUS.h b/Marlin/src/pins/sanguino/pins_GEN3_PLUS.h index 86869fc85f..d9c07eec50 100644 --- a/Marlin/src/pins/sanguino/pins_GEN3_PLUS.h +++ b/Marlin/src/pins/sanguino/pins_GEN3_PLUS.h @@ -82,5 +82,5 @@ // // Misc. Functions // -#define SDSS 4 +#define SD_SS_PIN 4 #define PS_ON_PIN 14 diff --git a/Marlin/src/pins/sanguino/pins_GEN6.h b/Marlin/src/pins/sanguino/pins_GEN6.h index ad8ef97cb4..e3c5802919 100644 --- a/Marlin/src/pins/sanguino/pins_GEN6.h +++ b/Marlin/src/pins/sanguino/pins_GEN6.h @@ -88,7 +88,7 @@ // // Misc. Functions // -#define SDSS 17 +#define SD_SS_PIN 17 #define DEBUG_PIN 0 #ifndef CASE_LIGHT_PIN diff --git a/Marlin/src/pins/sanguino/pins_GEN7_CUSTOM.h b/Marlin/src/pins/sanguino/pins_GEN7_CUSTOM.h index c363e528d3..eb03fe3178 100644 --- a/Marlin/src/pins/sanguino/pins_GEN7_CUSTOM.h +++ b/Marlin/src/pins/sanguino/pins_GEN7_CUSTOM.h @@ -85,7 +85,7 @@ // // Misc. Functions // -#define SDSS 31 // SCL pin of I2C header || CS Pin for SD Card support +#define SD_SS_PIN 31 // SCL pin of I2C header || CS Pin for SD Card support #define PS_ON_PIN 19 #ifndef CASE_LIGHT_PIN diff --git a/Marlin/src/pins/sanguino/pins_MELZI_CREALITY.h b/Marlin/src/pins/sanguino/pins_MELZI_CREALITY.h index ba3c6767b2..adbbbc0300 100644 --- a/Marlin/src/pins/sanguino/pins_MELZI_CREALITY.h +++ b/Marlin/src/pins/sanguino/pins_MELZI_CREALITY.h @@ -70,7 +70,7 @@ #define DOGLCD_A0 EXP1_06_PIN #endif - #define LCD_SDSS 31 // Controller's SD card + #define LCD_SDSS_PIN 31 // Controller's SD card #define BTN_ENC EXP1_02_PIN #define BTN_EN1 EXP1_03_PIN diff --git a/Marlin/src/pins/sanguino/pins_MELZI_CREALITY_E2.h b/Marlin/src/pins/sanguino/pins_MELZI_CREALITY_E2.h index dd557265c4..991e8ec665 100644 --- a/Marlin/src/pins/sanguino/pins_MELZI_CREALITY_E2.h +++ b/Marlin/src/pins/sanguino/pins_MELZI_CREALITY_E2.h @@ -76,7 +76,7 @@ #define LCD_PINS_DEFINED #endif -#define LCD_SDSS 31 // Controller's SD card +#define LCD_SDSS_PIN 31 // Controller's SD card #include "pins_MELZI.h" // ... SANGUINOLOLU_12 ... SANGUINOLOLU_11 diff --git a/Marlin/src/pins/sanguino/pins_MELZI_TRONXY.h b/Marlin/src/pins/sanguino/pins_MELZI_TRONXY.h index 99cdfd0b42..fcaeb3ba33 100644 --- a/Marlin/src/pins/sanguino/pins_MELZI_TRONXY.h +++ b/Marlin/src/pins/sanguino/pins_MELZI_TRONXY.h @@ -30,7 +30,7 @@ #define Z_ENABLE_PIN 14 -#define LCD_SDSS -1 +#define LCD_SDSS_PIN -1 #if ANY(CR10_STOCKDISPLAY, LCD_FOR_MELZI) #define BTN_ENC 26 diff --git a/Marlin/src/pins/sanguino/pins_OMCA.h b/Marlin/src/pins/sanguino/pins_OMCA.h index 428151ed51..07a614a7ff 100644 --- a/Marlin/src/pins/sanguino/pins_OMCA.h +++ b/Marlin/src/pins/sanguino/pins_OMCA.h @@ -123,7 +123,7 @@ // // Misc. Functions // -#define SDSS 11 +#define SD_SS_PIN 11 #define I2C_SCL_PIN 16 #define I2C_SDA_PIN 17 diff --git a/Marlin/src/pins/sanguino/pins_OMCA_A.h b/Marlin/src/pins/sanguino/pins_OMCA_A.h index e3a46664b1..b60591aa58 100644 --- a/Marlin/src/pins/sanguino/pins_OMCA_A.h +++ b/Marlin/src/pins/sanguino/pins_OMCA_A.h @@ -118,6 +118,6 @@ // // Misc. Functions // -#define SDSS 11 +#define SD_SS_PIN 11 /* Unused (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) */ diff --git a/Marlin/src/pins/sanguino/pins_SANGUINOLOLU_11.h b/Marlin/src/pins/sanguino/pins_SANGUINOLOLU_11.h index 50df2c9509..f65b55ca5c 100644 --- a/Marlin/src/pins/sanguino/pins_SANGUINOLOLU_11.h +++ b/Marlin/src/pins/sanguino/pins_SANGUINOLOLU_11.h @@ -109,8 +109,8 @@ * If you encounter issues with these pins, upgrade your * Sanguino libraries! See #368. */ -//#define SDSS 24 -#define SDSS AUX1_09 +//#define SD_SS_PIN 24 +#define SD_SS_PIN AUX1_09 #if IS_MELZI #define LED_PIN AUX1_01 @@ -243,8 +243,8 @@ #if IS_MELZI #define BTN_ENC AUX1_05 - #ifndef LCD_SDSS - #define LCD_SDSS AUX1_07 // Panelolu2 SD card reader rather than the Melzi + #ifndef LCD_SDSS_PIN + #define LCD_SDSS_PIN AUX1_07 // Panelolu2 SD card reader rather than the Melzi #endif #else #define BTN_ENC AUX1_07 @@ -254,8 +254,8 @@ #else // !LCD_FOR_MELZI && !ZONESTAR_LCD && !LCD_I2C_PANELOLU2 #define BTN_ENC AUX1_02 - #ifndef LCD_SDSS - #define LCD_SDSS AUX1_03 // Smart Controller SD card reader rather than the Melzi + #ifndef LCD_SDSS_PIN + #define LCD_SDSS_PIN AUX1_03 // Smart Controller SD card reader rather than the Melzi #endif #endif diff --git a/Marlin/src/pins/sanguino/pins_ZMIB_V2.h b/Marlin/src/pins/sanguino/pins_ZMIB_V2.h index 39d55d1b28..b583c17b31 100644 --- a/Marlin/src/pins/sanguino/pins_ZMIB_V2.h +++ b/Marlin/src/pins/sanguino/pins_ZMIB_V2.h @@ -159,7 +159,7 @@ // SD card // #if HAS_MEDIA - #define SDSS 4 + #define SD_SS_PIN 4 #endif #define SD_DETECT_PIN -1 @@ -191,7 +191,7 @@ // #define LCDSCREEN_NAME "ZONESTAR_12864LCD" #define FORCE_SOFT_SPI - //#define LCD_SDSS EXP1_03_PIN + //#define LCD_SDSS_PIN EXP1_03_PIN #define LCD_PINS_RS EXP1_03_PIN // ST7920 CS (LCD-4) #define LCD_PINS_EN EXP1_06_PIN // ST7920 DAT (LCD-5) #define LCD_PINS_D4 EXP1_04_PIN // ST7920 CLK (LCD-6) diff --git a/Marlin/src/pins/stm32f0/pins_MALYAN_M300.h b/Marlin/src/pins/stm32f0/pins_MALYAN_M300.h index ba6263cd74..9687feacab 100644 --- a/Marlin/src/pins/stm32f0/pins_MALYAN_M300.h +++ b/Marlin/src/pins/stm32f0/pins_MALYAN_M300.h @@ -37,11 +37,6 @@ #endif #endif -// -// SD CARD SPI -// -#define SDSS SD_SS_PIN - // // Timers // diff --git a/Marlin/src/pins/stm32f1/pins_BEAST.h b/Marlin/src/pins/stm32f1/pins_BEAST.h index cf64ff1c6a..466f7fdbbe 100644 --- a/Marlin/src/pins/stm32f1/pins_BEAST.h +++ b/Marlin/src/pins/stm32f1/pins_BEAST.h @@ -77,7 +77,7 @@ // // Misc. Functions // -#define SDSS PA15 +#define SD_SS_PIN PA15 #define LED_PIN PB2 // diff --git a/Marlin/src/pins/stm32f1/pins_BTT_SKR_CR6.h b/Marlin/src/pins/stm32f1/pins_BTT_SKR_CR6.h index 7693aa6902..c9b1d93525 100644 --- a/Marlin/src/pins/stm32f1/pins_BTT_SKR_CR6.h +++ b/Marlin/src/pins/stm32f1/pins_BTT_SKR_CR6.h @@ -174,7 +174,7 @@ #if SD_CONNECTION_IS(ONBOARD) #define SD_DETECT_PIN PC4 #define ONBOARD_SD_CS_PIN PA4 // Chip select for "System" SD card - #define SDSS ONBOARD_SD_CS_PIN + #define SD_SS_PIN ONBOARD_SD_CS_PIN #endif // diff --git a/Marlin/src/pins/stm32f1/pins_BTT_SKR_E3_DIP.h b/Marlin/src/pins/stm32f1/pins_BTT_SKR_E3_DIP.h index de7ded7d52..ab1684ae26 100644 --- a/Marlin/src/pins/stm32f1/pins_BTT_SKR_E3_DIP.h +++ b/Marlin/src/pins/stm32f1/pins_BTT_SKR_E3_DIP.h @@ -368,4 +368,4 @@ #define ONBOARD_SPI_DEVICE 1 // SPI1 #define ONBOARD_SD_CS_PIN PA4 // Chip select for "System" SD card -#define SDSS ONBOARD_SD_CS_PIN +#define SD_SS_PIN ONBOARD_SD_CS_PIN diff --git a/Marlin/src/pins/stm32f1/pins_BTT_SKR_MINI_E3_common.h b/Marlin/src/pins/stm32f1/pins_BTT_SKR_MINI_E3_common.h index 09acba180b..8c463717f4 100644 --- a/Marlin/src/pins/stm32f1/pins_BTT_SKR_MINI_E3_common.h +++ b/Marlin/src/pins/stm32f1/pins_BTT_SKR_MINI_E3_common.h @@ -416,7 +416,7 @@ #define ONBOARD_SD_CS_PIN PA4 // Chip select for "System" SD card #define ENABLE_SPI1 -#define SDSS ONBOARD_SD_CS_PIN +#define SD_SS_PIN ONBOARD_SD_CS_PIN #define SD_SCK_PIN PA5 #define SD_MISO_PIN PA6 #define SD_MOSI_PIN PA7 diff --git a/Marlin/src/pins/stm32f1/pins_BTT_SKR_MINI_V1_1.h b/Marlin/src/pins/stm32f1/pins_BTT_SKR_MINI_V1_1.h index 70f3f85747..301453cd70 100644 --- a/Marlin/src/pins/stm32f1/pins_BTT_SKR_MINI_V1_1.h +++ b/Marlin/src/pins/stm32f1/pins_BTT_SKR_MINI_V1_1.h @@ -283,4 +283,3 @@ #define ONBOARD_SPI_DEVICE 1 // SPI1 #define ONBOARD_SD_CS_PIN PA4 // Chip select for "System" SD card -#define SDSS SD_SS_PIN diff --git a/Marlin/src/pins/stm32f1/pins_CHITU3D.h b/Marlin/src/pins/stm32f1/pins_CHITU3D.h index bdc609c7b5..ee3e8c989d 100644 --- a/Marlin/src/pins/stm32f1/pins_CHITU3D.h +++ b/Marlin/src/pins/stm32f1/pins_CHITU3D.h @@ -67,7 +67,6 @@ // // Misc. Functions // -#define SDSS -1 #define LED_PIN -1 #ifndef CASE_LIGHT_PIN @@ -158,7 +157,7 @@ #define BTN_EN1 PC15 // 47 #define BTN_EN2 PC11 // 43 #define BTN_ENC PC0 // 32 - #define LCD_SDSS PD5 // 53 + #define LCD_SDSS_PIN PD5 // 53 #define SD_DETECT_PIN -1 #define KILL_PIN PC9 // 41 #undef LCD_PINS_EN // not used, causes false pin conflict report @@ -169,7 +168,7 @@ #define BTN_EN2 PA7 // 7 // 22/7 are unused on RAMPS_14. 22 is unused and 7 the SERVO0_PIN on RAMPS_13. #define BTN_ENC -1 - #define LCD_SDSS PD5 // 53 + #define LCD_SDSS_PIN PD5 // 53 #define SD_DETECT_PIN PD1 // 49 #elif ANY(VIKI2, miniVIKI) @@ -184,7 +183,7 @@ #define BTN_EN2 PA7 // 7 #define BTN_ENC PC7 // 39 - #define SDSS PD5 // 53 + #define SD_SS_PIN PD5 // 53 #define SD_DETECT_PIN -1 // Pin 49 for display sd interface, 72 for easy adapter board #define KILL_PIN PB15 // 31 @@ -199,7 +198,7 @@ #define BTN_EN2 PC5 // 37 #define BTN_ENC PB15 // 31 #define SD_DETECT_PIN PD1 // 49 - #define LCD_SDSS PD5 // 53 + #define LCD_SDSS_PIN PD5 // 53 #define KILL_PIN PC9 // 41 #define BEEPER_PIN PB7 // 23 #define DOGLCD_CS PB13 // 29 @@ -213,7 +212,7 @@ #define DOGLCD_A0 PC12 // 44 #define DOGLCD_CS PE2 // 66 #define LCD_BACKLIGHT_PIN PE1 // 65 // backlight LED on A11/D65 - #define SDSS PD5 // 53 + #define SD_SS_PIN PD5 // 53 #define KILL_PIN PE0 // 64 diff --git a/Marlin/src/pins/stm32f1/pins_FLSUN_HISPEED.h b/Marlin/src/pins/stm32f1/pins_FLSUN_HISPEED.h index caac738bb9..b42a249e85 100644 --- a/Marlin/src/pins/stm32f1/pins_FLSUN_HISPEED.h +++ b/Marlin/src/pins/stm32f1/pins_FLSUN_HISPEED.h @@ -256,7 +256,6 @@ #define SD_SCK_PIN PC12 #define SD_MISO_PIN PC8 #define SD_MOSI_PIN PD2 - #define SD_SS_PIN -1 #define SD_DETECT_PIN PD12 // SD_CD (if -1 no detection) #else #define ONBOARD_SDIO diff --git a/Marlin/src/pins/stm32f1/pins_FLY_MINI.h b/Marlin/src/pins/stm32f1/pins_FLY_MINI.h index 22c977d8b9..1f62a10149 100644 --- a/Marlin/src/pins/stm32f1/pins_FLY_MINI.h +++ b/Marlin/src/pins/stm32f1/pins_FLY_MINI.h @@ -155,7 +155,6 @@ #define SD_MISO_PIN EXP2_01_PIN #define SD_MOSI_PIN EXP2_06_PIN - #define SDSS SD_SS_PIN #define SD_DETECT_PIN EXP2_07_PIN #define BEEPER_PIN EXP1_01_PIN diff --git a/Marlin/src/pins/stm32f1/pins_FYSETC_AIO_II.h b/Marlin/src/pins/stm32f1/pins_FYSETC_AIO_II.h index d32479267d..3153f4956c 100644 --- a/Marlin/src/pins/stm32f1/pins_FYSETC_AIO_II.h +++ b/Marlin/src/pins/stm32f1/pins_FYSETC_AIO_II.h @@ -152,7 +152,7 @@ // // Misc. Functions // -#define SDSS PA4 +#define SD_SS_PIN PA4 // // LCD Pins diff --git a/Marlin/src/pins/stm32f1/pins_FYSETC_CHEETAH.h b/Marlin/src/pins/stm32f1/pins_FYSETC_CHEETAH.h index 042966cb3a..875d3dc998 100644 --- a/Marlin/src/pins/stm32f1/pins_FYSETC_CHEETAH.h +++ b/Marlin/src/pins/stm32f1/pins_FYSETC_CHEETAH.h @@ -119,7 +119,7 @@ // // Misc. Functions // -#define SDSS PA4 +#define SD_SS_PIN PA4 #define SD_DETECT_PIN PC3 #ifndef RGB_LED_R_PIN diff --git a/Marlin/src/pins/stm32f1/pins_GTM32_MINI.h b/Marlin/src/pins/stm32f1/pins_GTM32_MINI.h index 94c6dc2bfa..6baee148c7 100644 --- a/Marlin/src/pins/stm32f1/pins_GTM32_MINI.h +++ b/Marlin/src/pins/stm32f1/pins_GTM32_MINI.h @@ -225,8 +225,6 @@ #define SD_DETECT_PIN -1 // Card detect is not connected #endif -#define SDSS SD_SS_PIN - #if ENABLED(WIFISUPPORT) // // ESP WiFi can be soldered to J9 connector which is wired to USART2. diff --git a/Marlin/src/pins/stm32f1/pins_GTM32_MINI_A30.h b/Marlin/src/pins/stm32f1/pins_GTM32_MINI_A30.h index 5f66f9bc3b..ee605c8765 100644 --- a/Marlin/src/pins/stm32f1/pins_GTM32_MINI_A30.h +++ b/Marlin/src/pins/stm32f1/pins_GTM32_MINI_A30.h @@ -219,8 +219,6 @@ #define SD_DETECT_PIN -1 // Card detect is not connected #endif -#define SDSS SD_SS_PIN - #if ENABLED(WIFISUPPORT) // // ESP WiFi can be soldered to J9 connector which is wired to USART2. diff --git a/Marlin/src/pins/stm32f1/pins_GTM32_PRO_VB.h b/Marlin/src/pins/stm32f1/pins_GTM32_PRO_VB.h index 9f7efa99c4..c636dea493 100644 --- a/Marlin/src/pins/stm32f1/pins_GTM32_PRO_VB.h +++ b/Marlin/src/pins/stm32f1/pins_GTM32_PRO_VB.h @@ -230,8 +230,6 @@ #define SD_DETECT_PIN -1 // Card detect is not connected #endif -#define SDSS SD_SS_PIN - #if ENABLED(WIFISUPPORT) // // ESP WiFi can be soldered to J9 connector which is wired to USART2. diff --git a/Marlin/src/pins/stm32f1/pins_GTM32_REV_B.h b/Marlin/src/pins/stm32f1/pins_GTM32_REV_B.h index 3f6ae1414b..814844d95b 100644 --- a/Marlin/src/pins/stm32f1/pins_GTM32_REV_B.h +++ b/Marlin/src/pins/stm32f1/pins_GTM32_REV_B.h @@ -222,8 +222,6 @@ #define SD_DETECT_PIN -1 // Card detect is not connected #endif -#define SDSS SD_SS_PIN - #if ENABLED(WIFISUPPORT) // // ESP WiFi can be soldered to J9 connector which is wired to USART2. diff --git a/Marlin/src/pins/stm32f1/pins_LONGER3D_LK.h b/Marlin/src/pins/stm32f1/pins_LONGER3D_LK.h index 37ac753fc8..95d7889768 100644 --- a/Marlin/src/pins/stm32f1/pins_LONGER3D_LK.h +++ b/Marlin/src/pins/stm32f1/pins_LONGER3D_LK.h @@ -163,7 +163,6 @@ #if SD_CONNECTION_IS(ONBOARD) #define ONBOARD_SDIO - #define SD_SS_PIN -1 // else SDSS set to PA4 in M43 (spi_pins.h) #endif /** diff --git a/Marlin/src/pins/stm32f1/pins_MALYAN_M200.h b/Marlin/src/pins/stm32f1/pins_MALYAN_M200.h index 94e5340099..35ad992209 100644 --- a/Marlin/src/pins/stm32f1/pins_MALYAN_M200.h +++ b/Marlin/src/pins/stm32f1/pins_MALYAN_M200.h @@ -41,8 +41,6 @@ #define FLASH_EEPROM_EMULATION #endif -#define SDSS SD_SS_PIN // Also in HAL/STM32F1/spi_pins.h - // Based on PWM timer usage, we have to use these timers and soft PWM for the fans // On STM32F103: // PB3, PB6, PB7, and PB8 can be used with pwm, which rules out TIM2 and TIM4. diff --git a/Marlin/src/pins/stm32f1/pins_MD_D301.h b/Marlin/src/pins/stm32f1/pins_MD_D301.h index 5d7a2dbf88..23e44ad4a0 100644 --- a/Marlin/src/pins/stm32f1/pins_MD_D301.h +++ b/Marlin/src/pins/stm32f1/pins_MD_D301.h @@ -159,7 +159,7 @@ #define ONBOARD_SPI_DEVICE 1 // SPI1 #define ONBOARD_SD_CS_PIN PA4 // Chip select for "System" SD card -#define SDSS ONBOARD_SD_CS_PIN +#define SD_SS_PIN ONBOARD_SD_CS_PIN // // Misc. Functions diff --git a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN.h b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN.h index 4e9a06f7da..353eefae76 100644 --- a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN.h +++ b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN.h @@ -225,9 +225,8 @@ #define SD_SCK_PIN PC12 #define SD_MISO_PIN PC8 #define SD_MOSI_PIN PD2 - #define SD_SS_PIN -1 #define ONBOARD_SD_CS_PIN PC11 - #define SDSS PD2 + #define SD_SS_PIN PD2 #define SD_DETECT_PIN -1 #endif diff --git a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_E3P.h b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_E3P.h index 087a064c05..02aec548d4 100644 --- a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_E3P.h +++ b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_E3P.h @@ -256,7 +256,7 @@ #define ONBOARD_SD_CS_PIN PC11 #elif SD_CONNECTION_IS(LCD) #define ENABLE_SPI1 - #define SDSS EXP2_04_PIN + #define SD_SS_PIN EXP2_04_PIN #define SD_SCK_PIN EXP2_02_PIN #define SD_MISO_PIN EXP2_01_PIN #define SD_MOSI_PIN EXP2_06_PIN diff --git a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_E3_common.h b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_E3_common.h index 31ef7f5c24..547d0f230a 100644 --- a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_E3_common.h +++ b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_E3_common.h @@ -254,8 +254,7 @@ // #define SDCARD_CONNECTION ONBOARD #define ONBOARD_SPI_DEVICE 2 // Maple -#define SDSS SD_SS_PIN -#define ONBOARD_SD_CS_PIN SD_SS_PIN +#define ONBOARD_SD_CS_PIN EXP2_04_PIN #define SD_DETECT_PIN EXP2_07_PIN #define NO_SD_HOST_DRIVE @@ -264,4 +263,4 @@ #define SD_SCK_PIN EXP2_02_PIN #define SD_MISO_PIN EXP2_01_PIN #define SD_MOSI_PIN EXP2_06_PIN -#define SD_SS_PIN EXP2_04_PIN +#define SD_SS_PIN ONBOARD_SD_CS_PIN diff --git a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_NANO_V2.h b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_NANO_V2.h index 5c09d8e807..39a54e388f 100644 --- a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_NANO_V2.h +++ b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_NANO_V2.h @@ -256,7 +256,7 @@ #define ONBOARD_SD_CS_PIN PC11 #elif SD_CONNECTION_IS(LCD) #define ENABLE_SPI1 - #define SDSS EXP2_04_PIN + #define SD_SS_PIN EXP2_04_PIN #define SD_SCK_PIN EXP2_02_PIN #define SD_MISO_PIN EXP2_01_PIN #define SD_MOSI_PIN EXP2_06_PIN diff --git a/Marlin/src/pins/stm32f1/pins_MORPHEUS.h b/Marlin/src/pins/stm32f1/pins_MORPHEUS.h index 08e5455b30..65d71fccd1 100644 --- a/Marlin/src/pins/stm32f1/pins_MORPHEUS.h +++ b/Marlin/src/pins/stm32f1/pins_MORPHEUS.h @@ -88,6 +88,6 @@ // Misc. // #define LED_PIN PC13 -#define SDSS PA3 +#define SD_SS_PIN PA3 #define TFTGLCD_CS PA4 #define SD_DETECT_PIN PC14 diff --git a/Marlin/src/pins/stm32f1/pins_PANDA_PI_V29.h b/Marlin/src/pins/stm32f1/pins_PANDA_PI_V29.h index f2b903e96d..61ee75fa2a 100644 --- a/Marlin/src/pins/stm32f1/pins_PANDA_PI_V29.h +++ b/Marlin/src/pins/stm32f1/pins_PANDA_PI_V29.h @@ -144,7 +144,7 @@ // #define ONBOARD_SPI_DEVICE 1 // SPI1 #define ONBOARD_SD_CS_PIN PA4 // Chip select for "System" SD card -#define SDSS ONBOARD_SD_CS_PIN +#define SD_SS_PIN ONBOARD_SD_CS_PIN #ifndef SDCARD_CONNECTION #define SDCARD_CONNECTION ONBOARD diff --git a/Marlin/src/pins/stm32f1/pins_STM32F1R.h b/Marlin/src/pins/stm32f1/pins_STM32F1R.h index 9cbc69149c..c17a881962 100644 --- a/Marlin/src/pins/stm32f1/pins_STM32F1R.h +++ b/Marlin/src/pins/stm32f1/pins_STM32F1R.h @@ -74,7 +74,7 @@ // // Misc. Functions // -#define SDSS PA4 +#define SD_SS_PIN PA4 #define LED_PIN PD2 // diff --git a/Marlin/src/pins/stm32f1/pins_STM3R_MINI.h b/Marlin/src/pins/stm32f1/pins_STM3R_MINI.h index e5b16460f0..d98fb70526 100644 --- a/Marlin/src/pins/stm32f1/pins_STM3R_MINI.h +++ b/Marlin/src/pins/stm32f1/pins_STM3R_MINI.h @@ -73,7 +73,7 @@ // // Misc. Functions // -#define SDSS PA15 +#define SD_SS_PIN PA15 #define LED_PIN PB2 // diff --git a/Marlin/src/pins/stm32f1/pins_TRIGORILLA_PRO.h b/Marlin/src/pins/stm32f1/pins_TRIGORILLA_PRO.h index 2f9d706b29..b611d945dc 100644 --- a/Marlin/src/pins/stm32f1/pins_TRIGORILLA_PRO.h +++ b/Marlin/src/pins/stm32f1/pins_TRIGORILLA_PRO.h @@ -199,9 +199,8 @@ #define SD_SCK_PIN PC12 #define SD_MISO_PIN PC8 #define SD_MOSI_PIN PD2 - #define SD_SS_PIN -1 #define ONBOARD_SD_CS_PIN PC11 - #define SDSS PD2 + #define SD_SS_PIN PD2 #define SD_DETECT_PIN -1 #endif diff --git a/Marlin/src/pins/stm32f4/pins_ANET_ET4.h b/Marlin/src/pins/stm32f4/pins_ANET_ET4.h index 79b6483785..794674569c 100644 --- a/Marlin/src/pins/stm32f4/pins_ANET_ET4.h +++ b/Marlin/src/pins/stm32f4/pins_ANET_ET4.h @@ -206,8 +206,7 @@ #if DISABLED(ONBOARD_SDIO) #define SOFTWARE_SPI - #define SDSS PC11 - #define SD_SS_PIN SDSS + #define SD_SS_PIN PC11 #define SD_SCK_PIN PC12 #define SD_MISO_PIN PC8 #define SD_MOSI_PIN PD2 diff --git a/Marlin/src/pins/stm32f4/pins_ARMED.h b/Marlin/src/pins/stm32f4/pins_ARMED.h index 027faf8299..8f2ae0b93a 100644 --- a/Marlin/src/pins/stm32f4/pins_ARMED.h +++ b/Marlin/src/pins/stm32f4/pins_ARMED.h @@ -135,7 +135,7 @@ // // Misc functions // -#define SDSS PE7 +#define SD_SS_PIN PE7 #define LED_PIN PB7 // Heart beat #define PS_ON_PIN PA10 #define KILL_PIN PA8 diff --git a/Marlin/src/pins/stm32f4/pins_ARTILLERY_RUBY.h b/Marlin/src/pins/stm32f4/pins_ARTILLERY_RUBY.h index 3fe629aea1..4d487355a3 100644 --- a/Marlin/src/pins/stm32f4/pins_ARTILLERY_RUBY.h +++ b/Marlin/src/pins/stm32f4/pins_ARTILLERY_RUBY.h @@ -115,13 +115,6 @@ // #define SERVO0_PIN PC3 -// -// SPI -// -#define SCK_PIN PC10 -#define MISO_PIN PC11 -#define MOSI_PIN PC12 - // // LCD / Controller // @@ -175,7 +168,7 @@ #define BEEPER_PIN PC13 #if HAS_MEDIA - #define SDSS PA15 + #define SD_SS_PIN PA15 #define SD_DETECT_PIN PD2 #endif diff --git a/Marlin/src/pins/stm32f4/pins_BLACKBEEZMINI.h b/Marlin/src/pins/stm32f4/pins_BLACKBEEZMINI.h index 2117820736..8869de6363 100644 --- a/Marlin/src/pins/stm32f4/pins_BLACKBEEZMINI.h +++ b/Marlin/src/pins/stm32f4/pins_BLACKBEEZMINI.h @@ -100,7 +100,7 @@ // // SD Card // -#define SDSS PA4 +#define SD_SS_PIN PA4 #define SD_DETECT_PIN -1 #define SD_SCK_PIN PA5 #define SD_MISO_PIN PA6 diff --git a/Marlin/src/pins/stm32f4/pins_BLACKPILL_CUSTOM.h b/Marlin/src/pins/stm32f4/pins_BLACKPILL_CUSTOM.h index 9ad0da13f5..647ab802e6 100644 --- a/Marlin/src/pins/stm32f4/pins_BLACKPILL_CUSTOM.h +++ b/Marlin/src/pins/stm32f4/pins_BLACKPILL_CUSTOM.h @@ -110,15 +110,14 @@ // SD Card // #define ONBOARD_SPI_DEVICE 1 -// #define ONBOARD_SD_CS_PIN PA4 // SDSS - #define SD_DETECT_PIN -1 #define SDCARD_CONNECTION ONBOARD //#define ONBOARD_SDIO #define NO_SD_HOST_DRIVE // This board's SD is only seen by the printer #if SD_CONNECTION_IS(ONBOARD) - #define SDSS PA4 + #define ONBOARD_SD_CS_PIN PA4 + #define SD_SS_PIN ONBOARD_SD_CS_PIN #define SD_SCK_PIN PA5 #define SD_MISO_PIN PA6 #define SD_MOSI_PIN PA7 diff --git a/Marlin/src/pins/stm32f4/pins_BLACK_STM32F407VE.h b/Marlin/src/pins/stm32f4/pins_BLACK_STM32F407VE.h index 025a1fc9f1..8bd14b219e 100644 --- a/Marlin/src/pins/stm32f4/pins_BLACK_STM32F407VE.h +++ b/Marlin/src/pins/stm32f4/pins_BLACK_STM32F407VE.h @@ -148,7 +148,7 @@ #define ONBOARD_SDIO // Use SDIO for onboard SD #if DISABLED(ONBOARD_SDIO) #define SOFTWARE_SPI // Use soft SPI for onboard SD - #define SDSS PC11 + #define SD_SS_PIN PC11 #define SD_SCK_PIN PC12 #define SD_MISO_PIN PC8 #define SD_MOSI_PIN PD2 diff --git a/Marlin/src/pins/stm32f4/pins_BTT_BTT002_V1_0.h b/Marlin/src/pins/stm32f4/pins_BTT_BTT002_V1_0.h index 42cc30407e..bcbdaedcf2 100644 --- a/Marlin/src/pins/stm32f4/pins_BTT_BTT002_V1_0.h +++ b/Marlin/src/pins/stm32f4/pins_BTT_BTT002_V1_0.h @@ -228,8 +228,6 @@ #define SD_MISO_PIN EXP2_01_PIN // SPI1 MISO #define SD_MOSI_PIN EXP2_06_PIN // SPI1 MOSI -#define SDSS EXP2_04_PIN - // // LCD / Controller // diff --git a/Marlin/src/pins/stm32f4/pins_BTT_GTR_V1_0.h b/Marlin/src/pins/stm32f4/pins_BTT_GTR_V1_0.h index de3e026b05..256868d9bc 100644 --- a/Marlin/src/pins/stm32f4/pins_BTT_GTR_V1_0.h +++ b/Marlin/src/pins/stm32f4/pins_BTT_GTR_V1_0.h @@ -347,12 +347,11 @@ #if SD_CONNECTION_IS(LCD) #define SD_DETECT_PIN EXP2_07_PIN - #define SDSS EXP2_04_PIN + #define SD_SS_PIN EXP2_04_PIN #elif SD_CONNECTION_IS(ONBOARD) - #define SDSS PA4 - #define SD_SS_PIN SDSS + #define SD_SS_PIN PA4 #define SD_SCK_PIN PA5 #define SD_MISO_PIN PA6 #define SD_MOSI_PIN PA7 diff --git a/Marlin/src/pins/stm32f4/pins_BTT_OCTOPUS_V1_common.h b/Marlin/src/pins/stm32f4/pins_BTT_OCTOPUS_V1_common.h index 53d84e020b..93cbeb11d6 100644 --- a/Marlin/src/pins/stm32f4/pins_BTT_OCTOPUS_V1_common.h +++ b/Marlin/src/pins/stm32f4/pins_BTT_OCTOPUS_V1_common.h @@ -344,8 +344,7 @@ #define SD_DETECT_PIN PC14 #elif SD_CONNECTION_IS(LCD) - #define SDSS PA4 - #define SD_SS_PIN SDSS + #define SD_SS_PIN PA4 #define SD_SCK_PIN PA5 #define SD_MISO_PIN PA6 #define SD_MOSI_PIN PA7 diff --git a/Marlin/src/pins/stm32f4/pins_BTT_SKR_MINI_E3_V3_0_1.h b/Marlin/src/pins/stm32f4/pins_BTT_SKR_MINI_E3_V3_0_1.h index 8b70b22e56..31501e3ddf 100644 --- a/Marlin/src/pins/stm32f4/pins_BTT_SKR_MINI_E3_V3_0_1.h +++ b/Marlin/src/pins/stm32f4/pins_BTT_SKR_MINI_E3_V3_0_1.h @@ -348,7 +348,6 @@ #define ONBOARD_SD_CS_PIN PA4 // Chip select for "System" SD card #define ENABLE_SPI1 -#define SDSS ONBOARD_SD_CS_PIN #define SD_SS_PIN ONBOARD_SD_CS_PIN #define SD_SCK_PIN PA5 #define SD_MISO_PIN PA6 diff --git a/Marlin/src/pins/stm32f4/pins_BTT_SKR_PRO_common.h b/Marlin/src/pins/stm32f4/pins_BTT_SKR_PRO_common.h index 0b8dd71f74..943c0ed761 100644 --- a/Marlin/src/pins/stm32f4/pins_BTT_SKR_PRO_common.h +++ b/Marlin/src/pins/stm32f4/pins_BTT_SKR_PRO_common.h @@ -343,7 +343,7 @@ #if SD_CONNECTION_IS(LCD) #define SD_DETECT_PIN EXP2_07_PIN - #define SDSS EXP2_04_PIN + #define SD_SS_PIN EXP2_04_PIN #elif SD_CONNECTION_IS(ONBOARD) @@ -352,7 +352,7 @@ // function with Hardware SPI. This is not currently configurable in the HAL, // so force Software SPI to work around this issue. #define SOFTWARE_SPI - #define SDSS PA4 + #define SD_SS_PIN PA4 #define SD_SCK_PIN PA5 #define SD_MISO_PIN PA6 #define SD_MOSI_PIN PB5 diff --git a/Marlin/src/pins/stm32f4/pins_BTT_SKR_V2_0_common.h b/Marlin/src/pins/stm32f4/pins_BTT_SKR_V2_0_common.h index d0d78ed7f5..692b50be40 100644 --- a/Marlin/src/pins/stm32f4/pins_BTT_SKR_V2_0_common.h +++ b/Marlin/src/pins/stm32f4/pins_BTT_SKR_V2_0_common.h @@ -357,8 +357,7 @@ // Must use soft SPI because Marlin's default hardware SPI is tied to LCD's EXP2 // #if SD_CONNECTION_IS(LCD) - #define SDSS EXP2_04_PIN - #define SD_SS_PIN SDSS + #define SD_SS_PIN EXP2_04_PIN #define SD_SCK_PIN EXP2_02_PIN #define SD_MISO_PIN EXP2_01_PIN #define SD_MOSI_PIN EXP2_06_PIN diff --git a/Marlin/src/pins/stm32f4/pins_FLYF407ZG.h b/Marlin/src/pins/stm32f4/pins_FLYF407ZG.h index d63c6ea724..ac8a75ecd2 100644 --- a/Marlin/src/pins/stm32f4/pins_FLYF407ZG.h +++ b/Marlin/src/pins/stm32f4/pins_FLYF407ZG.h @@ -218,7 +218,7 @@ #if DISABLED(ONBOARD_SDIO) #define SOFTWARE_SPI // Use soft SPI for onboard SD - #define SDSS PC11 + #define SD_SS_PIN PC11 #define SD_SCK_PIN PC12 #define SD_MISO_PIN PC8 #define SD_MOSI_PIN PD2 @@ -229,7 +229,7 @@ #define SD_SCK_PIN EXP2_02_PIN #define SD_MISO_PIN EXP2_01_PIN #define SD_MOSI_PIN EXP2_06_PIN - #define SDSS EXP2_04_PIN + #define SD_SS_PIN EXP2_04_PIN #define SD_DETECT_PIN EXP2_07_PIN #endif diff --git a/Marlin/src/pins/stm32f4/pins_FYSETC_CHEETAH_V20.h b/Marlin/src/pins/stm32f4/pins_FYSETC_CHEETAH_V20.h index 7d7126b640..6fd927f783 100644 --- a/Marlin/src/pins/stm32f4/pins_FYSETC_CHEETAH_V20.h +++ b/Marlin/src/pins/stm32f4/pins_FYSETC_CHEETAH_V20.h @@ -129,7 +129,7 @@ // // Misc. Functions // -#define SDSS PA4 +#define SD_SS_PIN PA4 #define SD_DETECT_PIN PC3 #ifndef RGB_LED_R_PIN diff --git a/Marlin/src/pins/stm32f4/pins_FYSETC_CHEETAH_V30.h b/Marlin/src/pins/stm32f4/pins_FYSETC_CHEETAH_V30.h index 3da978c06f..54e1acc936 100644 --- a/Marlin/src/pins/stm32f4/pins_FYSETC_CHEETAH_V30.h +++ b/Marlin/src/pins/stm32f4/pins_FYSETC_CHEETAH_V30.h @@ -148,7 +148,7 @@ // Misc. Functions // #if 0 - #define SDSS PA4 + #define SD_SS_PIN PA4 #define SD_DETECT_PIN PC3 #endif @@ -209,7 +209,7 @@ #define SD_MISO_PIN EXP2_10_PIN #define SD_MOSI_PIN EXP2_05_PIN -#define SDSS EXP2_07_PIN +#define SD_SS_PIN EXP2_07_PIN #define SD_DETECT_PIN EXP2_04_PIN #if HAS_WIRED_LCD diff --git a/Marlin/src/pins/stm32f4/pins_FYSETC_S6_common.h b/Marlin/src/pins/stm32f4/pins_FYSETC_S6_common.h index b016db655c..ce61bce1cf 100644 --- a/Marlin/src/pins/stm32f4/pins_FYSETC_S6_common.h +++ b/Marlin/src/pins/stm32f4/pins_FYSETC_S6_common.h @@ -185,7 +185,7 @@ #define SD_MISO_PIN EXP2_01_PIN #define SD_MOSI_PIN EXP2_06_PIN -#define SDSS EXP2_04_PIN +#define SD_SS_PIN EXP2_04_PIN #define SD_DETECT_PIN EXP2_07_PIN // @@ -232,7 +232,7 @@ #define BTN_EN1 EXP2_03_PIN #define BTN_EN2 EXP2_05_PIN - #define LCD_SDSS EXP2_04_PIN + #define LCD_SDSS_PIN EXP2_04_PIN #define LCD_PINS_EN EXP1_03_PIN #define LCD_PINS_D4 EXP1_05_PIN diff --git a/Marlin/src/pins/stm32f4/pins_FYSETC_SPIDER_KING407.h b/Marlin/src/pins/stm32f4/pins_FYSETC_SPIDER_KING407.h index 2164223d44..b01b5bda6a 100644 --- a/Marlin/src/pins/stm32f4/pins_FYSETC_SPIDER_KING407.h +++ b/Marlin/src/pins/stm32f4/pins_FYSETC_SPIDER_KING407.h @@ -255,7 +255,7 @@ #define SD_MISO_PIN EXP2_10_PIN #define SD_MOSI_PIN EXP2_05_PIN -#define SDSS EXP2_07_PIN +#define SD_SS_PIN EXP2_07_PIN #define SD_DETECT_PIN EXP2_04_PIN // @@ -291,7 +291,7 @@ #define BTN_EN1 EXP2_08_PIN #define BTN_EN2 EXP2_06_PIN - #define LCD_SDSS EXP2_07_PIN + #define LCD_SDSS_PIN EXP2_07_PIN #define LCD_PINS_EN EXP1_08_PIN #define LCD_PINS_D4 EXP1_06_PIN diff --git a/Marlin/src/pins/stm32f4/pins_I3DBEEZ9.h b/Marlin/src/pins/stm32f4/pins_I3DBEEZ9.h index 79599d5928..e36bdae3a8 100644 --- a/Marlin/src/pins/stm32f4/pins_I3DBEEZ9.h +++ b/Marlin/src/pins/stm32f4/pins_I3DBEEZ9.h @@ -385,7 +385,7 @@ #if SD_CONNECTION_IS(LCD) #define SD_DETECT_PIN EXP2_07_PIN - #define SDSS EXP2_04_PIN + #define SD_SS_PIN EXP2_04_PIN #elif SD_CONNECTION_IS(ONBOARD) @@ -394,7 +394,7 @@ // function with Hardware SPI. This is not currently configurable in the HAL, // so force Software SPI to work around this issue. #define SOFTWARE_SPI - #define SDSS PA4 + #define SD_SS_PIN PA4 #define SD_SCK_PIN PA5 #define SD_MISO_PIN PA6 #define SD_MOSI_PIN PB5 diff --git a/Marlin/src/pins/stm32f4/pins_LERDGE_K.h b/Marlin/src/pins/stm32f4/pins_LERDGE_K.h index 4b6dc89f06..402e7f5ddc 100644 --- a/Marlin/src/pins/stm32f4/pins_LERDGE_K.h +++ b/Marlin/src/pins/stm32f4/pins_LERDGE_K.h @@ -209,7 +209,6 @@ #define SD_MISO_PIN PC8 #define SD_MOSI_PIN PD2 #define SD_SS_PIN PC11 - #define SDSS PC11 #endif // diff --git a/Marlin/src/pins/stm32f4/pins_LERDGE_S.h b/Marlin/src/pins/stm32f4/pins_LERDGE_S.h index b72e146ad3..0d129cb624 100644 --- a/Marlin/src/pins/stm32f4/pins_LERDGE_S.h +++ b/Marlin/src/pins/stm32f4/pins_LERDGE_S.h @@ -169,7 +169,6 @@ #define SD_MISO_PIN PC8 #define SD_MOSI_PIN PD2 #define SD_SS_PIN PC11 - #define SDSS PC11 #endif // diff --git a/Marlin/src/pins/stm32f4/pins_LERDGE_X.h b/Marlin/src/pins/stm32f4/pins_LERDGE_X.h index 43b4f02961..6aa5d348dc 100644 --- a/Marlin/src/pins/stm32f4/pins_LERDGE_X.h +++ b/Marlin/src/pins/stm32f4/pins_LERDGE_X.h @@ -126,7 +126,6 @@ #define SD_MISO_PIN PC8 #define SD_MOSI_PIN PD2 #define SD_SS_PIN PC11 - #define SDSS PC11 #endif // diff --git a/Marlin/src/pins/stm32f4/pins_MELLOW_FLY_E3_V2.h b/Marlin/src/pins/stm32f4/pins_MELLOW_FLY_E3_V2.h index f24e61c750..3fff8515b9 100644 --- a/Marlin/src/pins/stm32f4/pins_MELLOW_FLY_E3_V2.h +++ b/Marlin/src/pins/stm32f4/pins_MELLOW_FLY_E3_V2.h @@ -252,8 +252,7 @@ // Must use soft SPI because Marlin's default hardware SPI is tied to LCD's EXP2 // #if SD_CONNECTION_IS(LCD) - #define SDSS EXP2_04_PIN - #define SD_SS_PIN SDSS + #define SD_SS_PIN EXP2_04_PIN #define SD_SCK_PIN EXP2_02_PIN #define SD_MISO_PIN EXP2_01_PIN #define SD_MOSI_PIN EXP2_06_PIN diff --git a/Marlin/src/pins/stm32f4/pins_MKS_MONSTER8_common.h b/Marlin/src/pins/stm32f4/pins_MKS_MONSTER8_common.h index 9c81eb1c85..38ed31cabe 100644 --- a/Marlin/src/pins/stm32f4/pins_MKS_MONSTER8_common.h +++ b/Marlin/src/pins/stm32f4/pins_MKS_MONSTER8_common.h @@ -257,15 +257,14 @@ // #if SD_CONNECTION_IS(ONBOARD) #define ENABLE_SPI3 - #define SD_SS_PIN -1 - #define SDSS PC9 + #define SD_SS_PIN PC9 #define SD_SCK_PIN PC10 #define SD_MISO_PIN PC11 #define SD_MOSI_PIN PC12 #define SD_DETECT_PIN PC4 // SD_DETECT_PIN doesn't work with NO_SD_HOST_DRIVE disabled #elif SD_CONNECTION_IS(LCD) #define ENABLE_SPI1 - #define SDSS EXP2_04_PIN + #define SD_SS_PIN EXP2_04_PIN #define SD_SCK_PIN EXP2_02_PIN #define SD_MISO_PIN EXP2_01_PIN #define SD_MOSI_PIN EXP2_06_PIN diff --git a/Marlin/src/pins/stm32f4/pins_MKS_ROBIN2.h b/Marlin/src/pins/stm32f4/pins_MKS_ROBIN2.h index 3018a2d68c..6004643e6e 100644 --- a/Marlin/src/pins/stm32f4/pins_MKS_ROBIN2.h +++ b/Marlin/src/pins/stm32f4/pins_MKS_ROBIN2.h @@ -102,8 +102,6 @@ // // Misc. Functions // -#define SDSS -1 // PB12 - #define SD_DETECT_PIN PF9 #define BEEPER_PIN PG2 diff --git a/Marlin/src/pins/stm32f4/pins_MKS_ROBIN_NANO_V3_common.h b/Marlin/src/pins/stm32f4/pins_MKS_ROBIN_NANO_V3_common.h index 8f4e5ff6b8..c9ecc617b7 100644 --- a/Marlin/src/pins/stm32f4/pins_MKS_ROBIN_NANO_V3_common.h +++ b/Marlin/src/pins/stm32f4/pins_MKS_ROBIN_NANO_V3_common.h @@ -216,8 +216,7 @@ // #if SD_CONNECTION_IS(ONBOARD) #define ENABLE_SPI3 - #define SD_SS_PIN -1 - #define SDSS PC9 + #define SD_SS_PIN PC9 #define SD_SCK_PIN PC10 #define SD_MISO_PIN PC11 #define SD_MOSI_PIN PC12 @@ -267,7 +266,7 @@ // #if SD_CONNECTION_IS(LCD) #define ENABLE_SPI1 - #define SDSS EXP2_04_PIN + #define SD_SS_PIN EXP2_04_PIN #define SD_SCK_PIN EXP2_02_PIN #define SD_MISO_PIN EXP2_01_PIN #define SD_MOSI_PIN EXP2_06_PIN diff --git a/Marlin/src/pins/stm32f4/pins_MKS_ROBIN_PRO_V2.h b/Marlin/src/pins/stm32f4/pins_MKS_ROBIN_PRO_V2.h index e8b9938c95..11edadcd58 100644 --- a/Marlin/src/pins/stm32f4/pins_MKS_ROBIN_PRO_V2.h +++ b/Marlin/src/pins/stm32f4/pins_MKS_ROBIN_PRO_V2.h @@ -219,8 +219,7 @@ #define SD_SPI MARLIN_SPI(HardwareSPI3, PC9) #else #define ENABLE_SPI3 - #define SD_SS_PIN -1 - #define SDSS PC9 + #define SD_SS_PIN PC9 #define SD_SCK_PIN PC10 #define SD_MISO_PIN PC11 #define SD_MOSI_PIN PC12 @@ -261,7 +260,7 @@ /* #if SD_CONNECTION_IS(LCD) #define ENABLE_SPI1 - #define SDSS EXP2_04_PIN + #define SD_SS_PIN EXP2_04_PIN #define SD_SCK_PIN EXP2_02_PIN #define SD_MISO_PIN EXP2_01_PIN #define SD_MOSI_PIN EXP2_06_PIN diff --git a/Marlin/src/pins/stm32f4/pins_MKS_SKIPR_V1_0.h b/Marlin/src/pins/stm32f4/pins_MKS_SKIPR_V1_0.h index a0b088db4b..7528ac77f0 100644 --- a/Marlin/src/pins/stm32f4/pins_MKS_SKIPR_V1_0.h +++ b/Marlin/src/pins/stm32f4/pins_MKS_SKIPR_V1_0.h @@ -267,7 +267,6 @@ #elif SD_CONNECTION_IS(CUSTOM_CABLE) #error "CUSTOM_CABLE is not a supported SDCARD_CONNECTION for this board" #endif - #define SDSS SD_SS_PIN #endif // diff --git a/Marlin/src/pins/stm32f4/pins_OPULO_LUMEN_REV3.h b/Marlin/src/pins/stm32f4/pins_OPULO_LUMEN_REV3.h index 010ae0ec05..33c0eaae8f 100644 --- a/Marlin/src/pins/stm32f4/pins_OPULO_LUMEN_REV3.h +++ b/Marlin/src/pins/stm32f4/pins_OPULO_LUMEN_REV3.h @@ -155,13 +155,9 @@ // // SPI // -#define MISO_PIN PB4 -#define MOSI_PIN PB5 -#define SCK_PIN PB3 - -#define TMC_SPI_MISO MISO_PIN -#define TMC_SPI_MOSI MOSI_PIN -#define TMC_SPI_SCK SCK_PIN +#define TMC_SPI_MISO PIN_SPI_MISO +#define TMC_SPI_MOSI PIN_SPI_MOSI +#define TMC_SPI_SCK PIN_SPI_SCK // // I2C diff --git a/Marlin/src/pins/stm32f4/pins_OPULO_LUMEN_REV4.h b/Marlin/src/pins/stm32f4/pins_OPULO_LUMEN_REV4.h index 0f275788f9..11fe08a980 100644 --- a/Marlin/src/pins/stm32f4/pins_OPULO_LUMEN_REV4.h +++ b/Marlin/src/pins/stm32f4/pins_OPULO_LUMEN_REV4.h @@ -155,13 +155,9 @@ // // SPI // -#define MISO_PIN PB4 -#define MOSI_PIN PB5 -#define SCK_PIN PB3 - -#define TMC_SPI_MISO MISO_PIN -#define TMC_SPI_MOSI MOSI_PIN -#define TMC_SPI_SCK SCK_PIN +#define TMC_SPI_MISO PIN_SPI_MISO +#define TMC_SPI_MOSI PIN_SPI_MOSI +#define TMC_SPI_SCK PIN_SPI_SCK // // I2C diff --git a/Marlin/src/pins/stm32f4/pins_RUMBA32_common.h b/Marlin/src/pins/stm32f4/pins_RUMBA32_common.h index 4574df53ac..02ed9d5099 100644 --- a/Marlin/src/pins/stm32f4/pins_RUMBA32_common.h +++ b/Marlin/src/pins/stm32f4/pins_RUMBA32_common.h @@ -135,7 +135,7 @@ #define PS_ON_PIN PE11 #define KILL_PIN PC5 -#define SDSS PA2 +#define SD_SS_PIN PA2 #define SD_DETECT_PIN PB0 #define BEEPER_PIN PE8 diff --git a/Marlin/src/pins/stm32f4/pins_TH3D_EZBOARD_V2.h b/Marlin/src/pins/stm32f4/pins_TH3D_EZBOARD_V2.h index cec7780b94..4d99b524f0 100644 --- a/Marlin/src/pins/stm32f4/pins_TH3D_EZBOARD_V2.h +++ b/Marlin/src/pins/stm32f4/pins_TH3D_EZBOARD_V2.h @@ -190,13 +190,13 @@ //#define SOFTWARE_SPI #define CUSTOM_SPI_PINS -#define SDSS PA4 +#define ONBOARD_SD_CS_PIN PA4 +//#define SD_DETECT_PIN -1 + +#define SD_SS_PIN ONBOARD_SD_CS_PIN #define SD_SCK_PIN PA5 #define SD_MISO_PIN PA6 #define SD_MOSI_PIN PA7 -#define SD_SS_PIN SDSS -//#define SD_DETECT_PIN -1 -//#define ONBOARD_SD_CS_PIN SDSS // // LCD / Controller diff --git a/Marlin/src/pins/stm32f4/pins_XTLW_CLIMBER_8TH.h b/Marlin/src/pins/stm32f4/pins_XTLW_CLIMBER_8TH.h index 9ab3331d4c..3ed778c16f 100644 --- a/Marlin/src/pins/stm32f4/pins_XTLW_CLIMBER_8TH.h +++ b/Marlin/src/pins/stm32f4/pins_XTLW_CLIMBER_8TH.h @@ -177,8 +177,7 @@ #define SDIO_CMD_PIN PD2 #elif SD_CONNECTION_IS(LCD) #define CUSTOM_SPI_PINS - #define SDSS PA4 - #define SD_SS_PIN SDSS + #define SD_SS_PIN PA4 #define SD_SCK_PIN PA5 #define SD_MISO_PIN PA6 #define SD_MOSI_PIN PA7 diff --git a/Marlin/src/pins/stm32f7/pins_NUCLEO_F767ZI.h b/Marlin/src/pins/stm32f7/pins_NUCLEO_F767ZI.h index 46840868ab..4355a82254 100644 --- a/Marlin/src/pins/stm32f7/pins_NUCLEO_F767ZI.h +++ b/Marlin/src/pins/stm32f7/pins_NUCLEO_F767ZI.h @@ -167,7 +167,6 @@ #define SD_MISO_PIN PA6 #define SD_MOSI_PIN PA7 #define SD_SS_PIN PA4 -#define SDSS PA4 #define LED_PIN LED_BLUE diff --git a/Marlin/src/pins/stm32f7/pins_REMRAM_V1.h b/Marlin/src/pins/stm32f7/pins_REMRAM_V1.h index 2db21be45e..7cf8d813a0 100644 --- a/Marlin/src/pins/stm32f7/pins_REMRAM_V1.h +++ b/Marlin/src/pins/stm32f7/pins_REMRAM_V1.h @@ -110,8 +110,8 @@ #define SERVO0_PIN 26 // PWM_EXT1 #define SERVO1_PIN 27 // PWM_EXT2 -#define SDSS 57 // Onboard SD card reader -//#define SDSS 9 // LCD SD card reader +#define SD_SS_PIN 57 // Onboard SD card reader +//#define SD_SS_PIN 9 // LCD SD card reader #define LED_PIN 21 // STATUS_LED // diff --git a/Marlin/src/pins/stm32g0/pins_BTT_MANTA_E3_EZ_V1_0.h b/Marlin/src/pins/stm32g0/pins_BTT_MANTA_E3_EZ_V1_0.h index ee7ea42bde..a3b305b04c 100644 --- a/Marlin/src/pins/stm32g0/pins_BTT_MANTA_E3_EZ_V1_0.h +++ b/Marlin/src/pins/stm32g0/pins_BTT_MANTA_E3_EZ_V1_0.h @@ -326,7 +326,6 @@ #define ONBOARD_SD_CS_PIN PC13 // Chip select for "System" SD card #define ENABLE_SPI3 -#define SDSS ONBOARD_SD_CS_PIN #define SD_SS_PIN ONBOARD_SD_CS_PIN #define SD_SCK_PIN PC10 #define SD_MISO_PIN PC11 diff --git a/Marlin/src/pins/stm32g0/pins_BTT_MANTA_M4P_V2_1.h b/Marlin/src/pins/stm32g0/pins_BTT_MANTA_M4P_V2_1.h index 4c4a6ca928..38d75a3d94 100644 --- a/Marlin/src/pins/stm32g0/pins_BTT_MANTA_M4P_V2_1.h +++ b/Marlin/src/pins/stm32g0/pins_BTT_MANTA_M4P_V2_1.h @@ -184,8 +184,7 @@ // Must use soft SPI because Marlin's default hardware SPI is tied to LCD's EXP2 // #if SD_CONNECTION_IS(LCD) - #define SDSS EXP2_04_PIN - #define SD_SS_PIN SDSS + #define SD_SS_PIN EXP2_04_PIN #define SD_SCK_PIN EXP2_02_PIN #define SD_MISO_PIN EXP2_01_PIN #define SD_MOSI_PIN EXP2_06_PIN diff --git a/Marlin/src/pins/stm32g0/pins_BTT_MANTA_M5P_V1_0.h b/Marlin/src/pins/stm32g0/pins_BTT_MANTA_M5P_V1_0.h index 90379e06e6..b2981f6734 100644 --- a/Marlin/src/pins/stm32g0/pins_BTT_MANTA_M5P_V1_0.h +++ b/Marlin/src/pins/stm32g0/pins_BTT_MANTA_M5P_V1_0.h @@ -210,8 +210,7 @@ // Must use soft SPI because Marlin's default hardware SPI is tied to LCD's EXP2 // #if SD_CONNECTION_IS(LCD) - #define SDSS EXP2_04_PIN - #define SD_SS_PIN SDSS + #define SD_SS_PIN EXP2_04_PIN #define SD_SCK_PIN EXP2_02_PIN #define SD_MISO_PIN EXP2_01_PIN #define SD_MOSI_PIN EXP2_06_PIN diff --git a/Marlin/src/pins/stm32g0/pins_BTT_MANTA_M8P_common.h b/Marlin/src/pins/stm32g0/pins_BTT_MANTA_M8P_common.h index e007292089..b05515003e 100644 --- a/Marlin/src/pins/stm32g0/pins_BTT_MANTA_M8P_common.h +++ b/Marlin/src/pins/stm32g0/pins_BTT_MANTA_M8P_common.h @@ -259,8 +259,7 @@ // Must use soft SPI because Marlin's default hardware SPI is tied to LCD's EXP2 // #if SD_CONNECTION_IS(LCD) - #define SDSS EXP2_04_PIN - #define SD_SS_PIN SDSS + #define SD_SS_PIN EXP2_04_PIN #define SD_SCK_PIN EXP2_02_PIN #define SD_MISO_PIN EXP2_01_PIN #define SD_MOSI_PIN EXP2_06_PIN diff --git a/Marlin/src/pins/stm32g0/pins_BTT_SKRAT_V1_0.h b/Marlin/src/pins/stm32g0/pins_BTT_SKRAT_V1_0.h index 7d3c249b90..9452ceb31d 100644 --- a/Marlin/src/pins/stm32g0/pins_BTT_SKRAT_V1_0.h +++ b/Marlin/src/pins/stm32g0/pins_BTT_SKRAT_V1_0.h @@ -380,7 +380,6 @@ #define ONBOARD_SD_CS_PIN PB8 // Chip select for "System" SD card #define ENABLE_SPI1 -#define SDSS ONBOARD_SD_CS_PIN #define SD_SS_PIN ONBOARD_SD_CS_PIN #define SD_SCK_PIN PA5 #define SD_MISO_PIN PA6 diff --git a/Marlin/src/pins/stm32g0/pins_BTT_SKR_MINI_E3_V3_0.h b/Marlin/src/pins/stm32g0/pins_BTT_SKR_MINI_E3_V3_0.h index 3afc829fed..12d1f5308a 100644 --- a/Marlin/src/pins/stm32g0/pins_BTT_SKR_MINI_E3_V3_0.h +++ b/Marlin/src/pins/stm32g0/pins_BTT_SKR_MINI_E3_V3_0.h @@ -443,7 +443,6 @@ #define ONBOARD_SD_CS_PIN PA4 // Chip select for "System" SD card #define ENABLE_SPI1 -#define SDSS ONBOARD_SD_CS_PIN #define SD_SS_PIN ONBOARD_SD_CS_PIN #define SD_SCK_PIN PA5 #define SD_MISO_PIN PA6 diff --git a/Marlin/src/pins/stm32h7/pins_BTT_KRAKEN_V1_0.h b/Marlin/src/pins/stm32h7/pins_BTT_KRAKEN_V1_0.h index 9f67c7a14c..8a16a04536 100644 --- a/Marlin/src/pins/stm32h7/pins_BTT_KRAKEN_V1_0.h +++ b/Marlin/src/pins/stm32h7/pins_BTT_KRAKEN_V1_0.h @@ -387,16 +387,14 @@ #elif SD_DETECT_STATE == LOW #error "BOARD_BTT_KRAKEN_V1_0 onboard SD requires SD_DETECT_STATE set to HIGH." #endif - #define SDSS PB12 - #define SD_SS_PIN SDSS + #define SD_SS_PIN PB12 #define SD_SCK_PIN PB13 #define SD_MISO_PIN PB14 #define SD_MOSI_PIN PB15 #define SD_DETECT_PIN PE15 #define SOFTWARE_SPI #elif SD_CONNECTION_IS(LCD) - #define SDSS EXP2_04_PIN - #define SD_SS_PIN SDSS + #define SD_SS_PIN EXP2_04_PIN #define SD_SCK_PIN EXP2_02_PIN #define SD_MISO_PIN EXP2_01_PIN #define SD_MOSI_PIN EXP2_06_PIN diff --git a/Marlin/src/pins/stm32h7/pins_BTT_MANTA_M8P_V2_0.h b/Marlin/src/pins/stm32h7/pins_BTT_MANTA_M8P_V2_0.h index 496668513d..4afea71f03 100644 --- a/Marlin/src/pins/stm32h7/pins_BTT_MANTA_M8P_V2_0.h +++ b/Marlin/src/pins/stm32h7/pins_BTT_MANTA_M8P_V2_0.h @@ -383,16 +383,14 @@ #elif SD_DETECT_STATE == LOW #error "BOARD_BTT_MANTA_M8P_V2_0 onboard SD requires SD_DETECT_STATE set to HIGH." #endif - #define SDSS PB12 - #define SD_SS_PIN SDSS + #define SD_SS_PIN PB12 #define SD_SCK_PIN PB13 #define SD_MISO_PIN PB14 #define SD_MOSI_PIN PB15 #define SD_DETECT_PIN -1 #define SOFTWARE_SPI #elif SD_CONNECTION_IS(LCD) - #define SDSS EXP2_04_PIN - #define SD_SS_PIN SDSS + #define SD_SS_PIN EXP2_04_PIN #define SD_SCK_PIN EXP2_02_PIN #define SD_MISO_PIN EXP2_01_PIN #define SD_MOSI_PIN EXP2_06_PIN diff --git a/Marlin/src/pins/stm32h7/pins_BTT_OCTOPUS_MAX_EZ.h b/Marlin/src/pins/stm32h7/pins_BTT_OCTOPUS_MAX_EZ.h index a6948cd08c..eb54293936 100644 --- a/Marlin/src/pins/stm32h7/pins_BTT_OCTOPUS_MAX_EZ.h +++ b/Marlin/src/pins/stm32h7/pins_BTT_OCTOPUS_MAX_EZ.h @@ -373,16 +373,14 @@ #elif SD_DETECT_STATE == LOW #error "BOARD_BTT_OCTOPUS_MAX_EZ onboard SD requires SD_DETECT_STATE set to HIGH." #endif - #define SDSS PB12 - #define SD_SS_PIN SDSS + #define SD_SS_PIN PB12 #define SD_SCK_PIN PE12 #define SD_MISO_PIN PE13 #define SD_MOSI_PIN PE14 #define SD_DETECT_PIN PB13 #define SOFTWARE_SPI #elif SD_CONNECTION_IS(LCD) - #define SDSS EXP2_04_PIN - #define SD_SS_PIN SDSS + #define SD_SS_PIN EXP2_04_PIN #define SD_SCK_PIN EXP2_02_PIN #define SD_MISO_PIN EXP2_01_PIN #define SD_MOSI_PIN EXP2_06_PIN diff --git a/Marlin/src/pins/stm32h7/pins_BTT_OCTOPUS_PRO_V1_common.h b/Marlin/src/pins/stm32h7/pins_BTT_OCTOPUS_PRO_V1_common.h index 45ca3c5588..787fa84c1c 100644 --- a/Marlin/src/pins/stm32h7/pins_BTT_OCTOPUS_PRO_V1_common.h +++ b/Marlin/src/pins/stm32h7/pins_BTT_OCTOPUS_PRO_V1_common.h @@ -349,8 +349,7 @@ #define SD_DETECT_PIN PC14 #elif SD_CONNECTION_IS(LCD) - #define SDSS PA4 - #define SD_SS_PIN SDSS + #define SD_SS_PIN PA4 #define SD_SCK_PIN PA5 #define SD_MISO_PIN PA6 #define SD_MOSI_PIN PA7 diff --git a/Marlin/src/pins/stm32h7/pins_BTT_SKR_SE_BX_common.h b/Marlin/src/pins/stm32h7/pins_BTT_SKR_SE_BX_common.h index f6f8442cdf..76817cae81 100644 --- a/Marlin/src/pins/stm32h7/pins_BTT_SKR_SE_BX_common.h +++ b/Marlin/src/pins/stm32h7/pins_BTT_SKR_SE_BX_common.h @@ -258,8 +258,7 @@ #endif #define SOFTWARE_SPI -#define SDSS PA15 -#define SD_SS_PIN SDSS +#define SD_SS_PIN PA15 #define SD_SCK_PIN PC10 #define SD_MISO_PIN PC11 #define SD_MOSI_PIN PC12 diff --git a/Marlin/src/pins/stm32h7/pins_BTT_SKR_V3_0_common.h b/Marlin/src/pins/stm32h7/pins_BTT_SKR_V3_0_common.h index fce16aebf1..74cb78f6e5 100644 --- a/Marlin/src/pins/stm32h7/pins_BTT_SKR_V3_0_common.h +++ b/Marlin/src/pins/stm32h7/pins_BTT_SKR_V3_0_common.h @@ -350,8 +350,7 @@ // Must use soft SPI because Marlin's default hardware SPI is tied to LCD's EXP2 // #if SD_CONNECTION_IS(LCD) - #define SDSS EXP2_04_PIN - #define SD_SS_PIN SDSS + #define SD_SS_PIN EXP2_04_PIN #define SD_SCK_PIN EXP2_02_PIN #define SD_MISO_PIN EXP2_01_PIN #define SD_MOSI_PIN EXP2_06_PIN diff --git a/Marlin/src/pins/teensy2/pins_5DPRINT.h b/Marlin/src/pins/teensy2/pins_5DPRINT.h index 1b1bbf122d..93c8c5434e 100644 --- a/Marlin/src/pins/teensy2/pins_5DPRINT.h +++ b/Marlin/src/pins/teensy2/pins_5DPRINT.h @@ -139,7 +139,7 @@ // // Misc. Functions // -#define SDSS 20 // B0 +#define SD_SS_PIN 20 // B0 //DIGIPOTS slave addresses #ifndef DIGIPOT_I2C_ADDRESS_A diff --git a/Marlin/src/pins/teensy2/pins_BRAINWAVE_PRO.h b/Marlin/src/pins/teensy2/pins_BRAINWAVE_PRO.h index a1ef48e524..1b28e59068 100644 --- a/Marlin/src/pins/teensy2/pins_BRAINWAVE_PRO.h +++ b/Marlin/src/pins/teensy2/pins_BRAINWAVE_PRO.h @@ -133,6 +133,6 @@ // // Misc. Functions // -#define SDSS 20 // B0 +#define SD_SS_PIN 20 // B0 #define SD_DETECT_PIN 24 // B4 #define LED_PIN 13 // C3 diff --git a/Marlin/src/pins/teensy2/pins_PRINTRBOARD.h b/Marlin/src/pins/teensy2/pins_PRINTRBOARD.h index 6dc4ab8392..653892f2a9 100644 --- a/Marlin/src/pins/teensy2/pins_PRINTRBOARD.h +++ b/Marlin/src/pins/teensy2/pins_PRINTRBOARD.h @@ -146,7 +146,7 @@ #define BTN_EN2 3 // D3 RX1 JP2-7 #define BTN_ENC 45 // F7 TDI JP2-12 - #define SDSS 43 // F5 TMS JP2-8 + #define SD_SS_PIN 43 // F5 TMS JP2-8 #define STAT_LED_RED_PIN 12 // C2 JP11-14 #define STAT_LED_BLUE_PIN 10 // C0 JP11-12 @@ -159,7 +159,7 @@ #define BTN_EN2 2 // D2 TX1 JP2-5 #define BTN_ENC 41 // F3 JP2-4 - #define SDSS 38 // F0 B-THERM connector - use SD card on Panelolu2 + #define SD_SS_PIN 38 // F0 B-THERM connector - use SD card on Panelolu2 #undef LCD_PINS_EN // not used, causes false pin conflict report #else @@ -173,5 +173,5 @@ #endif // HAS_WIRED_LCD && IS_NEWPANEL #ifndef SDSS - #define SDSS 26 // B6 SDCS + #define SD_SS_PIN 26 // B6 SDCS #endif diff --git a/Marlin/src/pins/teensy2/pins_PRINTRBOARD_REVF.h b/Marlin/src/pins/teensy2/pins_PRINTRBOARD_REVF.h index ef70d1a2cb..0c4a8028c8 100644 --- a/Marlin/src/pins/teensy2/pins_PRINTRBOARD_REVF.h +++ b/Marlin/src/pins/teensy2/pins_PRINTRBOARD_REVF.h @@ -224,7 +224,7 @@ #define BTN_EN2 3 // D3 RX1 JP2-7 #define BTN_ENC 45 // F7 TDI JP2-12 - #define SDSS 3 // F5 TMS JP2-8 + #define SD_SS_PIN 3 // F5 TMS JP2-8 #define STAT_LED_RED_PIN 12 // C2 JP11-14 #define STAT_LED_BLUE_PIN 10 // C0 JP11-12 @@ -235,7 +235,7 @@ #if DISABLED(USE_INTERNAL_SD) // PIN FASTIO PIN# ATUSB90 PIN# Teensy2.0++ PIN# Printrboard RevF Conn. MKSLCD12864 PIN# - #define SDSS 11 // 36 C1 EXP2-13 EXP2-07 + #define SD_SS_PIN 11 // 36 C1 EXP2-13 EXP2-07 #define SD_DETECT_PIN 9 // 34 E1 EXP2-11 EXP2-04 #endif @@ -272,7 +272,7 @@ // // PIN FASTIO PIN# ATUSB90 PIN# Teensy2.0++ PIN# Printrboard RevF Conn. #ifndef SDSS - #define SDSS 20 // 10 B0 + #define SD_SS_PIN 20 // 10 B0 #endif /** diff --git a/Marlin/src/pins/teensy2/pins_SAV_MKI.h b/Marlin/src/pins/teensy2/pins_SAV_MKI.h index a0d056f850..725bc4abf7 100644 --- a/Marlin/src/pins/teensy2/pins_SAV_MKI.h +++ b/Marlin/src/pins/teensy2/pins_SAV_MKI.h @@ -122,7 +122,7 @@ // // Misc. Functions // -#define SDSS 20 // B0 +#define SD_SS_PIN 20 // B0 // Extension header pin mapping // ---------------------------- diff --git a/Marlin/src/pins/teensy2/pins_TEENSY2.h b/Marlin/src/pins/teensy2/pins_TEENSY2.h index dac4c6c940..23664bec2b 100644 --- a/Marlin/src/pins/teensy2/pins_TEENSY2.h +++ b/Marlin/src/pins/teensy2/pins_TEENSY2.h @@ -156,7 +156,7 @@ // // Misc. Functions // -#define SDSS 20 // B0 +#define SD_SS_PIN 20 // B0 #define LED_PIN 6 // D6 #define PS_ON_PIN 27 // B7 diff --git a/Marlin/src/pins/teensy2/pins_TEENSYLU.h b/Marlin/src/pins/teensy2/pins_TEENSYLU.h index 454aff91fc..388342d9d8 100644 --- a/Marlin/src/pins/teensy2/pins_TEENSYLU.h +++ b/Marlin/src/pins/teensy2/pins_TEENSYLU.h @@ -139,7 +139,7 @@ // // Misc. Functions // -#define SDSS 20 // B0 JP31-6 +#define SD_SS_PIN 20 // B0 JP31-6 #ifndef CASE_LIGHT_PIN #define CASE_LIGHT_PIN 0 // D0 IO-14 PWM0B @@ -157,7 +157,7 @@ #define BTN_EN1 3 // D3 IO-8 #define BTN_EN2 2 // D2 IO-10 #define BTN_ENC 41 // F3 IO-7 - #define SDSS 38 // F0 IO-13 use SD card on Panelolu2 + #define SD_SS_PIN 38 // F0 IO-13 use SD card on Panelolu2 #endif #define SD_DETECT_PIN -1 diff --git a/Marlin/src/pins/teensy3/pins_TEENSY31_32.h b/Marlin/src/pins/teensy3/pins_TEENSY31_32.h index a6aa4fd86d..7e91377e3b 100644 --- a/Marlin/src/pins/teensy3/pins_TEENSY31_32.h +++ b/Marlin/src/pins/teensy3/pins_TEENSY31_32.h @@ -91,7 +91,7 @@ // #define LED_PIN 13 //#define SOL1_PIN 28 -//#define SDSS 16 // 8 +//#define SD_SS_PIN 16 // 8 // // LCD / Controller diff --git a/Marlin/src/pins/teensy3/pins_TEENSY35_36.h b/Marlin/src/pins/teensy3/pins_TEENSY35_36.h index 54bf6f8835..5f020b4f6c 100644 --- a/Marlin/src/pins/teensy3/pins_TEENSY35_36.h +++ b/Marlin/src/pins/teensy3/pins_TEENSY35_36.h @@ -128,7 +128,7 @@ // // SD Card // -#define SDSS 39 // 8 +#define SD_SS_PIN 39 // 8 #if HAS_WIRED_LCD #define LCD_PINS_RS 40 diff --git a/Marlin/src/sd/cardreader.cpp b/Marlin/src/sd/cardreader.cpp index 1f4b9695ac..fff330b15b 100644 --- a/Marlin/src/sd/cardreader.cpp +++ b/Marlin/src/sd/cardreader.cpp @@ -487,9 +487,9 @@ void CardReader::mount() { nrItems = -1; if (root.isOpen()) root.close(); - if (!driver->init(SD_SPI_SPEED, SDSS) - #if defined(LCD_SDSS) && (LCD_SDSS != SDSS) - && !driver->init(SD_SPI_SPEED, LCD_SDSS) + if (!driver->init(SD_SPI_SPEED, SD_SS_PIN) + #if PIN_EXISTS(LCD_SDSS) && (LCD_SDSS_PIN != SD_SS_PIN) + && !driver->init(SD_SPI_SPEED, LCD_SDSS_PIN) #endif ) SERIAL_ECHO_MSG(STR_SD_INIT_FAIL); else if (!volume.init(driver)) From 861dd33fa140a44fb8c49383317138e335de957e Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Fri, 24 Jan 2025 00:27:01 +0000 Subject: [PATCH 055/787] [cron] Bump distribution date (2025-01-24) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 01e082eeaa..3da702bec0 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-01-23" +//#define STRING_DISTRIBUTION_DATE "2025-01-24" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 30210ab983..9474bf59f9 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-01-23" + #define STRING_DISTRIBUTION_DATE "2025-01-24" #endif /** From 0a598071afc9491c4cc95a9cba8e615d0e8606bc Mon Sep 17 00:00:00 2001 From: Andrew <18502096+classicrocker883@users.noreply.github.com> Date: Thu, 23 Jan 2025 20:48:58 -0500 Subject: [PATCH 056/787] =?UTF-8?q?=F0=9F=8E=A8=20Adjust=20some=20Python?= =?UTF-8?q?=20formatting=20(#27649)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../share/PlatformIO/scripts/chitu_crypt.py | 20 +++++++++---------- .../PlatformIO/scripts/common-dependencies.py | 8 +++++++- .../share/PlatformIO/scripts/configuration.py | 5 ++++- .../share/PlatformIO/scripts/preprocessor.py | 1 + buildroot/share/scripts/validate_boards.py | 6 +++--- 5 files changed, 25 insertions(+), 15 deletions(-) diff --git a/buildroot/share/PlatformIO/scripts/chitu_crypt.py b/buildroot/share/PlatformIO/scripts/chitu_crypt.py index 7c94ef0a4a..a6761b01d3 100644 --- a/buildroot/share/PlatformIO/scripts/chitu_crypt.py +++ b/buildroot/share/PlatformIO/scripts/chitu_crypt.py @@ -12,7 +12,7 @@ if pioutil.is_pio_build(): accumulating_xor_value = seed for i in range(0, len(contents), 4): - value = struct.unpack('= level: print("[deps] %s" % str) @@ -206,6 +206,7 @@ if pioutil.is_pio_build(): else: blab("Added src file %s " % relp, 3) cur_srcs.add(relp) + # Special rule: If a direct folder is specified add all files within. fullplain = os.path.join(marlinbasedir, plain) if os.path.isdir(fullplain): @@ -218,6 +219,7 @@ if pioutil.is_pio_build(): def srepl(matchi): g0 = matchi.group(0) return r"**" + g0[1:] + gpattern = re.sub(r'[*]($|[^*])', srepl, plain) gpattern = os.path.join(marlinbasedir, gpattern) @@ -230,14 +232,17 @@ if pioutil.is_pio_build(): blab("Removed src file %s (%s)" % (relp, str(info)), 3) else: blab("Removed src file %s " % relp, 3) + fullplain = os.path.join(marlinbasedir, plain) if os.path.isdir(fullplain): blab("Directory content removal for %s " % plain, 2) + def filt(x): common = os.path.commonpath([plain, x]) if not common == os.path.normpath(plain): return True onremove(x, "dcr") return False + cur_srcs = set(filter(filt, cur_srcs)) else: # Remove matching source entries. @@ -245,6 +250,7 @@ if pioutil.is_pio_build(): if not fnmatch.fnmatch(x, plain): return True onremove(x) return False + cur_srcs = set(filter(filt, cur_srcs)) # Transform the resulting set into a string. for x in cur_srcs: diff --git a/buildroot/share/PlatformIO/scripts/configuration.py b/buildroot/share/PlatformIO/scripts/configuration.py index fdd2fa3854..e7b4998f75 100755 --- a/buildroot/share/PlatformIO/scripts/configuration.py +++ b/buildroot/share/PlatformIO/scripts/configuration.py @@ -28,7 +28,10 @@ def apply_opt(name, val, conf=None): # 7: Option value # 8: Whitespace after value # 9: End comment - regex = re.compile(rf'^(\s*)(//\s*)?(#define\s+)({name}\b)(\s?)(\s*)(.*?)(\s*)(//.*)?$', re.IGNORECASE) + regex = re.compile( + rf"^(\s*)(//\s*)?(#define\s+)({name}\b)(\s?)(\s*)(.*?)(\s*)(//.*)?$", + re.IGNORECASE + ) # Find and enable and/or update all matches for file in ("Configuration.h", "Configuration_adv.h"): diff --git a/buildroot/share/PlatformIO/scripts/preprocessor.py b/buildroot/share/PlatformIO/scripts/preprocessor.py index bda00dfd27..4f24458d96 100644 --- a/buildroot/share/PlatformIO/scripts/preprocessor.py +++ b/buildroot/share/PlatformIO/scripts/preprocessor.py @@ -15,6 +15,7 @@ def blab(str): # Invoke GCC to run the preprocessor and extract enabled features # preprocessor_cache = {} + def run_preprocessor(env, fn=None): filename = fn or 'buildroot/share/PlatformIO/scripts/common-dependencies.h' if filename in preprocessor_cache: diff --git a/buildroot/share/scripts/validate_boards.py b/buildroot/share/scripts/validate_boards.py index a495420d9d..8d5650d6c6 100755 --- a/buildroot/share/scripts/validate_boards.py +++ b/buildroot/share/scripts/validate_boards.py @@ -12,11 +12,11 @@ def logmsg(msg, line): # Print a formatted error def err(board, msg): - print(f'[ERROR] {board:30} {msg}') + print(f"[ERROR] {board:30} {msg}") # Print a formatted warning def warn(board, msg): - print(f'[WARNING] {board:30} {msg}') + print(f"[WARNING] {board:30} {msg}") def bshort(board): return board.replace('BOARD_', '') @@ -119,7 +119,7 @@ def boards_checks(argv): print(f'[ERROR] Non-matching boards order in pins.h. Expected {bshort(boards_boards[i])} but got {bshort(pins_boards[i])}') break - return ERRS; + return ERRS if __name__ == '__main__': ERR_COUNT = boards_checks(sys.argv[1:]) From 7f598ae66d2e5e923f6cd9c5f61daac4af4ef7a7 Mon Sep 17 00:00:00 2001 From: rondlh <77279634+rondlh@users.noreply.github.com> Date: Fri, 24 Jan 2025 11:18:46 +0800 Subject: [PATCH 057/787] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20STM32H7=20Serial?= =?UTF-8?q?=20DMA=20(#27633)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/HAL/STM32/HardwareSerial.cpp | 278 +++++++++++++++--------- Marlin/src/HAL/STM32/HardwareSerial.h | 6 +- Marlin/src/inc/SanityCheck.h | 2 +- 3 files changed, 182 insertions(+), 104 deletions(-) diff --git a/Marlin/src/HAL/STM32/HardwareSerial.cpp b/Marlin/src/HAL/STM32/HardwareSerial.cpp index 2a389447b7..d9948d0a34 100644 --- a/Marlin/src/HAL/STM32/HardwareSerial.cpp +++ b/Marlin/src/HAL/STM32/HardwareSerial.cpp @@ -37,7 +37,17 @@ #include "HardwareSerial.h" #include "uart.h" -// USART/UART PIN MAPPING FOR STM32F0/F1/F2/F4/F7 +// Prevent selection of LPUART1 on STM32H7xx +#if defined(STM32H7xx) && (PIN_SERIAL1_TX == PA_9) + #undef PIN_SERIAL1_TX + #define PIN_SERIAL1_TX PA_9_ALT1 +#endif +#if defined(STM32H7xx) && (PIN_SERIAL1_RX == PA_10) + #undef PIN_SERIAL1_RX + #define PIN_SERIAL1_RX PA_10_ALT1 +#endif + +// USART/UART pin mapping for STM32F0/F1/F2/F4/F7/H7 #ifndef PIN_SERIAL1_TX #define PIN_SERIAL1_TX PA9 #endif @@ -75,46 +85,6 @@ #define PIN_SERIAL6_RX PC7 #endif -// TODO: Get from include file - -#if ANY(STM32F2xx, STM32F4xx, STM32F7xx) - - #define RCC_AHB1Periph_DMA1 ((uint32_t)0x00200000) - #define RCC_AHB1Periph_DMA2 ((uint32_t)0x00400000) - - void RCC_AHB1PeriphClockCmd(uint32_t RCC_AHB1Periph, FunctionalState NewState) { - // Check the parameters - assert_param(IS_RCC_AHB1_CLOCK_PERIPH(RCC_AHB1Periph)); - - assert_param(IS_FUNCTIONAL_STATE(NewState)); - if (NewState != DISABLE) - RCC->AHB1ENR |= RCC_AHB1Periph; - else - RCC->AHB1ENR &= ~RCC_AHB1Periph; - } - -#endif - -#if ANY(STM32F0xx, STM32F1xx) - - #define RCC_AHBPeriph_DMA1 ((uint32_t)0x00000001) - #define RCC_AHBPeriph_DMA2 ((uint32_t)0x00000002) - - void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState) { - /* Check the parameters */ - assert_param(IS_RCC_AHB_PERIPH(RCC_AHBPeriph)); - assert_param(IS_FUNCTIONAL_STATE(NewState)); - - if (NewState != DISABLE) - RCC->AHBENR |= RCC_AHBPeriph; - else - RCC->AHBENR &= ~RCC_AHBPeriph; - } - -#endif - -// END OF TODO------------------------------------------------------ - // SerialEvent functions are weak, so when the user doesn't define them, // the linker just sets their address to 0 (which is checked below). #ifdef USING_HW_SERIAL1 @@ -161,11 +131,12 @@ HAL_HardwareSerial::HAL_HardwareSerial(void *peripheral) { setRx(PIN_SERIAL1_RX); setTx(PIN_SERIAL1_TX); _uart_index = 0; - #ifdef DMA2_Stream2 - RX_DMA = { USART1, RCC_AHB1Periph_DMA2, 4, DMA2_Stream2 }; + + #ifdef DMA2_Stream2 // F2 / F4 / F7 / H7 + RX_DMA = { USART1, 2, DMA2_Stream2 }; // USART, DMA controller no., DMA stream #endif - #ifdef DMA1_Channel5 - RX_DMA = { USART1, RCC_AHBPeriph_DMA1, DMA1, DMA1_Channel5 }; + #ifdef DMA1_Channel5 // F0 / F1 + RX_DMA = { USART1, 1, DMA1_Channel5 }; // USART, DMA controller no., DMA channel #endif } else if (peripheral == USART2) { @@ -173,10 +144,10 @@ HAL_HardwareSerial::HAL_HardwareSerial(void *peripheral) { setTx(PIN_SERIAL2_TX); _uart_index = 1; #ifdef DMA1_Stream5 - RX_DMA = { USART2, RCC_AHB1Periph_DMA1, 4, DMA1_Stream5 }; + RX_DMA = { USART2, 1, DMA1_Stream5 }; #endif #ifdef DMA1_Channel6 - RX_DMA = { USART2, RCC_AHBPeriph_DMA1, DMA1, DMA1_Channel6 }; + RX_DMA = { USART2, 1, DMA1_Channel6 }; #endif } else if (peripheral == USART3) { @@ -184,17 +155,17 @@ HAL_HardwareSerial::HAL_HardwareSerial(void *peripheral) { setTx(PIN_SERIAL3_TX); _uart_index = 2; #ifdef DMA1_Stream1 - RX_DMA = { USART3, RCC_AHB1Periph_DMA1, 4, DMA1_Stream1 }; + RX_DMA = { USART3, 1, DMA1_Stream1 }; #endif #ifdef DMA1_Channel3 // F0 has no support for UART3, requires system remapping - RX_DMA = { USART3, RCC_AHBPeriph_DMA1, DMA1, DMA1_Channel3 }; + RX_DMA = { USART3, 1, DMA1_Channel3 }; #endif } #ifdef USART4 // Only F2 / F4 / F7 else if (peripheral == USART4) { #ifdef DMA1_Stream2 - RX_DMA = { USART4, RCC_AHB1Periph_DMA1, 4, DMA1_Stream2 }; + RX_DMA = { USART4, 1, DMA1_Stream2 }; #endif setRx(PIN_SERIAL4_RX); setTx(PIN_SERIAL4_TX); @@ -205,10 +176,10 @@ HAL_HardwareSerial::HAL_HardwareSerial(void *peripheral) { #ifdef UART4 else if (peripheral == UART4) { #ifdef DMA1_Stream2 - RX_DMA = { UART4, RCC_AHB1Periph_DMA1, 4, DMA1_Stream2 }; + RX_DMA = { UART4, 1, DMA1_Stream2 }; #endif #ifdef DMA2_Channel3 // STM32F0xx has only 3 UARTs - RX_DMA = { UART4, RCC_AHBPeriph_DMA2, DMA2, DMA2_Channel3 }; + RX_DMA = { UART4, 2, DMA2_Channel3 }; #endif setRx(PIN_SERIAL4_RX); setTx(PIN_SERIAL4_TX); @@ -216,10 +187,10 @@ HAL_HardwareSerial::HAL_HardwareSerial(void *peripheral) { } #endif - #ifdef UART5 // Only F2 / F4 / F7 + #ifdef UART5 // Only F2 / F4 / F7 / H7 else if (peripheral == UART5) { #ifdef DMA1_Stream0 - RX_DMA = { UART5, RCC_AHB1Periph_DMA1, 4, DMA1_Stream0 }; + RX_DMA = { UART5, 1, DMA1_Stream0 }; #endif setRx(PIN_SERIAL5_RX); setTx(PIN_SERIAL5_TX); @@ -227,10 +198,10 @@ HAL_HardwareSerial::HAL_HardwareSerial(void *peripheral) { } #endif - #ifdef USART6 // Only F2 / F4 / F7 + #ifdef USART6 // Only F2 / F4 / F7 / H7 else if (peripheral == USART6) { #ifdef DMA2_Stream1 - RX_DMA = { USART6, RCC_AHB1Periph_DMA2, 4, DMA2_Stream1 }; + RX_DMA = { USART6, 2, DMA2_Stream1 }; #endif setRx(PIN_SERIAL6_RX); setTx(PIN_SERIAL6_TX); @@ -271,14 +242,34 @@ void HAL_HardwareSerial::init(PinName _rx, PinName _tx) { * @param obj : pointer to serial_t structure * @retval last character received */ -int HAL_HardwareSerial::_tx_complete_irq(serial_t *obj) { - // If interrupts are enabled, there must be more data in the output buffer. Send the next byte - obj->tx_tail = (obj->tx_tail + 1) % TX_BUFFER_SIZE; - if (obj->tx_head == obj->tx_tail) return -1; +#if DISABLED(STM32H7xx) - return 0; -} + int HAL_HardwareSerial::_tx_complete_irq(serial_t *obj) { + // If interrupts are enabled, there must be more data in the output buffer. Send the next byte + obj->tx_tail = (obj->tx_tail + 1) % TX_BUFFER_SIZE; + if (obj->tx_head == obj->tx_tail) + return -1; + + return 0; + } + +#else // STM32H7xx, has different uart_attach_tx_callback + + int HAL_HardwareSerial::_tx_complete_irq(serial_t *obj) { + // If interrupts are enabled, there must be more data in the output buffer. Send the next byte + obj->tx_tail = (obj->tx_tail + obj->tx_size) % TX_BUFFER_SIZE; + + if (obj->tx_head != obj->tx_tail) { + size_t remaining_data = (TX_BUFFER_SIZE + obj->tx_head - obj->tx_tail) % TX_BUFFER_SIZE; + obj->tx_size = min(remaining_data, (size_t)(TX_BUFFER_SIZE - obj->tx_tail)); + uart_attach_tx_callback(obj, _tx_complete_irq, obj->tx_size); + return -1; + } + return 0; + } + +#endif // Public Methods ////////////////////////////////////////////////////////////// @@ -340,7 +331,7 @@ void HAL_HardwareSerial::update_rx_head() { } #endif - #if ANY(STM32F2xx, STM32F4xx, STM32F7xx) + #if ANY(STM32F2xx, STM32F4xx, STM32F7xx, STM32H7xx) _serial.rx_head = RX_BUFFER_SIZE - RX_DMA.dma_streamRX->NDTR; #endif @@ -352,18 +343,22 @@ void HAL_HardwareSerial::update_rx_head() { int HAL_HardwareSerial::available() { update_rx_head(); + return ((unsigned int)(RX_BUFFER_SIZE + _serial.rx_head - _serial.rx_tail)) % RX_BUFFER_SIZE; } int HAL_HardwareSerial::peek() { update_rx_head(); - if (_serial.rx_head == _serial.rx_tail) return -1; + if (_serial.rx_head == _serial.rx_tail) + return -1; + return _serial.rx_buff[_serial.rx_tail]; } int HAL_HardwareSerial::read() { update_rx_head(); - if (_serial.rx_head == _serial.rx_tail) return -1; // No chars if the head isn't ahead of the tail + if (_serial.rx_head == _serial.rx_tail) + return -1; // No chars if the head isn't ahead of the tail unsigned char c = _serial.rx_buff[_serial.rx_tail]; _serial.rx_tail = (rx_buffer_index_t)(_serial.rx_tail + 1) % RX_BUFFER_SIZE; @@ -380,8 +375,18 @@ size_t HAL_HardwareSerial::write(uint8_t c) { // Interrupt based wri _serial.tx_buff[_serial.tx_head] = c; _serial.tx_head = i; - if (!serial_tx_active(&_serial)) - uart_attach_tx_callback(&_serial, _tx_complete_irq); // Write next byte, launch interrupt + #ifdef STM32H7xx // Support STM32H7xx with different uart_attach_tx_callback + if ((!serial_tx_active(&_serial)) && (_serial.tx_head != _serial.tx_tail)) { + size_t remaining_data = (TX_BUFFER_SIZE + _serial.tx_head -_serial.tx_tail) % TX_BUFFER_SIZE; + _serial.tx_size = min(remaining_data, (size_t)(TX_BUFFER_SIZE - _serial.tx_tail)); + uart_attach_tx_callback(&_serial, _tx_complete_irq, _serial.tx_size); + + return -1; + } + #else + if (!serial_tx_active(&_serial)) + uart_attach_tx_callback(&_serial, _tx_complete_irq); // Write next byte, launch interrupt + #endif return 1; } @@ -390,57 +395,132 @@ void HAL_HardwareSerial::flush() { while ((_serial.tx_head != _serial.tx_tail)) { /* nada */ } // nop, the interrupt handler will free up space for us } -#if ANY(STM32F2xx, STM32F4xx, STM32F7xx) +#if ANY(STM32F2xx, STM32F4xx, STM32F7xx, STM32H7xx) void HAL_HardwareSerial::Serial_DMA_Read_Enable() { - RCC_AHB1PeriphClockCmd(RX_DMA.dma_rcc, ENABLE); // Enable DMA clock - #ifdef STM32F7xx - RX_DMA.dma_streamRX->PAR = (uint32_t)(&RX_DMA.uart->RDR); // RX peripheral receive address (usart) F7 + if (RX_DMA.DMA_ID == 1) + __HAL_RCC_DMA1_CLK_ENABLE(); // Enable DMA1 clock + else + __HAL_RCC_DMA2_CLK_ENABLE(); // Enable DMA2 clock + + // Reset DMA, wait if needed to complete the running process + RX_DMA.dma_streamRX->CR = 0; // DMA stream clear/disable + while (RX_DMA.dma_streamRX->CR & DMA_SxCR_EN) { /* just wait for DMA to complete */ } + + // UART clear/disable + RX_DMA.uart->CR1 = 0; + + // Configure DMA + #if ANY(STM32F7xx, STM32H7xx) // F7 and H7 use RDR (Receive Data Register) + RX_DMA.dma_streamRX->PAR = (uint32_t)(&RX_DMA.uart->RDR); // DMA stream Peripheral Address Register = USART Data Register #else - RX_DMA.dma_streamRX->PAR = (uint32_t)(&RX_DMA.uart->DR); // RX peripheral address (usart) F2 / F4 + RX_DMA.dma_streamRX->PAR = (uint32_t)(&RX_DMA.uart->DR); // DMA stream Peripheral Address Register = USART Data Register #endif - RX_DMA.dma_streamRX->M0AR = (uint32_t)_serial.rx_buff; // RX destination address (memory) - RX_DMA.dma_streamRX->NDTR = RX_BUFFER_SIZE; // RX buffer size - RX_DMA.dma_streamRX->CR = (RX_DMA.dma_channel << 25); // RX channel selection, set to 0 all the other CR bits + RX_DMA.dma_streamRX->M0AR = (uint32_t)_serial.rx_buff; // DMA stream Memory 0 Adress Register = RX buffer address + RX_DMA.dma_streamRX->NDTR = RX_BUFFER_SIZE; // DMA stream Number of Data Transfer Register - RX_DMA.dma_streamRX->CR |= (3 << 16); // RX priority level: Very High + #if DISABLED(STM32H7xx) // Select channel via CR register - //RX_DMA.dma_streamRX->CR &= ~(3 << 13); // RX memory data size: 8 bit - //RX_DMA.dma_streamRX->CR &= ~(3 << 11); // RX peripheral data size: 8 bit - RX_DMA.dma_streamRX->CR |= (1 << 10); // RX memory increment mode - //RX_DMA.dma_streamRX->CR &= ~(1 << 9); // RX peripheral no increment mode - RX_DMA.dma_streamRX->CR |= (1 << 8); // RX circular mode enabled - //RX_DMA.dma_streamRX->CR &= ~(1 << 6); // RX data transfer direction: Peripheral-to-memory - RX_DMA.uart->CR3 |= (1 << 6); // Enable DMA receiver (DMAR) - RX_DMA.dma_streamRX->CR |= (1 << 0); // RX enable DMA + RX_DMA.dma_streamRX->CR = 4 << DMA_SxCR_CHSEL_Pos; // DMA stream Channel Selection, always use channel 4 + + #else // STM32H7xx, select channel with DMAMUX1, channel DMA1 is channel DMAMUX, channel DMA2 is channel DMAMUX + 8 + + if (RX_DMA.uart == USART1) DMAMUX1_Channel10->CCR |= DMA_REQUEST_USART1_RX; // DMA2, Stream 2 + if (RX_DMA.uart == USART2) DMAMUX1_Channel5->CCR |= DMA_REQUEST_USART2_RX; // DMA1, Stream 5 + if (RX_DMA.uart == USART3) DMAMUX1_Channel1->CCR |= DMA_REQUEST_USART3_RX; // DMA1, Stream 1 + #ifdef UART4 + if (RX_DMA.uart == UART4) DMAMUX1_Channel2->CCR |= DMA_REQUEST_UART4_RX; // DMA1, Stream 2 + #endif + #ifdef USART4 + if (RX_DMA.uart == USART4) DMAMUX1_Channel2->CCR |= DMA_REQUEST_USART4_RX; // DMA1, Stream 2 + #endif + #ifdef UART5 + if (RX_DMA.uart == UART5) DMAMUX1_Channel0->CCR |= DMA_REQUEST_UART5_RX; // DMA1, Stream 0 + #endif + #ifdef USART6 + if (RX_DMA.uart == USART6) DMAMUX1_Channel9->CCR |= DMA_REQUEST_USART6_RX; // DMA2, Stream 1 + #endif + + #endif // !STM32H7xx + + // Configure DMA + //RX_DMA.dma_streamRX->CR |= DMA_MBURST_SINGLE; // DMA stream Memory Burst transfer: single transfer = 0b00 + //RX_DMA.dma_streamRX->CR |= DMA_PBURST_SINGLE; // DMA stream Peripheral Burst transfer: single transfer = 0b00 + + #if ENABLED(STM32H7xx) + RX_DMA.dma_streamRX->CR |= DMA_SxCR_TRBUFF; // DMA stream Transfer handle bufferable (required for UART/USART) + #endif + + //RX_DMA.dma_streamRX->CR &= ~DMA_SxCR_CT; // DMA stream Current Target (only in double buffer mode) + //RX_DMA.dma_streamRX->CR &= ~DMA_SxCR_DBM; // DMA stream Double Buffer Mode + //RX_DMA.dma_streamRX->CR |= DMA_PRIORITY_LOW; // DMA stream Priority Level Low = 0b00 + //RX_DMA.dma_streamRX->CR &= ~DMA_SxCR_PINCOS; // DMA stream Peripheral Increment Offset Size + //RX_DMA.dma_streamRX->CR &= ~DMA_SxCR_MSIZE; // DMA stream Memory data Size: 8 bit = 0b00 + //RX_DMA.dma_streamRX->CR &= ~DMA_SxCR_PSIZE; // DMA stream Peripheral data Size: 8 bit = 0b00 + RX_DMA.dma_streamRX->CR |= DMA_SxCR_MINC; // DMA stream Memory Increment enable + //RX_DMA.dma_streamRX->CR &= ~DMA_SxCR_PINC; // DMA stream Peripheral increment + RX_DMA.dma_streamRX->CR |= DMA_SxCR_CIRC; // DMA stream Circular mode enable + //RX_DMA.dma_streamRX->CR |= DMA_PERIPH_TO_MEMORY; // DMA stream transfer Direction: Peripheral-to-memory = b00 + //RX_DMA.dma_streamRX->CR &= ~DMA_SxCR_PFCTRL; // DMA stream Peripheral Flow Controller: DMA = 0 + //RX_DMA.dma_streamRX->CR &= ~DMA_SxCR_TCIE; // DMA stream Transfer Complete Interrupt + //RX_DMA.dma_streamRX->CR &= ~DMA_SxCR_HTIE; // DMA stream Half Transfer Interrupt + //RX_DMA.dma_streamRX->CR &= ~DMA_SxCR_TEIE; // DMA stream Transfer Error Interrupt + //RX_DMA.dma_streamRX->CR &= ~DMA_SxCR_DMEIE; // DMA stream Direct Mode Error Interrupt + RX_DMA.dma_streamRX->CR |= DMA_SxCR_EN; // DMA stream Enable + + // Configure UART/USART + RX_DMA.uart->CR3 |= USART_CR3_DMAR; // UART DMA Receiver + RX_DMA.uart->CR1 |= USART_CR1_TE; // UART Transmitter Enable + RX_DMA.uart->CR1 |= USART_CR1_RE; // UART Receiver Enable + RX_DMA.uart->CR1 |= USART_CR1_UE; // UART Enable } -#endif // STM32F2xx || STM32F4xx || STM32F7xx +#endif // STM32F2xx || STM32F4xx || STM32F7xx || STM32H7xx #if ANY(STM32F0xx, STM32F1xx) void HAL_HardwareSerial::Serial_DMA_Read_Enable() { - RCC_AHBPeriphClockCmd(RX_DMA.dma_rcc, ENABLE); // enable DMA clock - RX_DMA.dma_channelRX->CPAR = (uint32_t)(&RX_DMA.uart->DR); // RX peripheral address (usart) - RX_DMA.dma_channelRX->CMAR = (uint32_t)_serial.rx_buff; // RX destination address (memory) - RX_DMA.dma_channelRX->CNDTR = RX_BUFFER_SIZE; // RX buffer size + if (RX_DMA.DMA_ID == 1) + __HAL_RCC_DMA1_CLK_ENABLE(); // enable DMA1 clock + else + __HAL_RCC_DMA2_CLK_ENABLE(); // enable DMA2 clock - RX_DMA.dma_channelRX->CCR = 0; // RX channel selection, set to 0 all the other CR bits + RX_DMA.dma_channelRX->CCR &= ~USART_CR1_UE; // DMA stream clear/disable + while (RX_DMA.dma_channelRX->CCR & DMA_CCR_EN) { /* just wait for DMA to complete */ } - RX_DMA.dma_channelRX->CCR |= (3<<12); // RX priority level: Very High + // Clear/disable UART and DMA + RX_DMA.uart->CR1 = 0; // UART clear CR1, disable DMA - //RX_DMA.dma_channelRX->CCR &= ~(1<<10); // RX memory data size: 8 bit - //RX_DMA.dma_channelRX->CCR &= ~(1<<8); // RX peripheral data size: 8 bit - RX_DMA.dma_channelRX->CCR |= (1<<7); // RX memory increment mode - //RX_DMA.dma_channelRX->CCR &= ~(1<<6); // RX peripheral no increment mode - RX_DMA.dma_channelRX->CCR |= (1<<5); // RX circular mode enabled - //RX_DMA.dma_channelRX->CCR &= ~(1<<4); // RX data transfer direction: Peripheral-to-memory + // Configure DMA - RX_DMA.uart->CR3 |= (1<<6); // enable DMA receiver (DMAR) - RX_DMA.dma_channelRX->CCR |= (1<<0); // RX enable DMA + #ifdef STM32F0xx + RX_DMA.dma_channelRX->CPAR = (uint32_t)(&RX_DMA.uart->RDR); // DMA channel Peripheral Address Register = USART Data Register + #else + RX_DMA.dma_channelRX->CPAR = (uint32_t)(&RX_DMA.uart->DR); // DMA channel Peripheral Address Register = USART Data Register + #endif + + RX_DMA.dma_channelRX->CMAR = (uint32_t)_serial.rx_buff; // DMA channel Memory Address Register + RX_DMA.dma_channelRX->CNDTR = RX_BUFFER_SIZE; // DMA channel Number of Data Transfer Register + //RX_DMA.dma_channelRX->CCR |= (0b00 << DMA_CCR_PL_Pos); // DMA channel Priority Level: Low = 0b00 + //RX_DMA.dma_channelRX->CCR &= ~DMA_CCR_MSIZE; // DMA channel Data Size: 8 bit = 0 + //RX_DMA.dma_channelRX->CCR &= ~DMA_CCR_PSIZE; // DMA channel Peripheral data size: 8 bit = 0 + RX_DMA.dma_channelRX->CCR |= DMA_CCR_MINC; // DMA channel Memory Increment enable + //RX_DMA.dma_channelRX->CCR &= ~DMA_CCR_PINC; // DMA channel Peripheral Increment disable + RX_DMA.dma_channelRX->CCR |= DMA_CCR_CIRC; // DMA channel Circular mode enable + //RX_DMA.dma_channelRX->CCR &= ~DMA_CCR_DIR; // DMA channel Data Transfer direction: 0=Read peripheral, 1=Read memory + //RX_DMA.dma_channelRX->CCR &= ~DMA_CCR_TEIE; // DMA channel Transfer Error Interrupt + //RX_DMA.dma_channelRX->CCR &= ~DMA_CCR_HTIE; // DMA channel Half Transfer Interrupt + //RX_DMA.dma_channelRX->CCR &= ~DMA_CCR_TCIE; // DMA channel Transfer Complete Interrupt + RX_DMA.dma_channelRX->CCR |= DMA_CCR_EN; // DMA channel enable + + // Configure UART/USART + RX_DMA.uart->CR3 |= USART_CR3_DMAR; // UART DMA Receiver enabled + RX_DMA.uart->CR1 |= USART_CR1_TE; // UART Transmitter Enable + RX_DMA.uart->CR1 |= USART_CR1_RE; // UART Receiver Enable + RX_DMA.uart->CR1 |= USART_CR1_UE; // UART Enable } #endif // STM32F0xx || STM32F1xx diff --git a/Marlin/src/HAL/STM32/HardwareSerial.h b/Marlin/src/HAL/STM32/HardwareSerial.h index cc564322b4..cf97637278 100644 --- a/Marlin/src/HAL/STM32/HardwareSerial.h +++ b/Marlin/src/HAL/STM32/HardwareSerial.h @@ -38,12 +38,10 @@ typedef struct { USART_TypeDef * uart; - uint32_t dma_rcc; + uint32_t DMA_ID; // DMA1=1; DM2=2; BDMA=3 #if ANY(STM32F0xx, STM32F1xx) // F0 / F1 - DMA_TypeDef * dma_controller; DMA_Channel_TypeDef * dma_channelRX; - #else // F2 / F4 / F7 - uint32_t dma_channel; + #else // F2 / F4 / F7 / H7 DMA_Stream_TypeDef * dma_streamRX; #endif } DMA_CFG; diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index 83159f2638..a11965a01c 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -245,7 +245,7 @@ static_assert(COUNT(arm) == LOGICAL_AXES, "AXIS_RELATIVE_MODES must contain " _L #if ENABLED(SERIAL_DMA) #ifdef ARDUINO_ARCH_HC32 // checks for HC32 are located in HAL/HC32/inc/SanityCheck.h - #elif DISABLED(HAL_STM32) || NONE(STM32F0xx, STM32F1xx, STM32F2xx, STM32F4xx, STM32F7xx) + #elif DISABLED(HAL_STM32) || NONE(STM32F0xx, STM32F1xx, STM32F2xx, STM32F4xx, STM32F7xx, STM32H7xx) #error "SERIAL_DMA is only available for some STM32 MCUs and requires HAL/STM32." #elif !defined(HAL_UART_MODULE_ENABLED) || defined(HAL_UART_MODULE_ONLY) #error "SERIAL_DMA requires STM32 platform HAL UART (without HAL_UART_MODULE_ONLY)." From 86f03cf57a23ffbfef5ac4df31b7b78299a58bc6 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Thu, 23 Jan 2025 22:55:36 -0600 Subject: [PATCH 058/787] =?UTF-8?q?=F0=9F=8E=A8=20Shared=20USB=20build=20f?= =?UTF-8?q?lags?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ini/stm32f1.ini | 17 +++++++--------- ini/stm32f4.ini | 54 ++++++++++++++----------------------------------- 2 files changed, 22 insertions(+), 49 deletions(-) diff --git a/ini/stm32f1.ini b/ini/stm32f1.ini index 86aeacdecd..b4c6f22372 100644 --- a/ini/stm32f1.ini +++ b/ini/stm32f1.ini @@ -63,14 +63,13 @@ build_flags = ${common_STM32F103RC_variant.build_flags} board_build.offset = 0x7000 board_upload.offset_address = 0x08007000 +[USBD_CDC_MSC] +build_flags = -DUSE_USB_FS -DUSBD_USE_CDC_MSC -DUSBD_IRQ_PRIO=5 -DUSBD_IRQ_SUBPRIO=6 + [env:STM32F103RC_btt_USB] extends = env:STM32F103RC_btt platform_packages = ${stm_flash_drive.platform_packages} -build_flags = ${env:STM32F103RC_btt.build_flags} - -DUSE_USB_FS - -DUSBD_IRQ_PRIO=5 - -DUSBD_IRQ_SUBPRIO=6 - -DUSBD_USE_CDC_MSC +build_flags = ${env:STM32F103RC_btt.build_flags} ${USBD_CDC_MSC.build_flags} build_unflags = ${env:STM32F103RC_btt.build_unflags} -DUSBD_USE_CDC # @@ -227,9 +226,7 @@ upload_protocol = jlink [env:STM32F103RE_btt_USB] extends = env:STM32F103RE_btt platform_packages = ${stm_flash_drive.platform_packages} -build_flags = ${env:STM32F103RE_btt.build_flags} - -DUSE_USB_FS -DUSBD_IRQ_PRIO=5 - -DUSBD_IRQ_SUBPRIO=6 -DUSBD_USE_CDC_MSC +build_flags = ${env:STM32F103RE_btt.build_flags} ${USBD_CDC_MSC.build_flags} build_unflags = ${env:STM32F103RE_btt.build_unflags} -DUSBD_USE_CDC # @@ -468,8 +465,8 @@ board_upload.offset_address = 0x08005000 board_build.offset = 0x5000 board_upload.maximum_size = 237568 extra_scripts = ${stm32_variant.extra_scripts} -build_flags = ${stm32_variant.build_flags} - -DSS_TIMER=4 -DTIMER_SERVO=TIM5 -DUSE_USB_FS -DUSBD_IRQ_PRIO=5 -DUSBD_IRQ_SUBPRIO=6 -DUSBD_USE_CDC_MSC +build_flags = ${stm32_variant.build_flags} ${USBD_CDC_MSC.build_flags} + -DSS_TIMER=4 -DTIMER_SERVO=TIM5 build_unflags = ${stm32_variant.build_unflags} -DUSBD_USE_CDC [env:STM32F103RC_ZM3E2_USB] diff --git a/ini/stm32f4.ini b/ini/stm32f4.ini index 3f7b5b6346..4cb3b91d09 100644 --- a/ini/stm32f4.ini +++ b/ini/stm32f4.ini @@ -254,6 +254,9 @@ build_flags = ${stm32_variant.build_flags} extends = env:BTT_BTT002 board = marlin_BTT_BTT002_VET6 +[USB_HS_IN_FS] +build_flags = -DUSE_USBHOST_HS -DUSE_USB_HS_IN_FS -DUSBD_IRQ_PRIO=5 -DUSBD_IRQ_SUBPRIO=6 + # # BigTreeTech SKR V2.0 (STM32F407VGT6 ARM Cortex-M4) with USB Flash Drive Support # @@ -264,9 +267,7 @@ board = marlin_STM32F407VGT6_CCM board_build.variant = MARLIN_F4x7Vx board_build.offset = 0x8000 board_upload.offset_address = 0x08008000 -build_flags = ${stm_flash_drive.build_flags} - -DUSE_USBHOST_HS -DUSE_USB_HS_IN_FS - -DUSBD_IRQ_PRIO=5 -DUSBD_IRQ_SUBPRIO=6 +build_flags = ${stm_flash_drive.build_flags} ${USB_HS_IN_FS.build_flags} -DHSE_VALUE=8000000U -DHAL_SD_MODULE_ENABLED -DPIN_SERIAL3_RX=PD_9 -DPIN_SERIAL3_TX=PD_8 upload_protocol = stlink @@ -324,11 +325,8 @@ build_flags = ${stm32_variant.build_flags} extends = env:STM32F446ZE_btt platform_packages = ${stm_flash_drive.platform_packages} build_unflags = -DUSBD_USE_CDC -build_flags = ${stm_flash_drive.build_flags} - -DSTM32F446_5VX -DUSE_USB_HS_IN_FS - -DUSE_USBHOST_HS -DUSBD_IRQ_PRIO=5 - -DUSBD_IRQ_SUBPRIO=6 - -DUSBD_USE_CDC_MSC +build_flags = ${stm_flash_drive.build_flags} -DSTM32F446_5VX + ${USB_HS_IN_FS.build_flags} -DUSBD_USE_CDC_MSC # # BigTreeTech Octopus V1.1 / Octopus Pro V1.0 (STM32F429ZGT6 ARM Cortex-M4) @@ -351,9 +349,7 @@ extends = env:STM32F429ZG_btt platform_packages = ${stm_flash_drive.platform_packages} build_unflags = -DUSBD_USE_CDC build_flags = ${stm_flash_drive.build_flags} - -DUSE_USB_HS_IN_FS -DUSE_USBHOST_HS - -DUSBD_IRQ_PRIO=5 -DUSBD_IRQ_SUBPRIO=6 - -DUSBD_USE_CDC_MSC + ${USB_HS_IN_FS.build_flags} -DUSBD_USE_CDC_MSC # # BigTreeTech Octopus / Octopus Pro (STM32F407ZET6 ARM Cortex-M4) @@ -373,10 +369,7 @@ build_flags = ${stm32_variant.build_flags} extends = env:STM32F407ZE_btt platform_packages = ${stm_flash_drive.platform_packages} build_unflags = -DUSBD_USE_CDC -build_flags = ${stm_flash_drive.build_flags} - -DUSE_USB_HS_IN_FS -DUSE_USBHOST_HS - -DUSBD_IRQ_PRIO=5 -DUSBD_IRQ_SUBPRIO=6 - -DUSBD_USE_CDC_MSC +build_flags = ${stm_flash_drive.build_flags} ${USB_HS_IN_FS.build_flags} -DUSBD_USE_CDC_MSC # # Lerdge base @@ -514,11 +507,7 @@ upload_protocol = jlink [env:mks_robin_nano_v3_usb_flash_drive] extends = env:mks_robin_nano_v3 platform_packages = ${stm_flash_drive.platform_packages} -build_flags = ${stm_flash_drive.build_flags} ${stm32f4_I2C1.build_flags} - -DUSE_USBHOST_HS - -DUSBD_IRQ_PRIO=5 - -DUSBD_IRQ_SUBPRIO=6 - -DUSE_USB_HS_IN_FS +build_flags = ${stm_flash_drive.build_flags} ${stm32f4_I2C1.build_flags} ${USB_HS_IN_FS.build_flags} # # MKS Robin Nano V3 with USB Flash Drive Support and Shared Media @@ -574,11 +563,7 @@ upload_protocol = jlink [env:mks_eagle_usb_flash_drive] extends = env:mks_eagle platform_packages = ${stm_flash_drive.platform_packages} -build_flags = ${stm_flash_drive.build_flags} ${stm32f4_I2C1.build_flags} - -DUSE_USBHOST_HS - -DUSBD_IRQ_PRIO=5 - -DUSBD_IRQ_SUBPRIO=6 - -DUSE_USB_HS_IN_FS +build_flags = ${stm_flash_drive.build_flags} ${stm32f4_I2C1.build_flags} ${USB_HS_IN_FS.build_flags} # # MKS Eagle with USB Flash Drive Support and Shared Media @@ -617,11 +602,7 @@ upload_protocol = jlink [env:mks_monster8_usb_flash_drive] extends = env:mks_monster8 platform_packages = ${stm_flash_drive.platform_packages} -build_flags = ${stm_flash_drive.build_flags} ${stm32f4_I2C1_CAN.build_flags} - -DUSE_USBHOST_HS - -DUSBD_IRQ_PRIO=5 - -DUSBD_IRQ_SUBPRIO=6 - -DUSE_USB_HS_IN_FS +build_flags = ${stm_flash_drive.build_flags} ${stm32f4_I2C1_CAN.build_flags} ${USB_HS_IN_FS.build_flags} # # MKS Monster8 V1 / V2 (STM32F407VET6 ARM Cortex-M4) with USB Flash Drive Support and Shared Media @@ -852,9 +833,8 @@ board = marlin_STM32F446ZET_tronxy board_build.ldscript = buildroot/share/PlatformIO/variants/MARLIN_F446Zx_TRONXY/ldscript.ld board_build.offset = 0x10000 board_build.offset_address = 0x08010000 -build_flags = ${stm32_variant.build_flags} - -DSTM32F4xx -DUSE_USB_HS - -DUSE_USB_HS_IN_FS +build_flags = ${stm32_variant.build_flags} -DSTM32F4xx + -DUSE_USB_HS -DUSE_USB_HS_IN_FS build_unflags = ${stm32_variant.build_unflags} -fno-rtti -fno-threadsafe-statics -fno-exceptions -DUSBD_USE_CDC -DUSBCON @@ -914,13 +894,11 @@ board = marlin_STM32F407VGT6_CCM board_build.variant = MARLIN_F4x7Vx board_build.offset = 0x8000 board_upload.offset_address = 0x08008000 -build_flags = ${stm32_variant.build_flags} +build_flags = ${stm32_variant.build_flags} ${USB_HS_IN_FS.build_flags} -DHAVE_HWSERIAL1 -DHAVE_HWSERIAL3 -DPIN_SERIAL1_RX=PA_10 -DPIN_SERIAL1_TX=PA_9 -DPIN_SERIAL3_RX=PD_9 -DPIN_SERIAL3_TX=PD_8 -DHAL_SD_MODULE_ENABLED - -DUSE_USBHOST_HS -DUSE_USB_HS_IN_FS - -DUSBD_IRQ_PRIO=5 -DUSBD_IRQ_SUBPRIO=6 -DHSE_VALUE=8000000U upload_protocol = stlink @@ -934,8 +912,6 @@ board = marlin_STM32F407VGT6_CCM board_build.variant = MARLIN_F4x7Vx board_build.offset = 0x8000 board_upload.offset_address = 0x08008000 -build_flags = ${stm_flash_drive.build_flags} - -DUSE_USBHOST_HS -DUSE_USB_HS_IN_FS - -DUSBD_IRQ_PRIO=5 -DUSBD_IRQ_SUBPRIO=6 +build_flags = ${stm_flash_drive.build_flags} ${USB_HS_IN_FS.build_flags} -DHSE_VALUE=8000000U -DHAL_SD_MODULE_ENABLED -DPIN_SERIAL3_RX=PD_9 -DPIN_SERIAL3_TX=PD_8 From 1e2e0c3a36e65f2e7561ccd129135811a8b31df7 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Fri, 24 Jan 2025 00:16:12 -0600 Subject: [PATCH 059/787] =?UTF-8?q?=F0=9F=8E=A8=20Flash=20EEPROM=20pins=20?= =?UTF-8?q?cleanup?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/HAL/STM32/eeprom_flash.cpp | 10 +++++----- Marlin/src/HAL/STM32F1/eeprom_flash.cpp | 2 +- Marlin/src/pins/gd32f1/pins_TRIGORILLA_V006.h | 2 +- Marlin/src/pins/hc32f4/pins_AQUILA_101.h | 4 ++-- Marlin/src/pins/hc32f4/pins_CREALITY_ENDER2P_V24S4.h | 4 ++-- Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_4.h | 4 ++-- Marlin/src/pins/lpc1769/pins_BTT_SKR_E3_TURBO.h | 2 +- Marlin/src/pins/lpc1769/pins_MKS_SGEN_L_V2.h | 2 +- Marlin/src/pins/mega/pins_GT2560_V41b.h | 4 ++-- Marlin/src/pins/native/pins_RAMPS_NATIVE.h | 2 +- Marlin/src/pins/ramps/pins_ZRIB_V53.h | 2 +- Marlin/src/pins/rp2040/pins_BTT_SKR_Pico.h | 2 +- Marlin/src/pins/rp2040/pins_RP2040.h | 2 +- Marlin/src/pins/sam/pins_KRATOS32.h | 2 +- Marlin/src/pins/sam/pins_RADDS.h | 2 +- Marlin/src/pins/sam/pins_RAMPS_FD_V2.h | 2 +- Marlin/src/pins/sam/pins_RAMPS_SMART.h | 2 +- Marlin/src/pins/sam/pins_RURAMPS4D_11.h | 2 +- Marlin/src/pins/sam/pins_RURAMPS4D_13.h | 2 +- Marlin/src/pins/samd/pins_BRICOLEMON_LITE_V1_0.h | 2 +- Marlin/src/pins/samd/pins_BRICOLEMON_V1_0.h | 2 +- Marlin/src/pins/samd/pins_MINITRONICS20.h | 2 +- Marlin/src/pins/samd/pins_RAMPS_144.h | 2 +- Marlin/src/pins/stm32f0/pins_MALYAN_M300.h | 2 +- Marlin/src/pins/stm32f1/pins_BTT_SKR_CR6.h | 4 ++-- Marlin/src/pins/stm32f1/pins_BTT_SKR_E3_DIP.h | 2 +- Marlin/src/pins/stm32f1/pins_BTT_SKR_MINI_E3_V2_0.h | 2 +- .../src/pins/stm32f1/pins_BTT_SKR_MINI_E3_common.h | 2 +- Marlin/src/pins/stm32f1/pins_BTT_SKR_MINI_V1_1.h | 2 +- Marlin/src/pins/stm32f1/pins_CCROBOT_MEEB_3DP.h | 2 +- Marlin/src/pins/stm32f1/pins_CHITU3D_common.h | 4 ++-- Marlin/src/pins/stm32f1/pins_CREALITY_V25S1.h | 4 ++-- Marlin/src/pins/stm32f1/pins_CREALITY_V4.h | 4 ++-- Marlin/src/pins/stm32f1/pins_CREALITY_V4210.h | 4 ++-- Marlin/src/pins/stm32f1/pins_CREALITY_V45x.h | 4 ++-- Marlin/src/pins/stm32f1/pins_CREALITY_V521.h | 4 ++-- Marlin/src/pins/stm32f1/pins_ERYONE_ERY32_MINI.h | 4 ++-- Marlin/src/pins/stm32f1/pins_FLSUN_HISPEED.h | 2 +- Marlin/src/pins/stm32f1/pins_FLY_MINI.h | 6 +++--- Marlin/src/pins/stm32f1/pins_FYSETC_AIO_II.h | 2 +- Marlin/src/pins/stm32f1/pins_FYSETC_CHEETAH.h | 2 +- Marlin/src/pins/stm32f1/pins_GTM32_MINI.h | 2 +- Marlin/src/pins/stm32f1/pins_GTM32_MINI_A30.h | 2 +- Marlin/src/pins/stm32f1/pins_GTM32_PRO_VB.h | 2 +- Marlin/src/pins/stm32f1/pins_GTM32_REV_B.h | 2 +- Marlin/src/pins/stm32f1/pins_JGAURORA_A5S_A1.h | 4 ++-- Marlin/src/pins/stm32f1/pins_KEDI_CONTROLLER_V1_2.h | 4 ++-- Marlin/src/pins/stm32f1/pins_LONGER3D_LK.h | 4 ++-- Marlin/src/pins/stm32f1/pins_MD_D301.h | 8 ++++---- Marlin/src/pins/stm32f1/pins_MINGDA_MPX_ARM_MINI.h | 4 ++-- Marlin/src/pins/stm32f1/pins_MKS_ROBIN.h | 4 ++-- Marlin/src/pins/stm32f1/pins_MKS_ROBIN_E3P.h | 2 +- .../src/pins/stm32f1/pins_MKS_ROBIN_E3_V1_1_common.h | 2 +- Marlin/src/pins/stm32f1/pins_MKS_ROBIN_E3_common.h | 2 +- Marlin/src/pins/stm32f1/pins_MKS_ROBIN_MINI.h | 4 ++-- Marlin/src/pins/stm32f1/pins_MKS_ROBIN_NANO_V2.h | 2 +- Marlin/src/pins/stm32f1/pins_MKS_ROBIN_NANO_common.h | 2 +- Marlin/src/pins/stm32f1/pins_MKS_ROBIN_PRO.h | 2 +- Marlin/src/pins/stm32f1/pins_PANDA_PI_V29.h | 2 +- Marlin/src/pins/stm32f1/pins_TRIGORILLA_PRO.h | 6 +++--- Marlin/src/pins/stm32f1/pins_ZM3E2_V1_0.h | 4 ++-- Marlin/src/pins/stm32f1/pins_ZM3E4_V1_0.h | 4 ++-- Marlin/src/pins/stm32f1/pins_ZM3E4_V2_0.h | 4 ++-- Marlin/src/pins/stm32f4/pins_ANET_ET4.h | 2 +- Marlin/src/pins/stm32f4/pins_ARMED.h | 2 +- Marlin/src/pins/stm32f4/pins_ARTILLERY_RUBY.h | 2 +- Marlin/src/pins/stm32f4/pins_BLACKBEEZMINI.h | 2 +- Marlin/src/pins/stm32f4/pins_BLACK_STM32F407VE.h | 2 +- Marlin/src/pins/stm32f4/pins_BTT_E3_RRF.h | 2 +- Marlin/src/pins/stm32f4/pins_BTT_GTR_V1_0.h | 2 +- Marlin/src/pins/stm32f4/pins_BTT_OCTOPUS_V1_common.h | 2 +- .../src/pins/stm32f4/pins_BTT_SKR_MINI_E3_V3_0_1.h | 2 +- Marlin/src/pins/stm32f4/pins_CREALITY_CR4NTXXC10.h | 4 ++-- Marlin/src/pins/stm32f4/pins_CREALITY_F401.h | 10 +++++----- Marlin/src/pins/stm32f4/pins_FLYF407ZG.h | 4 ++-- Marlin/src/pins/stm32f4/pins_FLY_RRF_E3_V1.h | 2 +- Marlin/src/pins/stm32f4/pins_FYSETC_S6_common.h | 2 +- Marlin/src/pins/stm32f4/pins_FYSETC_SPIDER.h | 2 +- Marlin/src/pins/stm32f4/pins_FYSETC_SPIDER_KING407.h | 2 +- Marlin/src/pins/stm32f4/pins_LERDGE_K.h | 2 +- Marlin/src/pins/stm32f4/pins_LERDGE_X.h | 2 +- Marlin/src/pins/stm32f4/pins_MKS_MONSTER8_common.h | 2 +- .../src/pins/stm32f4/pins_MKS_ROBIN_NANO_V3_common.h | 2 +- Marlin/src/pins/stm32f4/pins_MKS_ROBIN_PRO_V2.h | 2 +- Marlin/src/pins/stm32f4/pins_MKS_SKIPR_V1_0.h | 2 +- Marlin/src/pins/stm32f4/pins_OPULO_LUMEN_REV3.h | 2 +- Marlin/src/pins/stm32f4/pins_OPULO_LUMEN_REV4.h | 2 +- Marlin/src/pins/stm32f4/pins_RUMBA32_AUS3D.h | 4 ++-- Marlin/src/pins/stm32f4/pins_RUMBA32_BTT.h | 2 +- Marlin/src/pins/stm32f4/pins_RUMBA32_MKS.h | 2 +- Marlin/src/pins/stm32f4/pins_TH3D_EZBOARD_V2.h | 2 +- Marlin/src/pins/stm32f4/pins_TRONXY_CXY_446_V10.h | 12 ++++++------ Marlin/src/pins/stm32g0/pins_BTT_EBB42_V1_1.h | 6 +++--- Marlin/src/pins/stm32g0/pins_BTT_MANTA_E3_EZ_V1_0.h | 6 +++--- Marlin/src/pins/stm32g0/pins_BTT_MANTA_M4P_V2_1.h | 6 +++--- Marlin/src/pins/stm32g0/pins_BTT_MANTA_M5P_V1_0.h | 6 +++--- Marlin/src/pins/stm32g0/pins_BTT_MANTA_M8P_common.h | 6 +++--- Marlin/src/pins/stm32g0/pins_BTT_SKRAT_V1_0.h | 6 +++--- Marlin/src/pins/stm32g0/pins_BTT_SKR_MINI_E3_V3_0.h | 2 +- Marlin/src/pins/stm32h7/pins_BTT_KRAKEN_V1_0.h | 6 +++--- Marlin/src/pins/stm32h7/pins_BTT_MANTA_M8P_V2_0.h | 6 +++--- Marlin/src/pins/stm32h7/pins_BTT_OCTOPUS_MAX_EZ.h | 2 +- .../pins/stm32h7/pins_BTT_OCTOPUS_PRO_V1_common.h | 2 +- Marlin/src/pins/stm32h7/pins_BTT_SKR_SE_BX_common.h | 2 +- Marlin/src/pins/stm32h7/pins_BTT_SKR_V3_0_common.h | 2 +- ini/stm32f1-maple.ini | 8 +++++--- ini/stm32f1.ini | 9 ++++----- 107 files changed, 174 insertions(+), 173 deletions(-) diff --git a/Marlin/src/HAL/STM32/eeprom_flash.cpp b/Marlin/src/HAL/STM32/eeprom_flash.cpp index 48f3f402a7..14e6e4d854 100644 --- a/Marlin/src/HAL/STM32/eeprom_flash.cpp +++ b/Marlin/src/HAL/STM32/eeprom_flash.cpp @@ -63,7 +63,7 @@ #define FLASH_SECTOR (FLASH_SECTOR_TOTAL - 1) #endif #ifndef FLASH_UNIT_SIZE - #define FLASH_UNIT_SIZE 0x20000 // 128kB + #define FLASH_UNIT_SIZE 0x20000 // 128K #endif #ifndef FLASH_ADDRESS_START @@ -75,11 +75,11 @@ #define SLOT_ADDRESS(slot) (FLASH_ADDRESS_START + (slot * (MARLIN_EEPROM_SIZE))) #ifdef STM32H7xx - #define FLASHWORD_SIZE 32U // STM32H7xx a FLASHWORD is 32 bytes (256 bits) - #define FLASH_FLAGS_TO_CLEAR (FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGSERR) + #define FLASHWORD_SIZE 32U // STM32H7xx a FLASHWORD is 32 bytes (256 bits) + #define FLASH_FLAGS_TO_CLEAR (FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGSERR) #else - #define FLASHWORD_SIZE 4U // STM32F4xx a FLASHWORD is 4 bytes sizeof(uint32_t) - #define FLASH_FLAGS_TO_CLEAR (FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR) + #define FLASHWORD_SIZE 4U // STM32F4xx a FLASHWORD is 4 bytes sizeof(uint32_t) + #define FLASH_FLAGS_TO_CLEAR (FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR) #endif #define EMPTY_UINT32 ((uint32_t)-1) diff --git a/Marlin/src/HAL/STM32F1/eeprom_flash.cpp b/Marlin/src/HAL/STM32F1/eeprom_flash.cpp index afdfefd5f0..50d9cfc4f4 100644 --- a/Marlin/src/HAL/STM32F1/eeprom_flash.cpp +++ b/Marlin/src/HAL/STM32F1/eeprom_flash.cpp @@ -39,7 +39,7 @@ // Store settings in the last two pages #ifndef MARLIN_EEPROM_SIZE - #define MARLIN_EEPROM_SIZE ((EEPROM_PAGE_SIZE) * 2) + #define MARLIN_EEPROM_SIZE ((EEPROM_PAGE_SIZE) * 2UL) #endif size_t PersistentStore::capacity() { return MARLIN_EEPROM_SIZE - eeprom_exclude_size; } diff --git a/Marlin/src/pins/gd32f1/pins_TRIGORILLA_V006.h b/Marlin/src/pins/gd32f1/pins_TRIGORILLA_V006.h index 482d68616a..bb10c335ad 100644 --- a/Marlin/src/pins/gd32f1/pins_TRIGORILLA_V006.h +++ b/Marlin/src/pins/gd32f1/pins_TRIGORILLA_V006.h @@ -36,7 +36,7 @@ // EEPROM // #define FLASH_EEPROM_EMULATION -#define MARLIN_EEPROM_SIZE 0x1000 // 4KB +#define MARLIN_EEPROM_SIZE 0x1000U // 4K // // Limit Switches diff --git a/Marlin/src/pins/hc32f4/pins_AQUILA_101.h b/Marlin/src/pins/hc32f4/pins_AQUILA_101.h index 4716984933..8c3ce10c6d 100644 --- a/Marlin/src/pins/hc32f4/pins_AQUILA_101.h +++ b/Marlin/src/pins/hc32f4/pins_AQUILA_101.h @@ -65,9 +65,9 @@ #if ENABLED(IIC_BL24CXX_EEPROM) #define IIC_EEPROM_SDA PA11 #define IIC_EEPROM_SCL PA12 - #define MARLIN_EEPROM_SIZE 0x800 // 2K (24C16) + #define MARLIN_EEPROM_SIZE 0x800U // 2K (24C16) #elif ENABLED(SDCARD_EEPROM_EMULATION) - #define MARLIN_EEPROM_SIZE 0x800 // 2K + #define MARLIN_EEPROM_SIZE 0x800U // 2K #endif // diff --git a/Marlin/src/pins/hc32f4/pins_CREALITY_ENDER2P_V24S4.h b/Marlin/src/pins/hc32f4/pins_CREALITY_ENDER2P_V24S4.h index 2dde4bc5f7..df66d5c871 100644 --- a/Marlin/src/pins/hc32f4/pins_CREALITY_ENDER2P_V24S4.h +++ b/Marlin/src/pins/hc32f4/pins_CREALITY_ENDER2P_V24S4.h @@ -66,9 +66,9 @@ #if ENABLED(IIC_BL24CXX_EEPROM) #define IIC_EEPROM_SDA PA12 #define IIC_EEPROM_SCL PA11 - #define MARLIN_EEPROM_SIZE 0x800 // 2K (24C16) + #define MARLIN_EEPROM_SIZE 0x800U // 2K (24C16) #elif ENABLED(SDCARD_EEPROM_EMULATION) - #define MARLIN_EEPROM_SIZE 0x800 // 2K + #define MARLIN_EEPROM_SIZE 0x800U // 2K #endif // diff --git a/Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_4.h b/Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_4.h index 5219540db3..65718bbf45 100644 --- a/Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_4.h +++ b/Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_4.h @@ -48,9 +48,9 @@ #endif #if ENABLED(I2C_EEPROM) - #define MARLIN_EEPROM_SIZE 0x8000 // 32K + #define MARLIN_EEPROM_SIZE 0x8000U // 32K #elif ENABLED(SDCARD_EEPROM_EMULATION) - #define MARLIN_EEPROM_SIZE 0x800 // 2K + #define MARLIN_EEPROM_SIZE 0x800U // 2K #endif // diff --git a/Marlin/src/pins/lpc1769/pins_BTT_SKR_E3_TURBO.h b/Marlin/src/pins/lpc1769/pins_BTT_SKR_E3_TURBO.h index 4156fd5707..98da81781e 100644 --- a/Marlin/src/pins/lpc1769/pins_BTT_SKR_E3_TURBO.h +++ b/Marlin/src/pins/lpc1769/pins_BTT_SKR_E3_TURBO.h @@ -36,7 +36,7 @@ // Onboard I2C EEPROM #define I2C_EEPROM -#define MARLIN_EEPROM_SIZE 0x1000 // 4K (AT24C32) +#define MARLIN_EEPROM_SIZE 0x1000U // 4K (AT24C32) // // Servos diff --git a/Marlin/src/pins/lpc1769/pins_MKS_SGEN_L_V2.h b/Marlin/src/pins/lpc1769/pins_MKS_SGEN_L_V2.h index 56e7ef53b3..eb2f31cbcb 100644 --- a/Marlin/src/pins/lpc1769/pins_MKS_SGEN_L_V2.h +++ b/Marlin/src/pins/lpc1769/pins_MKS_SGEN_L_V2.h @@ -38,7 +38,7 @@ // #if NO_EEPROM_SELECTED #define I2C_EEPROM // AT24C32 - #define MARLIN_EEPROM_SIZE 0x1000 // 4K + #define MARLIN_EEPROM_SIZE 0x1000U // 4K #endif // diff --git a/Marlin/src/pins/mega/pins_GT2560_V41b.h b/Marlin/src/pins/mega/pins_GT2560_V41b.h index daebc6526d..689166cf39 100644 --- a/Marlin/src/pins/mega/pins_GT2560_V41b.h +++ b/Marlin/src/pins/mega/pins_GT2560_V41b.h @@ -25,7 +25,7 @@ * Geeetech GT2560 V4.1b Pins * Schematic: https://www.geeetech.com/download.html?spm=a2g0s.imconversation.0.0.22d23e5fXlQBWv&download_id=45 * ATmega2560 -*/ + */ #define ALLOW_MEGA1280 #include "env_validate.h" @@ -55,7 +55,7 @@ * --- --- --- --- * J3 J4 J5 J6 * -*/ + */ #ifndef X_STOP_PIN #ifndef X_MIN_PIN diff --git a/Marlin/src/pins/native/pins_RAMPS_NATIVE.h b/Marlin/src/pins/native/pins_RAMPS_NATIVE.h index 563ad9e5b3..ffc716a502 100644 --- a/Marlin/src/pins/native/pins_RAMPS_NATIVE.h +++ b/Marlin/src/pins/native/pins_RAMPS_NATIVE.h @@ -34,7 +34,7 @@ #endif #ifndef MARLIN_EEPROM_SIZE - #define MARLIN_EEPROM_SIZE 0x1000 // 4K + #define MARLIN_EEPROM_SIZE 0x1000U // 4K #endif // diff --git a/Marlin/src/pins/ramps/pins_ZRIB_V53.h b/Marlin/src/pins/ramps/pins_ZRIB_V53.h index c8502fe3fd..22b806a2b6 100644 --- a/Marlin/src/pins/ramps/pins_ZRIB_V53.h +++ b/Marlin/src/pins/ramps/pins_ZRIB_V53.h @@ -503,4 +503,4 @@ * ====== * | 12 | (12) PB6 ** Pin25 ** D12 * ====== -*/ + */ diff --git a/Marlin/src/pins/rp2040/pins_BTT_SKR_Pico.h b/Marlin/src/pins/rp2040/pins_BTT_SKR_Pico.h index 0d0807ee91..7eb0188820 100644 --- a/Marlin/src/pins/rp2040/pins_BTT_SKR_Pico.h +++ b/Marlin/src/pins/rp2040/pins_BTT_SKR_Pico.h @@ -34,7 +34,7 @@ #define USBCON #ifndef MARLIN_EEPROM_SIZE - #define MARLIN_EEPROM_SIZE 0x2000 // 8KB + #define MARLIN_EEPROM_SIZE 0x2000U // 8K #endif // diff --git a/Marlin/src/pins/rp2040/pins_RP2040.h b/Marlin/src/pins/rp2040/pins_RP2040.h index aef5f5f9fd..1b88ce347b 100644 --- a/Marlin/src/pins/rp2040/pins_RP2040.h +++ b/Marlin/src/pins/rp2040/pins_RP2040.h @@ -27,7 +27,7 @@ #define DEFAULT_MACHINE_NAME "RP2040 Test" #ifndef MARLIN_EEPROM_SIZE - #define MARLIN_EEPROM_SIZE 0x1000 // 4KB + #define MARLIN_EEPROM_SIZE 0x1000U // 4K #endif // diff --git a/Marlin/src/pins/sam/pins_KRATOS32.h b/Marlin/src/pins/sam/pins_KRATOS32.h index ff715270d2..35d2a610d1 100644 --- a/Marlin/src/pins/sam/pins_KRATOS32.h +++ b/Marlin/src/pins/sam/pins_KRATOS32.h @@ -34,7 +34,7 @@ // #if ANY(NO_EEPROM_SELECTED, I2C_EEPROM) #define I2C_EEPROM - #define MARLIN_EEPROM_SIZE 0x1F400 // 16K + #define MARLIN_EEPROM_SIZE 0x1F400U // 128000 bytes #endif // diff --git a/Marlin/src/pins/sam/pins_RADDS.h b/Marlin/src/pins/sam/pins_RADDS.h index 40f667eff4..513bccee5e 100644 --- a/Marlin/src/pins/sam/pins_RADDS.h +++ b/Marlin/src/pins/sam/pins_RADDS.h @@ -34,7 +34,7 @@ // #if ANY(NO_EEPROM_SELECTED, I2C_EEPROM) #define I2C_EEPROM - #define MARLIN_EEPROM_SIZE 0x2000 // 8K + #define MARLIN_EEPROM_SIZE 0x2000U // 8K #endif // diff --git a/Marlin/src/pins/sam/pins_RAMPS_FD_V2.h b/Marlin/src/pins/sam/pins_RAMPS_FD_V2.h index 57c7732de8..53fd7e6f88 100644 --- a/Marlin/src/pins/sam/pins_RAMPS_FD_V2.h +++ b/Marlin/src/pins/sam/pins_RAMPS_FD_V2.h @@ -41,7 +41,7 @@ #undef INVERTED_FAN_PINS #define I2C_EEPROM -#define MARLIN_EEPROM_SIZE 0x10000 // 64K in a 24C512 +#define MARLIN_EEPROM_SIZE 0x10000U // 64K in a 24C512 #ifndef PS_ON_PIN #define PS_ON_PIN 12 diff --git a/Marlin/src/pins/sam/pins_RAMPS_SMART.h b/Marlin/src/pins/sam/pins_RAMPS_SMART.h index 90e9b99697..8cdce283c7 100644 --- a/Marlin/src/pins/sam/pins_RAMPS_SMART.h +++ b/Marlin/src/pins/sam/pins_RAMPS_SMART.h @@ -64,7 +64,7 @@ // I2C EEPROM with 4K of space #define I2C_EEPROM -#define MARLIN_EEPROM_SIZE 0x1000 // 4K +#define MARLIN_EEPROM_SIZE 0x1000U // 4K // See EEPROM device datasheet for the following values. These are for 24xx256 #define EEPROM_DEVICE_ADDRESS 0x50 // 7 bit i2c address (without R/W bit) diff --git a/Marlin/src/pins/sam/pins_RURAMPS4D_11.h b/Marlin/src/pins/sam/pins_RURAMPS4D_11.h index 03ba77c077..a321796283 100644 --- a/Marlin/src/pins/sam/pins_RURAMPS4D_11.h +++ b/Marlin/src/pins/sam/pins_RURAMPS4D_11.h @@ -174,7 +174,7 @@ // // EEPROM // -#define MARLIN_EEPROM_SIZE 0x8000 // 32K (24lc256) +#define MARLIN_EEPROM_SIZE 0x8000U // 32K (24lc256) #define I2C_EEPROM // EEPROM on I2C-0 //#define EEPROM_SD // EEPROM on SDCARD //#define SPI_EEPROM // EEPROM on SPI-0 diff --git a/Marlin/src/pins/sam/pins_RURAMPS4D_13.h b/Marlin/src/pins/sam/pins_RURAMPS4D_13.h index a4574cda54..bcdabcff34 100644 --- a/Marlin/src/pins/sam/pins_RURAMPS4D_13.h +++ b/Marlin/src/pins/sam/pins_RURAMPS4D_13.h @@ -164,7 +164,7 @@ // // EEPROM // -#define MARLIN_EEPROM_SIZE 0x8000 // 32K (24lc256) +#define MARLIN_EEPROM_SIZE 0x8000U // 32K (24lc256) #define I2C_EEPROM // EEPROM on I2C-0 //#define EEPROM_SD // EEPROM on SDCARD //#define SPI_EEPROM // EEPROM on SPI-0 diff --git a/Marlin/src/pins/samd/pins_BRICOLEMON_LITE_V1_0.h b/Marlin/src/pins/samd/pins_BRICOLEMON_LITE_V1_0.h index 7f8943ac46..7e145ccc0e 100644 --- a/Marlin/src/pins/samd/pins_BRICOLEMON_LITE_V1_0.h +++ b/Marlin/src/pins/samd/pins_BRICOLEMON_LITE_V1_0.h @@ -44,7 +44,7 @@ */ //#define FLASH_EEPROM_EMULATION #define I2C_EEPROM // EEPROM on I2C-0 -#define MARLIN_EEPROM_SIZE 0x10000 // 64K (CAT24C512) +#define MARLIN_EEPROM_SIZE 0x10000U // 64K (CAT24C512) // This is another option to emulate an EEPROM, but it's more efficient to not lose the data in the first place. //#define SDCARD_EEPROM_EMULATION diff --git a/Marlin/src/pins/samd/pins_BRICOLEMON_V1_0.h b/Marlin/src/pins/samd/pins_BRICOLEMON_V1_0.h index e4766d33bb..c00caa73a4 100644 --- a/Marlin/src/pins/samd/pins_BRICOLEMON_V1_0.h +++ b/Marlin/src/pins/samd/pins_BRICOLEMON_V1_0.h @@ -48,7 +48,7 @@ */ //#define FLASH_EEPROM_EMULATION #define I2C_EEPROM // EEPROM on I2C-0 -#define MARLIN_EEPROM_SIZE 0x10000 // 64K (CAT24C512) +#define MARLIN_EEPROM_SIZE 0x10000U // 64K (CAT24C512) //This its another option to emulate an EEPROM, but its more efficient to dont loose the data the first One. //#define SDCARD_EEPROM_EMULATION diff --git a/Marlin/src/pins/samd/pins_MINITRONICS20.h b/Marlin/src/pins/samd/pins_MINITRONICS20.h index 3d625180ca..83206e3bc6 100644 --- a/Marlin/src/pins/samd/pins_MINITRONICS20.h +++ b/Marlin/src/pins/samd/pins_MINITRONICS20.h @@ -44,7 +44,7 @@ */ //#define FLASH_EEPROM_EMULATION //#define I2C_EEPROM // EEPROM on I2C-0 -#define MARLIN_EEPROM_SIZE 500 // 4000 bytes +#define MARLIN_EEPROM_SIZE 500U // 4000 bytes //This its another option to emulate an EEPROM, but its more efficient to dont loose the data the first One. //#define SDCARD_EEPROM_EMULATION diff --git a/Marlin/src/pins/samd/pins_RAMPS_144.h b/Marlin/src/pins/samd/pins_RAMPS_144.h index 97d662f8f2..fa88b81cf9 100644 --- a/Marlin/src/pins/samd/pins_RAMPS_144.h +++ b/Marlin/src/pins/samd/pins_RAMPS_144.h @@ -46,7 +46,7 @@ // //#define QSPI_EEPROM // Use AGCM4 onboard QSPI EEPROM (Uses 4K of RAM) #define I2C_EEPROM // EEPROM on I2C-0 -#define MARLIN_EEPROM_SIZE 0x8000 // 32K (24lc256) +#define MARLIN_EEPROM_SIZE 0x8000U // 32K (24lc256) // // Foam Cutter requirements diff --git a/Marlin/src/pins/stm32f0/pins_MALYAN_M300.h b/Marlin/src/pins/stm32f0/pins_MALYAN_M300.h index 9687feacab..5bc8c5f74b 100644 --- a/Marlin/src/pins/stm32f0/pins_MALYAN_M300.h +++ b/Marlin/src/pins/stm32f0/pins_MALYAN_M300.h @@ -33,7 +33,7 @@ #if NO_EEPROM_SELECTED #define FLASH_EEPROM_EMULATION #ifndef MARLIN_EEPROM_SIZE - #define MARLIN_EEPROM_SIZE 0x800U // 2K + #define MARLIN_EEPROM_SIZE 0x800U // 2K #endif #endif diff --git a/Marlin/src/pins/stm32f1/pins_BTT_SKR_CR6.h b/Marlin/src/pins/stm32f1/pins_BTT_SKR_CR6.h index c9b1d93525..e99de36a50 100644 --- a/Marlin/src/pins/stm32f1/pins_BTT_SKR_CR6.h +++ b/Marlin/src/pins/stm32f1/pins_BTT_SKR_CR6.h @@ -53,9 +53,9 @@ #if ENABLED(I2C_EEPROM) #define IIC_EEPROM_SDA PB7 #define IIC_EEPROM_SCL PB6 - #define MARLIN_EEPROM_SIZE 0x1000 // 4K + #define MARLIN_EEPROM_SIZE 0x1000U // 4K #elif ENABLED(SDCARD_EEPROM_EMULATION) - #define MARLIN_EEPROM_SIZE 0x1000 // 4K + #define MARLIN_EEPROM_SIZE 0x1000U // 4K #endif // diff --git a/Marlin/src/pins/stm32f1/pins_BTT_SKR_E3_DIP.h b/Marlin/src/pins/stm32f1/pins_BTT_SKR_E3_DIP.h index ab1684ae26..54a8ae104b 100644 --- a/Marlin/src/pins/stm32f1/pins_BTT_SKR_E3_DIP.h +++ b/Marlin/src/pins/stm32f1/pins_BTT_SKR_E3_DIP.h @@ -33,7 +33,7 @@ #if ANY(NO_EEPROM_SELECTED, FLASH_EEPROM_EMULATION) #define FLASH_EEPROM_EMULATION - #define EEPROM_PAGE_SIZE (0x800U) // 2K + #define EEPROM_PAGE_SIZE 0x800U // 2K #define EEPROM_START_ADDRESS (0x8000000UL + (STM32_FLASH_SIZE) * 1024UL - (EEPROM_PAGE_SIZE) * 2UL) #define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE // 2K #endif diff --git a/Marlin/src/pins/stm32f1/pins_BTT_SKR_MINI_E3_V2_0.h b/Marlin/src/pins/stm32f1/pins_BTT_SKR_MINI_E3_V2_0.h index d0f856b123..54546ae762 100644 --- a/Marlin/src/pins/stm32f1/pins_BTT_SKR_MINI_E3_V2_0.h +++ b/Marlin/src/pins/stm32f1/pins_BTT_SKR_MINI_E3_V2_0.h @@ -31,7 +31,7 @@ #if NO_EEPROM_SELECTED #define I2C_EEPROM #define SOFT_I2C_EEPROM - #define MARLIN_EEPROM_SIZE 0x1000 // 4K + #define MARLIN_EEPROM_SIZE 0x1000U // 4K #define I2C_SDA_PIN PB7 #define I2C_SCL_PIN PB6 #undef NO_EEPROM_SELECTED diff --git a/Marlin/src/pins/stm32f1/pins_BTT_SKR_MINI_E3_common.h b/Marlin/src/pins/stm32f1/pins_BTT_SKR_MINI_E3_common.h index 8c463717f4..6b6aec5197 100644 --- a/Marlin/src/pins/stm32f1/pins_BTT_SKR_MINI_E3_common.h +++ b/Marlin/src/pins/stm32f1/pins_BTT_SKR_MINI_E3_common.h @@ -33,7 +33,7 @@ #if ANY(NO_EEPROM_SELECTED, FLASH_EEPROM_EMULATION) #define FLASH_EEPROM_EMULATION - #define EEPROM_PAGE_SIZE (0x800U) // 2K + #define EEPROM_PAGE_SIZE 0x800U // 2K #define EEPROM_START_ADDRESS (0x8000000UL + (STM32_FLASH_SIZE) * 1024UL - (EEPROM_PAGE_SIZE) * 2UL) #define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE // 2K #endif diff --git a/Marlin/src/pins/stm32f1/pins_BTT_SKR_MINI_V1_1.h b/Marlin/src/pins/stm32f1/pins_BTT_SKR_MINI_V1_1.h index 301453cd70..0cdfa93d81 100644 --- a/Marlin/src/pins/stm32f1/pins_BTT_SKR_MINI_V1_1.h +++ b/Marlin/src/pins/stm32f1/pins_BTT_SKR_MINI_V1_1.h @@ -33,7 +33,7 @@ #if ANY(NO_EEPROM_SELECTED, FLASH_EEPROM_EMULATION) #define FLASH_EEPROM_EMULATION - #define EEPROM_PAGE_SIZE (0x800U) // 2K + #define EEPROM_PAGE_SIZE 0x800U // 2K #define EEPROM_START_ADDRESS (0x8000000UL + (STM32_FLASH_SIZE) * 1024UL - (EEPROM_PAGE_SIZE) * 2UL) #define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE // 2K #endif diff --git a/Marlin/src/pins/stm32f1/pins_CCROBOT_MEEB_3DP.h b/Marlin/src/pins/stm32f1/pins_CCROBOT_MEEB_3DP.h index e8f9cf0235..28dcfb7640 100644 --- a/Marlin/src/pins/stm32f1/pins_CCROBOT_MEEB_3DP.h +++ b/Marlin/src/pins/stm32f1/pins_CCROBOT_MEEB_3DP.h @@ -45,7 +45,7 @@ #define FLASH_EEPROM_EMULATION #define EEPROM_PAGE_SIZE 0x800U // 2K #define EEPROM_START_ADDRESS (0x8000000UL + (STM32_FLASH_SIZE) * 1024UL - (EEPROM_PAGE_SIZE) * 2UL) - #define MARLIN_EEPROM_SIZE 0x1000 // 4K + #define MARLIN_EEPROM_SIZE 0x1000U // 4K #endif // diff --git a/Marlin/src/pins/stm32f1/pins_CHITU3D_common.h b/Marlin/src/pins/stm32f1/pins_CHITU3D_common.h index 2fd713ee04..ab356dee61 100644 --- a/Marlin/src/pins/stm32f1/pins_CHITU3D_common.h +++ b/Marlin/src/pins/stm32f1/pins_CHITU3D_common.h @@ -43,8 +43,8 @@ #if ENABLED(FLASH_EEPROM_EMULATION) // SoC Flash (framework-arduinoststm32-maple/STM32F1/libraries/EEPROM/EEPROM.h) - #define EEPROM_START_ADDRESS (0x8000000UL + (512 * 1024) - 2 * EEPROM_PAGE_SIZE) - #define EEPROM_PAGE_SIZE (0x800U) // 2K, but will use 2x more (4K) + #define EEPROM_START_ADDRESS (0x8000000UL + (STM32_FLASH_SIZE) * 1024UL - (EEPROM_PAGE_SIZE) * 2UL) + #define EEPROM_PAGE_SIZE 0x800U // 2K #define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE #else #define MARLIN_EEPROM_SIZE 0x800U // On SD, Limit to 2K, require this amount of RAM diff --git a/Marlin/src/pins/stm32f1/pins_CREALITY_V25S1.h b/Marlin/src/pins/stm32f1/pins_CREALITY_V25S1.h index 6f178c7581..58e3a2e1bd 100644 --- a/Marlin/src/pins/stm32f1/pins_CREALITY_V25S1.h +++ b/Marlin/src/pins/stm32f1/pins_CREALITY_V25S1.h @@ -51,9 +51,9 @@ #if ENABLED(IIC_BL24CXX_EEPROM) #define IIC_EEPROM_SDA PA11 #define IIC_EEPROM_SCL PA12 - #define MARLIN_EEPROM_SIZE 0x800 // 2K (24C16) + #define MARLIN_EEPROM_SIZE 0x800U // 2K (24C16) #elif ANY(SDCARD_EEPROM_EMULATION, FLASH_EEPROM_EMULATION) - #define MARLIN_EEPROM_SIZE 0x800 // 2K + #define MARLIN_EEPROM_SIZE 0x800U // 2K #endif // diff --git a/Marlin/src/pins/stm32f1/pins_CREALITY_V4.h b/Marlin/src/pins/stm32f1/pins_CREALITY_V4.h index 38959a4c6c..a0e36c7f1b 100644 --- a/Marlin/src/pins/stm32f1/pins_CREALITY_V4.h +++ b/Marlin/src/pins/stm32f1/pins_CREALITY_V4.h @@ -63,9 +63,9 @@ #ifndef IIC_EEPROM_SCL #define IIC_EEPROM_SCL PA12 #endif - #define MARLIN_EEPROM_SIZE 0x800 // 2K (24C16) + #define MARLIN_EEPROM_SIZE 0x800U // 2K (24C16) #elif ENABLED(SDCARD_EEPROM_EMULATION) - #define MARLIN_EEPROM_SIZE 0x800 // 2K + #define MARLIN_EEPROM_SIZE 0x800U // 2K #endif // diff --git a/Marlin/src/pins/stm32f1/pins_CREALITY_V4210.h b/Marlin/src/pins/stm32f1/pins_CREALITY_V4210.h index 21503bd1e0..189ead3479 100644 --- a/Marlin/src/pins/stm32f1/pins_CREALITY_V4210.h +++ b/Marlin/src/pins/stm32f1/pins_CREALITY_V4210.h @@ -54,10 +54,10 @@ #if ENABLED(IIC_BL24CXX_EEPROM) #define IIC_EEPROM_SDA PA11 #define IIC_EEPROM_SCL PA12 - #define MARLIN_EEPROM_SIZE 0x800 // 2K (24C16) + #define MARLIN_EEPROM_SIZE 0x800U // 2K (24C16) #else #define SDCARD_EEPROM_EMULATION // SD EEPROM until all EEPROM is BL24CXX - #define MARLIN_EEPROM_SIZE 0x800 // 2K + #define MARLIN_EEPROM_SIZE 0x800U // 2K #endif // diff --git a/Marlin/src/pins/stm32f1/pins_CREALITY_V45x.h b/Marlin/src/pins/stm32f1/pins_CREALITY_V45x.h index d592b4808a..68974d60f8 100644 --- a/Marlin/src/pins/stm32f1/pins_CREALITY_V45x.h +++ b/Marlin/src/pins/stm32f1/pins_CREALITY_V45x.h @@ -47,9 +47,9 @@ #if ENABLED(IIC_BL24CXX_EEPROM) #define IIC_EEPROM_SDA PA11 #define IIC_EEPROM_SCL PA12 - #define MARLIN_EEPROM_SIZE 0x800 // 2K (24C16) + #define MARLIN_EEPROM_SIZE 0x800U // 2K (24C16) #elif ENABLED(SDCARD_EEPROM_EMULATION) - #define MARLIN_EEPROM_SIZE 0x800 // 2K + #define MARLIN_EEPROM_SIZE 0x800U // 2K #endif // diff --git a/Marlin/src/pins/stm32f1/pins_CREALITY_V521.h b/Marlin/src/pins/stm32f1/pins_CREALITY_V521.h index 2116aad8e9..60a0062621 100644 --- a/Marlin/src/pins/stm32f1/pins_CREALITY_V521.h +++ b/Marlin/src/pins/stm32f1/pins_CREALITY_V521.h @@ -50,10 +50,10 @@ #if ENABLED(IIC_BL24CXX_EEPROM) #define IIC_EEPROM_SDA PC2 #define IIC_EEPROM_SCL PC3 - #define MARLIN_EEPROM_SIZE 0x800 // 2K (24C16) + #define MARLIN_EEPROM_SIZE 0x800U // 2K (24C16) #else #define SDCARD_EEPROM_EMULATION // SD EEPROM until all EEPROM is BL24CXX - #define MARLIN_EEPROM_SIZE 0x800 // 2K + #define MARLIN_EEPROM_SIZE 0x800U // 2K #endif #undef NO_EEPROM_SELECTED diff --git a/Marlin/src/pins/stm32f1/pins_ERYONE_ERY32_MINI.h b/Marlin/src/pins/stm32f1/pins_ERYONE_ERY32_MINI.h index 30f3f939d8..b6e5e07644 100644 --- a/Marlin/src/pins/stm32f1/pins_ERYONE_ERY32_MINI.h +++ b/Marlin/src/pins/stm32f1/pins_ERYONE_ERY32_MINI.h @@ -41,9 +41,9 @@ #if ANY(NO_EEPROM_SELECTED, FLASH_EEPROM_EMULATION) #define FLASH_EEPROM_EMULATION - #define EEPROM_PAGE_SIZE (0x800U) // 2K + #define EEPROM_PAGE_SIZE 0x800U // 2K #define EEPROM_START_ADDRESS (0x8000000UL + (STM32_FLASH_SIZE) * 1024UL - (EEPROM_PAGE_SIZE) * 2UL) - #define MARLIN_EEPROM_SIZE (EEPROM_PAGE_SIZE) + #define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE // 2K #endif // diff --git a/Marlin/src/pins/stm32f1/pins_FLSUN_HISPEED.h b/Marlin/src/pins/stm32f1/pins_FLSUN_HISPEED.h index b42a249e85..88a91397d4 100644 --- a/Marlin/src/pins/stm32f1/pins_FLSUN_HISPEED.h +++ b/Marlin/src/pins/stm32f1/pins_FLSUN_HISPEED.h @@ -53,7 +53,7 @@ // #if ANY(NO_EEPROM_SELECTED, FLASH_EEPROM_EMULATION) #define FLASH_EEPROM_EMULATION - #define EEPROM_PAGE_SIZE (0x800U) // 2K + #define EEPROM_PAGE_SIZE 0x800U // 2K #define EEPROM_START_ADDRESS (0x8000000UL + (STM32_FLASH_SIZE) * 1024UL - (EEPROM_PAGE_SIZE) * 2UL) #define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE // 2K #endif diff --git a/Marlin/src/pins/stm32f1/pins_FLY_MINI.h b/Marlin/src/pins/stm32f1/pins_FLY_MINI.h index 1f62a10149..5f17afeb4a 100644 --- a/Marlin/src/pins/stm32f1/pins_FLY_MINI.h +++ b/Marlin/src/pins/stm32f1/pins_FLY_MINI.h @@ -32,9 +32,9 @@ // #if ANY(NO_EEPROM_SELECTED, FLASH_EEPROM_EMULATION) #define FLASH_EEPROM_EMULATION - #define EEPROM_PAGE_SIZE 0x800 // 2K - #define EEPROM_START_ADDRESS (0x8000000 + 256 * 1024 - 2 * EEPROM_PAGE_SIZE) // 256K firmware space - #define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE + #define EEPROM_PAGE_SIZE 0x800U // 2K + #define EEPROM_START_ADDRESS (0x8000000UL + (STM32_FLASH_SIZE) * 1024UL - (EEPROM_PAGE_SIZE) * 2UL) // 256K firmware space + #define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE // 2K #endif // diff --git a/Marlin/src/pins/stm32f1/pins_FYSETC_AIO_II.h b/Marlin/src/pins/stm32f1/pins_FYSETC_AIO_II.h index 3153f4956c..2b6d148f1f 100644 --- a/Marlin/src/pins/stm32f1/pins_FYSETC_AIO_II.h +++ b/Marlin/src/pins/stm32f1/pins_FYSETC_AIO_II.h @@ -40,7 +40,7 @@ // #if ANY(NO_EEPROM_SELECTED, FLASH_EEPROM_EMULATION) #define FLASH_EEPROM_EMULATION - #define EEPROM_PAGE_SIZE (0x800U) // 2K + #define EEPROM_PAGE_SIZE 0x800U // 2K #define EEPROM_START_ADDRESS (0x8000000UL + (STM32_FLASH_SIZE) * 1024UL - (EEPROM_PAGE_SIZE) * 2UL) #define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE // 2K #endif diff --git a/Marlin/src/pins/stm32f1/pins_FYSETC_CHEETAH.h b/Marlin/src/pins/stm32f1/pins_FYSETC_CHEETAH.h index 875d3dc998..0364517e24 100644 --- a/Marlin/src/pins/stm32f1/pins_FYSETC_CHEETAH.h +++ b/Marlin/src/pins/stm32f1/pins_FYSETC_CHEETAH.h @@ -35,7 +35,7 @@ #if ANY(NO_EEPROM_SELECTED, FLASH_EEPROM_EMULATION) #define FLASH_EEPROM_EMULATION - #define EEPROM_PAGE_SIZE (0x800U) // 2K + #define EEPROM_PAGE_SIZE 0x800U // 2K #define EEPROM_START_ADDRESS (0x8000000UL + (STM32_FLASH_SIZE) * 1024UL - (EEPROM_PAGE_SIZE) * 2UL) #define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE // 2K #endif diff --git a/Marlin/src/pins/stm32f1/pins_GTM32_MINI.h b/Marlin/src/pins/stm32f1/pins_GTM32_MINI.h index 6baee148c7..7af5ff2259 100644 --- a/Marlin/src/pins/stm32f1/pins_GTM32_MINI.h +++ b/Marlin/src/pins/stm32f1/pins_GTM32_MINI.h @@ -53,7 +53,7 @@ // Enable EEPROM Emulation for this board as it doesn't have EEPROM #if ANY(NO_EEPROM_SELECTED, FLASH_EEPROM_EMULATION) #define FLASH_EEPROM_EMULATION - #define MARLIN_EEPROM_SIZE 0x1000 // 4K + #define MARLIN_EEPROM_SIZE 0x1000U // 4K #endif // diff --git a/Marlin/src/pins/stm32f1/pins_GTM32_MINI_A30.h b/Marlin/src/pins/stm32f1/pins_GTM32_MINI_A30.h index ee605c8765..923ad5ea41 100644 --- a/Marlin/src/pins/stm32f1/pins_GTM32_MINI_A30.h +++ b/Marlin/src/pins/stm32f1/pins_GTM32_MINI_A30.h @@ -53,7 +53,7 @@ // Enable EEPROM Emulation for this board as it doesn't have EEPROM #if ANY(NO_EEPROM_SELECTED, FLASH_EEPROM_EMULATION) #define FLASH_EEPROM_EMULATION - #define MARLIN_EEPROM_SIZE 0x1000 // 4K + #define MARLIN_EEPROM_SIZE 0x1000U // 4K #endif // diff --git a/Marlin/src/pins/stm32f1/pins_GTM32_PRO_VB.h b/Marlin/src/pins/stm32f1/pins_GTM32_PRO_VB.h index c636dea493..62ecaf10b6 100644 --- a/Marlin/src/pins/stm32f1/pins_GTM32_PRO_VB.h +++ b/Marlin/src/pins/stm32f1/pins_GTM32_PRO_VB.h @@ -58,7 +58,7 @@ // Enable EEPROM Emulation for this board as it doesn't have EEPROM #if ANY(NO_EEPROM_SELECTED, FLASH_EEPROM_EMULATION) #define FLASH_EEPROM_EMULATION - #define MARLIN_EEPROM_SIZE 0x1000 // 4K + #define MARLIN_EEPROM_SIZE 0x1000U // 4K #endif // diff --git a/Marlin/src/pins/stm32f1/pins_GTM32_REV_B.h b/Marlin/src/pins/stm32f1/pins_GTM32_REV_B.h index 814844d95b..0264647c8e 100644 --- a/Marlin/src/pins/stm32f1/pins_GTM32_REV_B.h +++ b/Marlin/src/pins/stm32f1/pins_GTM32_REV_B.h @@ -53,7 +53,7 @@ // Enable EEPROM Emulation for this board as it doesn't have EEPROM #if ANY(NO_EEPROM_SELECTED, FLASH_EEPROM_EMULATION) #define FLASH_EEPROM_EMULATION - #define MARLIN_EEPROM_SIZE 0x1000 // 4K + #define MARLIN_EEPROM_SIZE 0x1000U // 4K #endif // diff --git a/Marlin/src/pins/stm32f1/pins_JGAURORA_A5S_A1.h b/Marlin/src/pins/stm32f1/pins_JGAURORA_A5S_A1.h index 497af7a8bd..3c44c6256b 100644 --- a/Marlin/src/pins/stm32f1/pins_JGAURORA_A5S_A1.h +++ b/Marlin/src/pins/stm32f1/pins_JGAURORA_A5S_A1.h @@ -53,9 +53,9 @@ #endif #if ENABLED(I2C_EEPROM) - //#define MARLIN_EEPROM_SIZE 0x8000UL // 32K + //#define MARLIN_EEPROM_SIZE 0x8000U // 32K #elif ENABLED(FLASH_EEPROM_EMULATION) - //#define MARLIN_EEPROM_SIZE 0x1000UL // 4K + //#define MARLIN_EEPROM_SIZE 0x1000U // 4K //#define MARLIN_EEPROM_SIZE (EEPROM_START_ADDRESS + (EEPROM_PAGE_SIZE) * 2UL) #endif diff --git a/Marlin/src/pins/stm32f1/pins_KEDI_CONTROLLER_V1_2.h b/Marlin/src/pins/stm32f1/pins_KEDI_CONTROLLER_V1_2.h index b136ef72c5..f7fde28374 100644 --- a/Marlin/src/pins/stm32f1/pins_KEDI_CONTROLLER_V1_2.h +++ b/Marlin/src/pins/stm32f1/pins_KEDI_CONTROLLER_V1_2.h @@ -33,9 +33,9 @@ #if ANY(NO_EEPROM_SELECTED, FLASH_EEPROM_EMULATION) #define FLASH_EEPROM_EMULATION - #define EEPROM_PAGE_SIZE (0x800U) // 2KB + #define EEPROM_PAGE_SIZE 0x800U // 2K #define EEPROM_START_ADDRESS (0x8000000UL + (STM32_FLASH_SIZE) * 1024UL - (EEPROM_PAGE_SIZE) * 2UL) - #define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE // 2KB + #define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE // 2K #endif // diff --git a/Marlin/src/pins/stm32f1/pins_LONGER3D_LK.h b/Marlin/src/pins/stm32f1/pins_LONGER3D_LK.h index 95d7889768..9babe7e977 100644 --- a/Marlin/src/pins/stm32f1/pins_LONGER3D_LK.h +++ b/Marlin/src/pins/stm32f1/pins_LONGER3D_LK.h @@ -205,9 +205,9 @@ #define SPI_FLASH_MOSI_PIN PA7 #elif ENABLED(FLASH_EEPROM_EMULATION) // SoC Flash (framework-arduinoststm32-maple/STM32F1/libraries/EEPROM/EEPROM.h) - #define EEPROM_PAGE_SIZE (0x800U) // 2K + #define EEPROM_PAGE_SIZE 0x800U // 2K #define EEPROM_START_ADDRESS (0x8000000UL + (STM32_FLASH_SIZE) * 1024UL - (EEPROM_PAGE_SIZE) * 2UL) - #define MARLIN_EEPROM_SIZE (EEPROM_PAGE_SIZE) + #define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE // 2K #else #define MARLIN_EEPROM_SIZE 0x800U // On SD, Limit to 2K, require this amount of RAM #endif diff --git a/Marlin/src/pins/stm32f1/pins_MD_D301.h b/Marlin/src/pins/stm32f1/pins_MD_D301.h index 23e44ad4a0..3cd7dffed3 100644 --- a/Marlin/src/pins/stm32f1/pins_MD_D301.h +++ b/Marlin/src/pins/stm32f1/pins_MD_D301.h @@ -33,16 +33,16 @@ #define DISABLE_JTAG #define FLASH_EEPROM_EMULATION -#define EEPROM_PAGE_SIZE (0x800U) // 2KB -#define EEPROM_START_ADDRESS (0x8000000UL + (512) * 1024UL - (EEPROM_PAGE_SIZE) * 2UL) -#define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE // 2KB +#define EEPROM_PAGE_SIZE 0x800U // 2K +#define EEPROM_START_ADDRESS (0x8000000UL + (STM32_FLASH_SIZE) * 1024UL - (EEPROM_PAGE_SIZE) * 2UL) +#define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE // 2K /** * This board works with this SERIAL_PORT_* configuration * #define SERIAL_PORT 3 * #define BAUDRATE 115200 * #define SERIAL_PORT_2 -1 -*/ + */ // // Servos diff --git a/Marlin/src/pins/stm32f1/pins_MINGDA_MPX_ARM_MINI.h b/Marlin/src/pins/stm32f1/pins_MINGDA_MPX_ARM_MINI.h index 333cf85325..5077db8c82 100644 --- a/Marlin/src/pins/stm32f1/pins_MINGDA_MPX_ARM_MINI.h +++ b/Marlin/src/pins/stm32f1/pins_MINGDA_MPX_ARM_MINI.h @@ -46,7 +46,7 @@ #define I2C_EEPROM #undef NO_EEPROM_SELECTED -#define MARLIN_EEPROM_SIZE 0x1000 // 4K +#define MARLIN_EEPROM_SIZE 0x1000U // 4K #define USE_SHARED_EEPROM 1 // Use Platform-independent Arduino functions for I2C EEPROM #define E2END 0xFFFF // EEPROM end address AT24C256 (32kB) */ @@ -54,7 +54,7 @@ #if ANY(NO_EEPROM_SELECTED, FLASH_EEPROM_EMULATION) #define FLASH_EEPROM_EMULATION #define EEPROM_PAGE_SIZE 0x800U // 2K - #define EEPROM_START_ADDRESS (0x8000000UL + (STM32_FLASH_SIZE) * 1024UL - (EEPROM_PAGE_SIZE) * 2UL) + #define EEPROM_START_ADDRESS (0x8000000UL + (STM32_FLASH_SIZE) * 1024UL - (EEPROM_PAGE_SIZE) * 2UL) #define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE // 2K #endif diff --git a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN.h b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN.h index 353eefae76..ff438418fe 100644 --- a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN.h +++ b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN.h @@ -53,9 +53,9 @@ #endif #if ENABLED(FLASH_EEPROM_EMULATION) - #define EEPROM_PAGE_SIZE (0x800U) // 2K + #define EEPROM_PAGE_SIZE 0x800U // 2K #define EEPROM_START_ADDRESS (0x8000000UL + (STM32_FLASH_SIZE) * 1024UL - (EEPROM_PAGE_SIZE) * 2UL) - #define MARLIN_EEPROM_SIZE (EEPROM_PAGE_SIZE) + #define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE // 2K #endif // diff --git a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_E3P.h b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_E3P.h index 02aec548d4..af9c18acf8 100644 --- a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_E3P.h +++ b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_E3P.h @@ -54,7 +54,7 @@ #if ANY(NO_EEPROM_SELECTED, I2C_EEPROM) #define I2C_EEPROM // EEPROM on I2C-0 - #define MARLIN_EEPROM_SIZE 0x1000 // 4K + #define MARLIN_EEPROM_SIZE 0x1000U // 4K #endif // diff --git a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_E3_V1_1_common.h b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_E3_V1_1_common.h index 9fa5ec6b31..24e0d464e6 100644 --- a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_E3_V1_1_common.h +++ b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_E3_V1_1_common.h @@ -27,7 +27,7 @@ // Onboard I2C EEPROM #if NO_EEPROM_SELECTED #define I2C_EEPROM - #define MARLIN_EEPROM_SIZE 0x1000// 4K + #define MARLIN_EEPROM_SIZE 0x1000U // 4K #undef NO_EEPROM_SELECTED #endif diff --git a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_E3_common.h b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_E3_common.h index 547d0f230a..5ac10c5e22 100644 --- a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_E3_common.h +++ b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_E3_common.h @@ -40,7 +40,7 @@ // #if ANY(NO_EEPROM_SELECTED, FLASH_EEPROM_EMULATION) #define FLASH_EEPROM_EMULATION - #define EEPROM_PAGE_SIZE (0x800U) // 2K + #define EEPROM_PAGE_SIZE 0x800U // 2K #define EEPROM_START_ADDRESS (0x8000000UL + (STM32_FLASH_SIZE) * 1024UL - (EEPROM_PAGE_SIZE) * 2UL) #define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE // 2K #endif diff --git a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_MINI.h b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_MINI.h index e21760940c..b7c494c1af 100644 --- a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_MINI.h +++ b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_MINI.h @@ -45,8 +45,8 @@ // #if ANY(NO_EEPROM_SELECTED, FLASH_EEPROM_EMULATION) #define FLASH_EEPROM_EMULATION - #define EEPROM_PAGE_SIZE (0x800U) // 2K - #define EEPROM_START_ADDRESS (0x8000000UL + (STM32_FLASH_SIZE) * 1024UL - (EEPROM_PAGE_SIZE) * 2UL) + #define EEPROM_PAGE_SIZE 0x800U // 2K + #define EEPROM_START_ADDRESS (0x8000000UL + (STM32_FLASH_SIZE) * 1024UL - (EEPROM_PAGE_SIZE) * 2UL) #define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE // 2K #endif diff --git a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_NANO_V2.h b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_NANO_V2.h index 39a54e388f..2a2a42a4d4 100644 --- a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_NANO_V2.h +++ b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_NANO_V2.h @@ -56,7 +56,7 @@ #if ANY(NO_EEPROM_SELECTED, I2C_EEPROM) #define I2C_EEPROM // EEPROM on I2C-0 - #define MARLIN_EEPROM_SIZE 0x1000 // 4K + #define MARLIN_EEPROM_SIZE 0x1000U // 4K #endif // diff --git a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_NANO_common.h b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_NANO_common.h index 808b0c190c..526109589f 100644 --- a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_NANO_common.h +++ b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_NANO_common.h @@ -44,7 +44,7 @@ #endif #if ANY(NO_EEPROM_SELECTED, FLASH_EEPROM_EMULATION) #define FLASH_EEPROM_EMULATION - #define EEPROM_PAGE_SIZE (0x800U) // 2K + #define EEPROM_PAGE_SIZE 0x800U // 2K #define EEPROM_START_ADDRESS (0x8000000UL + (STM32_FLASH_SIZE) * 1024UL - (EEPROM_PAGE_SIZE) * 2UL) #define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE // 2K #endif diff --git a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_PRO.h b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_PRO.h index f89056d783..1639ffed59 100644 --- a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_PRO.h +++ b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_PRO.h @@ -45,7 +45,7 @@ // Onboard I2C EEPROM // #define IIC_BL24CXX_EEPROM // Use I2C EEPROM onboard IC (AT24C04C, Size 4K, PageSize 16B) -#define MARLIN_EEPROM_SIZE 0x1000 // 4K +#define MARLIN_EEPROM_SIZE 0x1000U // 4K #define IIC_EEPROM_SDA PB7 #define IIC_EEPROM_SCL PB6 #define EEPROM_DEVICE_ADDRESS 0xA0 diff --git a/Marlin/src/pins/stm32f1/pins_PANDA_PI_V29.h b/Marlin/src/pins/stm32f1/pins_PANDA_PI_V29.h index 61ee75fa2a..e732dd3d96 100644 --- a/Marlin/src/pins/stm32f1/pins_PANDA_PI_V29.h +++ b/Marlin/src/pins/stm32f1/pins_PANDA_PI_V29.h @@ -33,7 +33,7 @@ #if ANY(NO_EEPROM_SELECTED, FLASH_EEPROM_EMULATION) #define FLASH_EEPROM_EMULATION - #define EEPROM_PAGE_SIZE (0x800U) // 2K + #define EEPROM_PAGE_SIZE 0x800U // 2K #define EEPROM_START_ADDRESS (0x8000000UL + (STM32_FLASH_SIZE) * 1024UL - (EEPROM_PAGE_SIZE) * 2UL) #define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE // 2K #endif diff --git a/Marlin/src/pins/stm32f1/pins_TRIGORILLA_PRO.h b/Marlin/src/pins/stm32f1/pins_TRIGORILLA_PRO.h index b611d945dc..9359408fa1 100644 --- a/Marlin/src/pins/stm32f1/pins_TRIGORILLA_PRO.h +++ b/Marlin/src/pins/stm32f1/pins_TRIGORILLA_PRO.h @@ -50,11 +50,11 @@ #endif #if ENABLED(FLASH_EEPROM_EMULATION) // SoC Flash (framework-arduinoststm32-maple/STM32F1/libraries/EEPROM/EEPROM.h) - #define EEPROM_START_ADDRESS (0x8000000UL + (512 * 1024) - 2 * EEPROM_PAGE_SIZE) - #define EEPROM_PAGE_SIZE (0x800U) // 2K, but will use 2x more (4K) + #define EEPROM_START_ADDRESS (0x8000000UL + (STM32_FLASH_SIZE) * 1024UL - (EEPROM_PAGE_SIZE) * 2UL) + #define EEPROM_PAGE_SIZE 0x800U // 2K #define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE #else - #define MARLIN_EEPROM_SIZE (0x800U) // On SD, Limit to 2K, require this amount of RAM + #define MARLIN_EEPROM_SIZE 0x800U // On SD, Limit to 2K, require this amount of RAM #endif // diff --git a/Marlin/src/pins/stm32f1/pins_ZM3E2_V1_0.h b/Marlin/src/pins/stm32f1/pins_ZM3E2_V1_0.h index 8ce0f48839..ecea985494 100644 --- a/Marlin/src/pins/stm32f1/pins_ZM3E2_V1_0.h +++ b/Marlin/src/pins/stm32f1/pins_ZM3E2_V1_0.h @@ -30,8 +30,8 @@ #if NO_EEPROM_SELECTED #define FLASH_EEPROM_EMULATION - #define EEPROM_PAGE_SIZE (0x800) // 2K - #define EEPROM_START_ADDRESS (0x08000000 + (STM32_FLASH_SIZE) * 1024 - 2 * EEPROM_PAGE_SIZE) + #define EEPROM_PAGE_SIZE 0x800U // 2K + #define EEPROM_START_ADDRESS (0x8000000UL + (STM32_FLASH_SIZE) * 1024UL - (EEPROM_PAGE_SIZE) * 2UL) #define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE // 2K #endif diff --git a/Marlin/src/pins/stm32f1/pins_ZM3E4_V1_0.h b/Marlin/src/pins/stm32f1/pins_ZM3E4_V1_0.h index c1e5a46f70..069086a43b 100644 --- a/Marlin/src/pins/stm32f1/pins_ZM3E4_V1_0.h +++ b/Marlin/src/pins/stm32f1/pins_ZM3E4_V1_0.h @@ -30,8 +30,8 @@ #if NO_EEPROM_SELECTED #define FLASH_EEPROM_EMULATION - #define EEPROM_PAGE_SIZE (0x800) // 2K - #define EEPROM_START_ADDRESS (0x08000000 + (STM32_FLASH_SIZE) * 1024 - 2 * EEPROM_PAGE_SIZE) + #define EEPROM_PAGE_SIZE 0x800U // 2K + #define EEPROM_START_ADDRESS (0x8000000UL + (STM32_FLASH_SIZE) * 1024UL - (EEPROM_PAGE_SIZE) * 2UL) #define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE // 2K #endif diff --git a/Marlin/src/pins/stm32f1/pins_ZM3E4_V2_0.h b/Marlin/src/pins/stm32f1/pins_ZM3E4_V2_0.h index 24c7404360..66e538cb48 100644 --- a/Marlin/src/pins/stm32f1/pins_ZM3E4_V2_0.h +++ b/Marlin/src/pins/stm32f1/pins_ZM3E4_V2_0.h @@ -30,8 +30,8 @@ #if NO_EEPROM_SELECTED #define FLASH_EEPROM_EMULATION - #define EEPROM_PAGE_SIZE (0x800) // 2K - #define EEPROM_START_ADDRESS (0x08000000 + (STM32_FLASH_SIZE) * 1024 - 2 * EEPROM_PAGE_SIZE) + #define EEPROM_PAGE_SIZE 0x800U // 2K + #define EEPROM_START_ADDRESS (0x8000000UL + (STM32_FLASH_SIZE) * 1024UL - (EEPROM_PAGE_SIZE) * 2UL) #define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE // 2K #endif diff --git a/Marlin/src/pins/stm32f4/pins_ANET_ET4.h b/Marlin/src/pins/stm32f4/pins_ANET_ET4.h index 794674569c..6799bbb6f5 100644 --- a/Marlin/src/pins/stm32f4/pins_ANET_ET4.h +++ b/Marlin/src/pins/stm32f4/pins_ANET_ET4.h @@ -50,7 +50,7 @@ #define IIC_EEPROM_SDA PB11 #define IIC_EEPROM_SCL PB10 #define EEPROM_DEVICE_ADDRESS 0xA0 - #define MARLIN_EEPROM_SIZE 0x1000 // 4K + #define MARLIN_EEPROM_SIZE 0x1000U // 4K #endif // diff --git a/Marlin/src/pins/stm32f4/pins_ARMED.h b/Marlin/src/pins/stm32f4/pins_ARMED.h index 8f2ae0b93a..3553ca0d2c 100644 --- a/Marlin/src/pins/stm32f4/pins_ARMED.h +++ b/Marlin/src/pins/stm32f4/pins_ARMED.h @@ -39,7 +39,7 @@ #if NO_EEPROM_SELECTED #define I2C_EEPROM - #define MARLIN_EEPROM_SIZE 0x1000 // 4K + #define MARLIN_EEPROM_SIZE 0x1000U // 4K #endif // diff --git a/Marlin/src/pins/stm32f4/pins_ARTILLERY_RUBY.h b/Marlin/src/pins/stm32f4/pins_ARTILLERY_RUBY.h index 4d487355a3..8b60b234cd 100644 --- a/Marlin/src/pins/stm32f4/pins_ARTILLERY_RUBY.h +++ b/Marlin/src/pins/stm32f4/pins_ARTILLERY_RUBY.h @@ -33,7 +33,7 @@ #define FLASH_EEPROM_EMULATION //#define I2C_EEPROM #endif -#define MARLIN_EEPROM_SIZE 0x1000 // 4K +#define MARLIN_EEPROM_SIZE 0x1000U // 4K #define HAL_TIMER_RATE F_CPU diff --git a/Marlin/src/pins/stm32f4/pins_BLACKBEEZMINI.h b/Marlin/src/pins/stm32f4/pins_BLACKBEEZMINI.h index 8869de6363..ad41563ca4 100644 --- a/Marlin/src/pins/stm32f4/pins_BLACKBEEZMINI.h +++ b/Marlin/src/pins/stm32f4/pins_BLACKBEEZMINI.h @@ -45,7 +45,7 @@ #define FLASH_EEPROM_EMULATION #define FLASH_EEPROM_LEVELING #define FLASH_SECTOR (FLASH_SECTOR_TOTAL - 1) - #define FLASH_UNIT_SIZE 0x4000 // 16kB + #define FLASH_UNIT_SIZE 0x4000U // 16K #define MARLIN_EEPROM_SIZE FLASH_UNIT_SIZE #undef NO_EEPROM_SELECTED #endif diff --git a/Marlin/src/pins/stm32f4/pins_BLACK_STM32F407VE.h b/Marlin/src/pins/stm32f4/pins_BLACK_STM32F407VE.h index 8bd14b219e..28b3938906 100644 --- a/Marlin/src/pins/stm32f4/pins_BLACK_STM32F407VE.h +++ b/Marlin/src/pins/stm32f4/pins_BLACK_STM32F407VE.h @@ -42,7 +42,7 @@ //#define I2C_EEPROM #define SRAM_EEPROM_EMULATION -#define MARLIN_EEPROM_SIZE 0x2000 // 8K +#define MARLIN_EEPROM_SIZE 0x2000U // 8K // // Servos diff --git a/Marlin/src/pins/stm32f4/pins_BTT_E3_RRF.h b/Marlin/src/pins/stm32f4/pins_BTT_E3_RRF.h index cd198b76be..b91675a56e 100644 --- a/Marlin/src/pins/stm32f4/pins_BTT_E3_RRF.h +++ b/Marlin/src/pins/stm32f4/pins_BTT_E3_RRF.h @@ -34,7 +34,7 @@ // Onboard I2C EEPROM #define I2C_EEPROM -#define MARLIN_EEPROM_SIZE 0x1000 // 4K +#define MARLIN_EEPROM_SIZE 0x1000U // 4K // // Servos diff --git a/Marlin/src/pins/stm32f4/pins_BTT_GTR_V1_0.h b/Marlin/src/pins/stm32f4/pins_BTT_GTR_V1_0.h index 256868d9bc..be98edd605 100644 --- a/Marlin/src/pins/stm32f4/pins_BTT_GTR_V1_0.h +++ b/Marlin/src/pins/stm32f4/pins_BTT_GTR_V1_0.h @@ -37,7 +37,7 @@ // Onboard I2C EEPROM #define I2C_EEPROM -#define MARLIN_EEPROM_SIZE 0x2000 // 8K (24C64) +#define MARLIN_EEPROM_SIZE 0x2000U // 8K (24C64) // // Servos diff --git a/Marlin/src/pins/stm32f4/pins_BTT_OCTOPUS_V1_common.h b/Marlin/src/pins/stm32f4/pins_BTT_OCTOPUS_V1_common.h index 93cbeb11d6..ac96042b23 100644 --- a/Marlin/src/pins/stm32f4/pins_BTT_OCTOPUS_V1_common.h +++ b/Marlin/src/pins/stm32f4/pins_BTT_OCTOPUS_V1_common.h @@ -36,7 +36,7 @@ #if ANY(NO_EEPROM_SELECTED, I2C_EEPROM) #undef NO_EEPROM_SELECTED #define I2C_EEPROM - #define MARLIN_EEPROM_SIZE 0x1000 // 4K (AT24C32) + #define MARLIN_EEPROM_SIZE 0x1000U // 4K (AT24C32) #define SOFT_I2C_EEPROM // Force the use of Software I2C #define I2C_SCL_PIN PB8 #define I2C_SDA_PIN PB9 diff --git a/Marlin/src/pins/stm32f4/pins_BTT_SKR_MINI_E3_V3_0_1.h b/Marlin/src/pins/stm32f4/pins_BTT_SKR_MINI_E3_V3_0_1.h index 31501e3ddf..0582cdff61 100644 --- a/Marlin/src/pins/stm32f4/pins_BTT_SKR_MINI_E3_V3_0_1.h +++ b/Marlin/src/pins/stm32f4/pins_BTT_SKR_MINI_E3_V3_0_1.h @@ -49,7 +49,7 @@ #define SOFT_I2C_EEPROM // Force the use of Software I2C #define I2C_SCL_PIN PB8 #define I2C_SDA_PIN PB9 - #define MARLIN_EEPROM_SIZE 0x1000 // 4K + #define MARLIN_EEPROM_SIZE 0x1000U // 4K #endif // diff --git a/Marlin/src/pins/stm32f4/pins_CREALITY_CR4NTXXC10.h b/Marlin/src/pins/stm32f4/pins_CREALITY_CR4NTXXC10.h index 683f68089a..c06e48f8b2 100644 --- a/Marlin/src/pins/stm32f4/pins_CREALITY_CR4NTXXC10.h +++ b/Marlin/src/pins/stm32f4/pins_CREALITY_CR4NTXXC10.h @@ -59,9 +59,9 @@ #if ENABLED(IIC_BL24CXX_EEPROM) #define IIC_EEPROM_SDA PA11 #define IIC_EEPROM_SCL PA12 - #define MARLIN_EEPROM_SIZE 0x800 // 2K (24C16) + #define MARLIN_EEPROM_SIZE 0x800U // 2K (24C16) #elif ENABLED(SDCARD_EEPROM_EMULATION) - #define MARLIN_EEPROM_SIZE 0x800 // 2K + #define MARLIN_EEPROM_SIZE 0x800U // 2K #endif // diff --git a/Marlin/src/pins/stm32f4/pins_CREALITY_F401.h b/Marlin/src/pins/stm32f4/pins_CREALITY_F401.h index 50e766c35b..757dde06c9 100644 --- a/Marlin/src/pins/stm32f4/pins_CREALITY_F401.h +++ b/Marlin/src/pins/stm32f4/pins_CREALITY_F401.h @@ -26,18 +26,18 @@ #define BOARD_INFO_NAME "STM32F401RET6" #define DEFAULT_MACHINE_NAME "Ender-5 S1" -#define IIC_BL24CXX_EEPROM // EEPROM on I2C-0 used only for display settings +#define IIC_BL24CXX_EEPROM // EEPROM on I2C-0 used only for display settings #if ENABLED(IIC_BL24CXX_EEPROM) #define IIC_EEPROM_SDA PA11 #define IIC_EEPROM_SCL PA12 - #define MARLIN_EEPROM_SIZE 0x800 // 2Kb (24C16) + #define MARLIN_EEPROM_SIZE 0x800U // 2K (24C16) #else - #define SDCARD_EEPROM_EMULATION // SD EEPROM until all EEPROM is BL24CXX - #define MARLIN_EEPROM_SIZE 0x800 // 2Kb + #define SDCARD_EEPROM_EMULATION // SD EEPROM until all EEPROM is BL24CXX + #define MARLIN_EEPROM_SIZE 0x800U // 2K #endif // SPI -//#define SPI_EEPROM // EEPROM on SPI-0 +//#define SPI_EEPROM // EEPROM on SPI-0 //#define SPI_CHAN_EEPROM1 ? //#define SPI_EEPROM1_CS ? diff --git a/Marlin/src/pins/stm32f4/pins_FLYF407ZG.h b/Marlin/src/pins/stm32f4/pins_FLYF407ZG.h index ac8a75ecd2..b8dc7e99cc 100644 --- a/Marlin/src/pins/stm32f4/pins_FLYF407ZG.h +++ b/Marlin/src/pins/stm32f4/pins_FLYF407ZG.h @@ -50,11 +50,11 @@ // the 128kB sector allocated for EEPROM emulation. #define FLASH_EEPROM_LEVELING #elif ENABLED(I2C_EEPROM) - #define MARLIN_EEPROM_SIZE 0x2000 // 8K + #define MARLIN_EEPROM_SIZE 0x2000U // 8K #endif #ifndef MARLIN_EEPROM_SIZE - #define MARLIN_EEPROM_SIZE 0x1000 // 4K + #define MARLIN_EEPROM_SIZE 0x1000U // 4K #endif // diff --git a/Marlin/src/pins/stm32f4/pins_FLY_RRF_E3_V1.h b/Marlin/src/pins/stm32f4/pins_FLY_RRF_E3_V1.h index 2c61211dc2..b2f7dab7de 100644 --- a/Marlin/src/pins/stm32f4/pins_FLY_RRF_E3_V1.h +++ b/Marlin/src/pins/stm32f4/pins_FLY_RRF_E3_V1.h @@ -32,7 +32,7 @@ #if NO_EEPROM_SELECTED #define FLASH_EEPROM_EMULATION #endif -#define MARLIN_EEPROM_SIZE 0x1000 // 4K +#define MARLIN_EEPROM_SIZE 0x1000U // 4K // // Servos diff --git a/Marlin/src/pins/stm32f4/pins_FYSETC_S6_common.h b/Marlin/src/pins/stm32f4/pins_FYSETC_S6_common.h index ce61bce1cf..8b0557fcc9 100644 --- a/Marlin/src/pins/stm32f4/pins_FYSETC_S6_common.h +++ b/Marlin/src/pins/stm32f4/pins_FYSETC_S6_common.h @@ -48,7 +48,7 @@ // 128 kB sector allocated for EEPROM emulation. #define FLASH_EEPROM_LEVELING #elif ENABLED(I2C_EEPROM) - #define MARLIN_EEPROM_SIZE 0x1000 // 4K + #define MARLIN_EEPROM_SIZE 0x1000U // 4K #endif // diff --git a/Marlin/src/pins/stm32f4/pins_FYSETC_SPIDER.h b/Marlin/src/pins/stm32f4/pins_FYSETC_SPIDER.h index 24055cb3cc..41251aad0a 100644 --- a/Marlin/src/pins/stm32f4/pins_FYSETC_SPIDER.h +++ b/Marlin/src/pins/stm32f4/pins_FYSETC_SPIDER.h @@ -39,7 +39,7 @@ #endif #if ENABLED(I2C_EEPROM) - #define MARLIN_EEPROM_SIZE 0x1000 // 4K + #define MARLIN_EEPROM_SIZE 0x1000U // 4K #endif // diff --git a/Marlin/src/pins/stm32f4/pins_FYSETC_SPIDER_KING407.h b/Marlin/src/pins/stm32f4/pins_FYSETC_SPIDER_KING407.h index b01b5bda6a..8354df6289 100644 --- a/Marlin/src/pins/stm32f4/pins_FYSETC_SPIDER_KING407.h +++ b/Marlin/src/pins/stm32f4/pins_FYSETC_SPIDER_KING407.h @@ -48,7 +48,7 @@ #define I2C_EEPROM #define I2C_SCL_PIN PF1 #define I2C_SDA_PIN PF0 - #define MARLIN_EEPROM_SIZE 0x1000 // 4KB + #define MARLIN_EEPROM_SIZE 0x1000U // 4KB #endif // diff --git a/Marlin/src/pins/stm32f4/pins_LERDGE_K.h b/Marlin/src/pins/stm32f4/pins_LERDGE_K.h index 402e7f5ddc..b01e9cc5a8 100644 --- a/Marlin/src/pins/stm32f4/pins_LERDGE_K.h +++ b/Marlin/src/pins/stm32f4/pins_LERDGE_K.h @@ -37,7 +37,7 @@ #define SOFT_I2C_EEPROM // Force the use of Software I2C #define I2C_SCL_PIN PG14 #define I2C_SDA_PIN PG13 - #define MARLIN_EEPROM_SIZE 0x10000 + #define MARLIN_EEPROM_SIZE 0x10000U // 64K #endif #define HAS_OTG_USB_HOST_SUPPORT // USB Flash Drive support diff --git a/Marlin/src/pins/stm32f4/pins_LERDGE_X.h b/Marlin/src/pins/stm32f4/pins_LERDGE_X.h index 6aa5d348dc..1f4943dd6d 100644 --- a/Marlin/src/pins/stm32f4/pins_LERDGE_X.h +++ b/Marlin/src/pins/stm32f4/pins_LERDGE_X.h @@ -37,7 +37,7 @@ #define I2C_EEPROM #define I2C_SCL_PIN PB8 #define I2C_SDA_PIN PB9 -#define MARLIN_EEPROM_SIZE 0x10000 // FM24CL64 F-RAM 64K (8Kx8) +#define MARLIN_EEPROM_SIZE 0x10000U // FM24CL64 F-RAM 64K (8Kx8) #define HAS_OTG_USB_HOST_SUPPORT // USB Flash Drive support diff --git a/Marlin/src/pins/stm32f4/pins_MKS_MONSTER8_common.h b/Marlin/src/pins/stm32f4/pins_MKS_MONSTER8_common.h index 38ed31cabe..ec21f5ab7b 100644 --- a/Marlin/src/pins/stm32f4/pins_MKS_MONSTER8_common.h +++ b/Marlin/src/pins/stm32f4/pins_MKS_MONSTER8_common.h @@ -42,7 +42,7 @@ //#define SRAM_EEPROM_EMULATION // Use BackSRAM-based EEPROM emulation //#define FLASH_EEPROM_EMULATION // Use Flash-based EEPROM emulation #define I2C_EEPROM // Need use jumpers set i2c for EEPROM -#define MARLIN_EEPROM_SIZE 0x1000 // 4K +#define MARLIN_EEPROM_SIZE 0x1000U // 4K #define I2C_SCL_PIN PB8 // I2C_SCL and CAN_RX #define I2C_SDA_PIN PB9 // I2C_SDA and CAN_TX diff --git a/Marlin/src/pins/stm32f4/pins_MKS_ROBIN_NANO_V3_common.h b/Marlin/src/pins/stm32f4/pins_MKS_ROBIN_NANO_V3_common.h index c9ecc617b7..2db766ccc0 100644 --- a/Marlin/src/pins/stm32f4/pins_MKS_ROBIN_NANO_V3_common.h +++ b/Marlin/src/pins/stm32f4/pins_MKS_ROBIN_NANO_V3_common.h @@ -35,7 +35,7 @@ //#define FLASH_EEPROM_EMULATION // Use Flash-based EEPROM emulation #if ANY(NO_EEPROM_SELECTED, I2C_EEPROM) #define I2C_EEPROM - #define MARLIN_EEPROM_SIZE 0x1000 // 4K + #define MARLIN_EEPROM_SIZE 0x1000U // 4K #define I2C_SCL_PIN PB6 #define I2C_SDA_PIN PB7 #endif diff --git a/Marlin/src/pins/stm32f4/pins_MKS_ROBIN_PRO_V2.h b/Marlin/src/pins/stm32f4/pins_MKS_ROBIN_PRO_V2.h index 11edadcd58..5682200771 100644 --- a/Marlin/src/pins/stm32f4/pins_MKS_ROBIN_PRO_V2.h +++ b/Marlin/src/pins/stm32f4/pins_MKS_ROBIN_PRO_V2.h @@ -37,7 +37,7 @@ //#define SRAM_EEPROM_EMULATION // Use BackSRAM-based EEPROM emulation //#define FLASH_EEPROM_EMULATION // Use Flash-based EEPROM emulation #define I2C_EEPROM -#define MARLIN_EEPROM_SIZE 0x1000 // 4K +#define MARLIN_EEPROM_SIZE 0x1000U // 4K #define HAS_OTG_USB_HOST_SUPPORT // USB Flash Drive support diff --git a/Marlin/src/pins/stm32f4/pins_MKS_SKIPR_V1_0.h b/Marlin/src/pins/stm32f4/pins_MKS_SKIPR_V1_0.h index 7528ac77f0..b0eb8bf24f 100644 --- a/Marlin/src/pins/stm32f4/pins_MKS_SKIPR_V1_0.h +++ b/Marlin/src/pins/stm32f4/pins_MKS_SKIPR_V1_0.h @@ -35,7 +35,7 @@ // Onboard I2C EEPROM #define I2C_EEPROM -#define MARLIN_EEPROM_SIZE 0x1000 // 4K (AT24C32) +#define MARLIN_EEPROM_SIZE 0x1000U // 4K (AT24C32) #define I2C_SCL_PIN PB8 #define I2C_SDA_PIN PB9 diff --git a/Marlin/src/pins/stm32f4/pins_OPULO_LUMEN_REV3.h b/Marlin/src/pins/stm32f4/pins_OPULO_LUMEN_REV3.h index 33c0eaae8f..9474616f4c 100644 --- a/Marlin/src/pins/stm32f4/pins_OPULO_LUMEN_REV3.h +++ b/Marlin/src/pins/stm32f4/pins_OPULO_LUMEN_REV3.h @@ -40,7 +40,7 @@ */ #define SRAM_EEPROM_EMULATION -#define MARLIN_EEPROM_SIZE 0x2000 // 8K +#define MARLIN_EEPROM_SIZE 0x2000U // 8K // I2C MCP3426 (16-Bit, 240SPS, dual-channel ADC) #define HAS_MCP3426_ADC diff --git a/Marlin/src/pins/stm32f4/pins_OPULO_LUMEN_REV4.h b/Marlin/src/pins/stm32f4/pins_OPULO_LUMEN_REV4.h index 11fe08a980..03bb77c265 100644 --- a/Marlin/src/pins/stm32f4/pins_OPULO_LUMEN_REV4.h +++ b/Marlin/src/pins/stm32f4/pins_OPULO_LUMEN_REV4.h @@ -40,7 +40,7 @@ */ #define SRAM_EEPROM_EMULATION -#define MARLIN_EEPROM_SIZE 0x2000 // 8K +#define MARLIN_EEPROM_SIZE 0x2000U // 8K // I2C MCP3426 (16-Bit, 240SPS, dual-channel ADC) #define HAS_MCP3426_ADC diff --git a/Marlin/src/pins/stm32f4/pins_RUMBA32_AUS3D.h b/Marlin/src/pins/stm32f4/pins_RUMBA32_AUS3D.h index 8d9eacaf07..f4ff24e03e 100644 --- a/Marlin/src/pins/stm32f4/pins_RUMBA32_AUS3D.h +++ b/Marlin/src/pins/stm32f4/pins_RUMBA32_AUS3D.h @@ -33,10 +33,10 @@ #if NO_EEPROM_SELECTED #if MB(RUMBA32_V1_0) #define FLASH_EEPROM_EMULATION - #define MARLIN_EEPROM_SIZE 0x1000 // 4K + #define MARLIN_EEPROM_SIZE 0x1000U // 4K #elif MB(RUMBA32_V1_1) #define I2C_EEPROM - #define MARLIN_EEPROM_SIZE 0x2000 // 8K (24LC64T-I/OT) + #define MARLIN_EEPROM_SIZE 0x2000U // 8K (24LC64T-I/OT) #endif #endif diff --git a/Marlin/src/pins/stm32f4/pins_RUMBA32_BTT.h b/Marlin/src/pins/stm32f4/pins_RUMBA32_BTT.h index 1712b24f2b..0bac7da8d3 100644 --- a/Marlin/src/pins/stm32f4/pins_RUMBA32_BTT.h +++ b/Marlin/src/pins/stm32f4/pins_RUMBA32_BTT.h @@ -30,7 +30,7 @@ #if NO_EEPROM_SELECTED #define I2C_EEPROM - #define MARLIN_EEPROM_SIZE 0x1000 // 4K (24LC32AT-I/OT) + #define MARLIN_EEPROM_SIZE 0x1000U // 4K (24LC32AT-I/OT) #endif #if ENABLED(FLASH_EEPROM_EMULATION) diff --git a/Marlin/src/pins/stm32f4/pins_RUMBA32_MKS.h b/Marlin/src/pins/stm32f4/pins_RUMBA32_MKS.h index 3833a3a007..5540d12ead 100644 --- a/Marlin/src/pins/stm32f4/pins_RUMBA32_MKS.h +++ b/Marlin/src/pins/stm32f4/pins_RUMBA32_MKS.h @@ -37,7 +37,7 @@ #if NO_EEPROM_SELECTED #define FLASH_EEPROM_EMULATION - #define MARLIN_EEPROM_SIZE 0x1000 // 4K + #define MARLIN_EEPROM_SIZE 0x1000U // 4K #endif #if ENABLED(FLASH_EEPROM_EMULATION) diff --git a/Marlin/src/pins/stm32f4/pins_TH3D_EZBOARD_V2.h b/Marlin/src/pins/stm32f4/pins_TH3D_EZBOARD_V2.h index 4d99b524f0..ebb651e0d5 100644 --- a/Marlin/src/pins/stm32f4/pins_TH3D_EZBOARD_V2.h +++ b/Marlin/src/pins/stm32f4/pins_TH3D_EZBOARD_V2.h @@ -38,7 +38,7 @@ // Onboard I2C EEPROM #if NO_EEPROM_SELECTED #define I2C_EEPROM - #define MARLIN_EEPROM_SIZE 0x1000 // 4K + #define MARLIN_EEPROM_SIZE 0x1000U // 4K #define I2C_SCL_PIN PB6 #define I2C_SDA_PIN PB7 #undef NO_EEPROM_SELECTED diff --git a/Marlin/src/pins/stm32f4/pins_TRONXY_CXY_446_V10.h b/Marlin/src/pins/stm32f4/pins_TRONXY_CXY_446_V10.h index 1582397320..f99a1c5f55 100644 --- a/Marlin/src/pins/stm32f4/pins_TRONXY_CXY_446_V10.h +++ b/Marlin/src/pins/stm32f4/pins_TRONXY_CXY_446_V10.h @@ -50,11 +50,11 @@ #endif #if ENABLED(FLASH_EEPROM_EMULATION) - #define EEPROM_START_ADDRESS (0x8000000UL + (512 * 1024) - 2 * EEPROM_PAGE_SIZE) - #define EEPROM_PAGE_SIZE (0x800U) // 2K, but will use 2x more (4K) - #define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE + #define EEPROM_PAGE_SIZE 0x800U // 2K + #define EEPROM_START_ADDRESS (0x8000000UL + (STM32_FLASH_SIZE) * 1024UL - (EEPROM_PAGE_SIZE) * 2UL) + #define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE #else - #define MARLIN_EEPROM_SIZE 0x800 // 2K (FT24C16A) + #define MARLIN_EEPROM_SIZE 0x800U // 2K (FT24C16A) #endif // @@ -62,7 +62,7 @@ // #define SPI_FLASH // W25Q16 #if ENABLED(SPI_FLASH) - #define SPI_FLASH_SIZE 0x1000000 // 16MB + #define SPI_FLASH_SIZE 0x1000000 // 16MB #define SPI_FLASH_CS_PIN PG15 #define SPI_FLASH_MOSI_PIN PB5 #define SPI_FLASH_MISO_PIN PB4 @@ -79,7 +79,7 @@ // #define ONBOARD_SDIO #define SD_DETECT_PIN -1 -#define SDIO_CLOCK 4500000 +#define SDIO_CLOCK 4500000 #define SDIO_READ_RETRIES 16 #define SDIO_D0_PIN PC8 diff --git a/Marlin/src/pins/stm32g0/pins_BTT_EBB42_V1_1.h b/Marlin/src/pins/stm32g0/pins_BTT_EBB42_V1_1.h index 2d6cdb73f4..1b5aad04e1 100644 --- a/Marlin/src/pins/stm32g0/pins_BTT_EBB42_V1_1.h +++ b/Marlin/src/pins/stm32g0/pins_BTT_EBB42_V1_1.h @@ -44,9 +44,9 @@ #ifndef FLASH_EEPROM_EMULATION #define FLASH_EEPROM_EMULATION #endif - #define EEPROM_PAGE_SIZE (0x800UL) // 2K - #define EEPROM_START_ADDRESS (0x8000000UL + (STM32_FLASH_SIZE) * 1024UL - (EEPROM_PAGE_SIZE) * 1UL) - #define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE + #define EEPROM_PAGE_SIZE 0x800U // 2K + #define EEPROM_START_ADDRESS (0x8000000UL + (STM32_FLASH_SIZE) * 1024UL - (EEPROM_PAGE_SIZE) * 1UL) + #define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE #endif //#define USES_DIAG_JUMPERS diff --git a/Marlin/src/pins/stm32g0/pins_BTT_MANTA_E3_EZ_V1_0.h b/Marlin/src/pins/stm32g0/pins_BTT_MANTA_E3_EZ_V1_0.h index a3b305b04c..1f81fd6865 100644 --- a/Marlin/src/pins/stm32g0/pins_BTT_MANTA_E3_EZ_V1_0.h +++ b/Marlin/src/pins/stm32g0/pins_BTT_MANTA_E3_EZ_V1_0.h @@ -40,9 +40,9 @@ #ifndef FLASH_EEPROM_EMULATION #define FLASH_EEPROM_EMULATION #endif - #define EEPROM_PAGE_SIZE (0x800UL) // 2K - #define EEPROM_START_ADDRESS (0x8000000UL + (STM32_FLASH_SIZE) * 1024UL - (EEPROM_PAGE_SIZE) * 2UL) - #define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE + #define EEPROM_PAGE_SIZE 0x800U // 2K + #define EEPROM_START_ADDRESS (0x8000000UL + (STM32_FLASH_SIZE) * 1024UL - (EEPROM_PAGE_SIZE) * 2UL) + #define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE #endif // diff --git a/Marlin/src/pins/stm32g0/pins_BTT_MANTA_M4P_V2_1.h b/Marlin/src/pins/stm32g0/pins_BTT_MANTA_M4P_V2_1.h index 38d75a3d94..9c50f4b7d8 100644 --- a/Marlin/src/pins/stm32g0/pins_BTT_MANTA_M4P_V2_1.h +++ b/Marlin/src/pins/stm32g0/pins_BTT_MANTA_M4P_V2_1.h @@ -42,9 +42,9 @@ #ifndef FLASH_EEPROM_EMULATION #define FLASH_EEPROM_EMULATION #endif - #define EEPROM_PAGE_SIZE (0x800UL) // 2K - #define EEPROM_START_ADDRESS (0x8000000UL + (STM32_FLASH_SIZE) * 1024UL - (EEPROM_PAGE_SIZE) * 2UL) - #define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE + #define EEPROM_PAGE_SIZE 0x800U // 2K + #define EEPROM_START_ADDRESS (0x8000000UL + (STM32_FLASH_SIZE) * 1024UL - (EEPROM_PAGE_SIZE) * 2UL) + #define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE #endif // diff --git a/Marlin/src/pins/stm32g0/pins_BTT_MANTA_M5P_V1_0.h b/Marlin/src/pins/stm32g0/pins_BTT_MANTA_M5P_V1_0.h index b2981f6734..dce4f87cdf 100644 --- a/Marlin/src/pins/stm32g0/pins_BTT_MANTA_M5P_V1_0.h +++ b/Marlin/src/pins/stm32g0/pins_BTT_MANTA_M5P_V1_0.h @@ -40,9 +40,9 @@ #ifndef FLASH_EEPROM_EMULATION #define FLASH_EEPROM_EMULATION #endif - #define EEPROM_PAGE_SIZE (0x800UL) // 2K - #define EEPROM_START_ADDRESS (0x8000000UL + (STM32_FLASH_SIZE) * 1024UL - (EEPROM_PAGE_SIZE) * 2UL) - #define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE + #define EEPROM_PAGE_SIZE 0x800U // 2K + #define EEPROM_START_ADDRESS (0x8000000UL + (STM32_FLASH_SIZE) * 1024UL - (EEPROM_PAGE_SIZE) * 2UL) + #define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE #endif // diff --git a/Marlin/src/pins/stm32g0/pins_BTT_MANTA_M8P_common.h b/Marlin/src/pins/stm32g0/pins_BTT_MANTA_M8P_common.h index b05515003e..0af45e6645 100644 --- a/Marlin/src/pins/stm32g0/pins_BTT_MANTA_M8P_common.h +++ b/Marlin/src/pins/stm32g0/pins_BTT_MANTA_M8P_common.h @@ -38,9 +38,9 @@ #ifndef FLASH_EEPROM_EMULATION #define FLASH_EEPROM_EMULATION #endif - #define EEPROM_PAGE_SIZE (0x800UL) // 2K - #define EEPROM_START_ADDRESS (0x8000000UL + (STM32_FLASH_SIZE) * 1024UL - (EEPROM_PAGE_SIZE) * 2UL) - #define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE + #define EEPROM_PAGE_SIZE 0x800U // 2K + #define EEPROM_START_ADDRESS (0x8000000UL + (STM32_FLASH_SIZE) * 1024UL - (EEPROM_PAGE_SIZE) * 2UL) + #define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE #endif // diff --git a/Marlin/src/pins/stm32g0/pins_BTT_SKRAT_V1_0.h b/Marlin/src/pins/stm32g0/pins_BTT_SKRAT_V1_0.h index 9452ceb31d..5b3ff90f9e 100644 --- a/Marlin/src/pins/stm32g0/pins_BTT_SKRAT_V1_0.h +++ b/Marlin/src/pins/stm32g0/pins_BTT_SKRAT_V1_0.h @@ -50,9 +50,9 @@ #ifndef FLASH_EEPROM_EMULATION #define FLASH_EEPROM_EMULATION #endif - #define EEPROM_PAGE_SIZE (0x800UL) // 2K - #define EEPROM_START_ADDRESS (0x8000000UL + (STM32_FLASH_SIZE) * 1024UL - (EEPROM_PAGE_SIZE) * 2UL) - #define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE + #define EEPROM_PAGE_SIZE 0x800U // 2K + #define EEPROM_START_ADDRESS (0x8000000UL + (STM32_FLASH_SIZE) * 1024UL - (EEPROM_PAGE_SIZE) * 2UL) + #define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE // 2K #endif // diff --git a/Marlin/src/pins/stm32g0/pins_BTT_SKR_MINI_E3_V3_0.h b/Marlin/src/pins/stm32g0/pins_BTT_SKR_MINI_E3_V3_0.h index 12d1f5308a..121dbac336 100644 --- a/Marlin/src/pins/stm32g0/pins_BTT_SKR_MINI_E3_V3_0.h +++ b/Marlin/src/pins/stm32g0/pins_BTT_SKR_MINI_E3_V3_0.h @@ -43,7 +43,7 @@ #define SOFT_I2C_EEPROM // Force the use of Software I2C #define I2C_SCL_PIN PB6 #define I2C_SDA_PIN PB7 - #define MARLIN_EEPROM_SIZE 0x1000 // 4K + #define MARLIN_EEPROM_SIZE 0x1000U // 4K #endif // diff --git a/Marlin/src/pins/stm32h7/pins_BTT_KRAKEN_V1_0.h b/Marlin/src/pins/stm32h7/pins_BTT_KRAKEN_V1_0.h index 8a16a04536..3a0cc346e5 100644 --- a/Marlin/src/pins/stm32h7/pins_BTT_KRAKEN_V1_0.h +++ b/Marlin/src/pins/stm32h7/pins_BTT_KRAKEN_V1_0.h @@ -36,9 +36,9 @@ #ifndef FLASH_EEPROM_EMULATION #define FLASH_EEPROM_EMULATION #endif - #define EEPROM_PAGE_SIZE (0x800UL) // 2K - #define EEPROM_START_ADDRESS (0x8000000UL + (STM32_FLASH_SIZE) * 1024UL - (EEPROM_PAGE_SIZE) * 2UL) - #define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE + #define EEPROM_PAGE_SIZE 0x800U // 2K + #define EEPROM_START_ADDRESS (0x8000000UL + (STM32_FLASH_SIZE) * 1024UL - (EEPROM_PAGE_SIZE) * 2UL) + #define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE // 2K #endif // Avoid conflict with TIMER_TONE diff --git a/Marlin/src/pins/stm32h7/pins_BTT_MANTA_M8P_V2_0.h b/Marlin/src/pins/stm32h7/pins_BTT_MANTA_M8P_V2_0.h index 4afea71f03..d274c99e19 100644 --- a/Marlin/src/pins/stm32h7/pins_BTT_MANTA_M8P_V2_0.h +++ b/Marlin/src/pins/stm32h7/pins_BTT_MANTA_M8P_V2_0.h @@ -36,9 +36,9 @@ #ifndef FLASH_EEPROM_EMULATION #define FLASH_EEPROM_EMULATION // Use Flash-based EEPROM emulation #endif - #define EEPROM_PAGE_SIZE (0x800UL) // 2K - #define EEPROM_START_ADDRESS (0x8000000UL + (STM32_FLASH_SIZE) * 1024UL - (EEPROM_PAGE_SIZE) * 2UL) - #define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE + #define EEPROM_PAGE_SIZE 0x800U // 2K + #define EEPROM_START_ADDRESS (0x8000000UL + (STM32_FLASH_SIZE) * 1024UL - (EEPROM_PAGE_SIZE) * 2UL) + #define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE // 2K #endif // Avoid conflict with TIMER_TONE diff --git a/Marlin/src/pins/stm32h7/pins_BTT_OCTOPUS_MAX_EZ.h b/Marlin/src/pins/stm32h7/pins_BTT_OCTOPUS_MAX_EZ.h index eb54293936..b995b2269e 100644 --- a/Marlin/src/pins/stm32h7/pins_BTT_OCTOPUS_MAX_EZ.h +++ b/Marlin/src/pins/stm32h7/pins_BTT_OCTOPUS_MAX_EZ.h @@ -34,7 +34,7 @@ #define SOFT_I2C_EEPROM // Force the use of Software I2C #define I2C_SCL_PIN PB10 #define I2C_SDA_PIN PB11 - #define MARLIN_EEPROM_SIZE 0x1000 // 4KB + #define MARLIN_EEPROM_SIZE 0x1000U // 4KB #endif // Avoid conflict with TIMER_TONE diff --git a/Marlin/src/pins/stm32h7/pins_BTT_OCTOPUS_PRO_V1_common.h b/Marlin/src/pins/stm32h7/pins_BTT_OCTOPUS_PRO_V1_common.h index 787fa84c1c..8c8cd1d8a1 100644 --- a/Marlin/src/pins/stm32h7/pins_BTT_OCTOPUS_PRO_V1_common.h +++ b/Marlin/src/pins/stm32h7/pins_BTT_OCTOPUS_PRO_V1_common.h @@ -30,7 +30,7 @@ #if ANY(NO_EEPROM_SELECTED, I2C_EEPROM) #undef NO_EEPROM_SELECTED #define I2C_EEPROM - #define MARLIN_EEPROM_SIZE 0x1000 // 4K (AT24C32) + #define MARLIN_EEPROM_SIZE 0x1000U // 4K (AT24C32) #define SOFT_I2C_EEPROM // Force the use of Software I2C #define I2C_SCL_PIN PB8 #define I2C_SDA_PIN PB9 diff --git a/Marlin/src/pins/stm32h7/pins_BTT_SKR_SE_BX_common.h b/Marlin/src/pins/stm32h7/pins_BTT_SKR_SE_BX_common.h index 76817cae81..529e610624 100644 --- a/Marlin/src/pins/stm32h7/pins_BTT_SKR_SE_BX_common.h +++ b/Marlin/src/pins/stm32h7/pins_BTT_SKR_SE_BX_common.h @@ -30,7 +30,7 @@ // Onboard I2C EEPROM #define I2C_EEPROM -#define MARLIN_EEPROM_SIZE 0x1000 // 4K (24C32) +#define MARLIN_EEPROM_SIZE 0x1000U // 4K (24C32) #define HAS_OTG_USB_HOST_SUPPORT // USB Flash Drive support //#define SWD_DEBUG // Use pins PA13 and PA14 on STM32H7 for the SWD debugger diff --git a/Marlin/src/pins/stm32h7/pins_BTT_SKR_V3_0_common.h b/Marlin/src/pins/stm32h7/pins_BTT_SKR_V3_0_common.h index 74cb78f6e5..87afd7bb16 100644 --- a/Marlin/src/pins/stm32h7/pins_BTT_SKR_V3_0_common.h +++ b/Marlin/src/pins/stm32h7/pins_BTT_SKR_V3_0_common.h @@ -48,7 +48,7 @@ #define SOFT_I2C_EEPROM // Force the use of Software I2C #define I2C_SCL_PIN PA14 #define I2C_SDA_PIN PA13 - #define MARLIN_EEPROM_SIZE 0x1000 // 4K + #define MARLIN_EEPROM_SIZE 0x1000U // 4K #endif // diff --git a/ini/stm32f1-maple.ini b/ini/stm32f1-maple.ini index 59150f3858..0e77ff8dfa 100644 --- a/ini/stm32f1-maple.ini +++ b/ini/stm32f1-maple.ini @@ -270,6 +270,7 @@ board_build.ldscript = mks_robin_pro.ld # [env:trigorilla_pro_maple] extends = env:mks_robin_maple +build_flags = ${env:mks_robin_maple} -DSTM32_FLASH_SIZE=512 # # MKS Robin E3D (STM32F103RCT6) and @@ -350,7 +351,7 @@ board = marlin_maple_CHITU_F103 extra_scripts = ${STM32F1_maple.extra_scripts} pre:buildroot/share/PlatformIO/scripts/STM32F1_create_variant.py buildroot/share/PlatformIO/scripts/chitu_crypt.py -build_flags = ${STM32F1_maple.build_flags} -DSTM32F1xx -DSTM32_XL_DENSITY +build_flags = ${STM32F1_maple.build_flags} -DSTM32F1xx -DSTM32_XL_DENSITY -DSTM32_FLASH_SIZE=512 build_unflags = ${STM32F1_maple.build_unflags} -DCONFIG_MAPLE_MINI_NO_DISABLE_DEBUG= -DERROR_LED_PORT=GPIOE -DERROR_LED_PIN=6 @@ -449,8 +450,9 @@ board_build.address = 0x08007000 board_upload.maximum_size = 524288 board_build.ldscript = md301.ld board_build.variant = MARLIN_F103Zx -build_flags = ${STM32F1_maple.build_flags} -DDEBUG_LEVEL=0 -std=gnu++14 +build_flags = ${STM32F1_maple.build_flags} -DSTM32F1xx -DSTM32_FLASH_SIZE=512 + -DDEBUG_LEVEL=0 -std=gnu++14 -DSTM32_FLASH_SIZE=512 -DHAVE_SW_SERIAL -DSS_TIMER=4 -DUSART_RX_BUF_SIZE=256 -DUSART_TX_BUF_SIZE=256 -DUSE_USB_COMPOSITE -DTONE_TIMER=3 -DTONE_CHANNEL=3 - -DSTM32F1xx -DSTM32_XL_DENSITY + -DSTM32_XL_DENSITY diff --git a/ini/stm32f1.ini b/ini/stm32f1.ini index b4c6f22372..1500bbe92a 100644 --- a/ini/stm32f1.ini +++ b/ini/stm32f1.ini @@ -263,7 +263,7 @@ board = genericSTM32F103RC board_build.variant = MARLIN_F103Rx board_build.offset = 0x5000 board_upload.offset_address = 0x08005000 -build_flags = ${stm32_variant.build_flags} -DSS_TIMER=4 +build_flags = ${stm32_variant.build_flags} -DSS_TIMER=4 -DSTM32_FLASH_SIZE=256 # # (STM32F103VE_robin) @@ -404,7 +404,7 @@ extends = stm32_variant board = genericSTM32F103ZE board_build.variant = MARLIN_F103Zx build_flags = ${stm32_variant.build_flags} - -DENABLE_HWSERIAL3 -DTIMER_SERIAL=TIM5 + -DENABLE_HWSERIAL3 -DTIMER_SERIAL=TIM5 -DSTM32_FLASH_SIZE=512 build_unflags = ${stm32_variant.build_unflags} -DUSBCON -DUSBD_USE_CDC @@ -437,8 +437,7 @@ board_build.crypt_chitu = update.cbd board_build.variant = MARLIN_F103Zx board_build.offset = 0x8800 board_build.offset_address = 0x08008800 -build_flags = ${stm32_variant.build_flags} - -DSTM32F1xx +build_flags = ${stm32_variant.build_flags} -DSTM32F1xx -DSTM32_FLASH_SIZE=512 build_unflags = ${stm32_variant.build_unflags} extra_scripts = ${stm32_variant.extra_scripts} buildroot/share/PlatformIO/scripts/chitu_crypt.py @@ -496,7 +495,7 @@ board = genericSTM32F103ZE board_build.variant = MARLIN_F103Zx board_build.offset = 0x7000 board_upload.offset_address = 0x08007000 -build_flags = ${stm32_variant.build_flags} -DSTM32F1xx +build_flags = ${stm32_variant.build_flags} -DSTM32F1xx -DSTM32_FLASH_SIZE=512 # # ORCA 3D SPRINGER Modular Controller (STM32F103VCT6) From 279a393e81adb7565e2cdf0c8cb09f3c028761ed Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Fri, 24 Jan 2025 15:23:54 -0600 Subject: [PATCH 060/787] =?UTF-8?q?=F0=9F=8C=90=20Attach=20media=20message?= =?UTF-8?q?s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/lcd/dogm/fontdata/langdata_jp_kana.h | 15 ++++++++++ Marlin/src/lcd/dogm/fontdata/langdata_vi.h | 5 ++++ Marlin/src/lcd/dogm/fontdata/langdata_zh_CN.h | 10 +++++++ Marlin/src/lcd/dogm/fontdata/langdata_zh_TW.h | 25 ++++++++++++++++ Marlin/src/lcd/language/language_an.h | 7 ++++- Marlin/src/lcd/language/language_bg.h | 7 ++++- Marlin/src/lcd/language/language_ca.h | 7 ++++- Marlin/src/lcd/language/language_cz.h | 7 ++++- Marlin/src/lcd/language/language_de.h | 7 ++++- Marlin/src/lcd/language/language_el.h | 7 ++++- Marlin/src/lcd/language/language_el_gr.h | 7 ++++- Marlin/src/lcd/language/language_en.h | 9 ++++-- Marlin/src/lcd/language/language_es.h | 29 ++++++++++++------- Marlin/src/lcd/language/language_eu.h | 7 ++++- Marlin/src/lcd/language/language_fr.h | 7 ++++- Marlin/src/lcd/language/language_fr_na.h | 7 ++++- Marlin/src/lcd/language/language_gl.h | 19 ++++++++---- Marlin/src/lcd/language/language_hr.h | 7 ++++- Marlin/src/lcd/language/language_hu.h | 7 ++++- Marlin/src/lcd/language/language_it.h | 9 ++++-- Marlin/src/lcd/language/language_jp_kana.h | 7 ++++- Marlin/src/lcd/language/language_nl.h | 7 ++++- Marlin/src/lcd/language/language_pl.h | 7 ++++- Marlin/src/lcd/language/language_pt.h | 7 ++++- Marlin/src/lcd/language/language_pt_br.h | 7 ++++- Marlin/src/lcd/language/language_ro.h | 7 ++++- Marlin/src/lcd/language/language_ru.h | 7 ++++- Marlin/src/lcd/language/language_sk.h | 9 ++++-- Marlin/src/lcd/language/language_sv.h | 7 ++++- Marlin/src/lcd/language/language_tr.h | 9 ++++-- Marlin/src/lcd/language/language_uk.h | 7 ++++- Marlin/src/lcd/language/language_vi.h | 7 ++++- Marlin/src/lcd/language/language_zh_CN.h | 7 ++++- Marlin/src/lcd/language/language_zh_TW.h | 8 +++-- Marlin/src/lcd/menu/menu_main.cpp | 12 ++++---- 35 files changed, 260 insertions(+), 60 deletions(-) diff --git a/Marlin/src/lcd/dogm/fontdata/langdata_jp_kana.h b/Marlin/src/lcd/dogm/fontdata/langdata_jp_kana.h index dc483b7d2b..4c02fad09e 100644 --- a/Marlin/src/lcd/dogm/fontdata/langdata_jp_kana.h +++ b/Marlin/src/lcd/dogm/fontdata/langdata_jp_kana.h @@ -7,6 +7,18 @@ #include "langdata.h" +const u8g_fntpgm_uint8_t fontpage_96_217_217[47] U8G_FONT_SECTION("fontpage_96_217_217") = { + 0x00,0x0C,0x0F,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0xD9,0xD9,0x00,0x0B,0xFF,0x00, + 0x00,0x0A,0x0C,0x18,0x0C,0x00,0xFF,0x04,0x00,0x02,0x00,0x83,0xC0,0x7E,0x00,0x0A, + 0x00,0x16,0x00,0x12,0x00,0x0E,0x00,0x02,0x00,0x02,0x00,0x04,0x00,0x08,0x00}; +const u8g_fntpgm_uint8_t fontpage_97_139_139[33] U8G_FONT_SECTION("fontpage_97_139_139") = { + 0x00,0x0C,0x0F,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x8B,0x8B,0x00,0x09,0xFF,0x00, + 0x00,0x08,0x0A,0x0A,0x0C,0x01,0xFF,0x4E,0x34,0x08,0x10,0x3E,0x61,0x81,0x19,0x26, + 0x1C}; +const u8g_fntpgm_uint8_t fontpage_97_146_146[45] U8G_FONT_SECTION("fontpage_97_146_146") = { + 0x00,0x0C,0x0F,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x92,0x92,0x00,0x0A,0xFF,0x00, + 0x00,0x09,0x0B,0x16,0x0C,0x01,0xFF,0x08,0x00,0x08,0x00,0x9E,0x00,0x70,0x00,0x21, + 0x80,0x72,0x00,0x8C,0x00,0x14,0x00,0x24,0x00,0x20,0x00,0x1F,0x00}; const u8g_fntpgm_uint8_t fontpage_97_161_164[65] U8G_FONT_SECTION("fontpage_97_161_164") = { 0x00,0x0C,0x0F,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0xA1,0xA4,0x00,0x07,0x00,0x00, 0x00,0x04,0x05,0x05,0x06,0x00,0x00,0xF0,0x10,0x60,0x40,0x80,0x05,0x07,0x07,0x06, @@ -97,6 +109,9 @@ const u8g_fntpgm_uint8_t fontpage_97_252_252[25] U8G_FONT_SECTION("fontpage_97_2 0x00,0x05,0x02,0x02,0x06,0x00,0x03,0x80,0x78}; static const uxg_fontinfo_t g_fontinfo_jp_kana[] PROGMEM = { + FONTDATA_ITEM(96, 217, 217, fontpage_96_217_217), // 'す' -- 'す' + FONTDATA_ITEM(97, 139, 139, fontpage_97_139_139), // 'る' -- 'る' + FONTDATA_ITEM(97, 146, 146, fontpage_97_146_146), // 'を' -- 'を' FONTDATA_ITEM(97, 161, 164, fontpage_97_161_164), // 'ァ' -- 'イ' FONTDATA_ITEM(97, 166, 166, fontpage_97_166_166), // 'ウ' -- 'ウ' FONTDATA_ITEM(97, 168, 168, fontpage_97_168_168), // 'エ' -- 'エ' diff --git a/Marlin/src/lcd/dogm/fontdata/langdata_vi.h b/Marlin/src/lcd/dogm/fontdata/langdata_vi.h index 303c4c66d6..87c23f06fe 100644 --- a/Marlin/src/lcd/dogm/fontdata/langdata_vi.h +++ b/Marlin/src/lcd/dogm/fontdata/langdata_vi.h @@ -80,6 +80,10 @@ const u8g_fntpgm_uint8_t fontpage_61_183_183[33] U8G_FONT_SECTION("fontpage_61_1 0x00,0x0C,0x0F,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0xB7,0xB7,0x00,0x08,0xFE,0x00, 0x00,0x05,0x0A,0x0A,0x07,0x00,0xFE,0x48,0x30,0x00,0x70,0x08,0x78,0x88,0x78,0x00, 0x20}; +const u8g_fntpgm_uint8_t fontpage_61_187_187[32] U8G_FONT_SECTION("fontpage_61_187_187") = { + 0x00,0x0C,0x0F,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0xBB,0xBB,0x00,0x09,0x00,0x00, + 0x00,0x05,0x09,0x09,0x07,0x00,0x00,0x30,0x10,0x20,0x00,0x70,0x88,0xF0,0x80,0x78 + }; const u8g_fntpgm_uint8_t fontpage_61_191_191[33] U8G_FONT_SECTION("fontpage_61_191_191") = { 0x00,0x0C,0x0F,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0xBF,0xBF,0x00,0x0A,0x00,0x00, 0x00,0x06,0x0A,0x0A,0x07,0x00,0x00,0x04,0x08,0x20,0x50,0x00,0x70,0x88,0xF0,0x80, @@ -200,6 +204,7 @@ static const uxg_fontinfo_t g_fontinfo_vi[] PROGMEM = { FONTDATA_ITEM(61, 179, 179, fontpage_61_179_179), // 'ẳ' -- 'ẳ' FONTDATA_ITEM(61, 181, 181, fontpage_61_181_181), // 'ẵ' -- 'ẵ' FONTDATA_ITEM(61, 183, 183, fontpage_61_183_183), // 'ặ' -- 'ặ' + FONTDATA_ITEM(61, 187, 187, fontpage_61_187_187), // 'ẻ' -- 'ẻ' FONTDATA_ITEM(61, 191, 191, fontpage_61_191_191), // 'ế' -- 'ế' FONTDATA_ITEM(61, 193, 193, fontpage_61_193_193), // 'ề' -- 'ề' FONTDATA_ITEM(61, 195, 195, fontpage_61_195_195), // 'ể' -- 'ể' diff --git a/Marlin/src/lcd/dogm/fontdata/langdata_zh_CN.h b/Marlin/src/lcd/dogm/fontdata/langdata_zh_CN.h index ab2ccd024f..7bedd31384 100644 --- a/Marlin/src/lcd/dogm/fontdata/langdata_zh_CN.h +++ b/Marlin/src/lcd/dogm/fontdata/langdata_zh_CN.h @@ -675,6 +675,10 @@ const u8g_fntpgm_uint8_t fontpage_197_233_233[45] U8G_FONT_SECTION("fontpage_197 0x00,0x0C,0x0F,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0xE9,0xE9,0x00,0x0A,0xFF,0x00, 0x00,0x0B,0x0B,0x16,0x0C,0x00,0xFF,0x2F,0xE0,0x22,0x40,0xF9,0x80,0x22,0x40,0x2C, 0x20,0x31,0x00,0x67,0xC0,0xA1,0x00,0x2F,0xE0,0x21,0x00,0xE1,0x00}; +const u8g_fntpgm_uint8_t fontpage_198_130_130[45] U8G_FONT_SECTION("fontpage_198_130_130") = { + 0x00,0x0C,0x0F,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x82,0x82,0x00,0x0A,0xFF,0x00, + 0x00,0x0B,0x0B,0x16,0x0C,0x00,0xFF,0x21,0x00,0x27,0xC0,0xF9,0x00,0x21,0x00,0x2F, + 0xE0,0x31,0x00,0x61,0x00,0xA7,0xC0,0x21,0x00,0x21,0x00,0xEF,0xE0}; const u8g_fntpgm_uint8_t fontpage_198_137_137[45] U8G_FONT_SECTION("fontpage_198_137_137") = { 0x00,0x0C,0x0F,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x89,0x89,0x00,0x0A,0xFF,0x00, 0x00,0x0B,0x0B,0x16,0x0C,0x00,0xFF,0x21,0x00,0x20,0x80,0xFF,0xE0,0x25,0x20,0x29, @@ -1015,6 +1019,10 @@ const u8g_fntpgm_uint8_t fontpage_237_209_209[45] U8G_FONT_SECTION("fontpage_237 0x00,0x0C,0x0F,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0xD1,0xD1,0x00,0x0A,0xFF,0x00, 0x00,0x0B,0x0B,0x16,0x0C,0x00,0xFF,0x0A,0x00,0x4A,0x00,0x4B,0xE0,0x4A,0x00,0x4C, 0x80,0x48,0x40,0x08,0x00,0x7F,0xC0,0x4A,0x40,0x4A,0x40,0xFF,0xE0}; +const u8g_fntpgm_uint8_t fontpage_237_216_216[45] U8G_FONT_SECTION("fontpage_237_216_216") = { + 0x00,0x0C,0x0F,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0xD8,0xD8,0x00,0x0A,0xFF,0x00, + 0x00,0x0B,0x0B,0x16,0x0C,0x00,0xFF,0x04,0x00,0x1F,0x80,0x14,0x80,0x12,0x80,0x7F, + 0xE0,0x14,0x80,0x22,0x80,0x3F,0xC0,0x29,0x40,0x29,0x40,0xFF,0xE0}; const u8g_fntpgm_uint8_t fontpage_237_244_244[45] U8G_FONT_SECTION("fontpage_237_244_244") = { 0x00,0x0C,0x0F,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0xF4,0xF4,0x00,0x0A,0xFF,0x00, 0x00,0x0B,0x0B,0x16,0x0C,0x00,0xFF,0x04,0x00,0xFF,0xE0,0x04,0x00,0x3F,0x80,0x20, @@ -1645,6 +1653,7 @@ static const uxg_fontinfo_t g_fontinfo_zh_CN[] PROGMEM = { FONTDATA_ITEM(197, 189, 189, fontpage_197_189_189), // '抽' -- '抽' FONTDATA_ITEM(197, 212, 212, fontpage_197_212_212), // '拔' -- '拔' FONTDATA_ITEM(197, 233, 233, fontpage_197_233_233), // '择' -- '择' + FONTDATA_ITEM(198, 130, 130, fontpage_198_130_130), // '挂' -- '挂' FONTDATA_ITEM(198, 137, 137, fontpage_198_137_137), // '按' -- '按' FONTDATA_ITEM(198, 161, 161, fontpage_198_161_161), // '挡' -- '挡' FONTDATA_ITEM(198, 164, 164, fontpage_198_164_164), // '挤' -- '挤' @@ -1729,6 +1738,7 @@ static const uxg_fontinfo_t g_fontinfo_zh_CN[] PROGMEM = { FONTDATA_ITEM(236, 253, 253, fontpage_236_253_253), // '白' -- '白' FONTDATA_ITEM(237, 132, 132, fontpage_237_132_132), // '的' -- '的' FONTDATA_ITEM(237, 209, 209, fontpage_237_209_209), // '监' -- '监' + FONTDATA_ITEM(237, 216, 216, fontpage_237_216_216), // '盘' -- '盘' FONTDATA_ITEM(237, 244, 244, fontpage_237_244_244), // '直' -- '直' FONTDATA_ITEM(238, 129, 129, fontpage_238_129_129), // '省' -- '省' FONTDATA_ITEM(238, 160, 160, fontpage_238_160_160), // '眠' -- '眠' diff --git a/Marlin/src/lcd/dogm/fontdata/langdata_zh_TW.h b/Marlin/src/lcd/dogm/fontdata/langdata_zh_TW.h index 65ef7bf7df..9c93ec1fe1 100644 --- a/Marlin/src/lcd/dogm/fontdata/langdata_zh_TW.h +++ b/Marlin/src/lcd/dogm/fontdata/langdata_zh_TW.h @@ -531,6 +531,10 @@ const u8g_fntpgm_uint8_t fontpage_197_212_212[45] U8G_FONT_SECTION("fontpage_197 0x00,0x0C,0x0F,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0xD4,0xD4,0x00,0x0A,0xFF,0x00, 0x00,0x0B,0x0B,0x16,0x0C,0x00,0xFF,0x22,0x80,0x22,0x40,0xFF,0xE0,0x22,0x00,0x2B, 0xC0,0x32,0x40,0x65,0x40,0xA4,0x80,0x28,0x80,0x29,0x40,0xE6,0x20}; +const u8g_fntpgm_uint8_t fontpage_198_130_130[45] U8G_FONT_SECTION("fontpage_198_130_130") = { + 0x00,0x0C,0x0F,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x82,0x82,0x00,0x0A,0xFF,0x00, + 0x00,0x0B,0x0B,0x16,0x0C,0x00,0xFF,0x21,0x00,0x27,0xC0,0xF9,0x00,0x21,0x00,0x2F, + 0xE0,0x31,0x00,0x61,0x00,0xA7,0xC0,0x21,0x00,0x21,0x00,0xEF,0xE0}; const u8g_fntpgm_uint8_t fontpage_198_137_137[45] U8G_FONT_SECTION("fontpage_198_137_137") = { 0x00,0x0C,0x0F,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x89,0x89,0x00,0x0A,0xFF,0x00, 0x00,0x0B,0x0B,0x16,0x0C,0x00,0xFF,0x21,0x00,0x20,0x80,0xFF,0xE0,0x25,0x20,0x29, @@ -809,6 +813,10 @@ const u8g_fntpgm_uint8_t fontpage_240_141_141[45] U8G_FONT_SECTION("fontpage_240 0x00,0x0C,0x0F,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x8D,0x8D,0x00,0x0A,0xFF,0x00, 0x00,0x0B,0x0B,0x16,0x0C,0x00,0xFF,0x02,0x00,0xFA,0x00,0x23,0xE0,0x24,0x20,0x79, 0x40,0xC9,0x00,0x49,0x00,0x49,0x00,0x7A,0x80,0x4C,0x40,0x08,0x20}; +const u8g_fntpgm_uint8_t fontpage_241_159_159[45] U8G_FONT_SECTION("fontpage_241_159_159") = { + 0x00,0x0C,0x0F,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x9F,0x9F,0x00,0x0A,0xFF,0x00, + 0x00,0x0B,0x0B,0x16,0x0C,0x00,0xFF,0x05,0x40,0xFF,0xE0,0x25,0x40,0x25,0xC0,0x74, + 0x00,0xD7,0xE0,0x51,0x00,0x5F,0xE0,0x75,0x80,0x59,0x40,0x11,0x20}; const u8g_fntpgm_uint8_t fontpage_241_186_186[45] U8G_FONT_SECTION("fontpage_241_186_186") = { 0x00,0x0C,0x0F,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0xBA,0xBA,0x00,0x0A,0xFF,0x00, 0x00,0x0B,0x0B,0x16,0x0C,0x00,0xFF,0x01,0x00,0xFF,0xE0,0x2A,0x20,0x22,0x80,0x77, @@ -1011,6 +1019,10 @@ const u8g_fntpgm_uint8_t fontpage_283_221_221[45] U8G_FONT_SECTION("fontpage_283 0x00,0x0C,0x0F,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0xDD,0xDD,0x00,0x0A,0xFF,0x00, 0x00,0x0B,0x0B,0x16,0x0C,0x00,0xFF,0x7B,0xE0,0x4A,0x00,0x4A,0x00,0x7B,0xE0,0x12, 0x20,0x52,0x20,0x5A,0x20,0x53,0xE0,0x52,0x00,0x5E,0x00,0xE3,0xE0}; +const u8g_fntpgm_uint8_t fontpage_285_171_171[45] U8G_FONT_SECTION("fontpage_285_171_171") = { + 0x00,0x0C,0x0F,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0xAB,0xAB,0x00,0x0A,0xFF,0x00, + 0x00,0x0A,0x0B,0x16,0x0C,0x01,0xFF,0x08,0x00,0x3F,0x00,0x21,0x00,0x3F,0x00,0x21, + 0x40,0x3F,0x80,0x21,0x00,0xFF,0x00,0x09,0x00,0x35,0x00,0xC2,0x00}; const u8g_fntpgm_uint8_t fontpage_285_202_202[45] U8G_FONT_SECTION("fontpage_285_202_202") = { 0x00,0x0C,0x0F,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0xCA,0xCA,0x00,0x0A,0xFF,0x00, 0x00,0x0B,0x0B,0x16,0x0C,0x00,0xFF,0x04,0x00,0x7F,0xC0,0x04,0x00,0x3F,0x80,0x24, @@ -1039,6 +1051,10 @@ const u8g_fntpgm_uint8_t fontpage_286_201_201[45] U8G_FONT_SECTION("fontpage_286 0x00,0x0C,0x0F,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0xC9,0xC9,0x00,0x0A,0xFF,0x00, 0x00,0x0B,0x0B,0x16,0x0C,0x00,0xFF,0x21,0x00,0xFF,0xE0,0x25,0x40,0xFF,0xC0,0xAD, 0x40,0xFF,0xC0,0xA9,0x60,0xFF,0xE0,0x24,0x40,0xFA,0x40,0x20,0xC0}; +const u8g_fntpgm_uint8_t fontpage_286_253_253[45] U8G_FONT_SECTION("fontpage_286_253_253") = { + 0x00,0x0C,0x0F,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0xFD,0xFD,0x00,0x0A,0xFF,0x00, + 0x00,0x0B,0x0B,0x16,0x0C,0x00,0xFF,0x11,0x00,0x7D,0x40,0x11,0x20,0xFF,0xE0,0x21, + 0x00,0xFD,0x20,0x51,0x40,0x7C,0x80,0x10,0xA0,0xFD,0x60,0x12,0x20}; const u8g_fntpgm_uint8_t fontpage_287_209_209[45] U8G_FONT_SECTION("fontpage_287_209_209") = { 0x00,0x0C,0x0F,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0xD1,0xD1,0x00,0x0A,0xFF,0x00, 0x00,0x0B,0x0B,0x16,0x0C,0x00,0xFF,0x40,0xC0,0x27,0x00,0x24,0x00,0x07,0xE0,0xE4, @@ -1151,6 +1167,10 @@ const u8g_fntpgm_uint8_t fontpage_301_142_142[45] U8G_FONT_SECTION("fontpage_301 0x00,0x0C,0x0F,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x8E,0x8E,0x00,0x0A,0xFF,0x00, 0x00,0x0B,0x0B,0x16,0x0C,0x00,0xFF,0xF8,0x80,0x98,0xA0,0xAE,0xC0,0xC8,0xA0,0xAE, 0xE0,0x92,0x00,0x97,0xC0,0xF4,0x40,0xA7,0xC0,0x84,0x40,0x87,0xC0}; +const u8g_fntpgm_uint8_t fontpage_301_168_168[45] U8G_FONT_SECTION("fontpage_301_168_168") = { + 0x00,0x0C,0x0F,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0xA8,0xA8,0x00,0x0A,0xFF,0x00, + 0x00,0x0B,0x0B,0x16,0x0C,0x00,0xFF,0xF1,0x00,0x9B,0xE0,0xA4,0x80,0xC7,0xE0,0xA1, + 0x40,0x9D,0xC0,0x95,0x40,0xF5,0xC0,0xA5,0x40,0x8A,0x40,0x91,0xE0}; const u8g_fntpgm_uint8_t fontpage_301_217_217[45] U8G_FONT_SECTION("fontpage_301_217_217") = { 0x00,0x0C,0x0F,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0xD9,0xD9,0x00,0x0A,0xFF,0x00, 0x00,0x0B,0x0B,0x16,0x0C,0x00,0xFF,0x2A,0x80,0x3F,0xE0,0x6A,0x80,0xBF,0xC0,0x2A, @@ -1365,6 +1385,7 @@ static const uxg_fontinfo_t g_fontinfo_zh_TW[] PROGMEM = { FONTDATA_ITEM(197, 150, 150, fontpage_197_150_150), // '抖' -- '抖' FONTDATA_ITEM(197, 189, 189, fontpage_197_189_189), // '抽' -- '抽' FONTDATA_ITEM(197, 212, 212, fontpage_197_212_212), // '拔' -- '拔' + FONTDATA_ITEM(198, 130, 130, fontpage_198_130_130), // '挂' -- '挂' FONTDATA_ITEM(198, 137, 137, fontpage_198_137_137), // '按' -- '按' FONTDATA_ITEM(199, 137, 137, fontpage_199_137_137), // '掉' -- '掉' FONTDATA_ITEM(199, 162, 162, fontpage_199_162_162), // '探' -- '探' @@ -1433,6 +1454,7 @@ static const uxg_fontinfo_t g_fontinfo_zh_TW[] PROGMEM = { FONTDATA_ITEM(237, 244, 244, fontpage_237_244_244), // '直' -- '直' FONTDATA_ITEM(238, 160, 160, fontpage_238_160_160), // '眠' -- '眠' FONTDATA_ITEM(240, 141, 141, fontpage_240_141_141), // '砍' -- '砍' + FONTDATA_ITEM(241, 159, 159, fontpage_241_159_159), // '碟' -- '碟' FONTDATA_ITEM(241, 186, 186, fontpage_241_186_186), // '確' -- '確' FONTDATA_ITEM(243, 251, 251, fontpage_243_251_251), // '移' -- '移' FONTDATA_ITEM(244, 205, 205, fontpage_244_205_205), // '積' -- '積' @@ -1483,6 +1505,7 @@ static const uxg_fontinfo_t g_fontinfo_zh_TW[] PROGMEM = { FONTDATA_ITEM(279, 138, 138, fontpage_279_138_138), // '變' -- '變' FONTDATA_ITEM(281, 199, 199, fontpage_281_199_199), // '資' -- '資' FONTDATA_ITEM(283, 221, 221, fontpage_283_221_221), // '距' -- '距' + FONTDATA_ITEM(285, 171, 171, fontpage_285_171_171), // '身' -- '身' FONTDATA_ITEM(285, 202, 202, fontpage_285_202_202), // '車' -- '車' FONTDATA_ITEM(285, 223, 223, fontpage_285_223_223), // '軟' -- '軟' FONTDATA_ITEM(285, 248, 248, fontpage_285_248_248), // '軸' -- '軸' @@ -1490,6 +1513,7 @@ static const uxg_fontinfo_t g_fontinfo_zh_TW[] PROGMEM = { FONTDATA_ITEM(286, 175, 175, fontpage_286_175_175), // '輯' -- '輯' FONTDATA_ITEM(286, 184, 184, fontpage_286_184_184), // '輸' -- '輸' FONTDATA_ITEM(286, 201, 201, fontpage_286_201_201), // '轉' -- '轉' + FONTDATA_ITEM(286, 253, 253, fontpage_286_253_253), // '载' -- '载' FONTDATA_ITEM(287, 209, 209, fontpage_287_209_209), // '近' -- '近' FONTDATA_ITEM(287, 212, 212, fontpage_287_212_212), // '返' -- '返' FONTDATA_ITEM(288, 128, 128, fontpage_288_128_128), // '退' -- '退' @@ -1518,6 +1542,7 @@ static const uxg_fontinfo_t g_fontinfo_zh_TW[] PROGMEM = { FONTDATA_ITEM(300, 205, 205, fontpage_300_205_205), // '降' -- '降' FONTDATA_ITEM(300, 228, 228, fontpage_300_228_228), // '除' -- '除' FONTDATA_ITEM(301, 142, 142, fontpage_301_142_142), // '階' -- '階' + FONTDATA_ITEM(301, 168, 168, fontpage_301_168_168), // '隨' -- '隨' FONTDATA_ITEM(301, 217, 217, fontpage_301_217_217), // '雙' -- '雙' FONTDATA_ITEM(301, 226, 226, fontpage_301_226_226), // '離' -- '離' FONTDATA_ITEM(301, 251, 251, fontpage_301_251_251), // '電' -- '電' diff --git a/Marlin/src/lcd/language/language_an.h b/Marlin/src/lcd/language/language_an.h index bd54a4803e..c51891f6ec 100644 --- a/Marlin/src/lcd/language/language_an.h +++ b/Marlin/src/lcd/language/language_an.h @@ -155,7 +155,12 @@ namespace LanguageNarrow_an { LSTR MSG_AUTORETRACT = _UxGT("Retraccion auto."); LSTR MSG_FILAMENTCHANGE = _UxGT("Cambear filamento"); LSTR MSG_FILAMENTCHANGE_E = _UxGT("Cambear filamento *"); - LSTR MSG_ATTACH_MEDIA = _UxGT("Encetan. tarcheta"); + #if HAS_MULTI_VOLUME + LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Encetan. SD"); + LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Encetan. USB"); + #else + LSTR MSG_ATTACH_MEDIA = _UxGT("Encetan. SD"); + #endif LSTR MSG_CHANGE_MEDIA = _UxGT("Cambiar tarcheta"); LSTR MSG_ZPROBE_OUT = _UxGT("Sonda Z fuera"); LSTR MSG_BLTOUCH_RESET = _UxGT("Reset BLTouch"); diff --git a/Marlin/src/lcd/language/language_bg.h b/Marlin/src/lcd/language/language_bg.h index 7b58b263ee..3722dba3ad 100644 --- a/Marlin/src/lcd/language/language_bg.h +++ b/Marlin/src/lcd/language/language_bg.h @@ -139,7 +139,12 @@ namespace LanguageNarrow_bg { LSTR MSG_AUTORETRACT = _UxGT("Автоoткат"); LSTR MSG_FILAMENTCHANGE = _UxGT("Смяна нишка"); LSTR MSG_FILAMENTCHANGE_E = _UxGT("Смяна нишка *"); - LSTR MSG_ATTACH_MEDIA = _UxGT("Иниц. SD-Карта"); + #if HAS_MULTI_VOLUME + LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Иниц. SD-Карта"); + LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Иниц. USB-Карта"); + #else + LSTR MSG_ATTACH_MEDIA = _UxGT("Иниц. SD-Карта"); + #endif LSTR MSG_CHANGE_MEDIA = _UxGT("Смяна SD-Карта"); LSTR MSG_ZPROBE_OUT = _UxGT("Z-сондата е извадена"); LSTR MSG_ZPROBE_XOFFSET = _UxGT("X Отстояние"); diff --git a/Marlin/src/lcd/language/language_ca.h b/Marlin/src/lcd/language/language_ca.h index 3c753de53e..da784bc342 100644 --- a/Marlin/src/lcd/language/language_ca.h +++ b/Marlin/src/lcd/language/language_ca.h @@ -145,7 +145,12 @@ namespace LanguageNarrow_ca { LSTR MSG_AUTORETRACT = _UxGT("Auto retraccio"); LSTR MSG_FILAMENTCHANGE = _UxGT("Canvia filament"); LSTR MSG_FILAMENTCHANGE_E = _UxGT("Canvia filament *"); - LSTR MSG_ATTACH_MEDIA = _UxGT("Inicialitza SD"); + #if HAS_MULTI_VOLUME + LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Inicialitza SD"); + LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Inicialitza USB"); + #else + LSTR MSG_ATTACH_MEDIA = _UxGT("Inicialitza SD"); + #endif LSTR MSG_CHANGE_MEDIA = _UxGT("Canvia SD"); LSTR MSG_ZPROBE_OUT = _UxGT("Sonda Z fora"); LSTR MSG_BLTOUCH_RESET = _UxGT("Reinicia BLTouch"); diff --git a/Marlin/src/lcd/language/language_cz.h b/Marlin/src/lcd/language/language_cz.h index 2217ee5fbd..e54a69ec83 100644 --- a/Marlin/src/lcd/language/language_cz.h +++ b/Marlin/src/lcd/language/language_cz.h @@ -359,7 +359,12 @@ namespace LanguageNarrow_cz { LSTR MSG_FILAMENTUNLOAD_E = _UxGT("Vysunout filament *"); LSTR MSG_FILAMENTUNLOAD_ALL = _UxGT("Vysunout vše"); - LSTR MSG_ATTACH_MEDIA = _UxGT("Načíst médium"); + #if HAS_MULTI_VOLUME + LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Načíst SD"); + LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Načíst USB"); + #else + LSTR MSG_ATTACH_MEDIA = _UxGT("Načíst SD"); + #endif LSTR MSG_CHANGE_MEDIA = _UxGT("Vyměnit médium"); LSTR MSG_RELEASE_MEDIA = _UxGT("Vysunout médium"); LSTR MSG_ZPROBE_OUT = _UxGT("Sonda Z mimo podl"); diff --git a/Marlin/src/lcd/language/language_de.h b/Marlin/src/lcd/language/language_de.h index afabace283..e469a594ca 100644 --- a/Marlin/src/lcd/language/language_de.h +++ b/Marlin/src/lcd/language/language_de.h @@ -493,7 +493,12 @@ namespace LanguageNarrow_de { LSTR MSG_FILAMENTUNLOAD = _UxGT("Filament entladen"); LSTR MSG_FILAMENTUNLOAD_E = _UxGT("Filament entladen *"); LSTR MSG_FILAMENTUNLOAD_ALL = _UxGT("Alles entladen"); - LSTR MSG_ATTACH_MEDIA = _UxGT("Medium initial."); // Manually initialize the SD-card via user interface + #if HAS_MULTI_VOLUME + LSTR MSG_ATTACH_SD_MEDIA = _UxGT("SD initial."); + LSTR MSG_ATTACH_USB_MEDIA = _UxGT("USB initial."); + #else + LSTR MSG_ATTACH_MEDIA = _UxGT("SD initial."); + #endif LSTR MSG_CHANGE_MEDIA = _UxGT("Medium getauscht"); // SD-card changed by user. For machines with no autocarddetect. Both send "M21" LSTR MSG_RELEASE_MEDIA = _UxGT("Medium freigeben"); // if Marlin gets confused - M22 LSTR MSG_ZPROBE_OUT = _UxGT("Z-Sonde außerhalb"); diff --git a/Marlin/src/lcd/language/language_el.h b/Marlin/src/lcd/language/language_el.h index e971af32d5..b100f31781 100644 --- a/Marlin/src/lcd/language/language_el.h +++ b/Marlin/src/lcd/language/language_el.h @@ -180,7 +180,12 @@ namespace LanguageNarrow_el { LSTR MSG_AUTORETRACT = _UxGT("Αυτόματη ανάσυρση"); LSTR MSG_FILAMENTCHANGE = _UxGT("Αλλαγή νήματος"); LSTR MSG_FILAMENTCHANGE_E = _UxGT("Αλλαγή νήματος *"); - LSTR MSG_ATTACH_MEDIA = _UxGT("Προετοιμασία SD"); + #if HAS_MULTI_VOLUME + LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Προετοιμασία SD"); + LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Προετοιμασία USB"); + #else + LSTR MSG_ATTACH_MEDIA = _UxGT("Προετοιμασία SD"); + #endif LSTR MSG_CHANGE_MEDIA = _UxGT("Αλλαγή κάρτας SD"); LSTR MSG_ZPROBE_OUT = _UxGT("Διερεύνηση Z εκτός Επ.Εκτύπωσης"); // SHORTEN LSTR MSG_YX_UNHOMED = _UxGT("Επαναφορά Χ/Υ πρώτα"); diff --git a/Marlin/src/lcd/language/language_el_gr.h b/Marlin/src/lcd/language/language_el_gr.h index e2a34765ce..caef745a0e 100644 --- a/Marlin/src/lcd/language/language_el_gr.h +++ b/Marlin/src/lcd/language/language_el_gr.h @@ -170,7 +170,12 @@ namespace LanguageNarrow_el_gr { LSTR MSG_AUTORETRACT = _UxGT("Αυτόματη ανάσυρση"); LSTR MSG_FILAMENTCHANGE = _UxGT("Αλλαγή νήματος"); LSTR MSG_FILAMENTCHANGE_E = _UxGT("Αλλαγή νήματος *"); - LSTR MSG_ATTACH_MEDIA = _UxGT("Προετοιμασία κάρτας SD"); + #if HAS_MULTI_VOLUME + LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Προετοιμασία SD"); + LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Προετοιμασία USB"); + #else + LSTR MSG_ATTACH_MEDIA = _UxGT("Προετοιμασία SD"); + #endif LSTR MSG_CHANGE_MEDIA = _UxGT("Αλλαγή κάρτας SD"); LSTR MSG_ZPROBE_OUT = _UxGT("Διερεύνηση Z εκτός κλίνης"); LSTR MSG_YX_UNHOMED = _UxGT("Επαναφορά Χ/Υ πριν από Z"); diff --git a/Marlin/src/lcd/language/language_en.h b/Marlin/src/lcd/language/language_en.h index 71a7a6869d..bab95d2b86 100644 --- a/Marlin/src/lcd/language/language_en.h +++ b/Marlin/src/lcd/language/language_en.h @@ -606,9 +606,12 @@ namespace LanguageNarrow_en { LSTR MSG_FILAMENTUNLOAD = _UxGT("Unload Filament"); LSTR MSG_FILAMENTUNLOAD_E = _UxGT("Unload * Filament"); LSTR MSG_FILAMENTUNLOAD_ALL = _UxGT("Unload All"); - LSTR MSG_ATTACH_MEDIA = _UxGT("Attach ") MEDIA_TYPE_EN; - LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Attach SD Card"); - LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Attach USB Drive"); + #if HAS_MULTI_VOLUME + LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Attach SD Card"); + LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Attach USB Drive"); + #else + LSTR MSG_ATTACH_MEDIA = _UxGT("Attach ") MEDIA_TYPE_EN; + #endif LSTR MSG_CHANGE_MEDIA = _UxGT("Change ") MEDIA_TYPE_EN; LSTR MSG_RELEASE_MEDIA = _UxGT("Release ") MEDIA_TYPE_EN; LSTR MSG_ZPROBE_OUT = _UxGT("Z Probe Past Bed"); diff --git a/Marlin/src/lcd/language/language_es.h b/Marlin/src/lcd/language/language_es.h index 5863b63a0e..06e3c753be 100644 --- a/Marlin/src/lcd/language/language_es.h +++ b/Marlin/src/lcd/language/language_es.h @@ -28,6 +28,8 @@ * See also https://marlinfw.org/docs/development/lcd_language.html */ +#define MEDIA_TYPE_ES "SD/FD" + namespace LanguageNarrow_es { using namespace Language_en; // Inherit undefined strings from English @@ -39,11 +41,11 @@ namespace LanguageNarrow_es { LSTR MSG_NO = _UxGT("NO"); LSTR MSG_BACK = _UxGT("Atrás"); LSTR MSG_MEDIA_ABORTING = _UxGT("Cancelando..."); - LSTR MSG_MEDIA_INSERTED = _UxGT("SD/FD insertado"); - LSTR MSG_MEDIA_REMOVED = _UxGT("SD/FD retirado"); - LSTR MSG_MEDIA_WAITING = _UxGT("Esperando al SD/FD"); - LSTR MSG_MEDIA_INIT_FAIL = _UxGT("Fallo al iniciar SD/FD"); - LSTR MSG_MEDIA_READ_ERROR = _UxGT("Error lectura SD/FD"); + LSTR MSG_MEDIA_INSERTED = MEDIA_TYPE_ES _UxGT(" insertado"); + LSTR MSG_MEDIA_REMOVED = MEDIA_TYPE_ES _UxGT(" retirado"); + LSTR MSG_MEDIA_WAITING = _UxGT("Esperando al ") MEDIA_TYPE_ES; + LSTR MSG_MEDIA_INIT_FAIL = _UxGT("Fallo al iniciar ") MEDIA_TYPE_ES; + LSTR MSG_MEDIA_READ_ERROR = _UxGT("Error lectura ") MEDIA_TYPE_ES; LSTR MSG_MEDIA_USB_REMOVED = _UxGT("Disp. USB retirado"); LSTR MSG_MEDIA_USB_FAILED = _UxGT("Inicio USB fallido"); LSTR MSG_KILL_SUBCALL_OVERFLOW = _UxGT("Desbordamiento de subllamada"); @@ -310,7 +312,7 @@ namespace LanguageNarrow_es { LSTR MSG_ERR_EEPROM_CRC = _UxGT("Err: EEPROM CRC"); LSTR MSG_ERR_EEPROM_SIZE = _UxGT("Err: EEPROM Tamaño"); LSTR MSG_ERR_EEPROM_VERSION = _UxGT("Err: Versión EEPROM"); - LSTR MSG_MEDIA_UPDATE = _UxGT("Actualizar SD/FD"); + LSTR MSG_MEDIA_UPDATE = _UxGT("Actualizar ") MEDIA_TYPE_ES; LSTR MSG_RESET_PRINTER = _UxGT("Resetear Impresora"); LSTR MSG_REFRESH = LCD_STR_REFRESH _UxGT("Recargar"); LSTR MSG_INFO_SCREEN = _UxGT("Pantalla de Inf."); @@ -333,8 +335,8 @@ namespace LanguageNarrow_es { LSTR MSG_CANCEL_OBJECT = _UxGT("Cancelar Objeto"); LSTR MSG_CANCEL_OBJECT_N = _UxGT("Cancelar Objeto {"); LSTR MSG_OUTAGE_RECOVERY = _UxGT("Rec. Fallo electrico"); - LSTR MSG_MEDIA_MENU = _UxGT("Imprim. desde SD/FD"); - LSTR MSG_NO_MEDIA = _UxGT("SD/FD no presente"); + LSTR MSG_MEDIA_MENU = _UxGT("Imprim. desde ") MEDIA_TYPE_ES; + LSTR MSG_NO_MEDIA = MEDIA_TYPE_ES _UxGT(" no presente"); LSTR MSG_DWELL = _UxGT("Reposo..."); LSTR MSG_USERWAIT = _UxGT("Pulsar para Reanudar"); LSTR MSG_PRINT_PAUSED = _UxGT("Impresión Pausada"); @@ -366,9 +368,14 @@ namespace LanguageNarrow_es { LSTR MSG_FILAMENTUNLOAD = _UxGT("Descargar filamento"); LSTR MSG_FILAMENTUNLOAD_E = _UxGT("Descargar fil. *"); LSTR MSG_FILAMENTUNLOAD_ALL = _UxGT("Descargar todo"); - LSTR MSG_ATTACH_MEDIA = _UxGT("Iniciar SD/FD"); - LSTR MSG_CHANGE_MEDIA = _UxGT("Cambiar SD/FD"); - LSTR MSG_RELEASE_MEDIA = _UxGT("Lanzar SD/FD"); + #if HAS_MULTI_VOLUME + LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Iniciar SD"); + LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Iniciar USB"); + #else + LSTR MSG_ATTACH_MEDIA = _UxGT("Iniciar ") MEDIA_TYPE_ES; + #endif + LSTR MSG_CHANGE_MEDIA = _UxGT("Cambiar ") MEDIA_TYPE_ES; + LSTR MSG_RELEASE_MEDIA = _UxGT("Lanzar ") MEDIA_TYPE_ES; LSTR MSG_ZPROBE_OUT = _UxGT("Sonda Z fuera cama"); LSTR MSG_SKEW_FACTOR = _UxGT("Factor de desviación"); LSTR MSG_BLTOUCH = _UxGT("BLTouch"); diff --git a/Marlin/src/lcd/language/language_eu.h b/Marlin/src/lcd/language/language_eu.h index 2e49cf50e9..df6e6395d1 100644 --- a/Marlin/src/lcd/language/language_eu.h +++ b/Marlin/src/lcd/language/language_eu.h @@ -219,7 +219,12 @@ namespace LanguageNarrow_eu { LSTR MSG_FILAMENTUNLOAD = _UxGT("Harizpia deskargatu"); LSTR MSG_FILAMENTUNLOAD_E = _UxGT("Harizpia deskargatu *"); LSTR MSG_FILAMENTUNLOAD_ALL = _UxGT("Erabat deskargatu"); - LSTR MSG_ATTACH_MEDIA = _UxGT("Hasieratu SD-a"); + #if HAS_MULTI_VOLUME + LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Hasieratu SD-a"); + LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Hasieratu USB-a"); + #else + LSTR MSG_ATTACH_MEDIA = _UxGT("Hasieratu SD-a"); + #endif LSTR MSG_CHANGE_MEDIA = _UxGT("Aldatu txartela"); LSTR MSG_ZPROBE_OUT = _UxGT("Z zunda kanpora"); LSTR MSG_SKEW_FACTOR = _UxGT("Okertze faktorea"); diff --git a/Marlin/src/lcd/language/language_fr.h b/Marlin/src/lcd/language/language_fr.h index 169363339e..2a65cd2671 100644 --- a/Marlin/src/lcd/language/language_fr.h +++ b/Marlin/src/lcd/language/language_fr.h @@ -392,7 +392,12 @@ namespace LanguageNarrow_fr { LSTR MSG_FILAMENTUNLOAD = _UxGT("Retrait filament"); LSTR MSG_FILAMENTUNLOAD_E = _UxGT("Retrait filament *"); LSTR MSG_FILAMENTUNLOAD_ALL = _UxGT("Retirer tout"); - LSTR MSG_ATTACH_MEDIA = _UxGT("Charger le média"); + #if HAS_MULTI_VOLUME + LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Charger le SD"); + LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Charger le USB"); + #else + LSTR MSG_ATTACH_MEDIA = _UxGT("Charger le SD"); + #endif LSTR MSG_CHANGE_MEDIA = _UxGT("Actualiser média"); LSTR MSG_RELEASE_MEDIA = _UxGT("Retirer le média"); LSTR MSG_ZPROBE_OUT = _UxGT("Sonde Z hors lit"); diff --git a/Marlin/src/lcd/language/language_fr_na.h b/Marlin/src/lcd/language/language_fr_na.h index a2c5f024b9..0aad606af5 100644 --- a/Marlin/src/lcd/language/language_fr_na.h +++ b/Marlin/src/lcd/language/language_fr_na.h @@ -392,7 +392,12 @@ namespace LanguageNarrow_fr_na { LSTR MSG_FILAMENTUNLOAD = _UxGT("Retrait filament"); LSTR MSG_FILAMENTUNLOAD_E = _UxGT("Retrait filament *"); LSTR MSG_FILAMENTUNLOAD_ALL = _UxGT("Retirer tout"); - LSTR MSG_ATTACH_MEDIA = _UxGT("Charger le media"); + #if HAS_MULTI_VOLUME + LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Charger le SD"); + LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Charger le USB"); + #else + LSTR MSG_ATTACH_MEDIA = _UxGT("Charger le SD"); + #endif LSTR MSG_CHANGE_MEDIA = _UxGT("Actualiser media"); LSTR MSG_RELEASE_MEDIA = _UxGT("Retirer le media"); LSTR MSG_ZPROBE_OUT = _UxGT("Sonde Z hors lit"); diff --git a/Marlin/src/lcd/language/language_gl.h b/Marlin/src/lcd/language/language_gl.h index dc04f481ec..ada1fd2fa2 100644 --- a/Marlin/src/lcd/language/language_gl.h +++ b/Marlin/src/lcd/language/language_gl.h @@ -30,6 +30,8 @@ #define DISPLAY_CHARSET_ISO10646_1 +#define MEDIA_TYPE_GL "SD/FD" + namespace LanguageNarrow_gl { using namespace Language_en; // Inherit undefined strings from English @@ -43,8 +45,8 @@ namespace LanguageNarrow_gl { LSTR MSG_MEDIA_ABORTING = _UxGT("Cancelando..."); LSTR MSG_MEDIA_INSERTED = _UxGT("Tarxeta inserida"); LSTR MSG_MEDIA_REMOVED = _UxGT("Tarxeta retirada"); - LSTR MSG_MEDIA_WAITING = _UxGT("Agardando ao SD/FD"); - LSTR MSG_MEDIA_READ_ERROR = _UxGT("Erro lectura SD/FD"); + LSTR MSG_MEDIA_WAITING = _UxGT("Agardando ao ") MEDIA_TYPE_GL; + LSTR MSG_MEDIA_READ_ERROR = _UxGT("Erro lectura ") MEDIA_TYPE_GL; LSTR MSG_MEDIA_USB_REMOVED = _UxGT("Disp. USB retirado"); LSTR MSG_MEDIA_USB_FAILED = _UxGT("Inicio USB fallido"); LSTR MSG_KILL_SUBCALL_OVERFLOW = _UxGT("Desbord. Subch."); @@ -313,7 +315,7 @@ namespace LanguageNarrow_gl { LSTR MSG_ERR_EEPROM_SIZE = _UxGT("Erro: Tamaño EEPROM"); LSTR MSG_ERR_EEPROM_VERSION = _UxGT("Erro: Versión EEPROM"); LSTR MSG_SETTINGS_STORED = _UxGT("Config Gardada"); - LSTR MSG_MEDIA_UPDATE = _UxGT("Actualizar SD/FD"); + LSTR MSG_MEDIA_UPDATE = _UxGT("Actualizar ") MEDIA_TYPE_GL; LSTR MSG_RESET_PRINTER = _UxGT("Reiniciar Impresora"); LSTR MSG_REFRESH = LCD_STR_REFRESH _UxGT("Recargar"); LSTR MSG_INFO_SCREEN = _UxGT("Información"); @@ -381,9 +383,14 @@ namespace LanguageNarrow_gl { LSTR MSG_FILAMENTUNLOAD = _UxGT("Descargar Filamento"); LSTR MSG_FILAMENTUNLOAD_E = _UxGT("Descargar Filamento *"); LSTR MSG_FILAMENTUNLOAD_ALL = _UxGT("Descargar Todo"); - LSTR MSG_ATTACH_MEDIA = _UxGT("Iniciar SD/FD"); - LSTR MSG_CHANGE_MEDIA = _UxGT("Cambiar SD/FD"); - LSTR MSG_RELEASE_MEDIA = _UxGT("Lanzar SD/FD"); + #if HAS_MULTI_VOLUME + LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Iniciar SD"); + LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Iniciar USB"); + #else + LSTR MSG_ATTACH_MEDIA = _UxGT("Iniciar ") MEDIA_TYPE_GL; + #endif + LSTR MSG_CHANGE_MEDIA = _UxGT("Cambiar ") MEDIA_TYPE_GL; + LSTR MSG_RELEASE_MEDIA = _UxGT("Lanzar ") MEDIA_TYPE_GL; LSTR MSG_ZPROBE_OUT = _UxGT("Sonda-Z fóra Cama"); LSTR MSG_SKEW_FACTOR = _UxGT("Factor de Desviación"); LSTR MSG_BLTOUCH = _UxGT("BLTouch"); diff --git a/Marlin/src/lcd/language/language_hr.h b/Marlin/src/lcd/language/language_hr.h index ced6d3f25b..9f259693e7 100644 --- a/Marlin/src/lcd/language/language_hr.h +++ b/Marlin/src/lcd/language/language_hr.h @@ -117,7 +117,12 @@ namespace LanguageNarrow_hr { LSTR MSG_STOPPED = _UxGT("ZAUSTAVLJEN. "); LSTR MSG_FILAMENTCHANGE = _UxGT("Promijeni filament"); LSTR MSG_FILAMENTCHANGE_E = _UxGT("Promijeni filament *"); - LSTR MSG_ATTACH_MEDIA = _UxGT("Init. SD karticu"); + #if HAS_MULTI_VOLUME + LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Init. SD karticu"); + LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Init. USB pogon"); + #else + LSTR MSG_ATTACH_MEDIA = _UxGT("Init. SD karticu"); + #endif LSTR MSG_CHANGE_MEDIA = _UxGT("Promijeni SD karticu"); LSTR MSG_ERR_HEATING_FAILED = _UxGT("Grijanje neuspješno"); LSTR MSG_HEATING = _UxGT("Grijanje..."); diff --git a/Marlin/src/lcd/language/language_hu.h b/Marlin/src/lcd/language/language_hu.h index fd81dc6b18..2f744abc6f 100644 --- a/Marlin/src/lcd/language/language_hu.h +++ b/Marlin/src/lcd/language/language_hu.h @@ -431,7 +431,12 @@ namespace LanguageNarrow_hu { LSTR MSG_FILAMENTUNLOAD = _UxGT("Szál eltávolítás"); LSTR MSG_FILAMENTUNLOAD_E = _UxGT("Szál eltávolítás *"); LSTR MSG_FILAMENTUNLOAD_ALL = _UxGT("Mindet eltávolít"); - LSTR MSG_ATTACH_MEDIA = _UxGT("Tároló"); + #if HAS_MULTI_VOLUME + LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Tároló SD"); + LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Tároló USB"); + #else + LSTR MSG_ATTACH_MEDIA = _UxGT("Tároló SD"); + #endif LSTR MSG_CHANGE_MEDIA = _UxGT("Tároló csere"); LSTR MSG_RELEASE_MEDIA = _UxGT("Tároló Kiadása"); LSTR MSG_ZPROBE_OUT = _UxGT("Z szonda tálcán kivül"); diff --git a/Marlin/src/lcd/language/language_it.h b/Marlin/src/lcd/language/language_it.h index 005f0b45a4..13a6f88a01 100644 --- a/Marlin/src/lcd/language/language_it.h +++ b/Marlin/src/lcd/language/language_it.h @@ -581,9 +581,12 @@ namespace LanguageNarrow_it { LSTR MSG_FILAMENTUNLOAD = _UxGT("Rimuovi filamento"); LSTR MSG_FILAMENTUNLOAD_E = _UxGT("Rimuovi filam. *"); LSTR MSG_FILAMENTUNLOAD_ALL = _UxGT("Rimuovi tutto"); - LSTR MSG_ATTACH_MEDIA = _UxGT("Collega ") MEDIA_TYPE_IT; - LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Collega scheda SD"); - LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Collega penna USB"); + #if HAS_MULTI_VOLUME + LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Collega scheda SD"); + LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Collega penna USB"); + #else + LSTR MSG_ATTACH_MEDIA = _UxGT("Collega ") MEDIA_TYPE_IT; + #endif LSTR MSG_CHANGE_MEDIA = _UxGT("Cambia ") MEDIA_TYPE_IT; LSTR MSG_RELEASE_MEDIA = _UxGT("Rilascia ") MEDIA_TYPE_IT; LSTR MSG_ZPROBE_OUT = _UxGT("Z probe fuori piatto"); diff --git a/Marlin/src/lcd/language/language_jp_kana.h b/Marlin/src/lcd/language/language_jp_kana.h index f7c37bad16..cbc680460a 100644 --- a/Marlin/src/lcd/language/language_jp_kana.h +++ b/Marlin/src/lcd/language/language_jp_kana.h @@ -168,7 +168,12 @@ namespace LanguageNarrow_jp_kana { LSTR MSG_CONTROL_RETRACT_RECOVERF = _UxGT("ホショウソクド mm/s"); // "Unretract V" LSTR MSG_AUTORETRACT = _UxGT("ジドウヒキコミ"); // "Auto-Retract" LSTR MSG_FILAMENTCHANGE = _UxGT("フィラメントコウカン"); // "Change filament" - LSTR MSG_ATTACH_MEDIA = _UxGT("メディアサイヨミコミ"); // "Init. SD card" + #if HAS_MULTI_VOLUME + LSTR MSG_ATTACH_SD_MEDIA = _UxGT("SDカードをマウントする"); // "Attach SD Card" + LSTR MSG_ATTACH_USB_MEDIA = _UxGT("USBメモリをマウントする"); // "Attach USB Drive" + #else + LSTR MSG_ATTACH_MEDIA = _UxGT("SDカードをマウントする"); // "Attach SD Card" + #endif LSTR MSG_CHANGE_MEDIA = _UxGT("メディアコウカン"); // "Change SD card" LSTR MSG_ZPROBE_OUT = _UxGT("Zプローブ ベッドガイ"); // "Z probe out. bed" LSTR MSG_BLTOUCH_SELFTEST = _UxGT("BLTouch ジコシンダン"); // "BLTouch Self-Test" diff --git a/Marlin/src/lcd/language/language_nl.h b/Marlin/src/lcd/language/language_nl.h index 2c542999ca..f47bc053b8 100644 --- a/Marlin/src/lcd/language/language_nl.h +++ b/Marlin/src/lcd/language/language_nl.h @@ -146,7 +146,12 @@ namespace LanguageNarrow_nl { LSTR MSG_AUTORETRACT = _UxGT("Auto-Retract"); LSTR MSG_FILAMENTCHANGE = _UxGT("Verv. Filament"); LSTR MSG_FILAMENTCHANGE_E = _UxGT("Verv. Filament *"); - LSTR MSG_ATTACH_MEDIA = _UxGT("Init. SD kaart"); + #if HAS_MULTI_VOLUME + LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Init. SD kaart"); + LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Init. USB stick"); + #else + LSTR MSG_ATTACH_MEDIA = _UxGT("Init. SD kaart"); + #endif LSTR MSG_CHANGE_MEDIA = _UxGT("Verv. SD Kaart"); LSTR MSG_ZPROBE_OUT = _UxGT("Z probe uit. bed"); LSTR MSG_BLTOUCH_SELFTEST = _UxGT("BLTouch Zelf-Test"); diff --git a/Marlin/src/lcd/language/language_pl.h b/Marlin/src/lcd/language/language_pl.h index 64759ee841..087a26967d 100644 --- a/Marlin/src/lcd/language/language_pl.h +++ b/Marlin/src/lcd/language/language_pl.h @@ -358,7 +358,12 @@ namespace LanguageNarrow_pl { LSTR MSG_FILAMENTUNLOAD = _UxGT("Wysuń Filament"); LSTR MSG_FILAMENTUNLOAD_E = _UxGT("Wysuń Filament *"); LSTR MSG_FILAMENTUNLOAD_ALL = _UxGT("Wysuń wszystkie"); - LSTR MSG_ATTACH_MEDIA = _UxGT("Inicjal. karty SD"); + #if HAS_MULTI_VOLUME + LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Inicjal. karty SD"); + LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Inicjal. dysk flash"); + #else + LSTR MSG_ATTACH_MEDIA = _UxGT("Inicjal. karty SD"); + #endif LSTR MSG_CHANGE_MEDIA = _UxGT("Zmiana karty SD"); LSTR MSG_RELEASE_MEDIA = _UxGT("Zwolnienie karty"); LSTR MSG_ZPROBE_OUT = _UxGT("Sonda Z za stołem"); diff --git a/Marlin/src/lcd/language/language_pt.h b/Marlin/src/lcd/language/language_pt.h index 682ebba9fa..8f9745c04b 100644 --- a/Marlin/src/lcd/language/language_pt.h +++ b/Marlin/src/lcd/language/language_pt.h @@ -142,7 +142,12 @@ namespace LanguageNarrow_pt { LSTR MSG_AUTORETRACT = _UxGT(" Auto-Retract"); LSTR MSG_FILAMENTCHANGE = _UxGT("Trocar filamento"); LSTR MSG_FILAMENTCHANGE_E = _UxGT("Trocar filamento *"); - LSTR MSG_ATTACH_MEDIA = _UxGT("Inici. cartão SD"); + #if HAS_MULTI_VOLUME + LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Inici. cartão SD"); + LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Inici. flash USB"); + #else + LSTR MSG_ATTACH_MEDIA = _UxGT("Inici. cartão SD"); + #endif LSTR MSG_CHANGE_MEDIA = _UxGT("Trocar cartão SD"); LSTR MSG_ZPROBE_OUT = _UxGT("Sensor fora/base"); LSTR MSG_ZPROBE_XOFFSET = _UxGT("Desvio X"); diff --git a/Marlin/src/lcd/language/language_pt_br.h b/Marlin/src/lcd/language/language_pt_br.h index f131e06ad8..4908986bdb 100644 --- a/Marlin/src/lcd/language/language_pt_br.h +++ b/Marlin/src/lcd/language/language_pt_br.h @@ -321,7 +321,12 @@ namespace LanguageNarrow_pt_br { LSTR MSG_FILAMENTUNLOAD = _UxGT("Descarreg. Filamento"); LSTR MSG_FILAMENTUNLOAD_E = _UxGT("Descarreg. Filamento *"); LSTR MSG_FILAMENTUNLOAD_ALL = _UxGT("Descarregar Todos"); - LSTR MSG_ATTACH_MEDIA = _UxGT("Iniciar SD"); + #if HAS_MULTI_VOLUME + LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Iniciar cartão SD"); + LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Iniciar flash USB"); + #else + LSTR MSG_ATTACH_MEDIA = _UxGT("Iniciar cartão SD"); + #endif LSTR MSG_CHANGE_MEDIA = _UxGT("Trocar SD"); LSTR MSG_RELEASE_MEDIA = _UxGT("Liberar SD"); LSTR MSG_ZPROBE_OUT = _UxGT("Sonda fora da mesa"); diff --git a/Marlin/src/lcd/language/language_ro.h b/Marlin/src/lcd/language/language_ro.h index e45c93e34d..15278a43e7 100644 --- a/Marlin/src/lcd/language/language_ro.h +++ b/Marlin/src/lcd/language/language_ro.h @@ -388,7 +388,12 @@ namespace LanguageNarrow_ro { LSTR MSG_FILAMENTUNLOAD = _UxGT("Scoatere Filament"); LSTR MSG_FILAMENTUNLOAD_E = _UxGT("Scoatere Filament *"); LSTR MSG_FILAMENTUNLOAD_ALL = _UxGT("Scoate Tot"); - LSTR MSG_ATTACH_MEDIA = _UxGT("Atasare Media"); + #if HAS_MULTI_VOLUME + LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Atasare card SD"); + LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Atasare FD USB"); + #else + LSTR MSG_ATTACH_MEDIA = _UxGT("Atasare card SD"); + #endif LSTR MSG_CHANGE_MEDIA = _UxGT("Inlocuire Media"); LSTR MSG_RELEASE_MEDIA = _UxGT("Eliberare Media"); LSTR MSG_ZPROBE_OUT = _UxGT("Z Probe Past Bed"); diff --git a/Marlin/src/lcd/language/language_ru.h b/Marlin/src/lcd/language/language_ru.h index 9d6509d70d..a8d862e889 100644 --- a/Marlin/src/lcd/language/language_ru.h +++ b/Marlin/src/lcd/language/language_ru.h @@ -435,7 +435,12 @@ namespace LanguageNarrow_ru { LSTR MSG_FILAMENTLOAD_E = _UxGT("Подать филамент *"); LSTR MSG_FILAMENTUNLOAD_E = _UxGT("Убрать филамент *"); LSTR MSG_FILAMENTUNLOAD_ALL = _UxGT("Выгрузить всё"); - LSTR MSG_ATTACH_MEDIA = _UxGT("Установить SD карту"); + #if HAS_MULTI_VOLUME + LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Установить SD карту"); + LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Установить флешка"); + #else + LSTR MSG_ATTACH_MEDIA = _UxGT("Установить SD карту"); + #endif LSTR MSG_CHANGE_MEDIA = _UxGT("Сменить SD карту"); LSTR MSG_RELEASE_MEDIA = _UxGT("Освободить SD карту"); LSTR MSG_ZPROBE_OUT = _UxGT("Z-зонд вне стола"); diff --git a/Marlin/src/lcd/language/language_sk.h b/Marlin/src/lcd/language/language_sk.h index 50729dfbd0..30a8076d39 100644 --- a/Marlin/src/lcd/language/language_sk.h +++ b/Marlin/src/lcd/language/language_sk.h @@ -533,9 +533,12 @@ namespace LanguageNarrow_sk { LSTR MSG_FILAMENTUNLOAD = _UxGT("Vysunúť filament"); LSTR MSG_FILAMENTUNLOAD_E = _UxGT("Vysunúť filament *"); LSTR MSG_FILAMENTUNLOAD_ALL = _UxGT("Vysunúť všetko"); - LSTR MSG_ATTACH_MEDIA = _UxGT("Načítať kartu"); - LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Načítať SD kartu"); - LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Načítať USB disk"); + #if HAS_MULTI_VOLUME + LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Načítať SD kartu"); + LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Načítať USB disk"); + #else + LSTR MSG_ATTACH_MEDIA = _UxGT("Načítať SD kartu"); + #endif LSTR MSG_CHANGE_MEDIA = _UxGT("Vymeniť kartu"); LSTR MSG_RELEASE_MEDIA = _UxGT("Odpojiť kartu"); LSTR MSG_ZPROBE_OUT = _UxGT("Sonda Z mimo podl."); diff --git a/Marlin/src/lcd/language/language_sv.h b/Marlin/src/lcd/language/language_sv.h index 76cd39fcea..b7702a7985 100644 --- a/Marlin/src/lcd/language/language_sv.h +++ b/Marlin/src/lcd/language/language_sv.h @@ -417,7 +417,12 @@ namespace LanguageNarrow_sv { LSTR MSG_FILAMENTUNLOAD = _UxGT("Lossa Tråd"); LSTR MSG_FILAMENTUNLOAD_E = _UxGT("Lossa *"); LSTR MSG_FILAMENTUNLOAD_ALL = _UxGT("Lossa All"); - LSTR MSG_ATTACH_MEDIA = _UxGT("Bifoga Media"); + #if HAS_MULTI_VOLUME + LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Bifoga SD-kort"); + LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Bifoga USB-minne"); + #else + LSTR MSG_ATTACH_MEDIA = _UxGT("Bifoga SD-kort"); + #endif LSTR MSG_CHANGE_MEDIA = _UxGT("Byt Media"); LSTR MSG_RELEASE_MEDIA = _UxGT("Släpp Media"); LSTR MSG_ZPROBE_OUT = _UxGT("Z Sond Utanför Bädd"); diff --git a/Marlin/src/lcd/language/language_tr.h b/Marlin/src/lcd/language/language_tr.h index e22a4c75d0..2055713eeb 100644 --- a/Marlin/src/lcd/language/language_tr.h +++ b/Marlin/src/lcd/language/language_tr.h @@ -550,9 +550,12 @@ namespace LanguageNarrow_tr { LSTR MSG_FILAMENTUNLOAD = _UxGT("Filaman Çıkart"); LSTR MSG_FILAMENTUNLOAD_E = _UxGT("Filaman Çıkart *"); LSTR MSG_FILAMENTUNLOAD_ALL = _UxGT("Tümünü Çıkart"); - LSTR MSG_ATTACH_MEDIA = _UxGT("Medyayı Ekle"); - LSTR MSG_ATTACH_SD_MEDIA = _UxGT("SD Kartı takın"); - LSTR MSG_ATTACH_USB_MEDIA = _UxGT("USB Sürücüyü takın"); + #if HAS_MULTI_VOLUME + LSTR MSG_ATTACH_SD_MEDIA = _UxGT("SD Kartı takın"); + LSTR MSG_ATTACH_USB_MEDIA = _UxGT("USB Sürücüyü takın"); + #else + LSTR MSG_ATTACH_MEDIA = _UxGT("Medyayı Ekle"); + #endif LSTR MSG_CHANGE_MEDIA = _UxGT("Medyayı Değiştir"); LSTR MSG_RELEASE_MEDIA = _UxGT("Medyayı Çıkart"); LSTR MSG_ZPROBE_OUT = _UxGT("Z Prob Tablayı Geçti"); diff --git a/Marlin/src/lcd/language/language_uk.h b/Marlin/src/lcd/language/language_uk.h index 63a721fe9f..0add5acc3e 100644 --- a/Marlin/src/lcd/language/language_uk.h +++ b/Marlin/src/lcd/language/language_uk.h @@ -445,7 +445,12 @@ namespace LanguageNarrow_uk { LSTR MSG_FILAMENTUNLOAD = _UxGT("Видалити пруток"); LSTR MSG_FILAMENTUNLOAD_E = _UxGT("Видалити пруток *"); LSTR MSG_FILAMENTUNLOAD_ALL = _UxGT("Видалити все"); - LSTR MSG_ATTACH_MEDIA = _UxGT("Вставити SD-картку"); + #if HAS_MULTI_VOLUME + LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Вставити SD-картку"); + LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Вставити USB флешка"); + #else + LSTR MSG_ATTACH_MEDIA = _UxGT("Вставити SD-картку"); + #endif LSTR MSG_CHANGE_MEDIA = _UxGT("Заміна SD-картки"); LSTR MSG_RELEASE_MEDIA = _UxGT("Видаліть SD-картку"); LSTR MSG_ZPROBE_OUT = _UxGT("Z-Зонд поза столом"); diff --git a/Marlin/src/lcd/language/language_vi.h b/Marlin/src/lcd/language/language_vi.h index deed0fda7b..fda9b65367 100644 --- a/Marlin/src/lcd/language/language_vi.h +++ b/Marlin/src/lcd/language/language_vi.h @@ -309,7 +309,12 @@ namespace LanguageNarrow_vi { LSTR MSG_FILAMENTUNLOAD = _UxGT("Dỡ dây nhựa"); // Unload filament LSTR MSG_FILAMENTUNLOAD_E = _UxGT("Dỡ dây nhựa *"); // Unload filament LSTR MSG_FILAMENTUNLOAD_ALL = _UxGT("Dỡ tất cả"); // Unload All - LSTR MSG_ATTACH_MEDIA = _UxGT("Khởi tạo phương tiện"); // Attach media + #if HAS_MULTI_VOLUME + LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Khởi tạo thẻ SD"); // Attach SD Card + LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Khởi tạo thanh USB"); // Attach USB Drive + #else + LSTR MSG_ATTACH_MEDIA = _UxGT("Khởi tạo phương tiện"); // Attach media + #endif LSTR MSG_CHANGE_MEDIA = _UxGT("Thay phương tiện"); // Change midea LSTR MSG_RELEASE_MEDIA = _UxGT("Phát hành phương tiện"); LSTR MSG_ZPROBE_OUT = _UxGT("Đầu Dò Z qua bàn"); // Z Probe past bed diff --git a/Marlin/src/lcd/language/language_zh_CN.h b/Marlin/src/lcd/language/language_zh_CN.h index 120bbdca35..13c49fa9f1 100644 --- a/Marlin/src/lcd/language/language_zh_CN.h +++ b/Marlin/src/lcd/language/language_zh_CN.h @@ -398,7 +398,12 @@ namespace LanguageNarrow_zh_CN { LSTR MSG_FILAMENTUNLOAD = _UxGT("卸载丝料"); // "Unload filament" LSTR MSG_FILAMENTUNLOAD_E = _UxGT("卸载丝料 *"); // "Unload filament" LSTR MSG_FILAMENTUNLOAD_ALL = _UxGT("卸载全部"); // "Unload All" - LSTR MSG_ATTACH_MEDIA = _UxGT("初始化存储卡"); // "Init. SD card" + #if HAS_MULTI_VOLUME + LSTR MSG_ATTACH_SD_MEDIA = _UxGT("挂载存储卡"); // "Attach SD Card" + LSTR MSG_ATTACH_USB_MEDIA = _UxGT("挂载U盘"); // "Attach USB Drive" + #else + LSTR MSG_ATTACH_MEDIA = _UxGT("挂载存储卡"); // "Attach SD Card" + #endif LSTR MSG_CHANGE_MEDIA = _UxGT("更换存储卡"); // "Change SD card" LSTR MSG_RELEASE_MEDIA = _UxGT("释放存储卡"); LSTR MSG_ZPROBE_OUT = _UxGT("Z探针在热床之外"); // "Z probe out. bed" Z probe is not within the physical limits diff --git a/Marlin/src/lcd/language/language_zh_TW.h b/Marlin/src/lcd/language/language_zh_TW.h index 43378e5874..c705d126cb 100644 --- a/Marlin/src/lcd/language/language_zh_TW.h +++ b/Marlin/src/lcd/language/language_zh_TW.h @@ -350,8 +350,12 @@ namespace LanguageNarrow_zh_TW { LSTR MSG_FILAMENTUNLOAD = _UxGT("卸載絲料"); // "Unload filament" LSTR MSG_FILAMENTUNLOAD_E = _UxGT("卸載絲料 *"); // "Unload filament" LSTR MSG_FILAMENTUNLOAD_ALL = _UxGT("卸載全部"); // "Unload All" - LSTR MSG_INIT_MEDIA = _UxGT("初始化記憶卡"); // "Init. SD card" - LSTR MSG_ATTACH_MEDIA = _UxGT("連接記憶卡"); // "Attach Media + #if HAS_MULTI_VOLUME + LSTR MSG_ATTACH_SD_MEDIA = _UxGT("挂载記憶卡"); // "Attach SD Card" + LSTR MSG_ATTACH_USB_MEDIA = _UxGT("挂载隨身碟"); // "Attach USB Drive" + #else + LSTR MSG_ATTACH_MEDIA = _UxGT("連接記憶卡"); // "Attach Media" + #endif LSTR MSG_CHANGE_MEDIA = _UxGT("更換記憶卡"); // "Change SD card" LSTR MSG_RELEASE_MEDIA = _UxGT("釋放媒體"); // "Release Media" LSTR MSG_ZPROBE_OUT = _UxGT("Z探針在熱床之外"); // "Z probe out. bed" Z probe is not within the physical limits diff --git a/Marlin/src/lcd/menu/menu_main.cpp b/Marlin/src/lcd/menu/menu_main.cpp index c74d6b2a1d..6142e0e153 100644 --- a/Marlin/src/lcd/menu/menu_main.cpp +++ b/Marlin/src/lcd/menu/menu_main.cpp @@ -441,12 +441,12 @@ void menu_main() { #if HAS_SD_DETECT ACTION_ITEM(MSG_NO_MEDIA, nullptr); // "No Media" #else - #if HAS_MULTI_VOLUME - GCODES_ITEM(MSG_ATTACH_SD_MEDIA, F("M21S")); // M21S Attach SD Card - GCODES_ITEM(MSG_ATTACH_USB_MEDIA, F("M21U")); // M21U Attach USB Media - #else - GCODES_ITEM(MSG_ATTACH_MEDIA, F("M21")); // M21 Attach Media - #endif + #if HAS_MULTI_VOLUME + GCODES_ITEM(MSG_ATTACH_SD_MEDIA, F("M21S")); // M21S Attach SD Card + GCODES_ITEM(MSG_ATTACH_USB_MEDIA, F("M21U")); // M21U Attach USB Media + #else + GCODES_ITEM(MSG_ATTACH_MEDIA, F("M21")); // M21 Attach Media + #endif #endif } // END MEDIA MENU From 09fbe372dae280f5a048dba3b555f0426f753e9f Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Fri, 24 Jan 2025 17:53:19 -0600 Subject: [PATCH 061/787] =?UTF-8?q?=F0=9F=94=A8=20Elegoo=20Neptune=20board?= =?UTF-8?q?s=20("elegoo.bin")=20(#24895)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/core/boards.h | 4 + Marlin/src/pins/mega/pins_WEEDO_62A.h | 2 +- Marlin/src/pins/pins.h | 8 + Marlin/src/pins/ramps/pins_PXMALION_CORE_I3.h | 1 + .../pins/stm32f4/pins_CREALITY_CR4NTXXC10.h | 1 + Marlin/src/pins/stm32f4/pins_MKS_NEPTUNE_3.h | 143 ++++++++ Marlin/src/pins/stm32f4/pins_MKS_NEPTUNE_X.h | 52 +++ .../pins/stm32f4/pins_MKS_NEPTUNE_X_common.h | 309 ++++++++++++++++++ .../pins/stm32f4/pins_TRONXY_CXY_446_V10.h | 3 +- ini/stm32f1.ini | 7 + ini/stm32f4.ini | 48 +++ 11 files changed, 575 insertions(+), 3 deletions(-) create mode 100644 Marlin/src/pins/stm32f4/pins_MKS_NEPTUNE_3.h create mode 100644 Marlin/src/pins/stm32f4/pins_MKS_NEPTUNE_X.h create mode 100644 Marlin/src/pins/stm32f4/pins_MKS_NEPTUNE_X_common.h diff --git a/Marlin/src/core/boards.h b/Marlin/src/core/boards.h index e56e2177e5..a0e0a29151 100644 --- a/Marlin/src/core/boards.h +++ b/Marlin/src/core/boards.h @@ -473,6 +473,10 @@ #define BOARD_BLACKBEEZMINI_V1 5251 // BlackBeezMini V1 (STM32F401CCU6) #define BOARD_XTLW_CLIMBER_8TH 5252 // XTLW Climber-8th (STM32F407VGT6) #define BOARD_FLY_RRF_E3_V1 5253 // Fly RRF E3 V1.0 (STM32F407VG) +#define BOARD_ZNP_ROBIN_NANO 5254 // Elegoo Neptune 2 v1.2 board +#define BOARD_ZNP_ROBIN_NANO_V1_3 5255 // Elegoo Neptune 2 v1.3 board +#define BOARD_MKS_NEPTUNE_X 5256 // Elegoo Neptune X +#define BOARD_MKS_NEPTUNE_3 5257 // Elegoo Neptune 3 // // Other ARM Cortex-M4 diff --git a/Marlin/src/pins/mega/pins_WEEDO_62A.h b/Marlin/src/pins/mega/pins_WEEDO_62A.h index b7143c7912..bb5e53122b 100644 --- a/Marlin/src/pins/mega/pins_WEEDO_62A.h +++ b/Marlin/src/pins/mega/pins_WEEDO_62A.h @@ -19,13 +19,13 @@ * along with this program. If not, see . * */ +#pragma once /** * Based on WEEDO 62A pin configuration * Copyright (c) 2019 WEEDO3D Perron * ATmega2560 */ -#pragma once #include "env_validate.h" diff --git a/Marlin/src/pins/pins.h b/Marlin/src/pins/pins.h index 11b8f32c92..94990834ea 100644 --- a/Marlin/src/pins/pins.h +++ b/Marlin/src/pins/pins.h @@ -845,6 +845,14 @@ #include "stm32f4/pins_XTLW_CLIMBER_8TH.h" // STM32F4 env:XTLW_CLIMBER_8TH #elif MB(FLY_RRF_E3_V1) #include "stm32f4/pins_FLY_RRF_E3_V1.h" // STM32F4 env:FLY_RRF_E3_V1 +#elif MB(ZNP_ROBIN_NANO) + #include "stm32f1/pins_MKS_ROBIN_NANO.h" // STM32F1 env:znp_robin_nano35 +#elif MB(ZNP_ROBIN_NANO_V1_3) + #include "stm32f4/pins_MKS_ROBIN_NANO_V1_3_F4.h" // STM32F4 env:znp_robin_nano_v1_3 +#elif MB(MKS_NEPTUNE_X) + #include "stm32f4/pins_MKS_NEPTUNE_X.h" // STM32F4 env:mks_neptune_x +#elif MB(MKS_NEPTUNE_3) + #include "stm32f4/pins_MKS_NEPTUNE_3.h" // STM32F4 env:mks_neptune_3 // // Other ARM Cortex-M4 diff --git a/Marlin/src/pins/ramps/pins_PXMALION_CORE_I3.h b/Marlin/src/pins/ramps/pins_PXMALION_CORE_I3.h index ee0633992e..9b190cc5c1 100644 --- a/Marlin/src/pins/ramps/pins_PXMALION_CORE_I3.h +++ b/Marlin/src/pins/ramps/pins_PXMALION_CORE_I3.h @@ -19,6 +19,7 @@ * along with this program. If not, see . * */ +#pragma once /** * Pxmalion Core i3 - https://github.com/Pxmalion diff --git a/Marlin/src/pins/stm32f4/pins_CREALITY_CR4NTXXC10.h b/Marlin/src/pins/stm32f4/pins_CREALITY_CR4NTXXC10.h index c06e48f8b2..3b22085b3d 100644 --- a/Marlin/src/pins/stm32f4/pins_CREALITY_CR4NTXXC10.h +++ b/Marlin/src/pins/stm32f4/pins_CREALITY_CR4NTXXC10.h @@ -19,6 +19,7 @@ * along with this program. If not, see . * */ +#pragma once /** * Creality CREALITY_CR4NTXXC10 (STM32F401RET6) board pin assignments diff --git a/Marlin/src/pins/stm32f4/pins_MKS_NEPTUNE_3.h b/Marlin/src/pins/stm32f4/pins_MKS_NEPTUNE_3.h new file mode 100644 index 0000000000..2ee641d1c5 --- /dev/null +++ b/Marlin/src/pins/stm32f4/pins_MKS_NEPTUNE_3.h @@ -0,0 +1,143 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2024 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +// +// MKS Neptune 3 +// + +// Avoid conflict with TIMER_TONE +#define ALLOW_STM32F4 +#include "env_validate.h" + +#define BOARD_INFO_NAME "MKS Neptune 3" + +// +// Release PB4 (Z_DIR_PIN) from JTAG NRST role +// +//#define DISABLE_DEBUG + +// Use one of these or SDCard-based Emulation will be used +//#define SRAM_EEPROM_EMULATION // Use BackSRAM-based EEPROM emulation +//#define FLASH_EEPROM_EMULATION // Use Flash-based EEPROM emulation +#if EITHER(NO_EEPROM_SELECTED, I2C_EEPROM) + #define I2C_EEPROM + #define MARLIN_EEPROM_SIZE 0x1000U // 4KB + #define I2C_SCL_PIN PB6 + #define I2C_SDA_PIN PB7 +#endif + +// +// Servos +// +#define SERVO0_PIN PA8 // BLTOUCH + +// +// Limit Switches +// +//#define ZNP_TEST +#ifdef ZNP_TEST + #define X_DIAG_PIN PC14 // Z+ +#else + #define X_DIAG_PIN PA13 // X- +#endif + +#define Y_DIAG_PIN PB8 +#define Z_DIAG_PIN PC13 + +#define X_STOP_PIN X_DIAG_PIN +#define Y_STOP_PIN Y_DIAG_PIN +#define Z_STOP_PIN Z_DIAG_PIN + +// +// Z Probe (when not Z_MIN_PIN) +// +#ifndef Z_MIN_PROBE_PIN + #define Z_MIN_PROBE_PIN PC14 // PB9 +#endif + +// +// Steppers +// +#define X_ENABLE_PIN PD2 +#define X_STEP_PIN PC12 +#define X_DIR_PIN PB3 + +#define Y_ENABLE_PIN PC10 +#define Y_STEP_PIN PC11 +#define Y_DIR_PIN PA15 + +#define Z_ENABLE_PIN PC8 +#define Z_STEP_PIN PC7 +#define Z_DIR_PIN PC9 + +#define E0_ENABLE_PIN PC6 +#define E0_STEP_PIN PB10 +#define E0_DIR_PIN PB1 + +#define E1_ENABLE_PIN PC5 +#define E1_STEP_PIN PC4 +#define E1_DIR_PIN PA4 + +// +// Temperature Sensors +// +#define TEMP_0_PIN PC1 // TH1 +#define TEMP_1_PIN PC2 // TH2 +#define TEMP_BED_PIN PC0 // TB1 + +// +// Heaters / Fans +// +#define HEATER_0_PIN PA6 // HEATER1 +#define HEATER_BED_PIN PA5 // HOT BED + +#define FAN_PIN PB0 // FAN +//#define FAN1_PIN PA7 // FAN1 + +#if NEED_TOUCH_PINS + #define TOUCH_CS_PIN PA7 // SPI2_NSS + #define TOUCH_SCK_PIN PB13 // SPI2_SCK + #define TOUCH_MISO_PIN PB14 // SPI2_MISO + #define TOUCH_MOSI_PIN PB15 // SPI2_MOSI +#endif + +// +// SD Support +// +#ifndef SDCARD_CONNECTION + #define SDCARD_CONNECTION ONBOARD +#endif + +#if SD_CONNECTION_IS(ONBOARD) + #define ENABLE_SPI3 + #define SD_SS_PIN -1 + #define SDSS PB12 + #define SD_SCK_PIN PB13 + #define SD_MISO_PIN PB14 + #define SD_MOSI_PIN PB15 + #define SD_SPI_SPEED SPI_HALF_SPEED + #if ENABLED(NO_SD_HOST_DRIVE) + // Detect pin doesn't work when NO_SD_HOST_DRIVE disabled + #define SD_DETECT_PIN PC3 + #endif +#endif diff --git a/Marlin/src/pins/stm32f4/pins_MKS_NEPTUNE_X.h b/Marlin/src/pins/stm32f4/pins_MKS_NEPTUNE_X.h new file mode 100644 index 0000000000..34b794d27d --- /dev/null +++ b/Marlin/src/pins/stm32f4/pins_MKS_NEPTUNE_X.h @@ -0,0 +1,52 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2024 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +#define ALLOW_STM32DUINO +#include "env_validate.h" + +#if HOTENDS > 2 || E_STEPPERS > 2 + #error "MKS Neptune X supports up to 2 hotends / E steppers." +#endif + +#define BOARD_INFO_NAME "MKS Neptune X" + +// +// Software SPI pins for TMC2130 stepper drivers +// This board only supports SW SPI for stepper drivers +// +#if HAS_TMC_SPI && DISABLED(TMC_USE_SW_SPI) + #warning "TMC_USE_SW_SPI is required for MKS Neptune X with TMC drivers." +#endif +#if ENABLED(TMC_USE_SW_SPI) + #ifndef TMC_SW_MOSI + #define TMC_SW_MOSI PD14 + #endif + #ifndef TMC_SW_MISO + #define TMC_SW_MISO PD1 + #endif + #ifndef TMC_SW_SCK + #define TMC_SW_SCK PD0 + #endif +#endif + +#include "pins_MKS_NEPTUNE_X_common.h" diff --git a/Marlin/src/pins/stm32f4/pins_MKS_NEPTUNE_X_common.h b/Marlin/src/pins/stm32f4/pins_MKS_NEPTUNE_X_common.h new file mode 100644 index 0000000000..627e14faf3 --- /dev/null +++ b/Marlin/src/pins/stm32f4/pins_MKS_NEPTUNE_X_common.h @@ -0,0 +1,309 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2024 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +// +// MKS Neptune X +// + +#define HAS_OTG_USB_HOST_SUPPORT // USB Flash Drive support + +// Avoid conflict with TIMER_TONE +#define STEP_TIMER 10 + +// Use one of these or SDCard-based Emulation will be used +//#define SRAM_EEPROM_EMULATION // Use BackSRAM-based EEPROM emulation +//#define FLASH_EEPROM_EMULATION // Use Flash-based EEPROM emulation +#if EITHER(NO_EEPROM_SELECTED, I2C_EEPROM) + #define I2C_EEPROM + #define MARLIN_EEPROM_SIZE 0x1000U // 4K + #define I2C_SCL_PIN PB6 + #define I2C_SDA_PIN PB7 +#endif + +// +// Release PB4 (Z_DIR_PIN) from JTAG NRST role +// +//#define DISABLE_DEBUG + +// +// Servos +// +#define SERVO0_PIN PA8 // Enable BLTOUCH + +// +// Limit Switches +// +#define X_DIAG_PIN PA15 +#define Y_DIAG_PIN PC15 +#define Z_DIAG_PIN PC14 +#define E0_DIAG_PIN PC4 +#define E1_DIAG_PIN PE7 + +#define X_STOP_PIN X_DIAG_PIN +#define Y_STOP_PIN Y_DIAG_PIN +#define Z_MIN_PIN Z_DIAG_PIN +#define Z_MAX_PIN E0_DIAG_PIN + +// +// Steppers +// +#define X_ENABLE_PIN PE4 +#define X_STEP_PIN PE3 +#define X_DIR_PIN PE2 + +#define Y_ENABLE_PIN PE1 +#define Y_STEP_PIN PE0 +#define Y_DIR_PIN PB9 + +#define Z_ENABLE_PIN PB8 +#define Z_STEP_PIN PB5 +#define Z_DIR_PIN PB4 + +#define E0_ENABLE_PIN PB3 +#define E0_STEP_PIN PD6 +#define E0_DIR_PIN PD3 + +#define E1_ENABLE_PIN PA3 +#define E1_STEP_PIN PA6 +#define E1_DIR_PIN PA1 + +#if HAS_TMC_UART + // + // Software serial + // No Hardware serial for steppers + // + #define X_SERIAL_TX_PIN PD5 + #define X_SERIAL_RX_PIN X_SERIAL_TX_PIN + + #define Y_SERIAL_TX_PIN PD7 + #define Y_SERIAL_RX_PIN Y_SERIAL_TX_PIN + + #define Z_SERIAL_TX_PIN PD4 + #define Z_SERIAL_RX_PIN Z_SERIAL_TX_PIN + + #define E0_SERIAL_TX_PIN PD9 + #define E0_SERIAL_RX_PIN E0_SERIAL_TX_PIN + + #define E1_SERIAL_TX_PIN PD8 + #define E1_SERIAL_RX_PIN E1_SERIAL_TX_PIN + + // Reduce baud rate to improve software serial reliability + #define TMC_BAUD_RATE 19200 +#endif + +// +// Temperature Sensors +// +#define TEMP_0_PIN PC1 // TH1 +#define TEMP_1_PIN PA2 // TH2 +#define TEMP_BED_PIN PC0 // TB1 + +#if HOTENDS == 1 && !REDUNDANT_TEMP_MATCH(SOURCE, E1) + #if TEMP_SENSOR_PROBE + #define TEMP_PROBE_PIN TEMP_1_PIN + #elif TEMP_SENSOR_CHAMBER + #define TEMP_CHAMBER_PIN TEMP_1_PIN + #endif +#endif + +// +// Heaters / Fans +// +#define HEATER_0_PIN PC3 // HEATER1 +#define HEATER_1_PIN PB0 // HEATER2 +#define HEATER_BED_PIN PA0 // HOT BED + +#define FAN_PIN PC14 // FAN +#define FAN1_PIN PB1 // FAN1 + +// +// Thermocouples +// +//#define TEMP_0_CS_PIN HEATER_0_PIN // TC1 - CS1 +//#define TEMP_0_CS_PIN HEATER_1_PIN // TC2 - CS2 + +// +// Misc. Functions +// +#if HAS_TFT_LVGL_UI + #define MT_DET_1_PIN PA4 // MT_DET + #define MT_DET_2_PIN PE6 + #define MT_DET_PIN_STATE LOW +#endif + +#ifndef FIL_RUNOUT_PIN + #define FIL_RUNOUT_PIN PA4 +#endif +#ifndef FIL_RUNOUT2_PIN + #define FIL_RUNOUT2_PIN PE6 +#endif + +#ifndef POWER_LOSS_PIN + #define POWER_LOSS_PIN PA2 // PW_DET +#endif + +//#define SUICIDE_PIN PB2 +//#define LED_PIN PB2 +//#define KILL_PIN PA2 +//#define KILL_PIN_STATE LOW + +// +// Power Supply Control +// +#if ENABLED(MKS_PWC) + #if ENABLED(TFT_LVGL_UI) + #if ENABLED(PSU_CONTROL) + #error "PSU_CONTROL is incompatible with MKS_PWC plus TFT_LVGL_UI." + #endif + #undef MKS_PWC + #define SUICIDE_PIN PB2 + #define SUICIDE_PIN_STATE LOW + #else + #define PS_ON_PIN PB2 // PW_OFF + #endif + #define KILL_PIN PA13 // PW_DET + #define KILL_PIN_STATE HIGH +#endif + +// Random Info +#define USB_SERIAL -1 // USB Serial +#define WIFI_SERIAL 3 // USART3 +#define MKS_WIFI_MODULE_SERIAL 1 // USART1 +#define MKS_WIFI_MODULE_SPI 2 // SPI2 + +#ifndef SDCARD_CONNECTION + #define SDCARD_CONNECTION ONBOARD +#endif + +// MKS WIFI MODULE +#if ENABLED(MKS_WIFI_MODULE) + #define WIFI_IO0_PIN PC13 + #define WIFI_IO1_PIN PC7 + #define WIFI_RESET_PIN PE9 +#endif + +// MKS TEST +#if ENABLED(MKS_TEST) + #define MKS_TEST_POWER_LOSS_PIN PA13 // PW_DET + #define MKS_TEST_PS_ON_PIN PB2 // PW_OFF +#endif + +// +// TFT with FSMC interface +// +#if HAS_FSMC_TFT + /** + * Note: MKS Robin TFT screens use various TFT controllers. + * If the screen stays white, disable 'TFT_RESET_PIN' + * to let the bootloader init the screen. + */ + #define TFT_RESET_PIN PC6 // FSMC_RST + #define TFT_BACKLIGHT_PIN PD13 + + #define DOGLCD_MOSI -1 // Prevent auto-define by Conditionals_post.h + #define DOGLCD_SCK -1 + + #define TOUCH_CS_PIN PA7 // SPI2_NSS + #define TOUCH_SCK_PIN PB13 // SPI2_SCK + #define TOUCH_MISO_PIN PB14 // SPI2_MISO + #define TOUCH_MOSI_PIN PB15 // SPI2_MOSI + + #define LCD_USE_DMA_FSMC // Use DMA transfers to send data to the TFT + #define FSMC_CS_PIN PD7 + #define FSMC_RS_PIN PD11 + #define FSMC_DMA_DEV DMA2 + #define FSMC_DMA_CHANNEL DMA_CH5 + + #define TFT_CS_PIN FSMC_CS_PIN + #define TFT_RS_PIN FSMC_RS_PIN + + #define TOUCH_BUTTONS_HW_SPI + #define TOUCH_BUTTONS_HW_SPI_DEVICE 2 + + #define TFT_BUFFER_SIZE 14400 +#endif + +// +// Onboard SD card +// +// detect pin doesn't work when ONBOARD and NO_SD_HOST_DRIVE disabled +#if SD_CONNECTION_IS(ONBOARD) + #define ENABLE_SPI3 + #define SD_SS_PIN -1 + #define SDSS PC9 + #define SD_SCK_PIN PC10 + #define SD_MISO_PIN PC11 + #define SD_MOSI_PIN PC12 + #define SD_DETECT_PIN PD12 +#endif + +#define SPI_FLASH +#if ENABLED(SPI_FLASH) + #define HAS_SPI_FLASH 1 + #define SPI_DEVICE 2 + #define SPI_FLASH_SIZE 0x1000000 + #define SPI_FLASH_CS_PIN PB12 + #define SPI_FLASH_MOSI_PIN PC3 + #define SPI_FLASH_MISO_PIN PC2 + #define SPI_FLASH_SCK_PIN PB13 +#endif + +// +// LCD / Controller +// +#define BEEPER_PIN PC5 + +// +// TFT with FSMC interface +// +#if HAS_FSMC_TFT + /** + * Note: MKS Robin TFT screens use various TFT controllers. + * If the screen stays white, disable 'TFT_RESET_PIN' + * to let the bootloader init the screen. + */ + #define TFT_RESET_PIN PC6 // FSMC_RST + #define TFT_BACKLIGHT_PIN PD13 + + #define DOGLCD_MOSI -1 // Prevent auto-define by Conditionals_post.h + #define DOGLCD_SCK -1 + + #define TOUCH_CS_PIN PA7 // SPI2_NSS + #define TOUCH_SCK_PIN PB13 // SPI2_SCK + #define TOUCH_MISO_PIN PB14 // SPI2_MISO + #define TOUCH_MOSI_PIN PB15 // SPI2_MOSI + + #define LCD_USE_DMA_FSMC // Use DMA transfers to send data to the TFT + #define FSMC_CS_PIN PD7 + #define FSMC_RS_PIN PD11 + #define FSMC_DMA_DEV DMA2 + #define FSMC_DMA_CHANNEL DMA_CH5 + + #define TFT_CS_PIN FSMC_CS_PIN + #define TFT_RS_PIN FSMC_RS_PIN + + #define TOUCH_BUTTONS_HW_SPI + #define TOUCH_BUTTONS_HW_SPI_DEVICE 2 + + #define TFT_BUFFER_SIZE 14400 +#endif diff --git a/Marlin/src/pins/stm32f4/pins_TRONXY_CXY_446_V10.h b/Marlin/src/pins/stm32f4/pins_TRONXY_CXY_446_V10.h index f99a1c5f55..6648b131e4 100644 --- a/Marlin/src/pins/stm32f4/pins_TRONXY_CXY_446_V10.h +++ b/Marlin/src/pins/stm32f4/pins_TRONXY_CXY_446_V10.h @@ -19,6 +19,7 @@ * along with this program. If not, see . * */ +#pragma once /** * BOARD_TRONXY_CXY_446_V10 @@ -26,8 +27,6 @@ * CXY-V6-191121 / CXY-446-V10-220413 */ -#pragma once - #include "env_validate.h" #if EXTRUDERS > 2 || E_STEPPERS > 2 || NUM_RUNOUT_SENSORS > 2 diff --git a/ini/stm32f1.ini b/ini/stm32f1.ini index 1500bbe92a..96699d954d 100644 --- a/ini/stm32f1.ini +++ b/ini/stm32f1.ini @@ -229,6 +229,13 @@ platform_packages = ${stm_flash_drive.platform_packages} build_flags = ${env:STM32F103RE_btt.build_flags} ${USBD_CDC_MSC.build_flags} build_unflags = ${env:STM32F103RE_btt.build_unflags} -DUSBD_USE_CDC +# +# ZNP Robin Nano V1.2 +# +[env:znp_robin_nano35] +extends = mks_robin_nano_v1v2 +board_build.encrypt_mks = elegoo.bin + # # Mingda MPX_ARM_MINI # diff --git a/ini/stm32f4.ini b/ini/stm32f4.ini index 4cb3b91d09..8b9c45d38a 100644 --- a/ini/stm32f4.ini +++ b/ini/stm32f4.ini @@ -651,6 +651,47 @@ board_build.rename = Robin_nano35.bin debug_tool = jlink upload_protocol = jlink +# +# MKS Neptune X +# +[env:mks_neptune_x] +extends = stm32_variant +board = marlin_STM32F407VGT6_CCM +board_build.variant = MARLIN_F4x7Vx +board_build.offset = 0xC000 +board_upload.offset_address = 0x0800C000 +board_build.rename = elegoo.bin +platform_packages = ${stm_flash_drive.platform_packages} +build_flags = ${stm32_variant.build_flags} ${stm32f4_I2C1.build_flags} + ${stm_flash_drive.build_flags} ${USB_HS_IN_FS.build_flags} + -DHAL_PCD_MODULE_ENABLED -DHAL_SD_MODULE_ENABLED -DHAL_SRAM_MODULE_ENABLED + -DMCU_STM32F407VE -DSS_TIMER=4 -DENABLE_HWSERIAL3 + -DSTM32_FLASH_SIZE=512 + -DTIMER_TONE=TIM3 -DTIMER_SERVO=TIM2 +debug_tool = jlink +upload_protocol = jlink + +# +# MKS Neptune 3 +# +[env:mks_neptune_3] +extends = stm32_variant +board = marlin_STM32F407VGT6_CCM +board_build.variant = MARLIN_F4x7Vx +board_build.offset = 0xC000 +board_upload.offset_address = 0x0800C000 +board_build.rename = ZNP_ROBIN_NANO.bin +platform_packages = ${stm_flash_drive.platform_packages} +build_flags = ${stm32_variant.build_flags} + -DMCU_STM32F407VE -DSS_TIMER=4 -DENABLE_HWSERIAL3 + -DSTM32_FLASH_SIZE=512 + -DTIMER_TONE=TIM3 -DTIMER_SERVO=TIM2 + -DHAL_SD_MODULE_ENABLED -DHAL_SRAM_MODULE_ENABLED +build_unflags = ${stm32_variant.build_unflags} + -DUSBCON -DUSBD_USE_CDC +debug_tool = jlink +upload_protocol = jlink + # # BOARD_MKS_ROBIN_NANO_V1_3_F4 # - MKS Robin Nano V1.3 (STM32F407VET6, 5 Pololu Plug) @@ -676,6 +717,13 @@ build_flags = ${mks_robin_nano_v1_3_f4_common.build_flags} -DTIMER_SERVO=TIM2 -DTIMER_TONE=TIM3 -DSS_TIMER=4 -DHAL_SD_MODULE_ENABLED -DHAL_SRAM_MODULE_ENABLED +# +# Elegoo Neptune 2 +# +[env:znp_robin_nano_v1_3] +extends = mks_robin_nano_v1_3_f4 +board_build.rename = elegoo.bin + # # Artillery Ruby # From 40aab1e2980b4bc466d5c2926b37c3315abb8b90 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Sat, 25 Jan 2025 00:26:20 +0000 Subject: [PATCH 062/787] [cron] Bump distribution date (2025-01-25) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 3da702bec0..42f6e8f142 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-01-24" +//#define STRING_DISTRIBUTION_DATE "2025-01-25" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 9474bf59f9..058ac7de1b 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-01-24" + #define STRING_DISTRIBUTION_DATE "2025-01-25" #endif /** From 442f0baf1485c72be3bbe4d11f1b295fe00cea5d Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Fri, 24 Jan 2025 19:48:38 -0600 Subject: [PATCH 063/787] =?UTF-8?q?=F0=9F=94=A8=20Script=20for=20gcc=20set?= =?UTF-8?q?up=20on=20macOS=20(Simulator=20build)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- buildroot/bin/mac_gcc | 69 +++++++++++++++++++++++++++++++++++++++++++ ini/native.ini | 4 +++ 2 files changed, 73 insertions(+) create mode 100755 buildroot/bin/mac_gcc diff --git a/buildroot/bin/mac_gcc b/buildroot/bin/mac_gcc new file mode 100755 index 0000000000..870090919f --- /dev/null +++ b/buildroot/bin/mac_gcc @@ -0,0 +1,69 @@ +#!/usr/bin/env zsh +# +# Prepare a 'gcc' compatible with the native Simulator build. +# Support for MacPorts and Homebrew. +# To reset and use the system (Clang) compiler, run with 'apple'. +# +# Usage: mac_gcc apple|macports|homebrew +# + +which port >/dev/null && HAS_MACPORTS=1 +which brew >/dev/null && HAS_HOMEBREW=1 + +if [[ $1 == "apple" || $1 == "darwin" || $1 == "system" ]]; then + + if ((HAS_MACPORTS)); then + cd /opt/local/bin + sudo rm -f gcc g++ cc ld + cd - + fi + + if ((HAS_HOMEBREW)); then + cd /opt/homebrew/bin + sudo rm -f gcc g++ cc + cd - + fi + +elif [[ $1 =~ ".*ports" ]]; then + + ((HAS_MACPORTS)) || { echo "MacPorts is not installed"; exit 1; } + + GCCV=$( find /opt/local/bin -name "gcc-mp-*" | sort -r | head -1 | sed 's/.*gcc-mp-//' ) + [[ $GCCV -ge 11 ]] || GCCV=14 + + getport() { port installed $1 | grep $1 || sudo port install $1; } + getports() { for p in $@; do getport $p; done; } + + getports "gcc$GCCV" glm mesa libsdl2 libsdl2_net + + cd /opt/local/bin + sudo rm -f gcc g++ cc ld + sudo ln -s "gcc-mp-$GCCV" gcc + sudo ln -s "g++-mp-$GCCV" g++ + sudo ln -s g++ cc + sudo ln -s ld-classic ld + cd - + +elif [[ $1 =~ ".*brew" ]]; then + + ((HAS_HOMEBREW)) || { echo "Homebrew is not installed"; exit 1; } + + GCCV=$( find /opt/homebrew/bin -name "gcc-*" | sort -r | head -1 | sed 's/.*gcc-//' ) + [[ $GCCV -ge 11 ]] || { brew install gcc@14 ; GCCV=14 } + + brew install glm mesa sdl2 sdl2_net + + cd /opt/homebrew/bin + sudo rm -f gcc g++ cc + sudo ln -s "gcc-$GCCV" gcc + sudo ln -s "g++-$GCCV" g++ + sudo ln -s g++ cc + cd - + +else + + echo "Usage: $(basename $0) apple|macports|homebrew" + +fi + +rehash diff --git a/ini/native.ini b/ini/native.ini index 5b62c87add..c93ad7e6fa 100644 --- a/ini/native.ini +++ b/ini/native.ini @@ -81,8 +81,12 @@ build_flags = ${simulator_linux.build_flags} ${simulator_linux.release_flags} # Simulator for macOS (MacPorts) # +# +# Use the script buildroot/bin/mac_gcc to prepare your environment. # # MacPorts: +# https://www.macports.org/install.php +# # sudo port install gcc14 glm mesa libsdl2 libsdl2_net # # cd /opt/local/bin From c24ecfb6f0d3bc0d202bb396c3fb274a3725c2ed Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Sun, 26 Jan 2025 00:27:46 +0000 Subject: [PATCH 064/787] [cron] Bump distribution date (2025-01-26) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 42f6e8f142..54bcfca656 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-01-25" +//#define STRING_DISTRIBUTION_DATE "2025-01-26" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 058ac7de1b..969dd8a02c 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-01-25" + #define STRING_DISTRIBUTION_DATE "2025-01-26" #endif /** From 84113367fc81c2889876edb88df145cb44e31d34 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sat, 25 Jan 2025 20:17:05 -0600 Subject: [PATCH 065/787] =?UTF-8?q?=F0=9F=93=9D=20CardReader=20comments?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/sd/cardreader.cpp | 69 ++++++++++++++++++++++++++---------- 1 file changed, 51 insertions(+), 18 deletions(-) diff --git a/Marlin/src/sd/cardreader.cpp b/Marlin/src/sd/cardreader.cpp index fff330b15b..a83b39442f 100644 --- a/Marlin/src/sd/cardreader.cpp +++ b/Marlin/src/sd/cardreader.cpp @@ -512,13 +512,13 @@ void CardReader::mount() { ui.refresh(); } -/** - * Handle SD card events - */ #if MB(FYSETC_CHEETAH, FYSETC_AIO_II) #include "../module/stepper.h" #endif +/** + * Handle SD card events + */ void CardReader::manage_media() { static uint8_t prev_stat = 2; // At boot we don't know if media is present or not uint8_t stat = uint8_t(IS_SD_INSERTED()); @@ -639,6 +639,10 @@ void CardReader::abortFilePrintNow(TERN_(SD_RESORT, const bool re_sort/*=false*/ endFilePrintNow(TERN_(SD_RESORT, re_sort)); } +/** + * Open a log file for writing, if possible. + * Used by G-code M928 . + */ void CardReader::openLogFile(const char * const path) { flag.logging = DISABLED(SDCARD_READONLY); IF_DISABLED(SDCARD_READONLY, openFileWrite(path)); @@ -667,10 +671,16 @@ void CardReader::getAbsFilenameInCWD(char *dst) { *dst = '\0'; } +// +// Print "open failed, File: : .\n" to serial +// void openFailed(const char * const fname) { SERIAL_ECHOLNPGM(STR_SD_OPEN_FILE_FAIL, fname, "."); } +// +// Print "echo: Now doing/fresh file: \n" to all serial ports +// void announceOpen(const uint8_t doing, const char * const path) { if (doing) { PORT_REDIRECT(SerialMask::All); @@ -679,14 +689,14 @@ void announceOpen(const uint8_t doing, const char * const path) { } } -// -// Open a file by DOS path for read -// The 'subcall_type' flag indicates... -// - 0 : Standard open from host or user interface. -// - 1 : (file open) Opening a new sub-procedure. -// - 1 : (no file open) Opening a macro (M98). -// - 2 : Resuming from a sub-procedure -// +/** + * Open a file by DOS path for read + * The 'subcall_type' flag indicates... + * - 0 : Standard open from host or user interface. + * - 1 : (file open) Opening a new sub-procedure. + * - 1 : (no file open) Opening a macro (M98). + * - 2 : Resuming from a sub-procedure + */ void CardReader::openFileRead(const char * const path, const uint8_t subcall_type/*=0*/) { if (!isMounted()) return openFailed(path); @@ -749,6 +759,9 @@ void CardReader::openFileRead(const char * const path, const uint8_t subcall_typ openFailed(fname); } +// +// Print "Writing to file: \n" to serial +// inline void echo_write_to_file(const char * const fname) { SERIAL_ECHOLNPGM(STR_SD_WRITE_TO_FILE, fname); } @@ -782,10 +795,10 @@ void CardReader::openFileWrite(const char * const path) { openFailed(fname); } -// -// Check if a file exists by absolute or workDir-relative path -// If the file exists, the long name can also be fetched. -// +/** + * Check if a file exists by absolute or workDir-relative path + * If the file exists, the long name can also be fetched. + */ bool CardReader::fileExists(const char * const path) { if (!isMounted()) return false; @@ -852,6 +865,9 @@ void CardReader::report_status(TERN_(QUIETER_AUTO_REPORT_SD_STATUS, const bool i SERIAL_ECHOLNPGM(STR_SD_NOT_PRINTING); } +// +// Write a command to the log file +// void CardReader::write_command(char * const buf) { char *begin = buf, *npos = nullptr, @@ -988,16 +1004,20 @@ void CardReader::write_command(char * const buf) { #endif // ONE_CLICK_PRINT +// +// Close the working file. +// void CardReader::closefile(const bool store_location/*=false*/) { file.sync(); file.close(); flag.saving = flag.logging = false; sdpos = 0; + TERN_(EMERGENCY_PARSER, emergency_parser.enable()); if (store_location) { - //future: store printer state, filename and position for continuing a stopped print - // so one can unplug the printer and continue printing the next day. + // TODO: Store printer state, filename, position + // for continuing a stopped print. } } @@ -1139,6 +1159,9 @@ const char* CardReader::diveToFile(const bool update_cwd, MediaFile* &inDirPtr, return atom_ptr; } +// +// Change the working directory to the given sub-path +// void CardReader::cd(const char * relpath) { MediaFile newDir, *parent = &getWorkDir(); @@ -1154,6 +1177,9 @@ void CardReader::cd(const char * relpath) { SERIAL_ECHO_MSG(STR_SD_CANT_ENTER_SUBDIR, relpath); } +// +// Change the working directory to its parent +// int8_t CardReader::cdup() { if (workDirDepth > 0) { // At least 1 dir has been saved nrItems = -1; @@ -1164,6 +1190,9 @@ int8_t CardReader::cdup() { return workDirDepth; } +// +// Change the working directory to the volume root +// void CardReader::cdroot() { workDir = root; flag.workDirIsRoot = true; @@ -1406,6 +1435,9 @@ void CardReader::cdroot() { #endif // SDCARD_SORT_ALPHA +// +// Return the count of visible items in the working directory. +// int16_t CardReader::get_num_items() { if (!isMounted()) return 0; if (nrItems < 0) nrItems = countVisibleItems(workDir); @@ -1413,10 +1445,11 @@ int16_t CardReader::get_num_items() { } // -// Return from procedure or close out the Print Job +// Return from procedure or close out the Print Job. // void CardReader::fileHasFinished() { file.close(); + #if HAS_MEDIA_SUBCALLS if (file_subcall_ctr > 0) { // Resume calling file after closing procedure file_subcall_ctr--; From ab7137ab8e3138283abebceda8bc1c411cb0c12c Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sat, 25 Jan 2025 20:17:10 -0600 Subject: [PATCH 066/787] =?UTF-8?q?=F0=9F=A9=B9=20RP2040=20has=20PIN=5FSPI?= =?UTF-8?q?=5FSS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Followup to #27650 --- Marlin/src/HAL/RP2040/spi_pins.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Marlin/src/HAL/RP2040/spi_pins.h b/Marlin/src/HAL/RP2040/spi_pins.h index 949fdff36f..e6ee840b55 100644 --- a/Marlin/src/HAL/RP2040/spi_pins.h +++ b/Marlin/src/HAL/RP2040/spi_pins.h @@ -24,8 +24,6 @@ /** * Define SPI Pins: SCK, MISO, MOSI, SS */ -#define PIN_SPI_SS 2 - #ifndef SD_SCK_PIN #define SD_SCK_PIN PIN_SPI_SCK #endif @@ -35,3 +33,6 @@ #ifndef SD_MOSI_PIN #define SD_MOSI_PIN PIN_SPI_MOSI #endif +#ifndef SD_SS_PIN + #define SD_SS_PIN PIN_SPI_SS +#endif From 0cd1d9c3c971d6673e9e6fc339e5b2ad76fb8116 Mon Sep 17 00:00:00 2001 From: Andrew <18502096+classicrocker883@users.noreply.github.com> Date: Sun, 26 Jan 2025 00:58:40 -0500 Subject: [PATCH 067/787] =?UTF-8?q?=F0=9F=A9=B9=20Update=20some=20hex-prin?= =?UTF-8?q?ting=20(#27654)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Scott Lahteine --- Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp | 4 ++-- Marlin/src/gcode/parser.cpp | 4 ++-- Marlin/src/gcode/parser.h | 7 ++----- Marlin/src/sd/cardreader.cpp | 14 +++++++------- 4 files changed, 13 insertions(+), 16 deletions(-) diff --git a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp index 1d765988ed..31e7d5a626 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp +++ b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp @@ -1795,14 +1795,14 @@ void unified_bed_leveling::smart_fill_mesh() { SERIAL_ECHOLNPGM("ubl_state_at_invocation :", ubl_state_at_invocation, "\nubl_state_recursion_chk :", ubl_state_recursion_chk); serial_delay(50); - SERIAL_ECHOLNPGM("Meshes go from ", hex_address((void*)settings.meshes_start_index()), " to ", hex_address((void*)settings.meshes_end_index())); + SERIAL_ECHOLNPGM("Meshes go from ", _hex_word(settings.meshes_start_index()), " to ", _hex_word(settings.meshes_end_index())); serial_delay(50); SERIAL_ECHOLNPGM("sizeof(unified_bed_leveling) : ", sizeof(unified_bed_leveling)); SERIAL_ECHOLNPGM("z_value[][] size: ", sizeof(z_values)); serial_delay(25); - SERIAL_ECHOLNPGM("EEPROM free for UBL: ", hex_address((void*)(settings.meshes_end_index() - settings.meshes_start_index()))); + SERIAL_ECHOLNPGM("EEPROM free for UBL: ", _hex_word(settings.meshes_end_index() - settings.meshes_start_index())); serial_delay(50); SERIAL_ECHOLNPGM("EEPROM can hold ", settings.calc_num_meshes(), " meshes.\n"); diff --git a/Marlin/src/gcode/parser.cpp b/Marlin/src/gcode/parser.cpp index 6892d78b4a..99738461de 100644 --- a/Marlin/src/gcode/parser.cpp +++ b/Marlin/src/gcode/parser.cpp @@ -348,7 +348,7 @@ void GCodeParser::parse(char *p) { if (!has_val && !string_arg) { // No value? First time, keep as string_arg string_arg = p - 1; #if ENABLED(DEBUG_GCODE_PARSER) - if (debug) SERIAL_ECHOPGM(" string_arg: ", hex_address((void*)string_arg)); // DEBUG + if (debug) SERIAL_ECHOPGM(" string_arg: ", hex_address(string_arg)); // DEBUG #endif } @@ -359,7 +359,7 @@ void GCodeParser::parse(char *p) { else if (!string_arg) { // Not A-Z? First time, keep as the string_arg string_arg = p - 1; #if ENABLED(DEBUG_GCODE_PARSER) - if (debug) SERIAL_ECHOPGM(" string_arg: ", hex_address((void*)string_arg)); // DEBUG + if (debug) SERIAL_ECHOPGM(" string_arg: ", hex_address(string_arg)); // DEBUG #endif } diff --git a/Marlin/src/gcode/parser.h b/Marlin/src/gcode/parser.h index 9423b2380c..c2fe6880ed 100644 --- a/Marlin/src/gcode/parser.h +++ b/Marlin/src/gcode/parser.h @@ -132,11 +132,8 @@ public: SBI32(codebits, ind); // parameter exists param[ind] = ptr ? ptr - command_ptr : 0; // parameter offset or 0 #if ENABLED(DEBUG_GCODE_PARSER) - if (codenum == 800) { - SERIAL_ECHOPGM("Set bit ", ind, " of codebits (", hex_address((void*)(codebits >> 16))); - print_hex_word((uint16_t)(codebits & 0xFFFF)); - SERIAL_ECHOLNPGM(") | param = ", param[ind]); - } + if (codenum == 800) + SERIAL_ECHOLNPGM("Set bit ", ind, " of codebits (", _hex_long(codebits), ") | param = ", param[ind]); #endif } diff --git a/Marlin/src/sd/cardreader.cpp b/Marlin/src/sd/cardreader.cpp index a83b39442f..68b5846c2f 100644 --- a/Marlin/src/sd/cardreader.cpp +++ b/Marlin/src/sd/cardreader.cpp @@ -1089,7 +1089,7 @@ const char* CardReader::diveToFile(const bool update_cwd, MediaFile* &inDirPtr, if (path[0] == '/') { // Starting at the root directory? inDirPtr = &root; atom_ptr++; - DEBUG_ECHOLNPGM(" CWD to root: ", hex_address((void*)inDirPtr)); + DEBUG_ECHOLNPGM(" CWD to root: ", hex_address(inDirPtr)); if (update_cwd) workDirDepth = 0; // The cwd can be updated for the benefit of sub-programs } else @@ -1097,7 +1097,7 @@ const char* CardReader::diveToFile(const bool update_cwd, MediaFile* &inDirPtr, startDirPtr = inDirPtr; - DEBUG_ECHOLNPGM(" startDirPtr = ", hex_address((void*)startDirPtr)); + DEBUG_ECHOLNPGM(" startDirPtr = ", hex_address(startDirPtr)); while (atom_ptr) { // Find next subdirectory delimiter @@ -1113,7 +1113,7 @@ const char* CardReader::diveToFile(const bool update_cwd, MediaFile* &inDirPtr, if (echo) SERIAL_ECHOLN(dosSubdirname); - DEBUG_ECHOLNPGM(" sub = ", hex_address((void*)sub)); + DEBUG_ECHOLNPGM(" sub = ", hex_address(sub)); // Open inDirPtr (closing first) sub->close(); @@ -1125,13 +1125,13 @@ const char* CardReader::diveToFile(const bool update_cwd, MediaFile* &inDirPtr, // Close inDirPtr if not at starting-point if (inDirPtr != startDirPtr) { - DEBUG_ECHOLNPGM(" closing inDirPtr: ", hex_address((void*)inDirPtr)); + DEBUG_ECHOLNPGM(" closing inDirPtr: ", hex_address(inDirPtr)); inDirPtr->close(); } // inDirPtr now subDir inDirPtr = sub; - DEBUG_ECHOLNPGM(" inDirPtr = sub: ", hex_address((void*)inDirPtr)); + DEBUG_ECHOLNPGM(" inDirPtr = sub: ", hex_address(inDirPtr)); // Update workDirParents and workDirDepth if (update_cwd) { @@ -1142,7 +1142,7 @@ const char* CardReader::diveToFile(const bool update_cwd, MediaFile* &inDirPtr, // Point sub at the other scratch object sub = (inDirPtr != &newDir1) ? &newDir1 : &newDir2; - DEBUG_ECHOLNPGM(" swapping sub = ", hex_address((void*)sub)); + DEBUG_ECHOLNPGM(" swapping sub = ", hex_address(sub)); // Next path atom address atom_ptr = name_end + 1; @@ -1150,7 +1150,7 @@ const char* CardReader::diveToFile(const bool update_cwd, MediaFile* &inDirPtr, if (update_cwd) { workDir = *inDirPtr; - DEBUG_ECHOLNPGM(" final workDir = ", hex_address((void*)inDirPtr)); + DEBUG_ECHOLNPGM(" final workDir = ", hex_address(inDirPtr)); flag.workDirIsRoot = (workDirDepth == 0); TERN_(SDCARD_SORT_ALPHA, presort()); } From 0226692e6b7d2693858875bd38eef58f98390e94 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Mon, 27 Jan 2025 00:28:09 +0000 Subject: [PATCH 068/787] [cron] Bump distribution date (2025-01-27) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 54bcfca656..b4a8d79a7f 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-01-26" +//#define STRING_DISTRIBUTION_DATE "2025-01-27" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 969dd8a02c..5422e8bcd3 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-01-26" + #define STRING_DISTRIBUTION_DATE "2025-01-27" #endif /** From 81ef02e41fab45235b8036d5415f0f520a9a8702 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Mon, 27 Jan 2025 21:17:53 -0600 Subject: [PATCH 069/787] =?UTF-8?q?=F0=9F=94=A8=20Fix=20sim=20build=20with?= =?UTF-8?q?=20gcc-14?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- buildroot/share/PlatformIO/scripts/common-cxxflags.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/buildroot/share/PlatformIO/scripts/common-cxxflags.py b/buildroot/share/PlatformIO/scripts/common-cxxflags.py index 6e740eb4ff..f0295d8f91 100644 --- a/buildroot/share/PlatformIO/scripts/common-cxxflags.py +++ b/buildroot/share/PlatformIO/scripts/common-cxxflags.py @@ -16,6 +16,7 @@ if pioutil.is_pio_build(): if "teensy" not in env["PIOENV"]: cxxflags += ["-Wno-register"] env.Append(CXXFLAGS=cxxflags) + env.Append(CFLAGS=["-Wno-implicit-function-declaration"]) # # Add CPU frequency as a compile time constant instead of a runtime variable @@ -27,8 +28,8 @@ if pioutil.is_pio_build(): # Useful for JTAG debugging # # It will separate release and debug build folders. - # It useful to keep two live versions: a debug version for debugging and another for - # release, for flashing when upload is not done automatically by jlink/stlink. + # This is useful to keep two live versions: a debug version and a release version, + # for flashing when upload is not done automatically by jlink/stlink. # Without this, PIO needs to recompile everything twice for any small change. if env.GetBuildType() == "debug" and env.get("UPLOAD_PROTOCOL") not in ["jlink", "stlink", "custom"]: env["BUILD_DIR"] = "$PROJECT_BUILD_DIR/$PIOENV/debug" From 09a519bfb59d7f25e3b29c2c967467de68d1c86b Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Mon, 27 Jan 2025 21:18:29 -0600 Subject: [PATCH 070/787] =?UTF-8?q?=F0=9F=94=A5=20Not=20using=20.astylerc?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- buildroot/etc/.astylerc | 23 ----------------------- 1 file changed, 23 deletions(-) delete mode 100644 buildroot/etc/.astylerc diff --git a/buildroot/etc/.astylerc b/buildroot/etc/.astylerc deleted file mode 100644 index aefe32c7f4..0000000000 --- a/buildroot/etc/.astylerc +++ /dev/null @@ -1,23 +0,0 @@ ---style=google ---keep-one-line-blocks - ---indent=spaces=2 ---indent-preproc-block ---indent-preproc-define ---indent-col1-comments - ---remove-brackets ---break-after-logical ---delete-empty-lines - ---pad-oper ---pad-header ---unpad-paren ---align-pointer=type ---align-reference=type - ---attach-classes ---attach-inlines ---keep-one-line-statements - ---indent-namespaces From 485fbf20408e19f8854e3acecb9d4e5801c8a8cd Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Tue, 28 Jan 2025 06:08:30 +0000 Subject: [PATCH 071/787] [cron] Bump distribution date (2025-01-28) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index b4a8d79a7f..064026a5ab 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-01-27" +//#define STRING_DISTRIBUTION_DATE "2025-01-28" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 5422e8bcd3..2f9b29fdfb 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-01-27" + #define STRING_DISTRIBUTION_DATE "2025-01-28" #endif /** From a21fc27056bda422230bd4c4523f16325e579953 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sat, 1 Feb 2025 00:11:17 -0600 Subject: [PATCH 072/787] =?UTF-8?q?=F0=9F=8E=A8=20Minor=20config=20style?= =?UTF-8?q?=20updates?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/Configuration.h | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index f73ad0560d..14d1cfb168 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -3180,14 +3180,14 @@ // // Tiny, but very sharp OLED display // -//#define MKS_12864OLED // Uses the SH1106 controller (default) +//#define MKS_12864OLED // Uses the SH1106 controller //#define MKS_12864OLED_SSD1306 // Uses the SSD1306 controller // // Zonestar OLED 128×64 Full Graphics Controller // //#define ZONESTAR_12864LCD // Graphical (DOGM) with ST7920 controller -//#define ZONESTAR_12864OLED // 1.3" OLED with SH1106 controller (default) +//#define ZONESTAR_12864OLED // 1.3" OLED with SH1106 controller //#define ZONESTAR_12864OLED_SSD1306 // 0.96" OLED with SSD1306 controller // @@ -3436,7 +3436,7 @@ #if ENABLED(TFT_COLOR_UI) /** - * TFT Font for Color_UI. Choose one of the following: + * TFT Font for Color UI. Choose one of the following: * * NOTOSANS - Default font with anti-aliasing. Supports Latin Extended and non-Latin characters. * UNIFONT - Lightweight font, no anti-aliasing. Supports Latin Extended and non-Latin characters. @@ -3445,7 +3445,7 @@ #define TFT_FONT NOTOSANS /** - * TFT Theme for Color_UI. Choose one of the following or add a new one to 'Marlin/src/lcd/tft/themes' directory + * TFT Theme for Color UI. Choose one of the following or add a new one to 'Marlin/src/lcd/tft/themes' directory * * BLUE_MARLIN - Default theme with 'midnight blue' background * BLACK_MARLIN - Theme with 'black' background @@ -3521,7 +3521,9 @@ // https://reprapworld.com/products/electronics/ramps/keypad_v1_0_fully_assembled/ // //#define REPRAPWORLD_KEYPAD -//#define REPRAPWORLD_KEYPAD_MOVE_STEP 10.0 // (mm) Distance to move per key-press +#if ENABLED(REPRAPWORLD_KEYPAD) + //#define REPRAPWORLD_KEYPAD_MOVE_STEP 10.0 // (mm) Distance to move per key-press +#endif // // EasyThreeD ET-4000+ with button input and status LED From 479074ccba7656fd489dbd146fe9f5fb5f9150f4 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Sun, 2 Feb 2025 06:07:35 +0000 Subject: [PATCH 073/787] [cron] Bump distribution date (2025-02-02) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 064026a5ab..8edd6892b8 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-01-28" +//#define STRING_DISTRIBUTION_DATE "2025-02-02" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 2f9b29fdfb..e9fecbeae5 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-01-28" + #define STRING_DISTRIBUTION_DATE "2025-02-02" #endif /** From cd3997f045e5a666561e36f39df5f0d7758f878a Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Mon, 3 Feb 2025 15:38:18 -0600 Subject: [PATCH 074/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Mor?= =?UTF-8?q?e=20binary=20file=20types?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- buildroot/share/sublime/MarlinFirmware.sublime-project | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildroot/share/sublime/MarlinFirmware.sublime-project b/buildroot/share/sublime/MarlinFirmware.sublime-project index 62607ac0c6..32fbfa0a1f 100644 --- a/buildroot/share/sublime/MarlinFirmware.sublime-project +++ b/buildroot/share/sublime/MarlinFirmware.sublime-project @@ -11,7 +11,7 @@ ".vscode" ], "binary_file_patterns": - [ "*.psd", "*.png", "*.jpg", "*.jpeg", "*.bdf", "*.patch", "avrdude_5.*", "*.svg", "*.bin", "*.woff", "*.otf" ], + [ "*.psd", "*.png", "*.jpg", "*.jpeg", "*.bmp", "*.bdf", "*.patch", "avrdude_5.*", "*.svg", "*.bin", "*.woff", "*.otf", "*.pbm" ], "file_exclude_patterns": [ "Marlin/platformio.ini", From 99c3a7136d0831b07d457128a5f05eef4f91e99a Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Mon, 3 Feb 2025 15:37:50 -0600 Subject: [PATCH 075/787] =?UTF-8?q?=F0=9F=8E=A8=20Standard=20logical=20FLI?= =?UTF-8?q?P(X)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/core/macros.h | 3 +++ Marlin/src/feature/bedlevel/bedlevel.cpp | 2 +- Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp | 2 +- Marlin/src/feature/cooler.h | 4 ++-- Marlin/src/feature/fancheck.h | 2 +- Marlin/src/feature/max7219.cpp | 2 +- Marlin/src/feature/mmu3/SpoolJoin.cpp | 2 +- Marlin/src/gcode/bedlevel/abl/G29.cpp | 2 +- Marlin/src/gcode/calibrate/G33.cpp | 2 +- Marlin/src/gcode/calibrate/G34_M422.cpp | 2 +- Marlin/src/gcode/temp/M303.cpp | 2 +- Marlin/src/lcd/e3v2/jyersui/dwin.cpp | 22 +++++++++---------- Marlin/src/lcd/e3v2/proui/dwin.cpp | 4 ++-- Marlin/src/lcd/e3v2/proui/menus.cpp | 2 +- .../src/lcd/extui/anycubic_vyper/dgus_tft.cpp | 2 +- .../bioprinter/status_screen.cpp | 2 +- .../cocoa_press/load_chocolate.cpp | 2 +- .../generic/nudge_nozzle_screen.cpp | 2 +- .../generic/widget_demo_screen.cpp | 2 +- .../lcd/extui/ia_creality/ia_creality_rts.cpp | 2 +- .../extui/mks_ui/draw_encoder_settings.cpp | 2 +- .../lcd/extui/mks_ui/draw_filament_change.cpp | 2 +- Marlin/src/lcd/menu/game/invaders.cpp | 2 +- Marlin/src/lcd/menu/menu_item.h | 2 +- Marlin/src/lcd/menu/menu_motion.cpp | 2 +- Marlin/src/lcd/sovol_rts/sovol_rts.cpp | 4 ++-- 26 files changed, 41 insertions(+), 38 deletions(-) diff --git a/Marlin/src/core/macros.h b/Marlin/src/core/macros.h index e3fd9b6609..21d9929bc5 100644 --- a/Marlin/src/core/macros.h +++ b/Marlin/src/core/macros.h @@ -80,6 +80,7 @@ #define CBI32(n,b) (n &= ~_BV32(b)) #define TBI32(N,B) (N ^= _BV32(B)) +// Macros for common maths operations #define cu(x) ({__typeof__(x) _x = (x); (_x)*(_x)*(_x);}) #define RADIANS(d) ((d)*float(M_PI)/180.0f) #define DEGREES(r) ((r)*180.0f/float(M_PI)) @@ -93,6 +94,8 @@ #define SIGN(a) ({__typeof__(a) _a = (a); (_a>0)-(_a<0);}) #define IS_POWER_OF_2(x) ((x) && !((x) & ((x) - 1))) +#define FLIP(X) (X = !(X)) + // Macros to constrain values #ifdef __cplusplus diff --git a/Marlin/src/feature/bedlevel/bedlevel.cpp b/Marlin/src/feature/bedlevel/bedlevel.cpp index a76c6cdd26..12d620e5af 100644 --- a/Marlin/src/feature/bedlevel/bedlevel.cpp +++ b/Marlin/src/feature/bedlevel/bedlevel.cpp @@ -77,7 +77,7 @@ void set_bed_leveling_enabled(const bool enable/*=true*/) { // Get the corrected leveled / unleveled position planner.apply_modifiers(current_position, true); // Physical position with all modifiers - planner.leveling_active ^= true; // Toggle leveling between apply and unapply + FLIP(planner.leveling_active); // Toggle leveling between apply and unapply planner.unapply_modifiers(current_position, true); // Logical position with modifiers removed sync_plan_position(); diff --git a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp index 31e7d5a626..e6f93a001b 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp +++ b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp @@ -1607,7 +1607,7 @@ void unified_bed_leveling::smart_fill_mesh() { } if (abort_flag) break; - zig_zag ^= true; + FLIP(zig_zag); } } probe.stow(); diff --git a/Marlin/src/feature/cooler.h b/Marlin/src/feature/cooler.h index 9891514e23..ef3590c593 100644 --- a/Marlin/src/feature/cooler.h +++ b/Marlin/src/feature/cooler.h @@ -40,7 +40,7 @@ public: static bool enabled; static void enable() { enabled = true; } static void disable() { enabled = false; } - static void toggle() { enabled = !enabled; } + static void toggle() { FLIP(enabled); } static uint8_t mode; // 0 = CO2 Liquid cooling, 1 = Laser Diode TEC Heatsink Cooling static void set_mode(const uint8_t m) { mode = m; } @@ -96,7 +96,7 @@ public: #if ENABLED(FLOWMETER_SAFETY) static bool flowfault; // Flag that the cooler is in a fault state static bool flowsafety_enabled; // Flag to disable the cutter if flow rate is too low - static void flowsafety_toggle() { flowsafety_enabled = !flowsafety_enabled; } + static void flowsafety_toggle() { FLIP(flowsafety_enabled); } static bool check_flow_too_low() { const bool too_low = flowsafety_enabled && flowrate < (FLOWMETER_MIN_LITERS_PER_MINUTE); flowfault = too_low; diff --git a/Marlin/src/feature/fancheck.h b/Marlin/src/feature/fancheck.h index b13a34fb19..3c295b3020 100644 --- a/Marlin/src/feature/fancheck.h +++ b/Marlin/src/feature/fancheck.h @@ -67,7 +67,7 @@ class FanCheck { static void compute_speed(uint16_t elapsedTime); static void print_fan_states(); #if HAS_PWMFANCHECK - static void toggle_measuring() { measuring = !measuring; } + static void toggle_measuring() { FLIP(measuring); } static bool is_measuring() { return measuring; } #endif diff --git a/Marlin/src/feature/max7219.cpp b/Marlin/src/feature/max7219.cpp index a98248c53b..51ec219e20 100644 --- a/Marlin/src/feature/max7219.cpp +++ b/Marlin/src/feature/max7219.cpp @@ -526,7 +526,7 @@ void Max7219::register_setup() { } else sweepx -= MAX7219_X_LEDS * sweep_dir; - patt_on ^= true; + FLIP(patt_on); next_patt_ms += 100; if (++test_mode > 4) test_mode = 0; } diff --git a/Marlin/src/feature/mmu3/SpoolJoin.cpp b/Marlin/src/feature/mmu3/SpoolJoin.cpp index 48495a225c..f27d2bc7e9 100644 --- a/Marlin/src/feature/mmu3/SpoolJoin.cpp +++ b/Marlin/src/feature/mmu3/SpoolJoin.cpp @@ -47,7 +47,7 @@ void SpoolJoin::initStatus() { void SpoolJoin::toggle() { // Toggle enabled value. - enabled = !enabled; + FLIP(enabled); // Following Prusa's implementation let's save the value to the EEPROM // TODO: Move to settings.cpp diff --git a/Marlin/src/gcode/bedlevel/abl/G29.cpp b/Marlin/src/gcode/bedlevel/abl/G29.cpp index 6225c24360..b25fe5ebe3 100644 --- a/Marlin/src/gcode/bedlevel/abl/G29.cpp +++ b/Marlin/src/gcode/bedlevel/abl/G29.cpp @@ -700,7 +700,7 @@ G29_TYPE GcodeSuite::G29() { inInc = -1; // Zag left } - zig ^= true; // zag + FLIP(zig); // zag // An index to print current state grid_count_t pt_index = (PR_OUTER_VAR) * (PR_INNER_SIZE) + 1; diff --git a/Marlin/src/gcode/calibrate/G33.cpp b/Marlin/src/gcode/calibrate/G33.cpp index 80c4688a6e..395da649d3 100644 --- a/Marlin/src/gcode/calibrate/G33.cpp +++ b/Marlin/src/gcode/calibrate/G33.cpp @@ -241,7 +241,7 @@ static bool probe_calibration_points(float z_pt[NPP + 1], const int8_t probe_poi z_pt[uint8_t(LROUND(rad - interpol + NPP - 1)) % NPP + 1] += z_temp * sq(cos(RADIANS(interpol * 90))); z_pt[uint8_t(LROUND(rad - interpol)) % NPP + 1] += z_temp * sq(sin(RADIANS(interpol * 90))); } - zig_zag = !zig_zag; + FLIP(zig_zag); } if (_7p_intermed_points) LOOP_CAL_RAD(rad) diff --git a/Marlin/src/gcode/calibrate/G34_M422.cpp b/Marlin/src/gcode/calibrate/G34_M422.cpp index 17d576679f..41e5821450 100644 --- a/Marlin/src/gcode/calibrate/G34_M422.cpp +++ b/Marlin/src/gcode/calibrate/G34_M422.cpp @@ -365,7 +365,7 @@ void GcodeSuite::G34() { if (decreasing_accuracy(last_z_align_move[zstepper], z_align_abs)) { if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("> Z", zstepper + 1, " last_z_align_move = ", last_z_align_move[zstepper]); if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("> Z", zstepper + 1, " z_align_abs = ", z_align_abs); - adjustment_reverse = !adjustment_reverse; + FLIP(adjustment_reverse); } // Remember the alignment for the next iteration, but only if steppers move, diff --git a/Marlin/src/gcode/temp/M303.cpp b/Marlin/src/gcode/temp/M303.cpp index 730ec65ba4..c08b99edc6 100644 --- a/Marlin/src/gcode/temp/M303.cpp +++ b/Marlin/src/gcode/temp/M303.cpp @@ -49,7 +49,7 @@ void GcodeSuite::M303() { #if HAS_PID_DEBUG if (parser.seen_test('D')) { - thermalManager.pid_debug_flag ^= true; + FLIP(thermalManager.pid_debug_flag); SERIAL_ECHO_START(); SERIAL_ECHOPGM("PID Debug "); serialprintln_onoff(thermalManager.pid_debug_flag); diff --git a/Marlin/src/lcd/e3v2/jyersui/dwin.cpp b/Marlin/src/lcd/e3v2/jyersui/dwin.cpp index 115987b063..09100e5029 100644 --- a/Marlin/src/lcd/e3v2/jyersui/dwin.cpp +++ b/Marlin/src/lcd/e3v2/jyersui/dwin.cpp @@ -1342,7 +1342,7 @@ void JyersDWIN::menuItemHandler(const uint8_t menu, const uint8_t item, bool dra drawCheckbox(row, probe_deployed); } else { - probe_deployed ^= true; + FLIP(probe_deployed); probe.set_deployed(probe_deployed); drawCheckbox(row, probe_deployed); } @@ -1355,7 +1355,7 @@ void JyersDWIN::menuItemHandler(const uint8_t menu, const uint8_t item, bool dra drawCheckbox(row, livemove); } else { - livemove ^= true; + FLIP(livemove); drawCheckbox(row, livemove); } break; @@ -1400,7 +1400,7 @@ void JyersDWIN::menuItemHandler(const uint8_t menu, const uint8_t item, bool dra drawCheckbox(row, use_probe); } else { - use_probe ^= true; + FLIP(use_probe); drawCheckbox(row, use_probe); if (use_probe) { popupHandler(Popup_Level); @@ -1616,7 +1616,7 @@ void JyersDWIN::menuItemHandler(const uint8_t menu, const uint8_t item, bool dra planner.synchronize(); redrawMenu(); } - liveadjust ^= true; + FLIP(liveadjust); drawCheckbox(row, liveadjust); } break; @@ -2719,7 +2719,7 @@ void JyersDWIN::menuItemHandler(const uint8_t menu, const uint8_t item, bool dra drawCheckbox(row, eeprom_settings.time_format_textual); } else { - eeprom_settings.time_format_textual ^= true; + FLIP(eeprom_settings.time_format_textual); drawCheckbox(row, eeprom_settings.time_format_textual); } break; @@ -2877,7 +2877,7 @@ void JyersDWIN::menuItemHandler(const uint8_t menu, const uint8_t item, bool dra drawCheckbox(row, ui.sound_on); } else { - ui.sound_on ^= true; + FLIP(ui.sound_on); drawCheckbox(row, ui.sound_on); } break; @@ -2960,7 +2960,7 @@ void JyersDWIN::menuItemHandler(const uint8_t menu, const uint8_t item, bool dra drawCheckbox(row, runout.enabled); } else { - runout.enabled ^= true; + FLIP(runout.enabled); drawCheckbox(row, runout.enabled); } break; @@ -3403,7 +3403,7 @@ void JyersDWIN::menuItemHandler(const uint8_t menu, const uint8_t item, bool dra drawCheckbox(row, mesh_conf.viewer_print_value); } else { - mesh_conf.viewer_print_value ^= true; + FLIP(mesh_conf.viewer_print_value); drawCheckbox(row, mesh_conf.viewer_print_value); } break; @@ -3413,7 +3413,7 @@ void JyersDWIN::menuItemHandler(const uint8_t menu, const uint8_t item, bool dra drawCheckbox(row, mesh_conf.viewer_asymmetric_range); } else { - mesh_conf.viewer_asymmetric_range ^= true; + FLIP(mesh_conf.viewer_asymmetric_range); drawCheckbox(row, mesh_conf.viewer_asymmetric_range); } break; @@ -3596,7 +3596,7 @@ void JyersDWIN::menuItemHandler(const uint8_t menu, const uint8_t item, bool dra drawCheckbox(row, mesh_conf.goto_mesh_value); } else { - mesh_conf.goto_mesh_value ^= true; + FLIP(mesh_conf.goto_mesh_value); current_position.z = 0; mesh_conf.manual_mesh_move(true); drawCheckbox(row, mesh_conf.goto_mesh_value); @@ -3957,7 +3957,7 @@ void JyersDWIN::menuItemHandler(const uint8_t menu, const uint8_t item, bool dra drawCheckbox(row, runout.enabled); } else { - runout.enabled ^= true; + FLIP(runout.enabled); drawCheckbox(row, runout.enabled); } break; diff --git a/Marlin/src/lcd/e3v2/proui/dwin.cpp b/Marlin/src/lcd/e3v2/proui/dwin.cpp index c4d94d68b6..cbf806a7c9 100644 --- a/Marlin/src/lcd/e3v2/proui/dwin.cpp +++ b/Marlin/src/lcd/e3v2/proui/dwin.cpp @@ -1297,7 +1297,7 @@ void eachMomentUpdate() { if (ELAPSED(ms, next_var_update_ms)) { next_var_update_ms = ms + DWIN_VAR_UPDATE_INTERVAL; - blink = !blink; + FLIP(blink); updateVariable(); #if HAS_ESDIAG if (checkkey == ID_ESDiagProcess) esDiag.update(); @@ -2232,7 +2232,7 @@ void setMoveZ() { hmiValue.axis = Z_AXIS; setPFloatOnClick(Z_MIN_POS, Z_MAX_POS, #if ENABLED(BAUD_RATE_GCODE) void hmiSetBaudRate() { hmiData.baud115K ? setBaud115K() : setBaud250K(); } void setBaudRate() { - hmiData.baud115K ^= true; + FLIP(hmiData.baud115K); hmiSetBaudRate(); drawCheckboxLine(currentMenu->line(), hmiData.baud115K); dwinUpdateLCD(); diff --git a/Marlin/src/lcd/e3v2/proui/menus.cpp b/Marlin/src/lcd/e3v2/proui/menus.cpp index 0f0005e3d1..7edf32169d 100644 --- a/Marlin/src/lcd/e3v2/proui/menus.cpp +++ b/Marlin/src/lcd/e3v2/proui/menus.cpp @@ -95,7 +95,7 @@ void showCheckboxLine(const bool checked) { } void toggleCheckboxLine(bool &checked) { - checked = !checked; + FLIP(checked); showCheckboxLine(checked); } diff --git a/Marlin/src/lcd/extui/anycubic_vyper/dgus_tft.cpp b/Marlin/src/lcd/extui/anycubic_vyper/dgus_tft.cpp index f67b0930c1..d23b10898e 100644 --- a/Marlin/src/lcd/extui/anycubic_vyper/dgus_tft.cpp +++ b/Marlin/src/lcd/extui/anycubic_vyper/dgus_tft.cpp @@ -1134,7 +1134,7 @@ namespace Anycubic { } void DgusTFT::toggle_audio() { - lcd_info.audio_on = !lcd_info.audio_on; + FLIP(lcd_info.audio_on); goto_system_page(); lcdAudioSet(lcd_info.audio_on); } diff --git a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/status_screen.cpp b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/status_screen.cpp index 72a1d739f4..58abe245ff 100644 --- a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/status_screen.cpp +++ b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/status_screen.cpp @@ -318,7 +318,7 @@ bool StatusScreen::onTouchEnd(uint8_t tag) { case 13: GOTO_SCREEN(BioConfirmHomeE); break; case 14: SpinnerDialogBox::enqueueAndWait(F("G28Z")); break; case 15: GOTO_SCREEN(TemperatureScreen); break; - case 16: fine_motion = !fine_motion; break; + case 16: FLIP(fine_motion); break; default: return false; } // If a passcode is enabled, the LockScreen will prevent the diff --git a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/load_chocolate.cpp b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/load_chocolate.cpp index c7870eeaf8..03d47cf73a 100644 --- a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/load_chocolate.cpp +++ b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/load_chocolate.cpp @@ -123,7 +123,7 @@ bool LoadChocolateScreen::onTouchEnd(uint8_t tag) { switch (tag) { case 2: mydata.repeat_tag = 5; break; case 3: mydata.repeat_tag = 6; break; - case 4: mydata.repeating = !mydata.repeating; break; + case 4: FLIP(mydata.repeating); break; case 1: GOTO_PREVIOUS(); break; } return true; diff --git a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/nudge_nozzle_screen.cpp b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/nudge_nozzle_screen.cpp index 5688dd31af..9e744f57f1 100644 --- a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/nudge_nozzle_screen.cpp +++ b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/nudge_nozzle_screen.cpp @@ -108,7 +108,7 @@ bool NudgeNozzleScreen::onTouchHeld(uint8_t tag) { #if HAS_MULTI_EXTRUDER case 8: mydata.link_nozzles = !link; break; #endif - case 9: mydata.show_offsets = !mydata.show_offsets; break; + case 9: FLIP(mydata.show_offsets); break; case 10: GOTO_SCREEN(SaveSettingsDialogBox); break; default: return false; } diff --git a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/widget_demo_screen.cpp b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/widget_demo_screen.cpp index d02397abf9..86d7f47fd2 100644 --- a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/widget_demo_screen.cpp +++ b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/widget_demo_screen.cpp @@ -124,7 +124,7 @@ bool WidgetsScreen::onTouchStart(uint8_t tag) { case 5: cmd.track_linear (BTN_POS(3,4), BTN_SIZE(2,1), 5).execute(); break; case 6: cmd.track_linear (BTN_POS(3,5), BTN_SIZE(2,1), 6).execute(); break; #endif - case 7: show_grid = !show_grid; break; + case 7: FLIP(show_grid); break; default: return false; } diff --git a/Marlin/src/lcd/extui/ia_creality/ia_creality_rts.cpp b/Marlin/src/lcd/extui/ia_creality/ia_creality_rts.cpp index 0c9f8a2e34..84df4f5871 100644 --- a/Marlin/src/lcd/extui/ia_creality/ia_creality_rts.cpp +++ b/Marlin/src/lcd/extui/ia_creality/ia_creality_rts.cpp @@ -1252,7 +1252,7 @@ void RTS::handleData() { setTouchScreenConfiguration(); break; case 21: - dwin_settings.display_standby ^= true; + FLIP(dwin_settings.display_standby); setTouchScreenConfiguration(); break; case 22: diff --git a/Marlin/src/lcd/extui/mks_ui/draw_encoder_settings.cpp b/Marlin/src/lcd/extui/mks_ui/draw_encoder_settings.cpp index ec6d221e89..4b8eed034c 100644 --- a/Marlin/src/lcd/extui/mks_ui/draw_encoder_settings.cpp +++ b/Marlin/src/lcd/extui/mks_ui/draw_encoder_settings.cpp @@ -48,7 +48,7 @@ static void event_handler(lv_obj_t *obj, lv_event_t event) { draw_return_ui(); break; case ID_ENCODER_STATE: - gCfgItems.encoder_enable ^= true; + FLIP(gCfgItems.encoder_enable); lv_screen_menu_item_onoff_update(buttonEncoderState, gCfgItems.encoder_enable); update_spi_flash(); break; diff --git a/Marlin/src/lcd/extui/mks_ui/draw_filament_change.cpp b/Marlin/src/lcd/extui/mks_ui/draw_filament_change.cpp index be70fa9b4e..bd9c3ccbe7 100644 --- a/Marlin/src/lcd/extui/mks_ui/draw_filament_change.cpp +++ b/Marlin/src/lcd/extui/mks_ui/draw_filament_change.cpp @@ -87,7 +87,7 @@ static void event_handler(lv_obj_t *obj, lv_event_t event) { break; case ID_FILAMNT_TYPE: #if HAS_MULTI_EXTRUDER - uiCfg.extruderIndex = !uiCfg.extruderIndex; + FLIP(uiCfg.extruderIndex); #endif disp_filament_type(); break; diff --git a/Marlin/src/lcd/menu/game/invaders.cpp b/Marlin/src/lcd/menu/game/invaders.cpp index 330ead081e..d31238f88b 100644 --- a/Marlin/src/lcd/menu/game/invaders.cpp +++ b/Marlin/src/lcd/menu/game/invaders.cpp @@ -262,7 +262,7 @@ void InvadersGame::game_screen() { const bool did_blink = (++idat.blink_count > idat.count >> 1); if (did_blink) { - idat.game_blink = !idat.game_blink; + FLIP(idat.game_blink); idat.blink_count = 0; } diff --git a/Marlin/src/lcd/menu/menu_item.h b/Marlin/src/lcd/menu/menu_item.h index 0a5a5fb443..661deeb4e7 100644 --- a/Marlin/src/lcd/menu/menu_item.h +++ b/Marlin/src/lcd/menu/menu_item.h @@ -191,7 +191,7 @@ class MenuItem_bool : public MenuEditItemBase { draw(sel, row, fstr, pget()); } static void action(FSTR_P const fstr, bool * const ptr, const screenFunc_t callbackFunc=nullptr) { - *ptr ^= true; ui.refresh(); + FLIP(*ptr); ui.refresh(); if (callbackFunc) (*callbackFunc)(); } }; diff --git a/Marlin/src/lcd/menu/menu_motion.cpp b/Marlin/src/lcd/menu/menu_motion.cpp index 4aa7d78711..4717f4b221 100644 --- a/Marlin/src/lcd/menu/menu_motion.cpp +++ b/Marlin/src/lcd/menu/menu_motion.cpp @@ -419,7 +419,7 @@ void menu_move() { bool show_state = c.active; EDIT_ITEM(bool, MSG_FIXED_TIME_MOTION, &show_state, []{ - ftMotion.cfg.active ^= true; + FLIP(ftMotion.cfg.active); ftMotion.update_shaping_params(); }); diff --git a/Marlin/src/lcd/sovol_rts/sovol_rts.cpp b/Marlin/src/lcd/sovol_rts/sovol_rts.cpp index b0cb2001fa..1f3322ded7 100644 --- a/Marlin/src/lcd/sovol_rts/sovol_rts.cpp +++ b/Marlin/src/lcd/sovol_rts/sovol_rts.cpp @@ -259,7 +259,7 @@ void RTS::init() { inStop = -1; inInc = -1; } - zig ^= true; + FLIP(zig); for (int8_t x = inStart; x != inStop; x += inInc) { sendData(bedlevel.z_values[x][y] * 100, AUTO_BED_LEVEL_1POINT_VP + showcount * 2); showcount++; @@ -1207,7 +1207,7 @@ void RTS::handleData() { inStop = -1; inInc = -1; } - zig ^= true; + FLIP(zig); for (int8_t x = inStart; x != inStop; x += inInc) { sendData(bedlevel.z_values[x][y] * 100, AUTO_BED_LEVEL_1POINT_VP + showcount * 2); showcount++; From 4d0c6841f8052c1a44be3c697ae6516a877313e5 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Tue, 4 Feb 2025 12:10:52 +0000 Subject: [PATCH 076/787] [cron] Bump distribution date (2025-02-04) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 8edd6892b8..70f60478d5 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-02-02" +//#define STRING_DISTRIBUTION_DATE "2025-02-04" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index e9fecbeae5..57c8327e8e 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-02-02" + #define STRING_DISTRIBUTION_DATE "2025-02-04" #endif /** From 12b3f18bb29503d26787738e338fb36657712b35 Mon Sep 17 00:00:00 2001 From: Keith Bennett <13375512+thisiskeithb@users.noreply.github.com> Date: Sat, 15 Feb 2025 14:11:57 -0800 Subject: [PATCH 077/787] =?UTF-8?q?=F0=9F=94=A8=20mac=5Fgcc:=20Use=20confi?= =?UTF-8?q?gured=20brew/port=20paths=20(#27655)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- buildroot/bin/mac_gcc | 15 +++++++++------ ini/native.ini | 4 ++-- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/buildroot/bin/mac_gcc b/buildroot/bin/mac_gcc index 870090919f..05ee9dd295 100755 --- a/buildroot/bin/mac_gcc +++ b/buildroot/bin/mac_gcc @@ -10,16 +10,19 @@ which port >/dev/null && HAS_MACPORTS=1 which brew >/dev/null && HAS_HOMEBREW=1 +MACPORTS_PATH=$(dirname "$(which port)") +HOMEBREW_PATH="$(brew --prefix)/bin" + if [[ $1 == "apple" || $1 == "darwin" || $1 == "system" ]]; then if ((HAS_MACPORTS)); then - cd /opt/local/bin + cd $MACPORTS_PATH sudo rm -f gcc g++ cc ld cd - fi if ((HAS_HOMEBREW)); then - cd /opt/homebrew/bin + cd $HOMEBREW_PATH sudo rm -f gcc g++ cc cd - fi @@ -28,7 +31,7 @@ elif [[ $1 =~ ".*ports" ]]; then ((HAS_MACPORTS)) || { echo "MacPorts is not installed"; exit 1; } - GCCV=$( find /opt/local/bin -name "gcc-mp-*" | sort -r | head -1 | sed 's/.*gcc-mp-//' ) + GCCV=$( find $MACPORTS_PATH -name "gcc-mp-*" | sort -r | head -1 | sed 's/.*gcc-mp-//' ) [[ $GCCV -ge 11 ]] || GCCV=14 getport() { port installed $1 | grep $1 || sudo port install $1; } @@ -36,7 +39,7 @@ elif [[ $1 =~ ".*ports" ]]; then getports "gcc$GCCV" glm mesa libsdl2 libsdl2_net - cd /opt/local/bin + cd $MACPORTS_PATH sudo rm -f gcc g++ cc ld sudo ln -s "gcc-mp-$GCCV" gcc sudo ln -s "g++-mp-$GCCV" g++ @@ -48,12 +51,12 @@ elif [[ $1 =~ ".*brew" ]]; then ((HAS_HOMEBREW)) || { echo "Homebrew is not installed"; exit 1; } - GCCV=$( find /opt/homebrew/bin -name "gcc-*" | sort -r | head -1 | sed 's/.*gcc-//' ) + GCCV=$( find $HOMEBREW_PATH -name "gcc-*" | sort -r | head -1 | sed 's/.*gcc-//' ) [[ $GCCV -ge 11 ]] || { brew install gcc@14 ; GCCV=14 } brew install glm mesa sdl2 sdl2_net - cd /opt/homebrew/bin + cd $HOMEBREW_PATH sudo rm -f gcc g++ cc sudo ln -s "gcc-$GCCV" gcc sudo ln -s "g++-$GCCV" g++ diff --git a/ini/native.ini b/ini/native.ini index c93ad7e6fa..479155a78c 100644 --- a/ini/native.ini +++ b/ini/native.ini @@ -89,7 +89,7 @@ build_flags = ${simulator_linux.build_flags} ${simulator_linux.release_flags} # # sudo port install gcc14 glm mesa libsdl2 libsdl2_net # -# cd /opt/local/bin +# cd $(dirname "$(which port)") # sudo rm gcc g++ cc ld # sudo ln -s gcc-mp-14 gcc ; sudo ln -s g++-mp-14 g++ ; sudo ln -s g++ cc # sudo ln -s ld-classic ld @@ -103,7 +103,7 @@ build_flags = ${simulator_linux.build_flags} ${simulator_linux.release_flags} # # brew install gcc@14 glm mesa sdl2 sdl2_net # -# cd /opt/homebrew/bin +# cd "$(brew --prefix)/bin" # sudo rm -f gcc g++ cc # sudo ln -s gcc-14 gcc ; sudo ln -s g++-14 g++ ; sudo ln -s g++ cc # cd - From 0518737119546b2e6d1b03a5d5d2db7354851467 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Sun, 16 Feb 2025 00:30:26 +0000 Subject: [PATCH 078/787] [cron] Bump distribution date (2025-02-16) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 70f60478d5..f95a987362 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-02-04" +//#define STRING_DISTRIBUTION_DATE "2025-02-16" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 57c8327e8e..c7538b5cde 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-02-04" + #define STRING_DISTRIBUTION_DATE "2025-02-16" #endif /** From 89def456e8b567ccb6f3c1aeb6c152151e3ebbdb Mon Sep 17 00:00:00 2001 From: Luc <8822552+luc-github@users.noreply.github.com> Date: Wed, 19 Feb 2025 09:33:54 +0800 Subject: [PATCH 079/787] =?UTF-8?q?=F0=9F=94=A8=20Fix=20pioarduino=20path?= =?UTF-8?q?=20check=20for=20xtensa-esp32=20(#27693)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- buildroot/share/PlatformIO/scripts/preprocessor.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/buildroot/share/PlatformIO/scripts/preprocessor.py b/buildroot/share/PlatformIO/scripts/preprocessor.py index 4f24458d96..efc3a6261e 100644 --- a/buildroot/share/PlatformIO/scripts/preprocessor.py +++ b/buildroot/share/PlatformIO/scripts/preprocessor.py @@ -87,8 +87,8 @@ def search_compiler(env): # Use any item in $PATH corresponding to a platformio toolchain bin folder if ppath.match(env['PROJECT_PACKAGES_DIR'] + "/**/bin"): for gpath in ppath.glob(gcc_exe): - # Skip '*-elf-g++' (crosstool-NG) except for xtensa32 - if not gpath.stem.endswith('-elf-g++') or "xtensa32" in str(gpath): + # Skip '*-elf-g++' (crosstool-NG) except for xtensa32/xtensa-esp32 + if not gpath.stem.endswith('-elf-g++') or "xtensa" in str(gpath): gccpath = str(gpath.resolve()) break From 86c1fde309da0e11a0b00c48411f2cc9643561bf Mon Sep 17 00:00:00 2001 From: narno2202 <130909513+narno2202@users.noreply.github.com> Date: Wed, 19 Feb 2025 02:38:28 +0100 Subject: [PATCH 080/787] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20Always=20"optimize?= =?UTF-8?q?"=20FT=20Motion=20DIR=20states=20(#27692)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/module/stepper.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp index 5083c0a4d2..69c6f66fbc 100644 --- a/Marlin/src/module/stepper.cpp +++ b/Marlin/src/module/stepper.cpp @@ -651,7 +651,7 @@ void Stepper::disable_all_steppers() { TERN_(EXTENSIBLE_UI, ExtUI::onSteppersDisabled()); } -#if ENABLED(FTM_OPTIMIZE_DIR_STATES) +#if ENABLED(FT_MOTION) // We'll compare the updated DIR bits to the last set state static AxisBits last_set_direction; #endif @@ -681,7 +681,7 @@ void Stepper::apply_directions() { SET_STEP_DIR(U), SET_STEP_DIR(V), SET_STEP_DIR(W) ); - TERN_(FTM_OPTIMIZE_DIR_STATES, last_set_direction = last_direction_bits); + TERN_(FT_MOTION, last_set_direction = last_direction_bits); DIR_WAIT_AFTER(); } @@ -1836,7 +1836,7 @@ void Stepper::pulse_phase_isr() { last_direction_bits.toggle(_AXIS(AXIS)); \ DIR_WAIT_BEFORE(); \ SET_STEP_DIR(AXIS); \ - TERN_(FTM_OPTIMIZE_DIR_STATES, last_set_direction = last_direction_bits); \ + TERN_(FT_MOTION, last_set_direction = last_direction_bits); \ DIR_WAIT_AFTER(); \ } \ } \ @@ -2538,7 +2538,7 @@ hal_timer_t Stepper::block_phase_isr() { E_APPLY_DIR(forward_e, false); - TERN_(FTM_OPTIMIZE_DIR_STATES, last_set_direction = last_direction_bits); + TERN_(FT_MOTION, last_set_direction = last_direction_bits); DIR_WAIT_AFTER(); } @@ -3548,13 +3548,13 @@ void Stepper::report_positions() { #define _FTM_SET_DIR(AXIS) if (_FTM_STEP(AXIS)) last_direction_bits.bset(_AXIS(AXIS), _FTM_DIR(AXIS)); LOGICAL_AXIS_MAP(_FTM_SET_DIR); - if (TERN1(FTM_OPTIMIZE_DIR_STATES, last_set_direction != last_direction_bits)) { + if (last_set_direction != last_direction_bits) { // Apply directions (generally applying to the entire linear move) - #define _FTM_APPLY_DIR(A) if (TERN1(FTM_OPTIMIZE_DIR_STATES, last_direction_bits.A != last_set_direction.A)) \ + #define _FTM_APPLY_DIR(A) if (last_direction_bits.A != last_set_direction.A) \ SET_STEP_DIR(A); LOGICAL_AXIS_MAP(_FTM_APPLY_DIR); - TERN_(FTM_OPTIMIZE_DIR_STATES, last_set_direction = last_direction_bits); + last_set_direction = last_direction_bits; // Any DIR change requires a wait period DIR_WAIT_AFTER(); From c3a4ef77af29048c8febd8399b6d81f9d0087257 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Wed, 19 Feb 2025 06:08:42 +0000 Subject: [PATCH 081/787] [cron] Bump distribution date (2025-02-19) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index f95a987362..707bb7c36e 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-02-16" +//#define STRING_DISTRIBUTION_DATE "2025-02-19" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index c7538b5cde..78588d279a 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-02-16" + #define STRING_DISTRIBUTION_DATE "2025-02-19" #endif /** From b7485062300e0839582611bb7c82c0f1a0d73ee2 Mon Sep 17 00:00:00 2001 From: Farva42 <100859196+Farva42@users.noreply.github.com> Date: Wed, 19 Feb 2025 11:45:40 -0700 Subject: [PATCH 082/787] =?UTF-8?q?=F0=9F=A9=B9=20Fix=20MKS=20boards=20run?= =?UTF-8?q?out=20sensor=20pins=20(#27687)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Followup to #27640 --- Marlin/src/pins/stm32f1/pins_FLSUN_HISPEED.h | 18 ++++++------- .../src/pins/stm32f1/pins_MKS_ROBIN_NANO_V2.h | 22 +++++++-------- .../pins/stm32f1/pins_MKS_ROBIN_NANO_common.h | 27 +++++++++---------- .../stm32f4/pins_MKS_ROBIN_NANO_V3_common.h | 18 ++++++------- 4 files changed, 38 insertions(+), 47 deletions(-) diff --git a/Marlin/src/pins/stm32f1/pins_FLSUN_HISPEED.h b/Marlin/src/pins/stm32f1/pins_FLSUN_HISPEED.h index 88a91397d4..5e0e997a0c 100644 --- a/Marlin/src/pins/stm32f1/pins_FLSUN_HISPEED.h +++ b/Marlin/src/pins/stm32f1/pins_FLSUN_HISPEED.h @@ -220,16 +220,14 @@ //#define PS_ON_PIN PA3 // PW_CN /PW_OFF #endif -#if HAS_TFT_LVGL_UI - #ifndef FIL_RUNOUT_PIN - #define FIL_RUNOUT_PIN PA4 // MT_DET_1 - #endif - #ifndef FIL_RUNOUT2_PIN - #define FIL_RUNOUT2_PIN PE6 // MT_DET_2 - #endif - #ifndef FIL_RUNOUT_STATE - #define FIL_RUNOUT_STATE LOW - #endif +#ifndef FIL_RUNOUT_PIN + #define FIL_RUNOUT_PIN PA4 // MT_DET_1 +#endif +#ifndef FIL_RUNOUT2_PIN + #define FIL_RUNOUT2_PIN PE6 // MT_DET_2 +#endif +#ifndef FIL_RUNOUT_STATE + #define FIL_RUNOUT_STATE LOW #endif // diff --git a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_NANO_V2.h b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_NANO_V2.h index 2a2a42a4d4..14cc4c1eb3 100644 --- a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_NANO_V2.h +++ b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_NANO_V2.h @@ -210,17 +210,17 @@ // // Misc. Functions // -#if HAS_TFT_LVGL_UI - #ifndef FIL_RUNOUT_PIN - #define FIL_RUNOUT_PIN PA4 // MT_DET_1 - #endif - #ifndef FIL_RUNOUT2_PIN - #define FIL_RUNOUT2_PIN PE6 // MT_DET_2 - #endif - #ifndef FIL_RUNOUT_STATE - #define FIL_RUNOUT_STATE LOW - #endif +#ifndef FIL_RUNOUT_PIN + #define FIL_RUNOUT_PIN PA4 // MT_DET_1 +#endif +#ifndef FIL_RUNOUT2_PIN + #define FIL_RUNOUT2_PIN PE6 // MT_DET_2 +#endif +#ifndef FIL_RUNOUT_STATE + #define FIL_RUNOUT_STATE LOW +#endif +#if HAS_TFT_LVGL_UI #define WIFI_IO0_PIN PC13 #define WIFI_IO1_PIN PC7 #define WIFI_RESET_PIN PE9 @@ -236,8 +236,6 @@ #else //#define POWER_LOSS_PIN PA2 // PW_DET //#define PS_ON_PIN PB2 // PW_OFF - #define FIL_RUNOUT_PIN PA4 - #define FIL_RUNOUT2_PIN PE6 #endif //#define LED_PIN PB2 diff --git a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_NANO_common.h b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_NANO_common.h index 526109589f..db75ad03ed 100644 --- a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_NANO_common.h +++ b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_NANO_common.h @@ -148,25 +148,22 @@ // // Misc. Functions // -#if HAS_TFT_LVGL_UI - #ifndef FIL_RUNOUT_PIN - #define FIL_RUNOUT_PIN PA4 // MT_DET_1 - #endif - #ifndef FIL_RUNOUT2_PIN - #define FIL_RUNOUT2_PIN PE6 // MT_DET_2 - #endif - #ifndef FIL_RUNOUT_STATE - #define FIL_RUNOUT_STATE LOW - #endif +#ifndef FIL_RUNOUT_PIN + #define FIL_RUNOUT_PIN PA4 // MT_DET_1 +#endif +#ifndef FIL_RUNOUT2_PIN + #define FIL_RUNOUT2_PIN PE6 // MT_DET_2 +#endif +#ifndef FIL_RUNOUT_STATE + #define FIL_RUNOUT_STATE LOW +#endif + //#define POWER_LOSS_PIN PA2 // PW_DET + //#define PS_ON_PIN PB2 // PW_OFF +#if HAS_TFT_LVGL_UI #define WIFI_IO0_PIN PC13 #define WIFI_IO1_PIN PC7 #define WIFI_RESET_PIN PA5 -#else - //#define POWER_LOSS_PIN PA2 // PW_DET - //#define PS_ON_PIN PB2 // PW_OFF - #define FIL_RUNOUT_PIN PA4 - #define FIL_RUNOUT2_PIN PE6 #endif // diff --git a/Marlin/src/pins/stm32f4/pins_MKS_ROBIN_NANO_V3_common.h b/Marlin/src/pins/stm32f4/pins_MKS_ROBIN_NANO_V3_common.h index 2db766ccc0..72e96c137e 100644 --- a/Marlin/src/pins/stm32f4/pins_MKS_ROBIN_NANO_V3_common.h +++ b/Marlin/src/pins/stm32f4/pins_MKS_ROBIN_NANO_V3_common.h @@ -146,16 +146,14 @@ // // Misc. Functions // -#if HAS_TFT_LVGL_UI - #ifndef FIL_RUNOUT_PIN - #define FIL_RUNOUT_PIN PA4 // MT_DET_1 - #endif - #ifndef FIL_RUNOUT2_PIN - #define FIL_RUNOUT2_PIN PE6 // MT_DET_2 - #endif - #ifndef FIL_RUNOUT_STATE - #define FIL_RUNOUT_STATE LOW - #endif +#ifndef FIL_RUNOUT_PIN + #define FIL_RUNOUT_PIN PA4 // MT_DET_1 +#endif +#ifndef FIL_RUNOUT2_PIN + #define FIL_RUNOUT2_PIN PE6 // MT_DET_2 +#endif +#ifndef FIL_RUNOUT_STATE + #define FIL_RUNOUT_STATE LOW #endif #ifndef POWER_LOSS_PIN From 2cc35a9ad18f83a5d3aca6abf1d03e269bc78208 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Wed, 19 Feb 2025 15:36:51 -0600 Subject: [PATCH 083/787] =?UTF-8?q?=F0=9F=8E=A8=20Wrap=20BABYSTEP=5FSIZE?= =?UTF-8?q?=5F*?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/module/planner.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Marlin/src/module/planner.h b/Marlin/src/module/planner.h index 64381350cc..53717ca0a7 100644 --- a/Marlin/src/module/planner.h +++ b/Marlin/src/module/planner.h @@ -92,9 +92,9 @@ #define BABYSTEP_SIZE_Y int32_t((BABYSTEP_MULTIPLICATOR_XY) * planner.settings.axis_steps_per_mm[Y_AXIS]) #define BABYSTEP_SIZE_Z int32_t((BABYSTEP_MULTIPLICATOR_Z) * planner.settings.axis_steps_per_mm[Z_AXIS]) #else - #define BABYSTEP_SIZE_X BABYSTEP_MULTIPLICATOR_XY - #define BABYSTEP_SIZE_Y BABYSTEP_MULTIPLICATOR_XY - #define BABYSTEP_SIZE_Z BABYSTEP_MULTIPLICATOR_Z + #define BABYSTEP_SIZE_X (BABYSTEP_MULTIPLICATOR_XY) + #define BABYSTEP_SIZE_Y (BABYSTEP_MULTIPLICATOR_XY) + #define BABYSTEP_SIZE_Z (BABYSTEP_MULTIPLICATOR_Z) #endif #endif From efba06c4ce4253a42318da62dc696e8d64e21206 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Thu, 20 Feb 2025 00:28:00 +0000 Subject: [PATCH 084/787] [cron] Bump distribution date (2025-02-20) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 707bb7c36e..1016d1abec 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-02-19" +//#define STRING_DISTRIBUTION_DATE "2025-02-20" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 78588d279a..43fe20701d 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-02-19" + #define STRING_DISTRIBUTION_DATE "2025-02-20" #endif /** From 072b90d105ef2c819cbc83b6941f0e78c7862863 Mon Sep 17 00:00:00 2001 From: Keith Bennett <13375512+thisiskeithb@users.noreply.github.com> Date: Fri, 28 Feb 2025 18:57:40 -0800 Subject: [PATCH 085/787] =?UTF-8?q?=F0=9F=92=9A=20Fix=20Simulator=20CI=20b?= =?UTF-8?q?uild=20(#27712)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci-build-tests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci-build-tests.yml b/.github/workflows/ci-build-tests.yml index afe9292c19..3dabf82f46 100644 --- a/.github/workflows/ci-build-tests.yml +++ b/.github/workflows/ci-build-tests.yml @@ -188,6 +188,7 @@ jobs: - name: Install Simulator dependencies run: | + sudo apt-get update sudo apt-get install build-essential sudo apt-get install libsdl2-dev sudo apt-get install libsdl2-net-dev From 142177426ba53cac17c9935d9f47d7ccf265b984 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Sat, 1 Mar 2025 06:07:59 +0000 Subject: [PATCH 086/787] [cron] Bump distribution date (2025-03-01) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 1016d1abec..fb330132f6 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-02-20" +//#define STRING_DISTRIBUTION_DATE "2025-03-01" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 43fe20701d..bc1615febe 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-02-20" + #define STRING_DISTRIBUTION_DATE "2025-03-01" #endif /** From dd3bf2995b42c9040ead3d976493297b519ddf52 Mon Sep 17 00:00:00 2001 From: Farva42 <100859196+Farva42@users.noreply.github.com> Date: Fri, 28 Feb 2025 23:26:56 -0700 Subject: [PATCH 087/787] =?UTF-8?q?=F0=9F=94=A7=20Static=20assert=20Dual?= =?UTF-8?q?=20X=20min/max=20(#27701)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/inc/SanityCheck.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index a11965a01c..76b9c136d0 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -1933,8 +1933,9 @@ static_assert(NUM_SERVOS <= NUM_SERVO_PLUGS, "NUM_SERVOS (or some servo index) i #error "DUAL_X_CARRIAGE requires X2_HOME_POS, X2_MIN_POS, and X2_MAX_POS." #elif X_HOME_TO_MAX #error "DUAL_X_CARRIAGE requires X_HOME_DIR -1." - #elif (X2_HOME_POS <= X1_MAX_POS) || (X2_MAX_POS < X1_MAX_POS) - #error "DUAL_X_CARRIAGE will crash if X1 can meet or exceed X2 travel." + #else + static_assert((X2_HOME_POS) > (X1_MAX_POS), "X2_HOME_POS must be greater than X1_MAX_POS (i.e., X_BED_SIZE)."); + static_assert((X2_MIN_POS) > (X1_MIN_POS), "X2_MIN_POS must be greater than X1_MIN_POS (i.e., X_MIN_POS)."); #endif #endif From 147dcaf600c57abdbf6ca52178ebed6bfc15e39b Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sat, 1 Mar 2025 00:28:04 -0600 Subject: [PATCH 088/787] =?UTF-8?q?=F0=9F=93=9D=20Update=20MAX31865=20comm?= =?UTF-8?q?ent?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/Configuration.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 14d1cfb168..77a9176115 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -586,7 +586,7 @@ #define DUMMY_THERMISTOR_998_VALUE 25 #define DUMMY_THERMISTOR_999_VALUE 100 -// Resistor values when using MAX31865 sensors (-5) on TEMP_SENSOR_0 / 1 +// Resistor values when using MAX31865 sensors (-5) on TEMP_SENSOR_0 / 1 / 2 / BED #if TEMP_SENSOR_IS_MAX_TC(0) #define MAX31865_SENSOR_OHMS_0 100 // (Ω) Typically 100 or 1000 (PT100 or PT1000) #define MAX31865_CALIBRATION_OHMS_0 430 // (Ω) Typically 430 for Adafruit PT100; 4300 for Adafruit PT1000 From e787c8f26b8110486e9f1cba6d61957dde7cbbfd Mon Sep 17 00:00:00 2001 From: ellensp <530024+ellensp@users.noreply.github.com> Date: Sun, 2 Mar 2025 10:00:28 +1300 Subject: [PATCH 089/787] =?UTF-8?q?=F0=9F=9A=B8=20Fix=20extra=20echo:=20in?= =?UTF-8?q?=20M218=20report=20(#27674)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/gcode/config/M218.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/src/gcode/config/M218.cpp b/Marlin/src/gcode/config/M218.cpp index 006f9a1d2c..7d167e502d 100644 --- a/Marlin/src/gcode/config/M218.cpp +++ b/Marlin/src/gcode/config/M218.cpp @@ -65,7 +65,7 @@ void GcodeSuite::M218() { void GcodeSuite::M218_report(const bool forReplay/*=true*/) { TERN_(MARLIN_SMALL_BUILD, return); - report_heading_etc(forReplay, F(STR_HOTEND_OFFSETS)); + report_heading(forReplay, F(STR_HOTEND_OFFSETS)); for (uint8_t e = 1; e < HOTENDS; ++e) { report_echo_start(forReplay); SERIAL_ECHOLNPGM_P( From 73a0f3376750c30488cdb63fb97e276f4988dc0f Mon Sep 17 00:00:00 2001 From: ellensp <530024+ellensp@users.noreply.github.com> Date: Sun, 2 Mar 2025 12:45:31 +1300 Subject: [PATCH 090/787] =?UTF-8?q?=E2=9C=A8=20BUILD=5FINFO=5FMENU=5FITEM?= =?UTF-8?q?=20(#27590)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/Configuration_adv.h | 1 + Marlin/src/lcd/language/language_en.h | 2 +- Marlin/src/lcd/menu/menu_info.cpp | 16 ++++++++++++++++ buildroot/tests/teensy41 | 2 +- 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index a1e5443129..6e64112786 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -1551,6 +1551,7 @@ //#define LCD_INFO_MENU #if ENABLED(LCD_INFO_MENU) //#define LCD_PRINTER_INFO_IS_BOOTSCREEN // Show bootscreen(s) instead of Printer Info pages + //#define BUILD_INFO_MENU_ITEM // Add a menu item to display the build date and time #endif /** diff --git a/Marlin/src/lcd/language/language_en.h b/Marlin/src/lcd/language/language_en.h index bab95d2b86..3575e40bea 100644 --- a/Marlin/src/lcd/language/language_en.h +++ b/Marlin/src/lcd/language/language_en.h @@ -511,7 +511,7 @@ namespace LanguageNarrow_en { LSTR MSG_INFO_MACHINENAME = _UxGT("Machine Name"); LSTR MSG_INFO_SIZE = _UxGT("Size"); LSTR MSG_INFO_FWVERSION = _UxGT("Firmware Version"); - LSTR MSG_INFO_BUILD = _UxGT("Build Datetime"); + LSTR MSG_INFO_BUILD = _UxGT("Build Info"); LSTR MSG_PREPARE = _UxGT("Prepare"); LSTR MSG_TUNE = _UxGT("Tune"); LSTR MSG_POWER_MONITOR = _UxGT("Power monitor"); diff --git a/Marlin/src/lcd/menu/menu_info.cpp b/Marlin/src/lcd/menu/menu_info.cpp index 2db0caa805..1df70ba802 100644 --- a/Marlin/src/lcd/menu/menu_info.cpp +++ b/Marlin/src/lcd/menu/menu_info.cpp @@ -263,6 +263,18 @@ void menu_info_board() { #endif +// +// "Build Info" submenu +// +#if ENABLED(BUILD_INFO_MENU_ITEM) + void menu_info_build() { + if (ui.use_click()) return ui.go_back(); + START_SCREEN(); + STATIC_ITEM_F(F(__DATE__ " " __TIME__)); // YYYY-MM-DD HH:MM + END_SCREEN(); + } +#endif + // // "About Printer" submenu // @@ -306,6 +318,10 @@ void menu_info() { } #endif + #if ENABLED(BUILD_INFO_MENU_ITEM) + SUBMENU(MSG_INFO_BUILD, menu_info_build); // Build Info > + #endif + END_MENU(); } diff --git a/buildroot/tests/teensy41 b/buildroot/tests/teensy41 index 6cf3f4aba3..f66a9272ea 100755 --- a/buildroot/tests/teensy41 +++ b/buildroot/tests/teensy41 @@ -21,7 +21,7 @@ opt_set MOTHERBOARD BOARD_TEENSY41 \ NOZZLE_CLEAN_START_POINT "{ { 10, 10, 3 }, { 10, 10, 3 } }" \ NOZZLE_CLEAN_END_POINT "{ { 10, 20, 3 }, { 10, 20, 3 } }" opt_enable MAX31865_SENSOR_OHMS_0 MAX31865_CALIBRATION_OHMS_0 \ - EXTENSIBLE_UI LCD_INFO_MENU SDSUPPORT SDCARD_SORT_ALPHA \ + EXTENSIBLE_UI LCD_INFO_MENU BUILD_INFO_MENU_ITEM SDSUPPORT SDCARD_SORT_ALPHA \ FILAMENT_LCD_DISPLAY CALIBRATION_GCODE BAUD_RATE_GCODE \ FIX_MOUNTED_PROBE Z_SAFE_HOMING AUTO_BED_LEVELING_BILINEAR Z_MIN_PROBE_REPEATABILITY_TEST DEBUG_LEVELING_FEATURE \ BABYSTEPPING BABYSTEP_XY BABYSTEP_ZPROBE_OFFSET \ From e676d833a3668cdc6548315ae21bed167f79e4b8 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Sun, 2 Mar 2025 00:30:52 +0000 Subject: [PATCH 091/787] [cron] Bump distribution date (2025-03-02) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index fb330132f6..1efacafd64 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-03-01" +//#define STRING_DISTRIBUTION_DATE "2025-03-02" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index bc1615febe..53d34487fa 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-03-01" + #define STRING_DISTRIBUTION_DATE "2025-03-02" #endif /** From 05a46084b6ca0da82a36e09c51da9976991b4d22 Mon Sep 17 00:00:00 2001 From: Fly3DTeam Date: Wed, 5 Mar 2025 11:08:04 +0800 Subject: [PATCH 092/787] =?UTF-8?q?=E2=9C=A8=20FLY=5FD5,=20FLY=5FDP5,=20FL?= =?UTF-8?q?Y=5FD7,=20FLY=5FD8,=20FLY=5FD8=5FPRO,=20FLY=5FSUPER8=5FPRO,=20F?= =?UTF-8?q?LY=5FCDY=5FV3=20(#27580)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/core/boards.h | 169 +++-- Marlin/src/pins/pins.h | 16 + Marlin/src/pins/stm32f0/pins_FLY_D5.h | 192 +++++ Marlin/src/pins/stm32f0/pins_FLY_D7.h | 155 ++++ Marlin/src/pins/stm32f0/pins_FLY_DP5.h | 199 +++++ Marlin/src/pins/stm32f4/pins_FLY_CDY_V3.h | 315 ++++++++ Marlin/src/pins/stm32f4/pins_FLY_D8.h | 336 +++++++++ Marlin/src/pins/stm32f4/pins_FLY_RRF_E3_V1.h | 5 + Marlin/src/pins/stm32f4/pins_FLY_SUPER8.h | 346 +++++++++ Marlin/src/pins/stm32h7/pins_FLY_D8_PRO.h | 336 +++++++++ Marlin/src/pins/stm32h7/pins_FLY_SUPER8_PRO.h | 352 +++++++++ .../PlatformIO/boards/marlin_stm32F072.json | 48 ++ .../MARLIN_FLY_CDY_V3/PeripheralPins.c | 394 ++++++++++ .../variants/MARLIN_FLY_CDY_V3/PinNamesVar.h | 50 ++ .../MARLIN_FLY_CDY_V3/hal_conf_extra.h | 594 +++++++++++++++ .../variants/MARLIN_FLY_CDY_V3/ldscript.ld | 203 ++++++ .../variants/MARLIN_FLY_CDY_V3/variant.cpp | 275 +++++++ .../variants/MARLIN_FLY_CDY_V3/variant.h | 187 +++++ .../variants/MARLIN_FLY_D5/PeripheralPins.c | 271 +++++++ .../variants/MARLIN_FLY_D5/PinNamesVar.h | 49 ++ .../variants/MARLIN_FLY_D5/ldscript.ld | 177 +++++ .../variant_MARLIN_STM32F072.cpp | 137 ++++ .../MARLIN_FLY_D5/variant_MARLIN_STM32F072.h | 160 ++++ .../variants/MARLIN_FLY_D7/PeripheralPins.c | 271 +++++++ .../variants/MARLIN_FLY_D7/PinNamesVar.h | 49 ++ .../variants/MARLIN_FLY_D7/ldscript.ld | 177 +++++ .../variant_MARLIN_STM32F072.cpp | 137 ++++ .../MARLIN_FLY_D7/variant_MARLIN_STM32F072.h | 160 ++++ .../variants/MARLIN_FLY_D8/PeripheralPins.c | 394 ++++++++++ .../variants/MARLIN_FLY_D8/PinNamesVar.h | 50 ++ .../variants/MARLIN_FLY_D8/ldscript.ld | 203 ++++++ .../variants/MARLIN_FLY_D8/variant.cpp | 275 +++++++ .../variants/MARLIN_FLY_D8/variant.h | 184 +++++ .../MARLIN_FLY_D8_PRO/PeripheralPins.c | 590 +++++++++++++++ .../variants/MARLIN_FLY_D8_PRO/PinNamesVar.h | 108 +++ .../variants/MARLIN_FLY_D8_PRO/ldscript.ld | 174 +++++ .../variant_MARLIN_STM32H723VG.cpp | 273 +++++++ .../variant_MARLIN_STM32H723VG.h | 234 ++++++ .../MARLIN_FLY_F407ZG/PeripheralPins.c | 18 + .../MARLIN_FLY_SUPER8/PeripheralPins.c | 422 +++++++++++ .../variants/MARLIN_FLY_SUPER8/PinNamesVar.h | 50 ++ .../MARLIN_FLY_SUPER8/hal_conf_extra.h | 87 +++ .../variants/MARLIN_FLY_SUPER8/ldscript.ld | 207 ++++++ .../variants/MARLIN_FLY_SUPER8/variant.cpp | 212 ++++++ .../variants/MARLIN_FLY_SUPER8/variant.h | 233 ++++++ .../MARLIN_FLY_SUPER8_PRO/PeripheralPins.c | 688 ++++++++++++++++++ .../MARLIN_FLY_SUPER8_PRO/PinNamesVar.h | 117 +++ .../MARLIN_FLY_SUPER8_PRO/ldscript.ld | 174 +++++ .../variant_MARLIN_STM32H723ZG.cpp | 317 ++++++++ .../variant_MARLIN_STM32H723ZG.h | 273 +++++++ ini/stm32f0.ini | 30 + ini/stm32f1.ini | 4 +- ini/stm32f4.ini | 34 + ini/stm32h7.ini | 35 + 54 files changed, 11066 insertions(+), 80 deletions(-) create mode 100644 Marlin/src/pins/stm32f0/pins_FLY_D5.h create mode 100644 Marlin/src/pins/stm32f0/pins_FLY_D7.h create mode 100644 Marlin/src/pins/stm32f0/pins_FLY_DP5.h create mode 100644 Marlin/src/pins/stm32f4/pins_FLY_CDY_V3.h create mode 100644 Marlin/src/pins/stm32f4/pins_FLY_D8.h create mode 100644 Marlin/src/pins/stm32f4/pins_FLY_SUPER8.h create mode 100644 Marlin/src/pins/stm32h7/pins_FLY_D8_PRO.h create mode 100644 Marlin/src/pins/stm32h7/pins_FLY_SUPER8_PRO.h create mode 100644 buildroot/share/PlatformIO/boards/marlin_stm32F072.json create mode 100644 buildroot/share/PlatformIO/variants/MARLIN_FLY_CDY_V3/PeripheralPins.c create mode 100644 buildroot/share/PlatformIO/variants/MARLIN_FLY_CDY_V3/PinNamesVar.h create mode 100644 buildroot/share/PlatformIO/variants/MARLIN_FLY_CDY_V3/hal_conf_extra.h create mode 100644 buildroot/share/PlatformIO/variants/MARLIN_FLY_CDY_V3/ldscript.ld create mode 100644 buildroot/share/PlatformIO/variants/MARLIN_FLY_CDY_V3/variant.cpp create mode 100644 buildroot/share/PlatformIO/variants/MARLIN_FLY_CDY_V3/variant.h create mode 100644 buildroot/share/PlatformIO/variants/MARLIN_FLY_D5/PeripheralPins.c create mode 100644 buildroot/share/PlatformIO/variants/MARLIN_FLY_D5/PinNamesVar.h create mode 100644 buildroot/share/PlatformIO/variants/MARLIN_FLY_D5/ldscript.ld create mode 100644 buildroot/share/PlatformIO/variants/MARLIN_FLY_D5/variant_MARLIN_STM32F072.cpp create mode 100644 buildroot/share/PlatformIO/variants/MARLIN_FLY_D5/variant_MARLIN_STM32F072.h create mode 100644 buildroot/share/PlatformIO/variants/MARLIN_FLY_D7/PeripheralPins.c create mode 100644 buildroot/share/PlatformIO/variants/MARLIN_FLY_D7/PinNamesVar.h create mode 100644 buildroot/share/PlatformIO/variants/MARLIN_FLY_D7/ldscript.ld create mode 100644 buildroot/share/PlatformIO/variants/MARLIN_FLY_D7/variant_MARLIN_STM32F072.cpp create mode 100644 buildroot/share/PlatformIO/variants/MARLIN_FLY_D7/variant_MARLIN_STM32F072.h create mode 100644 buildroot/share/PlatformIO/variants/MARLIN_FLY_D8/PeripheralPins.c create mode 100644 buildroot/share/PlatformIO/variants/MARLIN_FLY_D8/PinNamesVar.h create mode 100644 buildroot/share/PlatformIO/variants/MARLIN_FLY_D8/ldscript.ld create mode 100644 buildroot/share/PlatformIO/variants/MARLIN_FLY_D8/variant.cpp create mode 100644 buildroot/share/PlatformIO/variants/MARLIN_FLY_D8/variant.h create mode 100644 buildroot/share/PlatformIO/variants/MARLIN_FLY_D8_PRO/PeripheralPins.c create mode 100644 buildroot/share/PlatformIO/variants/MARLIN_FLY_D8_PRO/PinNamesVar.h create mode 100644 buildroot/share/PlatformIO/variants/MARLIN_FLY_D8_PRO/ldscript.ld create mode 100644 buildroot/share/PlatformIO/variants/MARLIN_FLY_D8_PRO/variant_MARLIN_STM32H723VG.cpp create mode 100644 buildroot/share/PlatformIO/variants/MARLIN_FLY_D8_PRO/variant_MARLIN_STM32H723VG.h create mode 100644 buildroot/share/PlatformIO/variants/MARLIN_FLY_SUPER8/PeripheralPins.c create mode 100644 buildroot/share/PlatformIO/variants/MARLIN_FLY_SUPER8/PinNamesVar.h create mode 100644 buildroot/share/PlatformIO/variants/MARLIN_FLY_SUPER8/hal_conf_extra.h create mode 100644 buildroot/share/PlatformIO/variants/MARLIN_FLY_SUPER8/ldscript.ld create mode 100644 buildroot/share/PlatformIO/variants/MARLIN_FLY_SUPER8/variant.cpp create mode 100644 buildroot/share/PlatformIO/variants/MARLIN_FLY_SUPER8/variant.h create mode 100644 buildroot/share/PlatformIO/variants/MARLIN_FLY_SUPER8_PRO/PeripheralPins.c create mode 100644 buildroot/share/PlatformIO/variants/MARLIN_FLY_SUPER8_PRO/PinNamesVar.h create mode 100644 buildroot/share/PlatformIO/variants/MARLIN_FLY_SUPER8_PRO/ldscript.ld create mode 100644 buildroot/share/PlatformIO/variants/MARLIN_FLY_SUPER8_PRO/variant_MARLIN_STM32H723ZG.cpp create mode 100644 buildroot/share/PlatformIO/variants/MARLIN_FLY_SUPER8_PRO/variant_MARLIN_STM32H723ZG.h diff --git a/Marlin/src/core/boards.h b/Marlin/src/core/boards.h index a0e0a29151..c6713d0c98 100644 --- a/Marlin/src/core/boards.h +++ b/Marlin/src/core/boards.h @@ -318,7 +318,7 @@ #define BOARD_ADSK 3101 // Arduino DUE Shield Kit (ADSK) // -// STM32 ARM Cortex-M0+ +// STM32 ARM Cortex-M0/+ // #define BOARD_BTT_EBB42_V1_1 4000 // BigTreeTech EBB42 V1.1 (STM32G0B1CB) @@ -330,83 +330,91 @@ #define BOARD_BTT_MANTA_M8P_V1_1 4006 // BigTreeTech Manta M8P V1.1 (STM32G0B1VE) #define BOARD_BTT_SKRAT_V1_0 4007 // BigTreeTech SKRat V1.0 (STM32G0B1VE) +// +// STM32 ARM Cortex-M0 +// + +#define BOARD_MALYAN_M200_V2 4100 // STM32F070CB controller +#define BOARD_MALYAN_M300 4101 // STM32F070-based delta +#define BOARD_FLY_D5 4102 // FLY_D5 (STM32F072RB) +#define BOARD_FLY_DP5 4103 // FLY_DP5 (STM32F072RB) +#define BOARD_FLY_D7 4104 // FLY_D7 (STM32F072RB) + // // STM32 ARM Cortex-M3 // -#define BOARD_MALYAN_M200_V2 5000 // STM32F070CB controller -#define BOARD_MALYAN_M300 5001 // STM32F070-based delta -#define BOARD_STM32F103RE 5002 // STM32F103RE Libmaple-based STM32F1 controller -#define BOARD_MALYAN_M200 5003 // STM32C8 Libmaple-based STM32F1 controller -#define BOARD_STM3R_MINI 5004 // STM32F103RE Libmaple-based STM32F1 controller -#define BOARD_GTM32_PRO_VB 5005 // STM32F103VE controller -#define BOARD_GTM32_PRO_VD 5006 // STM32F103VE controller -#define BOARD_GTM32_MINI 5007 // STM32F103VE controller -#define BOARD_GTM32_MINI_A30 5008 // STM32F103VE controller -#define BOARD_GTM32_REV_B 5009 // STM32F103VE controller -#define BOARD_MORPHEUS 5010 // STM32F103C8 / STM32F103CB Libmaple-based STM32F1 controller -#define BOARD_CHITU3D 5011 // Chitu3D (STM32F103RE) -#define BOARD_MKS_ROBIN 5012 // MKS Robin (STM32F103ZE) -#define BOARD_MKS_ROBIN_MINI 5013 // MKS Robin Mini (STM32F103VE) -#define BOARD_MKS_ROBIN_NANO 5014 // MKS Robin Nano (STM32F103VE) -#define BOARD_MKS_ROBIN_NANO_V2 5015 // MKS Robin Nano V2 (STM32F103VE) -#define BOARD_MKS_ROBIN_LITE 5016 // MKS Robin Lite/Lite2 (STM32F103RC) -#define BOARD_MKS_ROBIN_LITE3 5017 // MKS Robin Lite3 (STM32F103RC) -#define BOARD_MKS_ROBIN_PRO 5018 // MKS Robin Pro (STM32F103ZE) -#define BOARD_MKS_ROBIN_E3 5019 // MKS Robin E3 (STM32F103RC) -#define BOARD_MKS_ROBIN_E3_V1_1 5020 // MKS Robin E3 V1.1 (STM32F103RC) -#define BOARD_MKS_ROBIN_E3D 5021 // MKS Robin E3D (STM32F103RC) -#define BOARD_MKS_ROBIN_E3D_V1_1 5022 // MKS Robin E3D V1.1 (STM32F103RC) -#define BOARD_MKS_ROBIN_E3P 5023 // MKS Robin E3P (STM32F103VE) -#define BOARD_BTT_SKR_MINI_V1_1 5024 // BigTreeTech SKR Mini v1.1 (STM32F103RC) -#define BOARD_BTT_SKR_MINI_E3_V1_0 5025 // BigTreeTech SKR Mini E3 (STM32F103RC) -#define BOARD_BTT_SKR_MINI_E3_V1_2 5026 // BigTreeTech SKR Mini E3 V1.2 (STM32F103RC) -#define BOARD_BTT_SKR_MINI_E3_V2_0 5027 // BigTreeTech SKR Mini E3 V2.0 (STM32F103RC / STM32F103RE) -#define BOARD_BTT_SKR_MINI_MZ_V1_0 5028 // BigTreeTech SKR Mini MZ V1.0 (STM32F103RC) -#define BOARD_BTT_SKR_E3_DIP 5029 // BigTreeTech SKR E3 DIP V1.0 (STM32F103RC / STM32F103RE) -#define BOARD_BTT_SKR_CR6 5030 // BigTreeTech SKR CR6 v1.0 (STM32F103RE) -#define BOARD_JGAURORA_A5S_A1 5031 // JGAurora A5S A1 (STM32F103ZE) -#define BOARD_FYSETC_AIO_II 5032 // FYSETC AIO_II (STM32F103RC) -#define BOARD_FYSETC_CHEETAH 5033 // FYSETC Cheetah (STM32F103RC) -#define BOARD_FYSETC_CHEETAH_V12 5034 // FYSETC Cheetah V1.2 (STM32F103RC) -#define BOARD_LONGER3D_LK 5035 // Longer3D LK1/2 - Alfawise U20/U20+/U30 (STM32F103VE) -#define BOARD_CCROBOT_MEEB_3DP 5036 // ccrobot-online.com MEEB_3DP (STM32F103RC) -#define BOARD_CHITU3D_V5 5037 // Chitu3D TronXY X5SA V5 Board (STM32F103ZE) -#define BOARD_CHITU3D_V6 5038 // Chitu3D TronXY X5SA V6 Board (STM32F103ZE) -#define BOARD_CHITU3D_V9 5039 // Chitu3D TronXY X5SA V9 Board (STM32F103ZE) -#define BOARD_CREALITY_V4 5040 // Creality v4.x (STM32F103RC / STM32F103RE) -#define BOARD_CREALITY_V422 5041 // Creality v4.2.2 (STM32F103RC / STM32F103RE) -#define BOARD_CREALITY_V423 5042 // Creality v4.2.3 (STM32F103RC / STM32F103RE) -#define BOARD_CREALITY_V425 5043 // Creality v4.2.5 (STM32F103RC / STM32F103RE) -#define BOARD_CREALITY_V427 5044 // Creality v4.2.7 (STM32F103RC / STM32F103RE) -#define BOARD_CREALITY_V4210 5045 // Creality v4.2.10 (STM32F103RC / STM32F103RE) as found in the CR-30 -#define BOARD_CREALITY_V431 5046 // Creality v4.3.1 (STM32F103RC / STM32F103RE) -#define BOARD_CREALITY_V431_A 5047 // Creality v4.3.1a (STM32F103RC / STM32F103RE) -#define BOARD_CREALITY_V431_B 5048 // Creality v4.3.1b (STM32F103RC / STM32F103RE) -#define BOARD_CREALITY_V431_C 5049 // Creality v4.3.1c (STM32F103RC / STM32F103RE) -#define BOARD_CREALITY_V431_D 5050 // Creality v4.3.1d (STM32F103RC / STM32F103RE) -#define BOARD_CREALITY_V452 5051 // Creality v4.5.2 (STM32F103RC / STM32F103RE) -#define BOARD_CREALITY_V453 5052 // Creality v4.5.3 (STM32F103RC / STM32F103RE) -#define BOARD_CREALITY_V521 5053 // Creality v5.2.1 (STM32F103VE) as found in the SV04 -#define BOARD_CREALITY_V24S1 5054 // Creality v2.4.S1 (STM32F103RC / STM32F103RE) CR-FDM-v2.4.S1_v101 as found in the Ender-7 -#define BOARD_CREALITY_V24S1_301 5055 // Creality v2.4.S1_301 (STM32F103RC / STM32F103RE) CR-FDM-v24S1_301 as found in the Ender-3 S1 -#define BOARD_CREALITY_V25S1 5056 // Creality v2.5.S1 (STM32F103RE) CR-FDM-v2.5.S1_100 as found in the CR-10 Smart Pro -#define BOARD_TRIGORILLA_PRO 5057 // Trigorilla Pro (STM32F103ZE) -#define BOARD_FLY_MINI 5058 // FLYmaker FLY MINI (STM32F103RC) -#define BOARD_FLSUN_HISPEED 5059 // FLSUN HiSpeedV1 (STM32F103VE) -#define BOARD_BEAST 5060 // STM32F103RE Libmaple-based controller -#define BOARD_MINGDA_MPX_ARM_MINI 5061 // STM32F103ZE Mingda MD-16 -#define BOARD_ZONESTAR_ZM3E2 5062 // Zonestar ZM3E2 (STM32F103RC) -#define BOARD_ZONESTAR_ZM3E4 5063 // Zonestar ZM3E4 V1 (STM32F103VC) -#define BOARD_ZONESTAR_ZM3E4V2 5064 // Zonestar ZM3E4 V2 (STM32F103VC) -#define BOARD_ERYONE_ERY32_MINI 5065 // Eryone Ery32 mini (STM32F103VE) -#define BOARD_PANDA_PI_V29 5066 // Panda Pi V2.9 - Standalone (STM32F103RC) -#define BOARD_SOVOL_V131 5067 // Sovol V1.3.1 (GD32F103RE) -#define BOARD_TRIGORILLA_V006 5068 // Trigorilla V0.0.6 (GD32F103RE) -#define BOARD_KEDI_CONTROLLER_V1_2 5069 // EDUTRONICS Kedi Controller V1.2 (STM32F103RC) -#define BOARD_MD_D301 5070 // Mingda D2 DZ301 V1.0 (STM32F103ZE) -#define BOARD_VOXELAB_AQUILA 5071 // Voxelab Aquila V1.0.0/V1.0.1 (GD32F103RC / N32G455RE / STM32F103RE) -#define BOARD_SPRINGER_CONTROLLER 5072 // ORCA 3D SPRINGER Modular Controller (STM32F103VC) +#define BOARD_STM32F103RE 5000 // STM32F103RE Libmaple-based STM32F1 controller +#define BOARD_MALYAN_M200 5001 // STM32C8 Libmaple-based STM32F1 controller +#define BOARD_STM3R_MINI 5002 // STM32F103RE Libmaple-based STM32F1 controller +#define BOARD_GTM32_PRO_VB 5003 // STM32F103VE controller +#define BOARD_GTM32_PRO_VD 5004 // STM32F103VE controller +#define BOARD_GTM32_MINI 5005 // STM32F103VE controller +#define BOARD_GTM32_MINI_A30 5006 // STM32F103VE controller +#define BOARD_GTM32_REV_B 5007 // STM32F103VE controller +#define BOARD_MORPHEUS 5008 // STM32F103C8 / STM32F103CB Libmaple-based STM32F1 controller +#define BOARD_CHITU3D 5009 // Chitu3D (STM32F103RE) +#define BOARD_MKS_ROBIN 5010 // MKS Robin (STM32F103ZE) +#define BOARD_MKS_ROBIN_MINI 5011 // MKS Robin Mini (STM32F103VE) +#define BOARD_MKS_ROBIN_NANO 5012 // MKS Robin Nano (STM32F103VE) +#define BOARD_MKS_ROBIN_NANO_V2 5013 // MKS Robin Nano V2 (STM32F103VE) +#define BOARD_MKS_ROBIN_LITE 5014 // MKS Robin Lite/Lite2 (STM32F103RC) +#define BOARD_MKS_ROBIN_LITE3 5015 // MKS Robin Lite3 (STM32F103RC) +#define BOARD_MKS_ROBIN_PRO 5016 // MKS Robin Pro (STM32F103ZE) +#define BOARD_MKS_ROBIN_E3 5017 // MKS Robin E3 (STM32F103RC) +#define BOARD_MKS_ROBIN_E3_V1_1 5018 // MKS Robin E3 V1.1 (STM32F103RC) +#define BOARD_MKS_ROBIN_E3D 5019 // MKS Robin E3D (STM32F103RC) +#define BOARD_MKS_ROBIN_E3D_V1_1 5020 // MKS Robin E3D V1.1 (STM32F103RC) +#define BOARD_MKS_ROBIN_E3P 5021 // MKS Robin E3P (STM32F103VE) +#define BOARD_BTT_SKR_MINI_V1_1 5022 // BigTreeTech SKR Mini v1.1 (STM32F103RC) +#define BOARD_BTT_SKR_MINI_E3_V1_0 5023 // BigTreeTech SKR Mini E3 (STM32F103RC) +#define BOARD_BTT_SKR_MINI_E3_V1_2 5024 // BigTreeTech SKR Mini E3 V1.2 (STM32F103RC) +#define BOARD_BTT_SKR_MINI_E3_V2_0 5025 // BigTreeTech SKR Mini E3 V2.0 (STM32F103RC / STM32F103RE) +#define BOARD_BTT_SKR_MINI_MZ_V1_0 5026 // BigTreeTech SKR Mini MZ V1.0 (STM32F103RC) +#define BOARD_BTT_SKR_E3_DIP 5027 // BigTreeTech SKR E3 DIP V1.0 (STM32F103RC / STM32F103RE) +#define BOARD_BTT_SKR_CR6 5028 // BigTreeTech SKR CR6 v1.0 (STM32F103RE) +#define BOARD_JGAURORA_A5S_A1 5029 // JGAurora A5S A1 (STM32F103ZE) +#define BOARD_FYSETC_AIO_II 5030 // FYSETC AIO_II (STM32F103RC) +#define BOARD_FYSETC_CHEETAH 5031 // FYSETC Cheetah (STM32F103RC) +#define BOARD_FYSETC_CHEETAH_V12 5032 // FYSETC Cheetah V1.2 (STM32F103RC) +#define BOARD_LONGER3D_LK 5033 // Longer3D LK1/2 - Alfawise U20/U20+/U30 (STM32F103VE) +#define BOARD_CCROBOT_MEEB_3DP 5034 // ccrobot-online.com MEEB_3DP (STM32F103RC) +#define BOARD_CHITU3D_V5 5035 // Chitu3D TronXY X5SA V5 Board (STM32F103ZE) +#define BOARD_CHITU3D_V6 5036 // Chitu3D TronXY X5SA V6 Board (STM32F103ZE) +#define BOARD_CHITU3D_V9 5037 // Chitu3D TronXY X5SA V9 Board (STM32F103ZE) +#define BOARD_CREALITY_V4 5038 // Creality v4.x (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V422 5039 // Creality v4.2.2 (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V423 5040 // Creality v4.2.3 (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V425 5041 // Creality v4.2.5 (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V427 5042 // Creality v4.2.7 (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V4210 5043 // Creality v4.2.10 (STM32F103RC / STM32F103RE) as found in the CR-30 +#define BOARD_CREALITY_V431 5044 // Creality v4.3.1 (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V431_A 5045 // Creality v4.3.1a (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V431_B 5046 // Creality v4.3.1b (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V431_C 5047 // Creality v4.3.1c (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V431_D 5048 // Creality v4.3.1d (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V452 5049 // Creality v4.5.2 (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V453 5050 // Creality v4.5.3 (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V521 5051 // Creality v5.2.1 (STM32F103VE) as found in the SV04 +#define BOARD_CREALITY_V24S1 5052 // Creality v2.4.S1 (STM32F103RC / STM32F103RE) CR-FDM-v2.4.S1_v101 as found in the Ender-7 +#define BOARD_CREALITY_V24S1_301 5053 // Creality v2.4.S1_301 (STM32F103RC / STM32F103RE) CR-FDM-v24S1_301 as found in the Ender-3 S1 +#define BOARD_CREALITY_V25S1 5054 // Creality v2.5.S1 (STM32F103RE) CR-FDM-v2.5.S1_100 as found in the CR-10 Smart Pro +#define BOARD_TRIGORILLA_PRO 5055 // Trigorilla Pro (STM32F103ZE) +#define BOARD_FLY_MINI 5056 // FLYmaker FLY MINI (STM32F103RC) +#define BOARD_FLSUN_HISPEED 5057 // FLSUN HiSpeedV1 (STM32F103VE) +#define BOARD_BEAST 5058 // STM32F103RE Libmaple-based controller +#define BOARD_MINGDA_MPX_ARM_MINI 5059 // STM32F103ZE Mingda MD-16 +#define BOARD_ZONESTAR_ZM3E2 5060 // Zonestar ZM3E2 (STM32F103RC) +#define BOARD_ZONESTAR_ZM3E4 5061 // Zonestar ZM3E4 V1 (STM32F103VC) +#define BOARD_ZONESTAR_ZM3E4V2 5062 // Zonestar ZM3E4 V2 (STM32F103VC) +#define BOARD_ERYONE_ERY32_MINI 5063 // Eryone Ery32 mini (STM32F103VE) +#define BOARD_PANDA_PI_V29 5064 // Panda Pi V2.9 - Standalone (STM32F103RC) +#define BOARD_SOVOL_V131 5065 // Sovol V1.3.1 (GD32F103RE) +#define BOARD_TRIGORILLA_V006 5066 // Trigorilla V0.0.6 (GD32F103RE) +#define BOARD_KEDI_CONTROLLER_V1_2 5067 // EDUTRONICS Kedi Controller V1.2 (STM32F103RC) +#define BOARD_MD_D301 5068 // Mingda D2 DZ301 V1.0 (STM32F103ZE) +#define BOARD_VOXELAB_AQUILA 5069 // Voxelab Aquila V1.0.0/V1.0.1 (GD32F103RC / N32G455RE / STM32F103RE) +#define BOARD_SPRINGER_CONTROLLER 5070 // ORCA 3D SPRINGER Modular Controller (STM32F103VC) // // ARM Cortex-M4F @@ -473,10 +481,13 @@ #define BOARD_BLACKBEEZMINI_V1 5251 // BlackBeezMini V1 (STM32F401CCU6) #define BOARD_XTLW_CLIMBER_8TH 5252 // XTLW Climber-8th (STM32F407VGT6) #define BOARD_FLY_RRF_E3_V1 5253 // Fly RRF E3 V1.0 (STM32F407VG) -#define BOARD_ZNP_ROBIN_NANO 5254 // Elegoo Neptune 2 v1.2 board -#define BOARD_ZNP_ROBIN_NANO_V1_3 5255 // Elegoo Neptune 2 v1.3 board -#define BOARD_MKS_NEPTUNE_X 5256 // Elegoo Neptune X -#define BOARD_MKS_NEPTUNE_3 5257 // Elegoo Neptune 3 +#define BOARD_FLY_SUPER8 5254 // Fly SUPER8 (STM32F407ZGT6) +#define BOARD_FLY_D8 5255 // FLY D8 (STM32F407VG) +#define BOARD_FLY_CDY_V3 5256 // FLY CDY V3 (STM32F407VGT6) +#define BOARD_ZNP_ROBIN_NANO 5257 // Elegoo Neptune 2 v1.2 board +#define BOARD_ZNP_ROBIN_NANO_V1_3 5258 // Elegoo Neptune 2 v1.3 board +#define BOARD_MKS_NEPTUNE_X 5259 // Elegoo Neptune X +#define BOARD_MKS_NEPTUNE_3 5260 // Elegoo Neptune 3 // // Other ARM Cortex-M4 @@ -500,6 +511,8 @@ #define BOARD_BTT_KRAKEN_V1_0 6010 // BigTreeTech Kraken v1.0 (STM32H723ZG) #define BOARD_TEENSY41 6011 // Teensy 4.1 #define BOARD_T41U5XBB 6012 // T41U5XBB Teensy 4.1 breakout board +#define BOARD_FLY_D8_PRO 6013 // FLY_D8_PRO (STM32H723VG) +#define BOARD_FLY_SUPER8_PRO 6014 // FLY SUPER8 PRO (STM32H723ZG) // // Espressif ESP32 WiFi diff --git a/Marlin/src/pins/pins.h b/Marlin/src/pins/pins.h index 94990834ea..4e36558ef8 100644 --- a/Marlin/src/pins/pins.h +++ b/Marlin/src/pins/pins.h @@ -586,6 +586,12 @@ #include "stm32f0/pins_MALYAN_M200_V2.h" // STM32F0 env:STM32F070RB_malyan env:STM32F070CB_malyan #elif MB(MALYAN_M300) #include "stm32f0/pins_MALYAN_M300.h" // STM32F0 env:malyan_M300 +#elif MB(FLY_D5) + #include "stm32f0/pins_FLY_D5.h" // STM32F0 env:FLY_D5 +#elif MB(FLY_DP5) + #include "stm32f0/pins_FLY_DP5.h" // STM32F0 env:FLY_D5 +#elif MB(FLY_D7) + #include "stm32f0/pins_FLY_D7.h" // STM32F0 env:FLY_D7 // // STM32 ARM Cortex-M3 @@ -845,6 +851,12 @@ #include "stm32f4/pins_XTLW_CLIMBER_8TH.h" // STM32F4 env:XTLW_CLIMBER_8TH #elif MB(FLY_RRF_E3_V1) #include "stm32f4/pins_FLY_RRF_E3_V1.h" // STM32F4 env:FLY_RRF_E3_V1 +#elif MB(FLY_SUPER8) + #include "stm32f4/pins_FLY_SUPER8.h" // STM32F4 env:FLY_SUPER8 +#elif MB(FLY_D8) + #include "stm32f4/pins_FLY_D8.h" // STM32F4 env:FLY_D8 +#elif MB(FLY_CDY_V3) + #include "stm32f4/pins_FLY_CDY_V3.h" // STM32F4 env:FLY_CDY_V3 #elif MB(ZNP_ROBIN_NANO) #include "stm32f1/pins_MKS_ROBIN_NANO.h" // STM32F1 env:znp_robin_nano35 #elif MB(ZNP_ROBIN_NANO_V1_3) @@ -891,6 +903,10 @@ #include "teensy4/pins_TEENSY41.h" // Teensy-4.x env:teensy41 #elif MB(T41U5XBB) #include "teensy4/pins_T41U5XBB.h" // Teensy-4.x env:teensy41 +#elif MB(FLY_D8_PRO) + #include "stm32h7/pins_FLY_D8_PRO.h" // STM32H7 env:FLY_D8_PRO +#elif MB(FLY_SUPER8_PRO) + #include "stm32h7/pins_FLY_SUPER8_PRO.h" // STM32H7 env:FLY_SUPER8_PRO // // Espressif ESP32 diff --git a/Marlin/src/pins/stm32f0/pins_FLY_D5.h b/Marlin/src/pins/stm32f0/pins_FLY_D5.h new file mode 100644 index 0000000000..b75a5a62ac --- /dev/null +++ b/Marlin/src/pins/stm32f0/pins_FLY_D5.h @@ -0,0 +1,192 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +/** + * Firmware download method + * https://mellow.klipper.cn/docs/ProductDoc/MainBoard/fly-d/fly-d5/flash/bl + * Burn the marlin folder/.pio/build/motherboard name/firmware.bin + * Some computers may have USB compatibility issues, which may cause the USB connection to fail. + * This problem can usually be solved by using a HUB expander. + * + */ + +#define BOARD_INFO_NAME "FLY_D5" + +// +// EEPROM Emulation +// +#if NO_EEPROM_SELECTED + #define FLASH_EEPROM_EMULATION + #ifndef MARLIN_EEPROM_SIZE + #define MARLIN_EEPROM_SIZE 0x800U // 2K + #endif +#endif + +// +// Timers +// +#define STEP_TIMER 6 +#define TEMP_TIMER 7 + +// +// Limit Switches +// +#define X_STOP_PIN PB4 +#define Y_STOP_PIN PB3 +#define Z_STOP_PIN PD2 +// +// Steppers +// +#define X_STEP_PIN PC15 +#define X_DIR_PIN PC14 +#define X_ENABLE_PIN PC2 +#ifndef X_CS_PIN + #define X_CS_PIN PC13 +#endif + +#define Y_STEP_PIN PA1 +#define Y_DIR_PIN PA0 +#define Y_ENABLE_PIN PA2 +#ifndef Y_CS_PIN + #define Y_CS_PIN PC3 +#endif + +#define Z_STEP_PIN PA5 +#define Z_DIR_PIN PA4 +#define Z_ENABLE_PIN PA6 +#ifndef Z_CS_PIN + #define Z_CS_PIN PA3 +#endif + +#define E0_STEP_PIN PC5 +#define E0_DIR_PIN PC4 +#define E0_ENABLE_PIN PB0 +#ifndef E0_CS_PIN + #define E0_CS_PIN PA7 +#endif + +#define E1_STEP_PIN PB10 +#define E1_DIR_PIN PB2 +#define E1_ENABLE_PIN PB11 +#ifndef E1_CS_PIN + #define E1_CS_PIN PB1 +#endif +// +// Trinamic SPI +// +#ifndef TMC_SPI_SCK + #define TMC_SPI_SCK EXP2_02_PIN +#endif +#ifndef TMC_SPI_MISO + #define TMC_SPI_MISO EXP2_01_PIN +#endif +#ifndef TMC_SPI_MOSI + #define TMC_SPI_MOSI EXP2_06_PIN +#endif + +// +// Trinamic Software Serial +// + +#if HAS_TMC_UART + #define X_SERIAL_TX_PIN PC13 + #define Y_SERIAL_TX_PIN PC3 + #define Z_SERIAL_TX_PIN PA3 + #define E0_SERIAL_TX_PIN PA7 + #define E1_SERIAL_TX_PIN PB1 +#endif + +// +// Temperature Sensors +// +#define TEMP_0_PIN PC1 // Analog Input (HOTEND0 thermistor) +#define TEMP_BED_PIN PC0 // Analog Input (BED thermistor) + +// +// Heaters / Fans +// +#define HEATER_0_PIN PC6 // HOTEND0 MOSFET +#define HEATER_BED_PIN PC7 // BED MOSFET + +#ifndef FAN0_PIN + #define FAN0_PIN PC8 +#endif +#define FAN1_PIN PC9 + +/** + * ------ ------ + * NC | 1 2 | PA15 PB14 | 1 2 | PB13 + * PC11 | 3 4 | PA14 PC12 | 3 4 | PB12 + * PC10 | 5 6 | PA13 PB6 | 5 6 | PB15 + * NC | 7 8 | NC PB7 | 7 8 | RESET + * GND | 9 10 | 5V GND | 9 10 | -- + * ------ ------ + * EXP1 EXP2 + */ +#define EXP1_01_PIN -1 +#define EXP1_02_PIN PA15 +#define EXP1_03_PIN PC11 +#define EXP1_04_PIN PA14 +#define EXP1_05_PIN PC10 +#define EXP1_06_PIN PA13 +#define EXP1_07_PIN -1 +#define EXP1_08_PIN -1 + +#define EXP2_01_PIN PB14 +#define EXP2_02_PIN PB13 +#define EXP2_03_PIN PC12 +#define EXP2_04_PIN PB12 +#define EXP2_05_PIN PB6 +#define EXP2_06_PIN PB15 +#define EXP2_07_PIN PB7 +#define EXP2_08_PIN -1 // RESET + +// +// Onboard SD support +// +#ifndef SDCARD_CONNECTION + #define SDCARD_CONNECTION ONBOARD +#endif + +#if ENABLED(SDSUPPORT) + + #define SD_SCK_PIN EXP2_02_PIN + #define SD_MISO_PIN EXP2_01_PIN + #define SD_MOSI_PIN EXP2_06_PIN + #define SDSS EXP2_04_PIN + #define SD_DETECT_PIN EXP2_07_PIN + +#endif + +// +// Filament runout +// + +#define FIL_RUNOUT_PIN PA3 + +// Alter timing for graphical display +#if IS_U8GLIB_ST7920 + #define BOARD_ST7920_DELAY_1 96 + #define BOARD_ST7920_DELAY_2 48 + #define BOARD_ST7920_DELAY_3 715 +#endif diff --git a/Marlin/src/pins/stm32f0/pins_FLY_D7.h b/Marlin/src/pins/stm32f0/pins_FLY_D7.h new file mode 100644 index 0000000000..78ce01d385 --- /dev/null +++ b/Marlin/src/pins/stm32f0/pins_FLY_D7.h @@ -0,0 +1,155 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +/** + * Firmware download method + * https://mellow.klipper.cn/docs/ProductDoc/MainBoard/fly-d/fly-d7/flash/bl + * Burn the marlin folder/.pio/build/motherboard name/firmware.bin + * Some computers may have USB compatibility issues, which may cause the USB connection to fail. + * This problem can usually be solved by using a HUB expander. + * + */ + +#define BOARD_INFO_NAME "FLY_D7" + +// +// EEPROM Emulation +// +#if NO_EEPROM_SELECTED + #define FLASH_EEPROM_EMULATION + #ifndef MARLIN_EEPROM_SIZE + #define MARLIN_EEPROM_SIZE 0x800U // 2K + #endif +#endif + +// +// Timers +// +#define STEP_TIMER 1 +#define TEMP_TIMER 3 + +// +// Limit Switches +// +#define X_STOP_PIN PB3 +#define Y_STOP_PIN PD2 +#define Z_STOP_PIN PA9 +#define E_STOP_PIN PA10 + +// +// Steppers +// +#define X_STEP_PIN PC14 +#define X_DIR_PIN PC13 +#define X_ENABLE_PIN PC15 +#ifndef X_CS_PIN + #define X_CS_PIN PB7 +#endif + +#define Y_STEP_PIN PA1 +#define Y_DIR_PIN PA0 +#define Y_ENABLE_PIN PA2 +#ifndef Y_CS_PIN + #define Y_CS_PIN PC3 +#endif + +#define Z_STEP_PIN PA5 +#define Z_DIR_PIN PA4 +#define Z_ENABLE_PIN PA6 +#ifndef Z_CS_PIN + #define Z_CS_PIN PA3 +#endif + +#define E0_STEP_PIN PC5 +#define E0_DIR_PIN PC4 +#define E0_ENABLE_PIN PB0 +#ifndef E0_CS_PIN + #define E0_CS_PIN PA7 +#endif + +#define E1_STEP_PIN PB10 +#define E1_DIR_PIN PB2 +#define E1_ENABLE_PIN PB11 +#ifndef E1_CS_PIN + #define E1_CS_PIN PB1 +#endif + +#define E2_STEP_PIN PC12 +#define E2_DIR_PIN PB5 +#define E2_ENABLE_PIN PC11 +#ifndef E2_CS_PIN + #define E2_CS_PIN PB6 +#endif + +#define E3_STEP_PIN PA15 +#define E3_DIR_PIN PA14 +#define E3_ENABLE_PIN PA13 +#ifndef E3_CS_PIN + #define E3_CS_PIN PC10 +#endif + +// +// Trinamic SPI +// +#ifndef TMC_SPI_SCK + #define TMC_SPI_SCK PB13 +#endif +#ifndef TMC_SPI_MISO + #define TMC_SPI_MISO PB14 +#endif +#ifndef TMC_SPI_MOSI + #define TMC_SPI_MOSI PB15 +#endif + +// +// Trinamic Software Serial +// + +#if HAS_TMC_UART + #define X_SERIAL_TX_PIN PB7 + #define Y_SERIAL_TX_PIN PC3 + #define Z_SERIAL_TX_PIN PA3 + #define E0_SERIAL_TX_PIN PA7 + #define E1_SERIAL_TX_PIN PB1 + #define E2_SERIAL_TX_PIN PB6 + #define E3_SERIAL_TX_PIN PC10 +#endif + +// +// Temperature Sensors +// +#define TEMP_0_PIN PC1 // Analog Input (HOTEND0 thermistor) +#define TEMP_1_PIN PC2 // Analog Input (HOTEND1 thermistor) +#define TEMP_BED_PIN PC0 // Analog Input (BED thermistor) + +// +// Heaters / Fans +// +#define HEATER_0_PIN PB12 // HOTEND0 MOSFET +#define HEATER_1_PIN PC6 // HOTEND0 MOSFET +#define HEATER_BED_PIN PC7 // BED MOSFET + +#ifndef FAN0_PIN + #define FAN0_PIN PC8 +#endif +#define FAN1_PIN PC9 diff --git a/Marlin/src/pins/stm32f0/pins_FLY_DP5.h b/Marlin/src/pins/stm32f0/pins_FLY_DP5.h new file mode 100644 index 0000000000..d3c7b50e45 --- /dev/null +++ b/Marlin/src/pins/stm32f0/pins_FLY_DP5.h @@ -0,0 +1,199 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +/** + * Firmware download method + * https://mellow.klipper.cn/docs/ProductDoc/MainBoard/fly-d/fly-dp5/flash/bl + * Burn the marlin folder/.pio/build/motherboard name/firmware.bin + * Some computers may have USB compatibility issues, which may cause the USB connection to fail. + * This problem can usually be solved by using a HUB expander. + * + */ + +#define BOARD_INFO_NAME "FLY_DP5" + +// +// EEPROM Emulation +// +#if NO_EEPROM_SELECTED + #define FLASH_EEPROM_EMULATION + #ifndef MARLIN_EEPROM_SIZE + #define MARLIN_EEPROM_SIZE 0x800U // 2K + #endif +#endif + +// +// Timers +// +#define STEP_TIMER 6 +#define TEMP_TIMER 7 + +// +// NEOPIXEL +// +#ifndef NEOPIXEL_PIN + #define NEOPIXEL_PIN PB7 +#endif + +// +// Limit Switches +// +#define X_STOP_PIN PB4 +#define Y_STOP_PIN PB3 +#define Z_STOP_PIN PD2 +// +// Steppers +// +#define X_STEP_PIN PC15 +#define X_DIR_PIN PC14 +#define X_ENABLE_PIN PC2 +#ifndef X_CS_PIN + #define X_CS_PIN PC13 +#endif + +#define Y_STEP_PIN PA1 +#define Y_DIR_PIN PA0 +#define Y_ENABLE_PIN PA2 +#ifndef Y_CS_PIN + #define Y_CS_PIN PC3 +#endif + +#define Z_STEP_PIN PA5 +#define Z_DIR_PIN PA4 +#define Z_ENABLE_PIN PA6 +#ifndef Z_CS_PIN + #define Z_CS_PIN PA3 +#endif + +#define E0_STEP_PIN PC5 +#define E0_DIR_PIN PC4 +#define E0_ENABLE_PIN PB0 +#ifndef E0_CS_PIN + #define E0_CS_PIN PA7 +#endif + +#define E1_STEP_PIN PB10 +#define E1_DIR_PIN PB2 +#define E1_ENABLE_PIN PB11 +#ifndef E1_CS_PIN + #define E1_CS_PIN PB1 +#endif +// +// Trinamic SPI +// +#ifndef TMC_SPI_SCK + #define TMC_SPI_SCK EXP2_02_PIN +#endif +#ifndef TMC_SPI_MISO + #define TMC_SPI_MISO EXP2_01_PIN +#endif +#ifndef TMC_SPI_MOSI + #define TMC_SPI_MOSI EXP2_06_PIN +#endif + +// +// Trinamic Software Serial +// + +#if HAS_TMC_UART + #define X_SERIAL_TX_PIN PC13 + #define Y_SERIAL_TX_PIN PC3 + #define Z_SERIAL_TX_PIN PA3 + #define E0_SERIAL_TX_PIN PA7 + #define E1_SERIAL_TX_PIN PB1 +#endif + +// +// Temperature Sensors +// +#define TEMP_0_PIN PC1 // Analog Input (HOTEND0 thermistor) +#define TEMP_BED_PIN PC0 // Analog Input (BED thermistor) + +// +// Heaters / Fans +// +#define HEATER_0_PIN PC6 // HOTEND0 MOSFET +#define HEATER_BED_PIN PC7 // BED MOSFET + +#ifndef FAN0_PIN + #define FAN0_PIN PC8 +#endif +#define FAN1_PIN PC9 + +/** + * ------ ------ + * NC | 1 2 | PA15 PB14 | 1 2 | PB13 + * PC11 | 3 4 | PA14 PC12 | 3 4 | PB12 + * PC10 | 5 6 | PA13 PB6 | 5 6 | PB15 + * NC | 7 8 | NC NC | 7 8 | RESET + * GND | 9 10 | 5V GND | 9 10 | -- + * ------ ------ + * EXP1 EXP2 + */ +#define EXP1_01_PIN -1 +#define EXP1_02_PIN PA15 +#define EXP1_03_PIN PC11 +#define EXP1_04_PIN PA14 +#define EXP1_05_PIN PC10 +#define EXP1_06_PIN PA13 +#define EXP1_07_PIN -1 +#define EXP1_08_PIN -1 + +#define EXP2_01_PIN PB14 +#define EXP2_02_PIN PB13 +#define EXP2_03_PIN PC12 +#define EXP2_04_PIN PB12 +#define EXP2_05_PIN PB6 +#define EXP2_06_PIN PB15 +#define EXP2_07_PIN -1 +#define EXP2_08_PIN -1 // RESET + +// +// Onboard SD support +// +#ifndef SDCARD_CONNECTION + #define SDCARD_CONNECTION ONBOARD +#endif + +#if ENABLED(SDSUPPORT) + + #define SD_SCK_PIN EXP2_02_PIN + #define SD_MISO_PIN EXP2_01_PIN + #define SD_MOSI_PIN EXP2_06_PIN + #define SDSS EXP2_04_PIN + #define SD_DETECT_PIN EXP2_07_PIN + +#endif + +// +// Filament runout +// + +#define FIL_RUNOUT_PIN PA3 + +// Alter timing for graphical display +#if IS_U8GLIB_ST7920 + #define BOARD_ST7920_DELAY_1 96 + #define BOARD_ST7920_DELAY_2 48 + #define BOARD_ST7920_DELAY_3 715 +#endif diff --git a/Marlin/src/pins/stm32f4/pins_FLY_CDY_V3.h b/Marlin/src/pins/stm32f4/pins_FLY_CDY_V3.h new file mode 100644 index 0000000000..44843da5bd --- /dev/null +++ b/Marlin/src/pins/stm32f4/pins_FLY_CDY_V3.h @@ -0,0 +1,315 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +/** + * Bootloader Download + * https://mellow.klipper.cn/docs/ProductDoc/MainBoard/fly-cdy/fly-cdy-v3/bl + */ + +#define ALLOW_STM32DUINO +#include "env_validate.h" + +#define BOARD_INFO_NAME "FLY CDY V3" +#define DEFAULT_MACHINE_NAME BOARD_INFO_NAME + +// Avoid conflict with fans and TIMER_TONE +#define TEMP_TIMER 3 +#define STEP_TIMER 5 + +// +// EEPROM Emulation +// +#if NO_EEPROM_SELECTED + #define FLASH_EEPROM_EMULATION + //#define SRAM_EEPROM_EMULATION + //#define I2C_EEPROM +#endif + +#if ENABLED(FLASH_EEPROM_EMULATION) + // Decrease delays and flash wear by spreading writes across + // the 128kB sector allocated for EEPROM emulation. + #define FLASH_EEPROM_LEVELING +#elif ENABLED(I2C_EEPROM) + #define MARLIN_EEPROM_SIZE 0x2000 // 8K +#endif + +#ifndef MARLIN_EEPROM_SIZE + #define MARLIN_EEPROM_SIZE 0x1000 // 4K +#endif + +// +// Servos +// +#define SERVO0_PIN PE6 + +// +// Limit Switches +// +#define X_MIN_PIN PC7 +#define X_MAX_PIN PC6 +#define Y_MIN_PIN PD11 +#define Y_MAX_PIN PD10 +#define Z_MIN_PIN PB10 +#define Z_MAX_PIN PB11 + +// +// Laser +// +#define SPINDLE_LASER_PWM_PIN PB9 + +// +// NEOPIXEL +// +#ifndef NEOPIXEL_PIN + #define NEOPIXEL_PIN PD15 +#endif + +// +// Z Probe (when not Z_MIN_PIN) +// +#define Z_MIN_PROBE_PIN PC2 + +// +// Steppers +// + +#define X_STEP_PIN PE5 +#define X_DIR_PIN PC0 +#define X_ENABLE_PIN PC1 +#ifndef X_CS_PIN + #define X_CS_PIN PC15 +#endif + +#define Y_STEP_PIN PE4 +#define Y_DIR_PIN PC13 +#define Y_ENABLE_PIN PC14 +#ifndef Y_CS_PIN + #define Y_CS_PIN PA8 +#endif + +#define Z_STEP_PIN PE3 +#define Z_DIR_PIN PB7 +#define Z_ENABLE_PIN PB8 +#ifndef Z_CS_PIN + #define Z_CS_PIN PB6 +#endif + +#define E0_STEP_PIN PE2 +#define E0_DIR_PIN PD6 +#define E0_ENABLE_PIN PD7 +#ifndef E0_CS_PIN + #define E0_CS_PIN PD5 +#endif + +#define E1_STEP_PIN PE1 +#define E1_DIR_PIN PD3 +#define E1_ENABLE_PIN PD4 +#ifndef E1_CS_PIN + #define E1_CS_PIN PD1 +#endif + +#define E2_STEP_PIN PE0 +#define E2_DIR_PIN PA15 +#define E2_ENABLE_PIN PD0 +#ifndef E2_CS_PIN + #define E2_CS_PIN PE9 +#endif + +// +// Temperature Sensors +// +#define TEMP_0_PIN PA3 // Analog Input +#define TEMP_1_PIN PC4 // Analog Input +#define TEMP_2_PIN PC5 // Analog Input +#define TEMP_BED_PIN PB1 // Analog Input + +// +// Heaters / Fans +// +#define HEATER_0_PIN PD12 +#define HEATER_1_PIN PD13 +#define HEATER_2_PIN PD14 +#define HEATER_BED_PIN PB0 + +#define FAN0_PIN PA0 +#define FAN1_PIN PA1 +#define FAN2_PIN PA2 + +/** + * ------ ------ + * NC | 1 2 | PA9 PA6 | 1 2 | PA5 + * PB2 | 3 4 | PA10 PD8 | 3 4 | PA4 + * PE15 5 6 | PE14 PD9 5 6 | PA7 + * PA13 | 7 8 | PA14 PE13 | 7 8 | RESET + * GND | 9 10 | 5V GND | 9 10 | -- + * ------ ------ + * EXP1 EXP2 + */ +#define EXP1_01_PIN -1 //NC +#define EXP1_02_PIN PA9 +#define EXP1_03_PIN PB2 +#define EXP1_04_PIN PA10 +#define EXP1_05_PIN PE15 +#define EXP1_06_PIN PE14 +#define EXP1_07_PIN PA13 +#define EXP1_08_PIN PA14 + +#define EXP2_01_PIN PA6 +#define EXP2_02_PIN PA5 +#define EXP2_03_PIN PD8 +#define EXP2_04_PIN PA4 +#define EXP2_05_PIN PD9 +#define EXP2_06_PIN PA7 +#define EXP2_07_PIN PE13 +#define EXP2_08_PIN -1 // RESET + +// +// Onboard SD support +// +#ifndef SDCARD_CONNECTION + #define SDCARD_CONNECTION ONBOARD +#endif + +#if SD_CONNECTION_IS(ONBOARD) + + #define ONBOARD_SDIO // Use SDIO for onboard SD + +#elif SD_CONNECTION_IS(LCD) + + #define SD_SCK_PIN EXP2_02_PIN + #define SD_MISO_PIN EXP2_01_PIN + #define SD_MOSI_PIN EXP2_06_PIN + #define SDSS EXP2_04_PIN + #define SD_DETECT_PIN EXP2_07_PIN + +#endif + +// +// Trinamic SPI +// +#ifndef TMC_SPI_SCK + #define TMC_SPI_SCK PB3 +#endif +#ifndef TMC_SPI_MISO + #define TMC_SPI_MISO PB4 +#endif +#ifndef TMC_SPI_MOSI + #define TMC_SPI_MOSI PB5 +#endif + +// +// Trinamic Software Serial +// + +#if HAS_TMC_UART + #define X_SERIAL_TX_PIN PC15 + #define Y_SERIAL_TX_PIN PA8 + #define Z_SERIAL_TX_PIN PB6 + #define E0_SERIAL_TX_PIN PD5 + #define E1_SERIAL_TX_PIN PD1 + #define E2_SERIAL_TX_PIN PE9 +#endif + +// +// LCD / Controller +// +#if ENABLED(FYSETC_242_OLED_12864) + + #define BTN_EN1 EXP1_01_PIN + #define BTN_EN2 EXP1_08_PIN + #define BTN_ENC EXP1_02_PIN + + #define BEEPER_PIN EXP2_03_PIN + + #define LCD_PINS_DC EXP1_06_PIN + #define LCD_PINS_RS EXP2_05_PIN // LCD_RST + #define DOGLCD_CS EXP1_04_PIN + #define DOGLCD_MOSI EXP1_05_PIN + #define DOGLCD_SCK EXP1_03_PIN + #define DOGLCD_A0 LCD_PINS_DC + #define FORCE_SOFT_SPI + + #define KILL_PIN -1 // NC + #define BOARD_NEOPIXEL_PIN EXP1_07_PIN + +#elif HAS_WIRED_LCD + + #define BEEPER_PIN EXP1_01_PIN + #define BTN_ENC EXP1_02_PIN + + #if ENABLED(CR10_STOCKDISPLAY) + #define LCD_PINS_RS EXP1_07_PIN + + #define BTN_EN1 EXP1_03_PIN + #define BTN_EN2 EXP1_05_PIN + + #define LCD_PINS_EN EXP1_08_PIN + #define LCD_PINS_D4 EXP1_06_PIN + + #else + + #define LCD_PINS_RS EXP1_04_PIN + + #define BTN_EN1 EXP2_03_PIN + #define BTN_EN2 EXP2_05_PIN + + #define LCD_SDSS EXP2_04_PIN + + #define LCD_PINS_EN EXP1_03_PIN + #define LCD_PINS_D4 EXP1_05_PIN + + #if ENABLED(FYSETC_MINI_12864) + // See https://wiki.fysetc.com/Mini12864_Panel + #define DOGLCD_CS EXP1_03_PIN + #define DOGLCD_A0 EXP1_04_PIN + #if ENABLED(FYSETC_GENERIC_12864_1_1) + #define LCD_BACKLIGHT_PIN EXP1_07_PIN + #endif + #define LCD_RESET_PIN EXP1_05_PIN // Must be high or open for LCD to operate normally. + #if ANY(FYSETC_MINI_12864_1_2, FYSETC_MINI_12864_2_0) + #ifndef RGB_LED_R_PIN + #define RGB_LED_R_PIN EXP1_06_PIN + #endif + #ifndef RGB_LED_G_PIN + #define RGB_LED_G_PIN EXP1_07_PIN + #endif + #ifndef RGB_LED_B_PIN + #define RGB_LED_B_PIN EXP1_08_PIN + #endif + #elif ENABLED(FYSETC_MINI_12864_2_1) + #define NEOPIXEL_PIN EXP1_06_PIN + #endif + #endif + + #if IS_ULTIPANEL + #define LCD_PINS_D5 EXP1_06_PIN + #define LCD_PINS_D6 EXP1_07_PIN + #define LCD_PINS_D7 EXP1_08_PIN + #if ENABLED(REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER) + #define BTN_ENC_EN LCD_PINS_D7 // Detect the presence of the encoder + #endif + #endif + + #endif + +#endif // HAS_WIRED_LCD diff --git a/Marlin/src/pins/stm32f4/pins_FLY_D8.h b/Marlin/src/pins/stm32f4/pins_FLY_D8.h new file mode 100644 index 0000000000..974595c559 --- /dev/null +++ b/Marlin/src/pins/stm32f4/pins_FLY_D8.h @@ -0,0 +1,336 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +/** + * Firmware download method + * https://mellow.klipper.cn/docs/ProductDoc/MainBoard/fly-d/fly-d8-f407/flash/bl + * Burn the marlin folder/.pio/build/motherboard name/firmware.bin + * + */ + +#define ALLOW_STM32DUINO +#include "env_validate.h" + +#define BOARD_INFO_NAME "FLY D8" +#define DEFAULT_MACHINE_NAME BOARD_INFO_NAME + +// Avoid conflict with fans and TIMER_TONE +#define TEMP_TIMER 3 +#define STEP_TIMER 5 + +// +// EEPROM Emulation +// +#if NO_EEPROM_SELECTED + #define FLASH_EEPROM_EMULATION + //#define SRAM_EEPROM_EMULATION + //#define I2C_EEPROM +#endif + +#if ENABLED(FLASH_EEPROM_EMULATION) + // Decrease delays and flash wear by spreading writes across + // the 128kB sector allocated for EEPROM emulation. + #define FLASH_EEPROM_LEVELING +#elif ENABLED(I2C_EEPROM) + #define MARLIN_EEPROM_SIZE 0x2000 // 8K +#endif + +#ifndef MARLIN_EEPROM_SIZE + #define MARLIN_EEPROM_SIZE 0x1000 // 4K +#endif + +// +// Servos +// +#define SERVO0_PIN PE6 + +// +// Limit Switches +// +#define X_MIN_PIN PD9 +#define X_MAX_PIN PD8 +#define Y_MIN_PIN PD11 +#define Y_MAX_PIN PD10 +#define Z_MIN_PIN PA5 +#define Z_MAX_PIN PA4 + +// +// NEOPIXEL +// + +#define NEOPIXEL_PIN PA3 +#define NEOPIXEL2_PIN PD15 + +// +// Z Probe (when not Z_MIN_PIN) +// +#define Z_MIN_PROBE_PIN PC0 + +// +// Steppers +// + +#define X_STEP_PIN PE5 +#define X_DIR_PIN PA8 +#define X_ENABLE_PIN PA15 +#ifndef X_CS_PIN + #define X_CS_PIN PC9 +#endif + +#define Y_STEP_PIN PE4 +#define Y_DIR_PIN PC11 +#define Y_ENABLE_PIN PC12 +#ifndef Y_CS_PIN + #define Y_CS_PIN PC10 +#endif + +#define Z_STEP_PIN PE3 +#define Z_DIR_PIN PD1 +#define Z_ENABLE_PIN PD2 +#ifndef Z_CS_PIN + #define Z_CS_PIN PD0 +#endif + +#define E0_STEP_PIN PE2 +#define E0_DIR_PIN PD4 +#define E0_ENABLE_PIN PD5 +#ifndef E0_CS_PIN + #define E0_CS_PIN PD3 +#endif + +#define E1_STEP_PIN PE1 +#define E1_DIR_PIN PD7 +#define E1_ENABLE_PIN PB6 +#ifndef E1_CS_PIN + #define E1_CS_PIN PD6 +#endif + +#define E2_STEP_PIN PE0 +#define E2_DIR_PIN PC13 +#define E2_ENABLE_PIN PC14 +#ifndef E2_CS_PIN + #define E2_CS_PIN PB7 +#endif + +#define E3_STEP_PIN PE7 +#define E3_DIR_PIN PE11 +#define E3_ENABLE_PIN PE10 +#ifndef E3_CS_PIN + #define E3_CS_PIN PC15 +#endif + +#define E4_STEP_PIN PE8 +#define E4_DIR_PIN PA7 +#define E4_ENABLE_PIN PA6 +#ifndef E4_CS_PIN + #define E4_CS_PIN PE9 +#endif + +// +// Temperature Sensors +// +#define TEMP_0_PIN PC2 // Analog Input +#define TEMP_1_PIN PC3 // Analog Input +#define TEMP_2_PIN PC4 // Analog Input +#define TEMP_BED_PIN PC5 // Analog Input + +// +// Heaters / Fans +// +#define HEATER_0_PIN PD12 +#define HEATER_1_PIN PD13 +#define HEATER_2_PIN PD14 +#define HEATER_BED_PIN PB0 + +#define FAN0_PIN PA0 +#define FAN1_PIN PA1 +#define FAN2_PIN PA2 +#define FAN3_PIN PC6 +#define FAN4_PIN PC7 +#define FAN5_PIN PC8 + +/** + * ------ ------ + * PB10 | 1 2 | PB1 PB14 | 1 2 | PB13 + * PA14 | 3 4 | PA13 PA9 | 3 4 | PB12 + * PE15 5 6 | PE14 PA10 5 6 | PB15 + * PE13 | 7 8 | PB11 PE12 | 7 8 | RESET + * GND | 9 10 | 5V GND | 9 10 | -- + * ------ ------ + * EXP1 EXP2 + */ +#define EXP1_01_PIN PB10 +#define EXP1_02_PIN PB1 +#define EXP1_03_PIN PA14 +#define EXP1_04_PIN PA13 +#define EXP1_05_PIN PE15 +#define EXP1_06_PIN PE14 +#define EXP1_07_PIN PE13 +#define EXP1_08_PIN PB11 + +#define EXP2_01_PIN PB14 +#define EXP2_02_PIN PB13 +#define EXP2_03_PIN PA9 +#define EXP2_04_PIN PB12 +#define EXP2_05_PIN PA10 +#define EXP2_06_PIN PB15 +#define EXP2_07_PIN PE12 +#define EXP2_08_PIN -1 // RESET + +// +// Onboard SD support +// +//#define SD_CARD_DETECT_PIN PC13 + +#ifndef SDCARD_CONNECTION + #define SDCARD_CONNECTION LCD +#endif + +#if SD_CONNECTION_IS(LCD) + + #define SD_SCK_PIN EXP2_02_PIN + #define SD_MISO_PIN EXP2_01_PIN + #define SD_MOSI_PIN EXP2_06_PIN + #define SDSS EXP2_04_PIN + #define SD_DETECT_PIN EXP2_07_PIN + +#endif + +// +// Trinamic SPI +// +#ifndef TMC_SPI_SCK + #define TMC_SPI_SCK PB3 +#endif +#ifndef TMC_SPI_MISO + #define TMC_SPI_MISO PB4 +#endif +#ifndef TMC_SPI_MOSI + #define TMC_SPI_MOSI PB5 +#endif + +// +// Trinamic Software Serial +// + +#if HAS_TMC_UART + #define X_SERIAL_TX_PIN PC9 + #define Y_SERIAL_TX_PIN PC10 + #define Z_SERIAL_TX_PIN PD0 + #define E0_SERIAL_TX_PIN PD3 + #define E1_SERIAL_TX_PIN PD6 + #define E2_SERIAL_TX_PIN PB7 + #define E3_SERIAL_TX_PIN PC15 + #define E4_SERIAL_TX_PIN PE9 +#endif + +// +// LCD / Controller +// +#if ENABLED(FYSETC_242_OLED_12864) + + #define BTN_EN1 EXP1_01_PIN + #define BTN_EN2 EXP1_08_PIN + #define BTN_ENC EXP1_02_PIN + + #define BEEPER_PIN EXP2_03_PIN + + #define LCD_PINS_DC EXP1_06_PIN + #define LCD_PINS_RS EXP2_05_PIN // LCD_RST + #define DOGLCD_CS EXP1_04_PIN + #define DOGLCD_MOSI EXP1_05_PIN + #define DOGLCD_SCK EXP1_03_PIN + #define DOGLCD_A0 LCD_PINS_DC + #define FORCE_SOFT_SPI + + #define KILL_PIN -1 // NC + #define BOARD_NEOPIXEL_PIN EXP1_07_PIN + +#elif HAS_WIRED_LCD + + #define BEEPER_PIN EXP1_01_PIN + #define BTN_ENC EXP1_02_PIN + + #if ENABLED(CR10_STOCKDISPLAY) + #define LCD_PINS_RS EXP1_07_PIN + + #define BTN_EN1 EXP1_03_PIN + #define BTN_EN2 EXP1_05_PIN + + #define LCD_PINS_EN EXP1_08_PIN + #define LCD_PINS_D4 EXP1_06_PIN + + #else + + #define LCD_PINS_RS EXP1_04_PIN + + #define BTN_EN1 EXP2_03_PIN + #define BTN_EN2 EXP2_05_PIN + + #define LCD_SDSS EXP2_04_PIN + + #define LCD_PINS_EN EXP1_03_PIN + #define LCD_PINS_D4 EXP1_05_PIN + + #if ENABLED(FYSETC_MINI_12864) + // See https://wiki.fysetc.com/Mini12864_Panel + #define DOGLCD_CS EXP1_03_PIN + #define DOGLCD_A0 EXP1_04_PIN + #if ENABLED(FYSETC_GENERIC_12864_1_1) + #define LCD_BACKLIGHT_PIN EXP1_07_PIN + #endif + #define LCD_RESET_PIN EXP1_05_PIN // Must be high or open for LCD to operate normally. + #if ANY(FYSETC_MINI_12864_1_2, FYSETC_MINI_12864_2_0) + #ifndef RGB_LED_R_PIN + #define RGB_LED_R_PIN EXP1_06_PIN + #endif + #ifndef RGB_LED_G_PIN + #define RGB_LED_G_PIN EXP1_07_PIN + #endif + #ifndef RGB_LED_B_PIN + #define RGB_LED_B_PIN EXP1_08_PIN + #endif + #elif ENABLED(FYSETC_MINI_12864_2_1) + #define NEOPIXEL_PIN EXP1_06_PIN + #endif + #endif + + #if IS_ULTIPANEL + #define LCD_PINS_D5 EXP1_06_PIN + #define LCD_PINS_D6 EXP1_07_PIN + #define LCD_PINS_D7 EXP1_08_PIN + #if ENABLED(REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER) + #define BTN_ENC_EN LCD_PINS_D7 // Detect the presence of the encoder + #endif + #endif + + #endif + +#endif // HAS_WIRED_LCD + +// Alter timing for graphical display +#if IS_U8GLIB_ST7920 + #define BOARD_ST7920_DELAY_1 96 + #define BOARD_ST7920_DELAY_2 48 + #define BOARD_ST7920_DELAY_3 715 +#endif diff --git a/Marlin/src/pins/stm32f4/pins_FLY_RRF_E3_V1.h b/Marlin/src/pins/stm32f4/pins_FLY_RRF_E3_V1.h index b2f7dab7de..33c479a355 100644 --- a/Marlin/src/pins/stm32f4/pins_FLY_RRF_E3_V1.h +++ b/Marlin/src/pins/stm32f4/pins_FLY_RRF_E3_V1.h @@ -21,6 +21,11 @@ */ #pragma once +/** + * Bootloader Download + * https://mellow.klipper.cn/docs/ProductDoc/MainBoard/fly-e3/fly-e3-v2/flash/bl + */ + #include "env_validate.h" #ifndef BOARD_INFO_NAME diff --git a/Marlin/src/pins/stm32f4/pins_FLY_SUPER8.h b/Marlin/src/pins/stm32f4/pins_FLY_SUPER8.h new file mode 100644 index 0000000000..3ce5790fb8 --- /dev/null +++ b/Marlin/src/pins/stm32f4/pins_FLY_SUPER8.h @@ -0,0 +1,346 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#pragma once + +/** + * Bootloader Download + * https://mellow.klipper.cn/docs/ProductDoc/MainBoard/fly-super/fly-super8/flash/bl + */ + +#define ALLOW_STM32DUINO +#include "env_validate.h" + +#define BOARD_INFO_NAME "FLY_SUPER8" +#define DEFAULT_MACHINE_NAME BOARD_INFO_NAME + +// Avoid conflict with fans and TIMER_TONE +#define TEMP_TIMER 3 +#define STEP_TIMER 5 + +// +// EEPROM Emulation +// +#if NO_EEPROM_SELECTED + #define FLASH_EEPROM_EMULATION + //#define SRAM_EEPROM_EMULATION + //#define I2C_EEPROM +#endif + +#if ENABLED(FLASH_EEPROM_EMULATION) + // Decrease delays and flash wear by spreading writes across + // the 128kB sector allocated for EEPROM emulation. + #define FLASH_EEPROM_LEVELING +#elif ENABLED(I2C_EEPROM) + #define MARLIN_EEPROM_SIZE 0x2000 // 8K +#endif + +#ifndef MARLIN_EEPROM_SIZE + #define MARLIN_EEPROM_SIZE 0x1000 // 4K +#endif + +// +// Servos +// +#define SERVO0_PIN PC6 + +// +// Limit Switches +// +#define X_MIN_PIN PG12 +#define X_MAX_PIN PG11 +#define Y_MIN_PIN PG10 +#define Y_MAX_PIN PG9 +#define Z_MIN_PIN PD7 +#define Z_MAX_PIN PD6 + +#define IO6 PA8 +#define IN7 PF8 + +// +// Z Probe (when not Z_MIN_PIN) +// +#define Z_MIN_PROBE_PIN PC3 + +// +// Steppers +// + +#define X_STEP_PIN PE2 +#define X_DIR_PIN PC5 +#define X_ENABLE_PIN PF11 +#ifndef X_CS_PIN + #define X_CS_PIN PC4 +#endif + +#define Y_STEP_PIN PE3 +#define Y_DIR_PIN PF13 +#define Y_ENABLE_PIN PF14 +#ifndef Y_CS_PIN + #define Y_CS_PIN PF12 +#endif + +#define Z_STEP_PIN PE4 +#define Z_DIR_PIN PG0 +#define Z_ENABLE_PIN PG1 +#ifndef Z_CS_PIN + #define Z_CS_PIN PF15 +#endif + +#define E0_STEP_PIN PE14 +#define E0_DIR_PIN PE8 +#define E0_ENABLE_PIN PE9 +#ifndef E0_CS_PIN + #define E0_CS_PIN PE7 +#endif + +#define E1_STEP_PIN PE15 +#define E1_DIR_PIN PE11 +#define E1_ENABLE_PIN PF2 +#ifndef E1_CS_PIN + #define E1_CS_PIN PE10 +#endif + +#define E2_STEP_PIN PE1 +#define E2_DIR_PIN PF0 +#define E2_ENABLE_PIN PC15 +#ifndef E2_CS_PIN + #define E2_CS_PIN PF1 +#endif + +#define E3_STEP_PIN PE0 +#define E3_DIR_PIN PG3 +#define E3_ENABLE_PIN PG4 +#ifndef E3_CS_PIN + #define E3_CS_PIN PG2 +#endif + +#define E4_STEP_PIN PE6 +#define E4_DIR_PIN PG6 +#define E4_ENABLE_PIN PG7 +#ifndef E4_CS_PIN + #define E4_CS_PIN PG5 +#endif + +// +// Temperature Sensors +// +#define TEMP_0_PIN PF4 // Analog Input +#define TEMP_1_PIN PF5 // Analog Input +#define TEMP_2_PIN PF9 // Analog Input +#define TEMP_3_PIN PF10 // Analog Input +#define TEMP_4_PIN PC0 // Analog Input +#define TEMP_BED_PIN PC1 // Analog Input + +// +// Heaters / Fans +// +#define HEATER_0_PIN PB0 +#define HEATER_1_PIN PB1 +#define HEATER_2_PIN PC7 +#define HEATER_3_PIN PF7 +#define HEATER_4_PIN PF6 +#define HEATER_BED_PIN PE5 + +#ifndef FAN0_PIN + #define FAN0_PIN PA0 +#endif +#define FAN1_PIN PA1 +#define FAN2_PIN PA2 +#define FAN3_PIN PA3 +#define FAN4_PIN PA15 +#define FAN5_PIN PB11 +#define FAN8_PIN PB10 +#define FAN9_PIN PD12 +#define FAN6_PIN PD14 +#define FAN7_PIN PD15 + +/** + * ------ ------ + * PE12 | 1 2 | PE13 PA6 | 1 2 | PA5 + * PB2 | 3 4 | PG8 PB7 | 3 4 | PA4 + * PC14 5 6 | PC13 PB6 5 6 | PA7 + * PG14 | 7 8 | PG13 PG15 | 7 8 | RESET + * GND | 9 10 | 5V GND | 9 10 | -- + * ------ ------ + * EXP1 EXP2 + */ +#define EXP1_01_PIN PE12 +#define EXP1_02_PIN PE13 +#define EXP1_03_PIN PB2 +#define EXP1_04_PIN PG8 +#define EXP1_05_PIN PC14 +#define EXP1_06_PIN PC13 +#define EXP1_07_PIN PG14 +#define EXP1_08_PIN PG13 + +#define EXP2_01_PIN PA6 +#define EXP2_02_PIN PA5 +#define EXP2_03_PIN PB7 +#define EXP2_04_PIN PA4 +#define EXP2_05_PIN PB6 +#define EXP2_06_PIN PA7 +#define EXP2_07_PIN PG15 +#define EXP2_08_PIN -1 // RESET + +// +// Onboard SD support +// +//#define SD_CARD_DETECT_PIN PC13 + +#ifndef SDCARD_CONNECTION + #define SDCARD_CONNECTION ONBOARD +#endif + +#if SD_CONNECTION_IS(ONBOARD) + + #define ONBOARD_SDIO // Use SDIO for onboard SD + +#elif SD_CONNECTION_IS(LCD) + + #define SD_SCK_PIN EXP2_02_PIN + #define SD_MISO_PIN EXP2_01_PIN + #define SD_MOSI_PIN EXP2_06_PIN + #define SDSS EXP2_04_PIN + #define SD_DETECT_PIN EXP2_07_PIN + +#endif + +// +// Trinamic SPI +// +#ifndef TMC_SPI_SCK + #define TMC_SPI_SCK PB3 +#endif +#ifndef TMC_SPI_MISO + #define TMC_SPI_MISO PB4 +#endif +#ifndef TMC_SPI_MOSI + #define TMC_SPI_MOSI PB5 +#endif + +// +// Trinamic Software Serial +// + +#if HAS_TMC_UART + #define X_SERIAL_TX_PIN PC4 + #define Y_SERIAL_TX_PIN PF12 + #define Z_SERIAL_TX_PIN PF15 + #define E0_SERIAL_TX_PIN PE7 + #define E1_SERIAL_TX_PIN PE10 + #define E2_SERIAL_TX_PIN PF1 + #define E3_SERIAL_TX_PIN PG2 + #define E4_SERIAL_TX_PIN PG5 +#endif + +// +// LCD / Controller +// + +#if ENABLED(FYSETC_242_OLED_12864) + + #define BTN_EN1 EXP1_01_PIN + #define BTN_EN2 EXP1_08_PIN + #define BTN_ENC EXP1_02_PIN + + #define BEEPER_PIN EXP2_03_PIN + + #define LCD_PINS_DC EXP1_06_PIN + #define LCD_PINS_RS EXP2_05_PIN // LCD_RST + #define DOGLCD_CS EXP1_04_PIN + #define DOGLCD_MOSI EXP1_05_PIN + #define DOGLCD_SCK EXP1_03_PIN + #define DOGLCD_A0 LCD_PINS_DC + #define FORCE_SOFT_SPI + + #define KILL_PIN -1 // NC + #define BOARD_NEOPIXEL_PIN EXP1_07_PIN + +#elif HAS_WIRED_LCD + + #define BEEPER_PIN EXP1_01_PIN + #define BTN_ENC EXP1_02_PIN + + #if ENABLED(CR10_STOCKDISPLAY) + #define LCD_PINS_RS EXP1_07_PIN + + #define BTN_EN1 EXP1_03_PIN + #define BTN_EN2 EXP1_05_PIN + + #define LCD_PINS_EN EXP1_08_PIN + #define LCD_PINS_D4 EXP1_06_PIN + + #else + + #define LCD_PINS_RS EXP1_04_PIN + + #define BTN_EN1 EXP2_03_PIN + #define BTN_EN2 EXP2_05_PIN + + #define LCD_SDSS EXP2_04_PIN + + #define LCD_PINS_EN EXP1_03_PIN + #define LCD_PINS_D4 EXP1_05_PIN + + #if ENABLED(FYSETC_MINI_12864) + // See https://wiki.fysetc.com/Mini12864_Panel + #define DOGLCD_CS EXP1_03_PIN + #define DOGLCD_A0 EXP1_04_PIN + #if ENABLED(FYSETC_GENERIC_12864_1_1) + #define LCD_BACKLIGHT_PIN EXP1_07_PIN + #endif + #define LCD_RESET_PIN EXP1_05_PIN // Must be high or open for LCD to operate normally. + #if ANY(FYSETC_MINI_12864_1_2, FYSETC_MINI_12864_2_0) + #ifndef RGB_LED_R_PIN + #define RGB_LED_R_PIN EXP1_06_PIN + #endif + #ifndef RGB_LED_G_PIN + #define RGB_LED_G_PIN EXP1_07_PIN + #endif + #ifndef RGB_LED_B_PIN + #define RGB_LED_B_PIN EXP1_08_PIN + #endif + #elif ENABLED(FYSETC_MINI_12864_2_1) + #define NEOPIXEL_PIN EXP1_06_PIN + #endif + #endif + + #if IS_ULTIPANEL + #define LCD_PINS_D5 EXP1_06_PIN + #define LCD_PINS_D6 EXP1_07_PIN + #define LCD_PINS_D7 EXP1_08_PIN + #if ENABLED(REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER) + #define BTN_ENC_EN LCD_PINS_D7 // Detect the presence of the encoder + #endif + #endif + + #endif + +#endif // HAS_WIRED_LCD + +// Alter timing for graphical display +#if IS_U8GLIB_ST7920 + #define BOARD_ST7920_DELAY_1 96 + #define BOARD_ST7920_DELAY_2 48 + #define BOARD_ST7920_DELAY_3 715 +#endif diff --git a/Marlin/src/pins/stm32h7/pins_FLY_D8_PRO.h b/Marlin/src/pins/stm32h7/pins_FLY_D8_PRO.h new file mode 100644 index 0000000000..9b7cfb32c1 --- /dev/null +++ b/Marlin/src/pins/stm32h7/pins_FLY_D8_PRO.h @@ -0,0 +1,336 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +/** + * Firmware download method + * https://mellow.klipper.cn/docs/ProductDoc/MainBoard/fly-d/fly-d8-h723/flash/bl + * Burn the marlin folder/.pio/build/motherboard name/firmware.bin + * + */ + +#define ALLOW_STM32DUINO +#include "env_validate.h" + +#define BOARD_INFO_NAME "FLY D8 PRO" +#define DEFAULT_MACHINE_NAME BOARD_INFO_NAME + +// Avoid conflict with fans and TIMER_TONE +//#define TEMP_TIMER 3 +//#define STEP_TIMER 5 + +// +// EEPROM Emulation +// +#if NO_EEPROM_SELECTED + #define FLASH_EEPROM_EMULATION + //#define SRAM_EEPROM_EMULATION + //#define I2C_EEPROM +#endif + +#if ENABLED(FLASH_EEPROM_EMULATION) + // Decrease delays and flash wear by spreading writes across + // the 128kB sector allocated for EEPROM emulation. + #define FLASH_EEPROM_LEVELING +#elif ENABLED(I2C_EEPROM) + #define MARLIN_EEPROM_SIZE 0x2000 // 8K +#endif + +#ifndef MARLIN_EEPROM_SIZE + #define MARLIN_EEPROM_SIZE 0x1000 // 4K +#endif + +// +// Servos +// +#define SERVO0_PIN PE6 + +// +// Limit Switches +// +#define X_MIN_PIN PD9 +#define X_MAX_PIN PD8 +#define Y_MIN_PIN PD11 +#define Y_MAX_PIN PD10 +#define Z_MIN_PIN PA6 +#define Z_MAX_PIN PA5 + +// +// NEOPIXEL +// +//#define NEOPIXEL_PIN PA4 +#define NEOPIXEL2_PIN PD15 + +// +// Z Probe (when not Z_MIN_PIN) +// +#define Z_MIN_PROBE_PIN PC0 + +// +// Steppers +// +#define X_STEP_PIN PE5 +#define X_DIR_PIN PA8 +#define X_ENABLE_PIN PA15 +#ifndef X_CS_PIN + #define X_CS_PIN PC9 +#endif + +#define Y_STEP_PIN PE4 +#define Y_DIR_PIN PC11 +#define Y_ENABLE_PIN PC12 +#ifndef Y_CS_PIN + #define Y_CS_PIN PC10 +#endif + +#define Z_STEP_PIN PE3 +#define Z_DIR_PIN PD1 +#define Z_ENABLE_PIN PD2 +#ifndef Z_CS_PIN + #define Z_CS_PIN PD0 +#endif + +#define E0_STEP_PIN PE2 +#define E0_DIR_PIN PD4 +#define E0_ENABLE_PIN PD5 +#ifndef E0_CS_PIN + #define E0_CS_PIN PD3 +#endif + +#define E1_STEP_PIN PE1 +#define E1_DIR_PIN PD7 +#define E1_ENABLE_PIN PB6 +#ifndef E1_CS_PIN + #define E1_CS_PIN PD6 +#endif + +#define E2_STEP_PIN PE0 +#define E2_DIR_PIN PC13 +#define E2_ENABLE_PIN PC14 +#ifndef E2_CS_PIN + #define E2_CS_PIN PB7 +#endif + +#define E3_STEP_PIN PE8 +#define E3_DIR_PIN PE12 +#define E3_ENABLE_PIN PE11 +#ifndef E3_CS_PIN + #define E3_CS_PIN PC15 +#endif + +#define E4_STEP_PIN PE9 +#define E4_DIR_PIN PC4 +#define E4_ENABLE_PIN PA7 +#ifndef E4_CS_PIN + #define E4_CS_PIN PE10 +#endif + +// +// Temperature Sensors +// +#define TEMP_0_PIN PC2 // Analog Input +#define TEMP_1_PIN PC3 // Analog Input +#define TEMP_2_PIN PC5 // Analog Input +#define TEMP_BED_PIN PB0 // Analog Input + +#define TEMP_3_PIN PC3 // Analog Input +#define TEMP_4_PIN PC5 // Analog Input + +// +// Heaters / Fans +// +#define HEATER_0_PIN PD12 +#define HEATER_1_PIN PD13 +#define HEATER_2_PIN PD14 +#define HEATER_BED_PIN PB1 + +#define HEATER_3_PIN PD13 +#define HEATER_4_PIN PD14 + +#define FAN0_PIN PA1 +#define FAN1_PIN PA2 +#define FAN2_PIN PA3 +#define FAN3_PIN PC6 +#define FAN4_PIN PC7 +#define FAN5_PIN PC8 + +/** + * ------ ------ + * PB11 | 1 2 | PE7 PB14 | 1 2 | PB13 + * PA14 | 3 4 | PA13 PA9 | 3 4 | PB12 + * PB10 5 6 | PE15 PA10 5 6 | PB15 + * PE14 | 7 8 | PA0 PE13 | 7 8 | RESET + * GND | 9 10 | 5V GND | 9 10 | -- + * ------ ------ + * EXP1 EXP2 + */ +#define EXP1_01_PIN PB11 +#define EXP1_02_PIN PE7 // (Not PB2) +#define EXP1_03_PIN PA14 +#define EXP1_04_PIN PA13 +#define EXP1_05_PIN PB10 +#define EXP1_06_PIN PE15 +#define EXP1_07_PIN PE14 +#define EXP1_08_PIN PA0 + +#define EXP2_01_PIN PB14 +#define EXP2_02_PIN PB13 +#define EXP2_03_PIN PA9 +#define EXP2_04_PIN PB12 +#define EXP2_05_PIN PA10 +#define EXP2_06_PIN PB15 +#define EXP2_07_PIN PE13 +#define EXP2_08_PIN -1 // RESET + +// +// Onboard SD support +// +#ifndef SDCARD_CONNECTION + #define SDCARD_CONNECTION LCD +#endif + +#if SD_CONNECTION_IS(LCD) + #define SD_SCK_PIN EXP2_02_PIN + #define SD_MISO_PIN EXP2_01_PIN + #define SD_MOSI_PIN EXP2_06_PIN + #define SDSS EXP2_04_PIN + #define SD_DETECT_PIN EXP2_07_PIN +#endif + +// +// Trinamic SPI +// +#ifndef TMC_SPI_SCK + #define TMC_SPI_SCK PB3 +#endif +#ifndef TMC_SPI_MISO + #define TMC_SPI_MISO PB4 +#endif +#ifndef TMC_SPI_MOSI + #define TMC_SPI_MOSI PB5 +#endif + +// +// Trinamic Software Serial +// + +#if HAS_TMC_UART + #define X_SERIAL_TX_PIN PC9 + #define Y_SERIAL_TX_PIN PC10 + #define Z_SERIAL_TX_PIN PD0 + #define E0_SERIAL_TX_PIN PD3 + #define E1_SERIAL_TX_PIN PD6 + #define E2_SERIAL_TX_PIN PB7 + #define E3_SERIAL_TX_PIN PC15 + #define E4_SERIAL_TX_PIN PE10 +#endif + +// +// LCD / Controller +// +#if ENABLED(FYSETC_242_OLED_12864) + + #define BTN_EN1 EXP1_01_PIN + #define BTN_EN2 EXP1_08_PIN + #define BTN_ENC EXP1_02_PIN + + #define BEEPER_PIN EXP2_03_PIN + + #define LCD_PINS_DC EXP1_06_PIN + #define LCD_PINS_RS EXP2_05_PIN // LCD_RST + #define DOGLCD_CS EXP1_04_PIN + #define DOGLCD_MOSI EXP1_05_PIN + #define DOGLCD_SCK EXP1_03_PIN + #define DOGLCD_A0 LCD_PINS_DC + #define FORCE_SOFT_SPI + + #define KILL_PIN -1 // NC + #define BOARD_NEOPIXEL_PIN EXP1_07_PIN + +#elif HAS_WIRED_LCD + + #define BEEPER_PIN EXP1_01_PIN + #define BTN_ENC EXP1_02_PIN + + #if ENABLED(CR10_STOCKDISPLAY) + #define LCD_PINS_RS EXP1_07_PIN + + #define BTN_EN1 EXP1_03_PIN + #define BTN_EN2 EXP1_05_PIN + + #define LCD_PINS_EN EXP1_08_PIN + #define LCD_PINS_D4 EXP1_06_PIN + + #else + + #define LCD_PINS_RS EXP1_04_PIN + + #define BTN_EN1 EXP2_03_PIN + #define BTN_EN2 EXP2_05_PIN + + #define LCD_SDSS EXP2_04_PIN + + #define LCD_PINS_EN EXP1_03_PIN + #define LCD_PINS_D4 EXP1_05_PIN + + #if ENABLED(FYSETC_MINI_12864) + // See https://wiki.fysetc.com/Mini12864_Panel + #define DOGLCD_CS EXP1_03_PIN + #define DOGLCD_A0 EXP1_04_PIN + #if ENABLED(FYSETC_GENERIC_12864_1_1) + #define LCD_BACKLIGHT_PIN EXP1_07_PIN + #endif + #define LCD_RESET_PIN EXP1_05_PIN // Must be high or open for LCD to operate normally. + #if ANY(FYSETC_MINI_12864_1_2, FYSETC_MINI_12864_2_0) + #ifndef RGB_LED_R_PIN + #define RGB_LED_R_PIN EXP1_06_PIN + #endif + #ifndef RGB_LED_G_PIN + #define RGB_LED_G_PIN EXP1_07_PIN + #endif + #ifndef RGB_LED_B_PIN + #define RGB_LED_B_PIN EXP1_08_PIN + #endif + #elif ENABLED(FYSETC_MINI_12864_2_1) + #define NEOPIXEL_PIN EXP1_06_PIN + #endif + #endif + + #if IS_ULTIPANEL + #define LCD_PINS_D5 EXP1_06_PIN + #define LCD_PINS_D6 EXP1_07_PIN + #define LCD_PINS_D7 EXP1_08_PIN + #if ENABLED(REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER) + #define BTN_ENC_EN LCD_PINS_D7 // Detect the presence of the encoder + #endif + #endif + + #endif + +#endif // HAS_WIRED_LCD + +// Alter timing for graphical display +#if IS_U8GLIB_ST7920 + #define BOARD_ST7920_DELAY_1 96 + #define BOARD_ST7920_DELAY_2 48 + #define BOARD_ST7920_DELAY_3 715 +#endif diff --git a/Marlin/src/pins/stm32h7/pins_FLY_SUPER8_PRO.h b/Marlin/src/pins/stm32h7/pins_FLY_SUPER8_PRO.h new file mode 100644 index 0000000000..4e19a0e05f --- /dev/null +++ b/Marlin/src/pins/stm32h7/pins_FLY_SUPER8_PRO.h @@ -0,0 +1,352 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +/** + * Bootloader Download + * https://mellow.klipper.cn/docs/ProductDoc/MainBoard/fly-super/fly-super8-pro/flash/bl + */ + +#define ALLOW_STM32DUINO +#include "env_validate.h" + +#define BOARD_INFO_NAME "FLY_SUPER8_PRO" +#define DEFAULT_MACHINE_NAME BOARD_INFO_NAME + +// Avoid conflict with fans and TIMER_TONE +#define TEMP_TIMER 3 +#define STEP_TIMER 5 + +// +// EEPROM Emulation +// +#if NO_EEPROM_SELECTED + #define FLASH_EEPROM_EMULATION + //#define SRAM_EEPROM_EMULATION + //#define I2C_EEPROM +#endif + +#if ENABLED(FLASH_EEPROM_EMULATION) + // Decrease delays and flash wear by spreading writes across + // the 128kB sector allocated for EEPROM emulation. + #define FLASH_EEPROM_LEVELING +#elif ENABLED(I2C_EEPROM) + #define MARLIN_EEPROM_SIZE 0x2000 // 8K +#endif + +#ifndef MARLIN_EEPROM_SIZE + #define MARLIN_EEPROM_SIZE 0x1000 // 4K +#endif + +// +// Servos +// +#define SERVO0_PIN PC6 + +// +// Limit Switches +// +#define X_MIN_PIN PG12 +#define X_MAX_PIN PG11 +#define Y_MIN_PIN PG10 +#define Y_MAX_PIN PG9 +#define Z_MIN_PIN PD7 +#define Z_MAX_PIN PD6 + +#define IO6 PA8 +#define IN7 PF8 +#define HVIN PF3 + +// +// Z Probe (when not Z_MIN_PIN) +// +#define Z_MIN_PROBE_PIN PC3 // Z3_PIN + +// +// Steppers +// + +#define X_STEP_PIN PE2 +#define X_DIR_PIN PC5 +#define X_ENABLE_PIN PF11 +#ifndef X_CS_PIN + #define X_CS_PIN PC4 +#endif + +#define Y_STEP_PIN PE3 +#define Y_DIR_PIN PF13 +#define Y_ENABLE_PIN PF14 +#ifndef Y_CS_PIN + #define Y_CS_PIN PF12 +#endif + +#define Z_STEP_PIN PE4 +#define Z_DIR_PIN PG0 +#define Z_ENABLE_PIN PG1 +#ifndef Z_CS_PIN + #define Z_CS_PIN PF15 +#endif + +#define E0_STEP_PIN PE14 +#define E0_DIR_PIN PE8 +#define E0_ENABLE_PIN PE9 +#ifndef E0_CS_PIN + #define E0_CS_PIN PE7 +#endif + +#define E1_STEP_PIN PE15 +#define E1_DIR_PIN PE11 +#define E1_ENABLE_PIN PF2 +#ifndef E1_CS_PIN + #define E1_CS_PIN PE10 +#endif + +#define E2_STEP_PIN PE1 +#define E2_DIR_PIN PF0 +#define E2_ENABLE_PIN PC15 +#ifndef E2_CS_PIN + #define E2_CS_PIN PF1 +#endif + +#define E3_STEP_PIN PE0 +#define E3_DIR_PIN PG3 +#define E3_ENABLE_PIN PG4 +#ifndef E3_CS_PIN + #define E3_CS_PIN PG2 +#endif + +#define E4_STEP_PIN PE6 +#define E4_DIR_PIN PG6 +#define E4_ENABLE_PIN PG7 +#ifndef E4_CS_PIN + #define E4_CS_PIN PG5 +#endif + +// +// Temperature Sensors +// +#define TEMP_0_PIN PF4 // Analog Input +#define TEMP_1_PIN PF5 // Analog Input +#define TEMP_2_PIN PF9 // Analog Input +#define TEMP_3_PIN PF10 // Analog Input +#define TEMP_4_PIN PC0 // Analog Input +#define TEMP_BED_PIN PC1 // Analog Input + +// +// Heaters / Fans +// +#define HEATER_0_PIN PB0 +#define HEATER_1_PIN PB1 +#define HEATER_2_PIN PC7 +#define HEATER_3_PIN PF7 +#define HEATER_4_PIN PF6 +#define HEATER_BED_PIN PE5 + +#ifndef FAN0_PIN + #define FAN0_PIN PA0 +#endif +#define FAN1_PIN PA1 +#define FAN2_PIN PA2 +#define FAN3_PIN PA3 +#define FAN4_PIN PA15 +#define FAN5_PIN PB11 +#define FAN8_PIN PB10 +#define FAN9_PIN PD12 +#define FAN6_PIN PD14 +#define FAN7_PIN PD15 + +/** + * ------ ------ + * PE12 | 1 2 | PE13 PA6 | 1 2 | PA5 + * PB2 | 3 4 | PG8 PB7 | 3 4 | PA4 + * PC14 5 6 | PC13 PB6 5 6 | PA7 + * PG14 | 7 8 | PG13 PG15 | 7 8 | RESET + * GND | 9 10 | 5V GND | 9 10 | -- + * ------ ------ + * EXP1 EXP2 + */ +#define EXP1_01_PIN PE12 +#define EXP1_02_PIN PE13 +#define EXP1_03_PIN PB2 +#define EXP1_04_PIN PG8 +#define EXP1_05_PIN PC14 +#define EXP1_06_PIN PC13 +#define EXP1_07_PIN PG14 +#define EXP1_08_PIN PG13 + +#define EXP2_01_PIN PA6 +#define EXP2_02_PIN PA5 +#define EXP2_03_PIN PB7 +#define EXP2_04_PIN PA4 +#define EXP2_05_PIN PB6 +#define EXP2_06_PIN PA7 +#define EXP2_07_PIN PG15 +#define EXP2_08_PIN -1 // RESET + +// +// Onboard SD support +// +//#define SD_CARD_DETECT_PIN PC13 + +#ifndef SDCARD_CONNECTION + #define SDCARD_CONNECTION LCD +#endif + +#if SD_CONNECTION_IS(ONBOARD) + + #define ONBOARD_SDIO // Use SDIO for onboard SD + +#elif SD_CONNECTION_IS(LCD) + + #define SD_SCK_PIN EXP2_02_PIN + #define SD_MISO_PIN EXP2_01_PIN + #define SD_MOSI_PIN EXP2_06_PIN + #define SDSS EXP2_04_PIN + #define SD_DETECT_PIN EXP2_07_PIN + +#endif + +// +// Trinamic SPI +// +#ifndef TMC_SPI_SCK + #define TMC_SPI_SCK PB3 +#endif +#ifndef TMC_SPI_MISO + #define TMC_SPI_MISO PB4 +#endif +#ifndef TMC_SPI_MOSI + #define TMC_SPI_MOSI PB5 +#endif + +// +// Trinamic Software Serial +// + +#if HAS_TMC_UART + #define X_SERIAL_TX_PIN PC4 + #define Y_SERIAL_TX_PIN PF12 + #define Z_SERIAL_TX_PIN PF15 + #define E0_SERIAL_TX_PIN PE7 + #define E1_SERIAL_TX_PIN PE10 + #define E2_SERIAL_TX_PIN PF1 + #define E3_SERIAL_TX_PIN PG2 + #define E4_SERIAL_TX_PIN PG5 +#endif + +// +// LCD / Controller +// + +#if ENABLED(FYSETC_242_OLED_12864) + + #define BTN_EN1 EXP1_01_PIN + #define BTN_EN2 EXP1_08_PIN + #define BTN_ENC EXP1_02_PIN + + #define BEEPER_PIN EXP2_03_PIN + + #define LCD_PINS_DC EXP1_06_PIN + #define LCD_PINS_RS EXP2_05_PIN // LCD_RST + #define DOGLCD_CS EXP1_04_PIN + #define DOGLCD_MOSI EXP1_05_PIN + #define DOGLCD_SCK EXP1_03_PIN + #define DOGLCD_A0 LCD_PINS_DC + #define FORCE_SOFT_SPI + + #define KILL_PIN -1 // NC + #define BOARD_NEOPIXEL_PIN EXP1_07_PIN + +#elif HAS_WIRED_LCD + + #define BEEPER_PIN EXP1_01_PIN + #define BTN_ENC EXP1_02_PIN + + #if ENABLED(CR10_STOCKDISPLAY) + #define LCD_PINS_RS EXP1_07_PIN + + #define BTN_EN1 EXP1_03_PIN + #define BTN_EN2 EXP1_05_PIN + + #define LCD_PINS_EN EXP1_08_PIN + #define LCD_PINS_D4 EXP1_06_PIN + + #else + + #define LCD_PINS_RS EXP1_04_PIN + + #define BTN_EN1 EXP2_03_PIN + #define BTN_EN2 EXP2_05_PIN + + #define LCD_SDSS EXP2_04_PIN + + #define LCD_PINS_EN EXP1_03_PIN + #define LCD_PINS_D4 EXP1_05_PIN + + #if ENABLED(FYSETC_MINI_12864) + // See https://wiki.fysetc.com/Mini12864_Panel + #define DOGLCD_CS EXP1_03_PIN + #define DOGLCD_A0 EXP1_04_PIN + #if ENABLED(FYSETC_GENERIC_12864_1_1) + #define LCD_BACKLIGHT_PIN EXP1_07_PIN + #endif + #define LCD_RESET_PIN EXP1_05_PIN // Must be high or open for LCD to operate normally. + #if ANY(FYSETC_MINI_12864_1_2, FYSETC_MINI_12864_2_0) + #ifndef RGB_LED_R_PIN + #define RGB_LED_R_PIN EXP1_06_PIN + #endif + #ifndef RGB_LED_G_PIN + #define RGB_LED_G_PIN EXP1_07_PIN + #endif + #ifndef RGB_LED_B_PIN + #define RGB_LED_B_PIN EXP1_08_PIN + #endif + #elif ENABLED(FYSETC_MINI_12864_2_1) + #define NEOPIXEL_PIN EXP1_06_PIN + #endif + #endif + + #if IS_ULTIPANEL + #define LCD_PINS_D5 EXP1_06_PIN + #define LCD_PINS_D6 EXP1_07_PIN + #define LCD_PINS_D7 EXP1_08_PIN + #if ENABLED(REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER) + #define BTN_ENC_EN LCD_PINS_D7 // Detect the presence of the encoder + #endif + #endif + + #endif + +#endif // HAS_WIRED_LCD + +// +// Filament runout +// + +#define FIL_RUNOUT_PIN PA8 + +// Alter timing for graphical display +#if IS_U8GLIB_ST7920 + #define BOARD_ST7920_DELAY_1 96 + #define BOARD_ST7920_DELAY_2 48 + #define BOARD_ST7920_DELAY_3 715 +#endif diff --git a/buildroot/share/PlatformIO/boards/marlin_stm32F072.json b/buildroot/share/PlatformIO/boards/marlin_stm32F072.json new file mode 100644 index 0000000000..3a85b7c4ec --- /dev/null +++ b/buildroot/share/PlatformIO/boards/marlin_stm32F072.json @@ -0,0 +1,48 @@ +{ + "build": { + "core": "stm32", + "cpu": "cortex-m0", + "extra_flags": "-DSTM32F072xB", + "f_cpu": "48000000L", + "mcu": "stm32f072rbt6", + "product_line": "STM32F072xB", + "variant": "MARLIN_FLY_D6" + }, + "connectivity": [ + "can" + ], + "debug": { + "default_tools": [ + "stlink" + ], + "jlink_device": "STM32F072RB", + "onboard_tools": [ + "stlink" + ], + "openocd_board": "st_nucleo_f0", + "openocd_target": "stm32f0x", + "svd_path": "STM32F072x.svd" + }, + "frameworks": [ + "arduino", + "cmsis", + "mbed", + "stm32cube", + "libopencm3" + ], + "name": "ST Nucleo F072RB", + "upload": { + "maximum_ram_size": 16384, + "maximum_size": 131072, + "protocol": "stlink", + "protocols": [ + "jlink", + "cmsis-dap", + "stlink", + "blackmagic", + "mbed" + ] + }, + "url": "https://developer.mbed.org/platforms/ST-Nucleo-F072RB/", + "vendor": "ST" +} diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FLY_CDY_V3/PeripheralPins.c b/buildroot/share/PlatformIO/variants/MARLIN_FLY_CDY_V3/PeripheralPins.c new file mode 100644 index 0000000000..03b8d0c4f4 --- /dev/null +++ b/buildroot/share/PlatformIO/variants/MARLIN_FLY_CDY_V3/PeripheralPins.c @@ -0,0 +1,394 @@ +/* + ******************************************************************************* + * Copyright (c) 2019, STMicroelectronics + * All rights reserved. + * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ******************************************************************************* + * Automatically generated from STM32F407V(E-G)Tx.xml + */ +#include "Arduino.h" +#include "PeripheralPins.h" + +/** + * Variant for: mks_robin_pro2, mks_robin_nano_v3, Anet_ET4_OpenBLT + */ + +/* ===== + * Note: Commented lines are alternative possibilities which are not used per default. + * If you change them, you will have to know what you do + * ===== + */ + +//*** ADC *** + +#ifdef HAL_ADC_MODULE_ENABLED +WEAK const PinMap PinMap_ADC[] = { + {PA_0, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 0, 0)}, // ADC1_IN0 + {PA_0, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 0, 0)}, // ADC2_IN0 + {PA_0, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 0, 0)}, // ADC3_IN0 + {PA_1, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 1, 0)}, // ADC1_IN1 + {PA_1, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 1, 0)}, // ADC2_IN1 + {PA_1, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 1, 0)}, // ADC3_IN1 + {PA_2, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 2, 0)}, // ADC1_IN2 + {PA_2, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 2, 0)}, // ADC2_IN2 + {PA_2, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 2, 0)}, // ADC3_IN2 + {PA_3, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 3, 0)}, // ADC1_IN3 + {PA_3, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 3, 0)}, // ADC2_IN3 + {PA_3, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 3, 0)}, // ADC3_IN3 + {PA_4, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 4, 0)}, // ADC1_IN4 + {PA_4, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 4, 0)}, // ADC2_IN4 + {PA_5, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 5, 0)}, // ADC1_IN5 + {PA_5, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 5, 0)}, // ADC2_IN5 + {PA_6, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 6, 0)}, // ADC1_IN6 + {PA_6, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 6, 0)}, // ADC2_IN6 + {PA_7, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 7, 0)}, // ADC1_IN7 + {PA_7, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 7, 0)}, // ADC2_IN7 + {PB_0, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 8, 0)}, // ADC1_IN8 + {PB_0, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 8, 0)}, // ADC2_IN8 + {PB_1, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 9, 0)}, // ADC1_IN9 + {PB_1, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 9, 0)}, // ADC2_IN9 + {PC_0, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 10, 0)}, // ADC1_IN10 + {PC_0, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 10, 0)}, // ADC2_IN10 + {PC_0, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 10, 0)}, // ADC3_IN10 + {PC_1, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 11, 0)}, // ADC1_IN11 + {PC_1, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 11, 0)}, // ADC2_IN11 + {PC_1, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 11, 0)}, // ADC3_IN11 + {PC_2, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 12, 0)}, // ADC1_IN12 + {PC_2, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 12, 0)}, // ADC2_IN12 + {PC_2, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 12, 0)}, // ADC3_IN12 + {PC_3, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 13, 0)}, // ADC1_IN13 + {PC_3, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 13, 0)}, // ADC2_IN13 + {PC_3, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 13, 0)}, // ADC3_IN13 + {PC_4, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 14, 0)}, // ADC1_IN14 + {PC_4, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 14, 0)}, // ADC2_IN14 + {PC_5, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 15, 0)}, // ADC1_IN15 + {PC_5, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 15, 0)}, // ADC2_IN15 + {NC, NP, 0} +}; +#endif + +//*** DAC *** + +#ifdef HAL_DAC_MODULE_ENABLED +WEAK const PinMap PinMap_DAC[] = { + {PA_4, DAC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 1, 0)}, // DAC_OUT1 + {PA_5, DAC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 2, 0)}, // DAC_OUT2 + {NC, NP, 0} +}; +#endif + +//*** I2C *** + +#ifdef HAL_I2C_MODULE_ENABLED +WEAK const PinMap PinMap_I2C_SDA[] = { + {PB_7, I2C1, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C1)}, + {PB_9, I2C1, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C1)}, + {PB_11, I2C2, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C2)}, + {PC_9, I2C3, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C3)}, + {NC, NP, 0} +}; + +WEAK const PinMap PinMap_I2C_SCL[] = { + {PA_8, I2C3, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C3)}, + {PB_6, I2C1, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C1)}, + {PB_8, I2C1, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C1)}, + {PB_10, I2C2, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C2)}, + {NC, NP, 0} +}; +#endif + +//*** PWM *** + +#ifdef HAL_TIM_MODULE_ENABLED +// Some pins can perform PWM from more than one timer. These were selected to utilize as many channels as +// possible from timers which were already dedicated to PWM output. + +// TIM1 = Pins are using for OTG FS +// TIM2 = [HEATER_BED], TIM2 is used OTG HS SOF +// TIM6 = Tone +// TIM8 = [FAN0, HEATER_1] OTG HS +// TIM7 = Servo +// TIM9 = [HEATER_0, ] +// TIM1, TIM8, TIM12 = Pins are using for OTG HS +// No timer = [FAN1 ] + +WEAK const PinMap PinMap_PWM[] = { + {PA_0, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 1, 0)}, // TIM2_CH1 + {PA_0, TIM5, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM5, 1, 0)}, // TIM5_CH1 + {PA_1, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 2, 0)}, // TIM2_CH2 + {PA_1, TIM5, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM5, 2, 0)}, // TIM5_CH2 + {PA_2, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 3, 0)}, // TIM2_CH3 + {PA_2, TIM5, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM5, 3, 0)}, // TIM5_CH3 + {PA_2, TIM9, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM9, 1, 0)}, // TIM9_CH1 + {PA_3, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 4, 0)}, // TIM2_CH4 + {PA_3, TIM5, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM5, 4, 0)}, // TIM5_CH4 + {PA_3, TIM9, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM9, 2, 0)}, // TIM9_CH2 + {PA_5, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 1, 0)}, // TIM2_CH1 + {PA_5, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 1, 1)}, // TIM8_CH1N + {PA_6, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 1, 0)}, // TIM3_CH1 + {PA_6, TIM13, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_TIM13, 1, 0)}, // TIM13_CH1 + {PA_7, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 1, 1)}, // TIM1_CH1N + {PA_7, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 2, 0)}, // TIM3_CH2 + {PA_7, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 1, 1)}, // TIM8_CH1N + {PA_7, TIM14, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_TIM14, 1, 0)}, // TIM14_CH1 + {PA_8, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 1, 0)}, // TIM1_CH1 + {PA_9, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 2, 0)}, // TIM1_CH2 + {PA_10, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 3, 0)}, // TIM1_CH3 + {PA_11, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 4, 0)}, // TIM1_CH4 + {PA_15, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 1, 0)}, // TIM2_CH1 + {PB_0, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 2, 1)}, // TIM1_CH2N + {PB_0, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 3, 0)}, // TIM3_CH3 + {PB_0, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 2, 1)}, // TIM8_CH2N + {PB_1, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 3, 1)}, // TIM1_CH3N + {PB_1, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 4, 0)}, // TIM3_CH4 + {PB_1, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 3, 1)}, // TIM8_CH3N + {PB_2, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 4, 0)}, // TIM2_CH4 + {PB_3, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 2, 0)}, // TIM2_CH2 + {PB_4, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 1, 0)}, // TIM3_CH1 + {PB_5, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 2, 0)}, // TIM3_CH2 + {PB_6, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 1, 0)}, // TIM4_CH1 + {PB_7, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 2, 0)}, // TIM4_CH2 + {PB_8, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 3, 0)}, // TIM4_CH3 + {PB_8, TIM10, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM10, 1, 0)}, // TIM10_CH1 + {PB_9, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 4, 0)}, // TIM4_CH4 + {PB_9, TIM11, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM11, 1, 0)}, // TIM11_CH1 + {PB_10, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 3, 0)}, // TIM2_CH3 + {PB_11, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 4, 0)}, // TIM2_CH4 + {PB_13, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 1, 1)}, // TIM1_CH1N + {PB_14, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 2, 1)}, // TIM1_CH2N + {PB_14, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 2, 1)}, // TIM8_CH2N + {PB_14, TIM12, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_TIM12, 1, 0)}, // TIM12_CH1 + {PB_15, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 3, 1)}, // TIM1_CH3N + {PB_15, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 3, 1)}, // TIM8_CH3N + {PB_15, TIM12, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_TIM12, 2, 0)}, // TIM12_CH2 + {PC_6, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 1, 0)}, // TIM3_CH1 + {PC_6, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 1, 0)}, // TIM8_CH1 + {PC_7, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 2, 0)}, // TIM3_CH2 + {PC_7, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 2, 0)}, // TIM8_CH2 + {PC_8, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 3, 0)}, // TIM3_CH3 + {PC_8, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 3, 0)}, // TIM8_CH3 + {PC_9, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 4, 0)}, // TIM3_CH4 + {PC_9, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 4, 0)}, // TIM8_CH4 + {PD_12, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 1, 0)}, // TIM4_CH1 + {PD_13, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 2, 0)}, // TIM4_CH2 + {PD_14, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 3, 0)}, // TIM4_CH3 + {PD_15, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 4, 0)}, // TIM4_CH4 + {PE_5, TIM9, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM9, 1, 0)}, // TIM9_CH1 + {PE_6, TIM9, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM9, 2, 0)}, // TIM9_CH2 + {PE_8, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 1, 1)}, // TIM1_CH1N + {PE_9, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 1, 0)}, // TIM1_CH1 + {PE_10, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 2, 1)}, // TIM1_CH2N + {PE_11, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 2, 0)}, // TIM1_CH2 + {PE_12, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 3, 1)}, // TIM1_CH3N + {PE_13, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 3, 0)}, // TIM1_CH3 + {PE_14, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 4, 0)}, // TIM1_CH4 + {NC, NP, 0} +}; +#endif + +//*** SERIAL *** + +#ifdef HAL_UART_MODULE_ENABLED +WEAK const PinMap PinMap_UART_TX[] = { + {PA_0, UART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART4)}, + {PA_2, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)}, + {PA_9, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART1)}, + {PB_6, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART1)}, + {PB_10, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + {PC_6, USART6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_USART6)}, + {PC_10, UART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART4)}, + {PC_10, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + {PC_12, UART5, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART5)}, + {PD_5, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)}, + {PD_8, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + {NC, NP, 0} +}; + +WEAK const PinMap PinMap_UART_RX[] = { + {PA_1, UART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART4)}, + {PA_3, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)}, + {PA_10, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART1)}, + {PB_7, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART1)}, + {PB_11, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + {PC_7, USART6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_USART6)}, + {PC_11, UART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART4)}, + {PC_11, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + {PD_2, UART5, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART5)}, + {PD_6, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)}, + {PD_9, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + {NC, NP, 0} +}; + +WEAK const PinMap PinMap_UART_RTS[] = { + {PA_1, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)}, + {PA_12, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART1)}, + {PB_14, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + {PD_4, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)}, + {PD_12, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + {NC, NP, 0} +}; + +WEAK const PinMap PinMap_UART_CTS[] = { + {PA_0, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)}, + {PA_11, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART1)}, + {PB_13, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + {PD_3, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)}, + {PD_11, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + {NC, NP, 0} +}; +#endif + +//*** SPI *** + +#ifdef HAL_SPI_MODULE_ENABLED +WEAK const PinMap PinMap_SPI_MOSI[] = { + {PA_7, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, + {PB_5, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, + {PB_5, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)}, + {PB_15, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + {PC_3, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + {PC_12, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)}, + {NC, NP, 0} +}; + +WEAK const PinMap PinMap_SPI_MISO[] = { + {PA_6, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, + {PB_4, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, + {PB_4, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)}, + {PB_14, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + {PC_2, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + {PC_11, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)}, + {NC, NP, 0} +}; + +WEAK const PinMap PinMap_SPI_SCLK[] = { + {PA_5, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, + {PB_3, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, + {PB_3, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)}, + {PB_10, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + {PB_13, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + {PC_10, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)}, + {NC, NP, 0} +}; + +WEAK const PinMap PinMap_SPI_SSEL[] = { + {PA_4, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, + {PA_4, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)}, + {PA_15, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, + {PA_15, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)}, + {PB_9, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + {PB_12, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + {NC, NP, 0} +}; +#endif + +//*** CAN *** + +#ifdef HAL_CAN_MODULE_ENABLED +WEAK const PinMap PinMap_CAN_RD[] = { + {PA_11, CAN1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_CAN1)}, + {PB_5, CAN2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_CAN2)}, + {PB_8, CAN1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_CAN1)}, + {PB_12, CAN2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_CAN2)}, + {PD_0, CAN1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_CAN1)}, + {NC, NP, 0} +}; + +WEAK const PinMap PinMap_CAN_TD[] = { + {PA_12, CAN1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_CAN1)}, + {PB_6, CAN2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_CAN2)}, + {PB_9, CAN1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_CAN1)}, + {PB_13, CAN2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_CAN2)}, + {PD_1, CAN1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_CAN1)}, + {NC, NP, 0} +}; +#endif + +//*** ETHERNET *** + +#ifdef HAL_ETH_MODULE_ENABLED +WEAK const PinMap PinMap_Ethernet[] = { + {PA_0, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_CRS + {PA_1, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_REF_CLK|ETH_RX_CLK + {PA_2, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_MDIO + {PA_3, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_COL + {PA_7, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_CRS_DV|ETH_RX_DV + {PB_0, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_RXD2 + {PB_1, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_RXD3 + {PB_5, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_PPS_OUT + {PB_8, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_TXD3 + {PB_10, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_RX_ER + {PB_11, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_TX_EN + {PB_12, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_TXD0 + {PB_13, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_TXD1 + {PC_1, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_MDC + {PC_2, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_TXD2 + {PC_3, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_TX_CLK + {PC_4, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_RXD0 + {PC_5, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_RXD1 + {PE_2, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_TXD3 + {NC, NP, 0} +}; +#endif + +//*** No QUADSPI *** + +//*** USB *** + +#ifdef HAL_PCD_MODULE_ENABLED +WEAK const PinMap PinMap_USB_OTG_FS[] = { + {PA_8, USB_OTG_FS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_FS)}, // USB_OTG_FS_SOF + {PA_9, USB_OTG_FS, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, GPIO_AF_NONE)}, // USB_OTG_FS_VBUS + {PA_10, USB_OTG_FS, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_PULLUP, GPIO_AF10_OTG_FS)}, // USB_OTG_FS_ID + {PA_11, USB_OTG_FS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_FS)}, // USB_OTG_FS_DM + {PA_12, USB_OTG_FS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_FS)}, // USB_OTG_FS_DP + {NC, NP, 0} +}; + +WEAK const PinMap PinMap_USB_OTG_HS[] = { +#ifdef USE_USB_HS_IN_FS + {PA_4, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_OTG_HS_FS)}, // USB_OTG_HS_SOF + {PB_12, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_PULLUP, GPIO_AF12_OTG_HS_FS)}, // USB_OTG_HS_ID + {PB_13, USB_OTG_HS, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, GPIO_AF_NONE)}, // USB_OTG_HS_VBUS + {PB_14, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_OTG_HS_FS)}, // USB_OTG_HS_DM + {PB_15, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_OTG_HS_FS)}, // USB_OTG_HS_DP +#else + {PA_3, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_HS)}, // USB_OTG_HS_ULPI_D0 + {PA_5, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_HS)}, // USB_OTG_HS_ULPI_CK + {PB_0, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_HS)}, // USB_OTG_HS_ULPI_D1 + {PB_1, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_HS)}, // USB_OTG_HS_ULPI_D2 + {PB_5, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_HS)}, // USB_OTG_HS_ULPI_D7 + {PB_10, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_HS)}, // USB_OTG_HS_ULPI_D3 + {PB_11, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_HS)}, // USB_OTG_HS_ULPI_D4 + {PB_12, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_HS)}, // USB_OTG_HS_ULPI_D5 + {PB_13, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_HS)}, // USB_OTG_HS_ULPI_D6 + {PC_0, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_HS)}, // USB_OTG_HS_ULPI_STP + {PC_2, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_HS)}, // USB_OTG_HS_ULPI_DIR + {PC_3, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_HS)}, // USB_OTG_HS_ULPI_NXT +#endif /* USE_USB_HS_IN_FS */ + {NC, NP, 0} +}; +#endif + +//*** SD *** + +#ifdef HAL_SD_MODULE_ENABLED +WEAK const PinMap PinMap_SD[] = { + {PB_8, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDIO)}, // SDIO_D4 + {PB_9, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDIO)}, // SDIO_D5 + {PC_6, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDIO)}, // SDIO_D6 + {PC_7, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDIO)}, // SDIO_D7 + {PC_8, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDIO)}, // SDIO_D0 + {PC_9, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDIO)}, // SDIO_D1 + {PC_10, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDIO)}, // SDIO_D2 + {PC_11, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDIO)}, // SDIO_D3 + {PC_12, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF12_SDIO)}, // SDIO_CK + {PD_2, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF12_SDIO)}, // SDIO_CMD + {NC, NP, 0} +}; +#endif diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FLY_CDY_V3/PinNamesVar.h b/buildroot/share/PlatformIO/variants/MARLIN_FLY_CDY_V3/PinNamesVar.h new file mode 100644 index 0000000000..2424885937 --- /dev/null +++ b/buildroot/share/PlatformIO/variants/MARLIN_FLY_CDY_V3/PinNamesVar.h @@ -0,0 +1,50 @@ +/* SYS_WKUP */ +#ifdef PWR_WAKEUP_PIN1 + SYS_WKUP1 = PA_0, +#endif +#ifdef PWR_WAKEUP_PIN2 + SYS_WKUP2 = NC, +#endif +#ifdef PWR_WAKEUP_PIN3 + SYS_WKUP3 = NC, +#endif +#ifdef PWR_WAKEUP_PIN4 + SYS_WKUP4 = NC, +#endif +#ifdef PWR_WAKEUP_PIN5 + SYS_WKUP5 = NC, +#endif +#ifdef PWR_WAKEUP_PIN6 + SYS_WKUP6 = NC, +#endif +#ifdef PWR_WAKEUP_PIN7 + SYS_WKUP7 = NC, +#endif +#ifdef PWR_WAKEUP_PIN8 + SYS_WKUP8 = NC, +#endif +/* USB */ +#ifdef USBCON + USB_OTG_FS_SOF = PA_8, + USB_OTG_FS_VBUS = PA_9, + USB_OTG_FS_ID = PA_10, + USB_OTG_FS_DM = PA_11, + USB_OTG_FS_DP = PA_12, + USB_OTG_HS_ULPI_D0 = PA_3, + USB_OTG_HS_SOF = PA_4, + USB_OTG_HS_ULPI_CK = PA_5, + USB_OTG_HS_ULPI_D1 = PB_0, + USB_OTG_HS_ULPI_D2 = PB_1, + USB_OTG_HS_ULPI_D7 = PB_5, + USB_OTG_HS_ULPI_D3 = PB_10, + USB_OTG_HS_ULPI_D4 = PB_11, + USB_OTG_HS_ID = PB_12, + USB_OTG_HS_ULPI_D5 = PB_12, + USB_OTG_HS_ULPI_D6 = PB_13, + USB_OTG_HS_VBUS = PB_13, + USB_OTG_HS_DM = PB_14, + USB_OTG_HS_DP = PB_15, + USB_OTG_HS_ULPI_STP = PC_0, + USB_OTG_HS_ULPI_DIR = PC_2, + USB_OTG_HS_ULPI_NXT = PC_3, +#endif diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FLY_CDY_V3/hal_conf_extra.h b/buildroot/share/PlatformIO/variants/MARLIN_FLY_CDY_V3/hal_conf_extra.h new file mode 100644 index 0000000000..2b3e239868 --- /dev/null +++ b/buildroot/share/PlatformIO/variants/MARLIN_FLY_CDY_V3/hal_conf_extra.h @@ -0,0 +1,594 @@ +/** + ****************************************************************************** + * @file stm32f4xx_hal_conf_template.h + * @author MCD Application Team + * @brief HAL configuration template file. + * This file should be copied to the application folder and renamed + * to stm32f4xx_hal_conf.h. + ****************************************************************************** + * @attention + * + * Copyright (c) 2017 STMicroelectronics. + * All rights reserved. + * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F4xx_HAL_CONF_H +#define __STM32F4xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ +#ifndef HAL_MODULE_ENABLED + #define HAL_MODULE_ENABLED +#endif +#ifndef HAL_ADC_MODULE_ENABLED + #define HAL_ADC_MODULE_ENABLED +#endif +#ifndef HAL_CAN_LEGACY_MODULE_ENABLED + #define HAL_CAN_LEGACY_MODULE_ENABLED +#endif +#ifndef HAL_CRC_MODULE_ENABLED + #define HAL_CRC_MODULE_ENABLED +#endif +#ifndef HAL_DAC_MODULE_ENABLED + #define HAL_DAC_MODULE_ENABLED +#endif +#ifndef HAL_DMA_MODULE_ENABLED + #define HAL_DMA_MODULE_ENABLED +#endif +#ifndef HAL_EXTI_MODULE_ENABLED + #define HAL_EXTI_MODULE_ENABLED // Needed for Endstop (and other external) Interrupts +#endif +#ifndef HAL_GPIO_MODULE_ENABLED + #define HAL_GPIO_MODULE_ENABLED +#endif +#ifndef HAL_I2C_MODULE_ENABLED + #define HAL_I2C_MODULE_ENABLED +#endif +#ifndef HAL_PWR_MODULE_ENABLED + #define HAL_PWR_MODULE_ENABLED +#endif +#ifndef HAL_RCC_MODULE_ENABLED + #define HAL_RCC_MODULE_ENABLED +#endif +#ifndef HAL_SPI_MODULE_ENABLED + #define HAL_SPI_MODULE_ENABLED +#endif +#ifndef HAL_TIM_MODULE_ENABLED + #define HAL_TIM_MODULE_ENABLED +#endif +#ifndef HAL_USART_MODULE_ENABLED + #define HAL_USART_MODULE_ENABLED +#endif +#ifndef HAL_CORTEX_MODULE_ENABLED + #define HAL_CORTEX_MODULE_ENABLED +#endif +#ifndef HAL_UART_MODULE_ENABLED + //#define HAL_UART_MODULE_ENABLED +#endif +#ifndef HAL_PCD_MODULE_ENABLED + //#define HAL_PCD_MODULE_ENABLED +#endif + +#ifndef HAL_CAN_MODULE_ENABLED + //#define HAL_CAN_MODULE_ENABLED +#endif +#ifndef HAL_CEC_MODULE_ENABLED + //#define HAL_CEC_MODULE_ENABLED +#endif +#ifndef HAL_CRYP_MODULE_ENABLED + //#define HAL_CRYP_MODULE_ENABLED +#endif +#ifndef HAL_DCMI_MODULE_ENABLED + //#define HAL_DCMI_MODULE_ENABLED +#endif +#ifndef HAL_DMA2D_MODULE_ENABLED + //#define HAL_DMA2D_MODULE_ENABLED +#endif +#ifndef HAL_ETH_MODULE_ENABLED + //#define HAL_ETH_MODULE_ENABLED +#endif +#ifndef HAL_FLASH_MODULE_ENABLED + //#define HAL_FLASH_MODULE_ENABLED +#endif +#ifndef HAL_NAND_MODULE_ENABLED + //#define HAL_NAND_MODULE_ENABLED +#endif +#ifndef HAL_NOR_MODULE_ENABLED + //#define HAL_NOR_MODULE_ENABLED +#endif +#ifndef HAL_PCCARD_MODULE_ENABLED + //#define HAL_PCCARD_MODULE_ENABLED +#endif +#ifndef HAL_SRAM_MODULE_ENABLED + //#define HAL_SRAM_MODULE_ENABLED +#endif +#ifndef HAL_SDRAM_MODULE_ENABLED + //#define HAL_SDRAM_MODULE_ENABLED +#endif +#ifndef HAL_HASH_MODULE_ENABLED + //#define HAL_HASH_MODULE_ENABLED +#endif +#ifndef HAL_SMBUS_MODULE_ENABLED + //#define HAL_SMBUS_MODULE_ENABLED +#endif +#ifndef HAL_I2S_MODULE_ENABLED + //#define HAL_I2S_MODULE_ENABLED +#endif +#ifndef HAL_IWDG_MODULE_ENABLED + //#define HAL_IWDG_MODULE_ENABLED +#endif +#ifndef HAL_LTDC_MODULE_ENABLED + //#define HAL_LTDC_MODULE_ENABLED +#endif +#ifndef HAL_DSI_MODULE_ENABLED + //#define HAL_DSI_MODULE_ENABLED +#endif +#ifndef HAL_QSPI_MODULE_ENABLED + //#define HAL_QSPI_MODULE_ENABLED +#endif +#ifndef HAL_RNG_MODULE_ENABLED + //#define HAL_RNG_MODULE_ENABLED +#endif +#ifndef HAL_RTC_MODULE_ENABLED + //#define HAL_RTC_MODULE_ENABLED +#endif +#ifndef HAL_SAI_MODULE_ENABLED + //#define HAL_SAI_MODULE_ENABLED +#endif +#ifndef HAL_SD_MODULE_ENABLED + //#define HAL_SD_MODULE_ENABLED +#endif +#ifndef HAL_IRDA_MODULE_ENABLED + //#define HAL_IRDA_MODULE_ENABLED +#endif +#ifndef HAL_SMARTCARD_MODULE_ENABLED + //#define HAL_SMARTCARD_MODULE_ENABLED +#endif +#ifndef HAL_WWDG_MODULE_ENABLED + //#define HAL_WWDG_MODULE_ENABLED +#endif +#ifndef HAL_HCD_MODULE_ENABLED + //#define HAL_HCD_MODULE_ENABLED +#endif +#ifndef HAL_FMPI2C_MODULE_ENABLED + //#define HAL_FMPI2C_MODULE_ENABLED +#endif +#ifndef HAL_SPDIFRX_MODULE_ENABLED + //#define HAL_SPDIFRX_MODULE_ENABLED +#endif +#ifndef HAL_DFSDM_MODULE_ENABLED + //#define HAL_DFSDM_MODULE_ENABLED +#endif +#ifndef HAL_LPTIM_MODULE_ENABLED + //#define HAL_LPTIM_MODULE_ENABLED +#endif +#ifndef HAL_MMC_MODULE_ENABLED + //#define HAL_MMC_MODULE_ENABLED +#endif + +/* ########################## HSE/HSI Values adaptation ##################### */ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#ifndef HSE_VALUE + #define HSE_VALUE 25000000U /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#ifndef HSE_STARTUP_TIMEOUT + #define HSE_STARTUP_TIMEOUT 100U /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#ifndef HSI_VALUE + #define HSI_VALUE 16000000U /*!< Value of the Internal oscillator in Hz */ +#endif /* HSI_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI) value. + */ +#ifndef LSI_VALUE + #define LSI_VALUE 32000U /*!< LSI Typical Value in Hz */ +#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz + The real value may vary depending on the variations + in voltage and temperature. */ +/** + * @brief External Low Speed oscillator (LSE) value. + */ +#ifndef LSE_VALUE + #define LSE_VALUE 32768U /*!< Value of the External Low Speed oscillator in Hz */ +#endif /* LSE_VALUE */ + +#ifndef LSE_STARTUP_TIMEOUT + #define LSE_STARTUP_TIMEOUT 5000U /*!< Time out for LSE start up, in ms */ +#endif /* LSE_STARTUP_TIMEOUT */ + +/** + * @brief External clock source for I2S peripheral + * This value is used by the I2S HAL module to compute the I2S clock source + * frequency, this source is inserted directly through I2S_CKIN pad. + */ +#ifndef EXTERNAL_CLOCK_VALUE + #define EXTERNAL_CLOCK_VALUE 12288000U /*!< Value of the External oscillator in Hz*/ +#endif /* EXTERNAL_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ +#define VDD_VALUE 3300U /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY 0x0FU /*!< tick interrupt priority */ +#define USE_RTOS 0U +#define PREFETCH_ENABLE 1U +#define INSTRUCTION_CACHE_ENABLE 1U +#define DATA_CACHE_ENABLE 1U + +#define USE_HAL_ADC_REGISTER_CALLBACKS 0U /* ADC register callback disabled */ +#define USE_HAL_CAN_REGISTER_CALLBACKS 0U /* CAN register callback disabled */ +#define USE_HAL_CEC_REGISTER_CALLBACKS 0U /* CEC register callback disabled */ +#define USE_HAL_CRYP_REGISTER_CALLBACKS 0U /* CRYP register callback disabled */ +#define USE_HAL_DAC_REGISTER_CALLBACKS 0U /* DAC register callback disabled */ +#define USE_HAL_DCMI_REGISTER_CALLBACKS 0U /* DCMI register callback disabled */ +#define USE_HAL_DFSDM_REGISTER_CALLBACKS 0U /* DFSDM register callback disabled */ +#define USE_HAL_DMA2D_REGISTER_CALLBACKS 0U /* DMA2D register callback disabled */ +#define USE_HAL_DSI_REGISTER_CALLBACKS 0U /* DSI register callback disabled */ +#define USE_HAL_ETH_REGISTER_CALLBACKS 0U /* ETH register callback disabled */ +#define USE_HAL_HASH_REGISTER_CALLBACKS 0U /* HASH register callback disabled */ +#define USE_HAL_HCD_REGISTER_CALLBACKS 0U /* HCD register callback disabled */ +#define USE_HAL_I2C_REGISTER_CALLBACKS 0U /* I2C register callback disabled */ +#define USE_HAL_FMPI2C_REGISTER_CALLBACKS 0U /* FMPI2C register callback disabled */ +#define USE_HAL_I2S_REGISTER_CALLBACKS 0U /* I2S register callback disabled */ +#define USE_HAL_IRDA_REGISTER_CALLBACKS 0U /* IRDA register callback disabled */ +#define USE_HAL_LPTIM_REGISTER_CALLBACKS 0U /* LPTIM register callback disabled */ +#define USE_HAL_LTDC_REGISTER_CALLBACKS 0U /* LTDC register callback disabled */ +#define USE_HAL_MMC_REGISTER_CALLBACKS 0U /* MMC register callback disabled */ +#define USE_HAL_NAND_REGISTER_CALLBACKS 0U /* NAND register callback disabled */ +#define USE_HAL_NOR_REGISTER_CALLBACKS 0U /* NOR register callback disabled */ +#define USE_HAL_PCCARD_REGISTER_CALLBACKS 0U /* PCCARD register callback disabled */ +#define USE_HAL_PCD_REGISTER_CALLBACKS 0U /* PCD register callback disabled */ +#define USE_HAL_QSPI_REGISTER_CALLBACKS 0U /* QSPI register callback disabled */ +#define USE_HAL_RNG_REGISTER_CALLBACKS 0U /* RNG register callback disabled */ +#define USE_HAL_RTC_REGISTER_CALLBACKS 0U /* RTC register callback disabled */ +#define USE_HAL_SAI_REGISTER_CALLBACKS 0U /* SAI register callback disabled */ +#define USE_HAL_SD_REGISTER_CALLBACKS 0U /* SD register callback disabled */ +#define USE_HAL_SMARTCARD_REGISTER_CALLBACKS 0U /* SMARTCARD register callback disabled */ +#define USE_HAL_SDRAM_REGISTER_CALLBACKS 0U /* SDRAM register callback disabled */ +#define USE_HAL_SRAM_REGISTER_CALLBACKS 0U /* SRAM register callback disabled */ +#define USE_HAL_SPDIFRX_REGISTER_CALLBACKS 0U /* SPDIFRX register callback disabled */ +#define USE_HAL_SMBUS_REGISTER_CALLBACKS 0U /* SMBUS register callback disabled */ +#define USE_HAL_SPI_REGISTER_CALLBACKS 0U /* SPI register callback disabled */ +#define USE_HAL_TIM_REGISTER_CALLBACKS 0U /* TIM register callback disabled */ +#define USE_HAL_UART_REGISTER_CALLBACKS 0U /* UART register callback disabled */ +#define USE_HAL_USART_REGISTER_CALLBACKS 0U /* USART register callback disabled */ +#define USE_HAL_WWDG_REGISTER_CALLBACKS 0U /* WWDG register callback disabled */ + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ +// #define USE_FULL_ASSERT 1U + +/* ################## Ethernet peripheral configuration ##################### */ + +/* Section 1 : Ethernet peripheral configuration */ + +/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */ +#define MAC_ADDR0 2U +#define MAC_ADDR1 0U +#define MAC_ADDR2 0U +#define MAC_ADDR3 0U +#define MAC_ADDR4 0U +#define MAC_ADDR5 0U + +/* Definition of the Ethernet driver buffers size and count */ +#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for receive */ +#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for transmit */ +#define ETH_RXBUFNB 4U /* 4 Rx buffers of size ETH_RX_BUF_SIZE */ +#define ETH_TXBUFNB 4U /* 4 Tx buffers of size ETH_TX_BUF_SIZE */ + +/* Section 2: PHY configuration section */ + +/* DP83848 PHY Address*/ +#define DP83848_PHY_ADDRESS 0x01U +/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ +#define PHY_RESET_DELAY 0x000000FFU +/* PHY Configuration delay */ +#define PHY_CONFIG_DELAY 0x00000FFFU + +#define PHY_READ_TO 0x0000FFFFU +#define PHY_WRITE_TO 0x0000FFFFU + +/* Section 3: Common PHY Registers */ + +#define PHY_BCR ((uint16_t)0x0000) /*!< Transceiver Basic Control Register */ +#define PHY_BSR ((uint16_t)0x0001) /*!< Transceiver Basic Status Register */ + +#define PHY_RESET ((uint16_t)0x8000) /*!< PHY Reset */ +#define PHY_LOOPBACK ((uint16_t)0x4000) /*!< Select loop-back mode */ +#define PHY_FULLDUPLEX_100M ((uint16_t)0x2100) /*!< Set the full-duplex mode at 100 Mb/s */ +#define PHY_HALFDUPLEX_100M ((uint16_t)0x2000) /*!< Set the half-duplex mode at 100 Mb/s */ +#define PHY_FULLDUPLEX_10M ((uint16_t)0x0100) /*!< Set the full-duplex mode at 10 Mb/s */ +#define PHY_HALFDUPLEX_10M ((uint16_t)0x0000) /*!< Set the half-duplex mode at 10 Mb/s */ +#define PHY_AUTONEGOTIATION ((uint16_t)0x1000) /*!< Enable auto-negotiation function */ +#define PHY_RESTART_AUTONEGOTIATION ((uint16_t)0x0200) /*!< Restart auto-negotiation function */ +#define PHY_POWERDOWN ((uint16_t)0x0800) /*!< Select the power down mode */ +#define PHY_ISOLATE ((uint16_t)0x0400) /*!< Isolate PHY from MII */ + +#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020) /*!< Auto-Negotiation process completed */ +#define PHY_LINKED_STATUS ((uint16_t)0x0004) /*!< Valid link established */ +#define PHY_JABBER_DETECTION ((uint16_t)0x0002) /*!< Jabber condition detected */ + +/* Section 4: Extended PHY Registers */ + +#define PHY_SR ((uint16_t)0x0010) /*!< PHY status register Offset */ +#define PHY_MICR ((uint16_t)0x0011) /*!< MII Interrupt Control Register */ +#define PHY_MISR ((uint16_t)0x0012) /*!< MII Interrupt Status and Misc. Control Register */ + +#define PHY_LINK_STATUS ((uint16_t)0x0001) /*!< PHY Link mask */ +#define PHY_SPEED_STATUS ((uint16_t)0x0002) /*!< PHY Speed mask */ +#define PHY_DUPLEX_STATUS ((uint16_t)0x0004) /*!< PHY Duplex mask */ + +#define PHY_MICR_INT_EN ((uint16_t)0x0002) /*!< PHY Enable interrupts */ +#define PHY_MICR_INT_OE ((uint16_t)0x0001) /*!< PHY Enable output interrupt events */ + +#define PHY_MISR_LINK_INT_EN ((uint16_t)0x0020) /*!< Enable Interrupt on change of link status */ +#define PHY_LINK_INTERRUPT ((uint16_t)0x2000) /*!< PHY link status interrupt mask */ + +/* ################## SPI peripheral configuration ########################## */ + +/* CRC FEATURE: Use to activate CRC feature inside HAL SPI Driver +* Activated: CRC code is present inside driver +* Deactivated: CRC code cleaned from driver +*/ + +#define USE_SPI_CRC 0U + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED + #include "stm32f4xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32f4xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_EXTI_MODULE_ENABLED + #include "stm32f4xx_hal_exti.h" +#endif /* HAL_EXTI_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32f4xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32f4xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32f4xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_CAN_MODULE_ENABLED + #include "stm32f4xx_hal_can.h" +#endif /* HAL_CAN_MODULE_ENABLED */ + +#ifdef HAL_CAN_LEGACY_MODULE_ENABLED + #include "stm32f4xx_hal_can_legacy.h" +#endif /* HAL_CAN_LEGACY_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32f4xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED + #include "stm32f4xx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_DMA2D_MODULE_ENABLED + #include "stm32f4xx_hal_dma2d.h" +#endif /* HAL_DMA2D_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED + #include "stm32f4xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_DCMI_MODULE_ENABLED + #include "stm32f4xx_hal_dcmi.h" +#endif /* HAL_DCMI_MODULE_ENABLED */ + +#ifdef HAL_ETH_MODULE_ENABLED + #include "stm32f4xx_hal_eth.h" +#endif /* HAL_ETH_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32f4xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED + #include "stm32f4xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED + #include "stm32f4xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_NAND_MODULE_ENABLED + #include "stm32f4xx_hal_nand.h" +#endif /* HAL_NAND_MODULE_ENABLED */ + +#ifdef HAL_PCCARD_MODULE_ENABLED + #include "stm32f4xx_hal_pccard.h" +#endif /* HAL_PCCARD_MODULE_ENABLED */ + +#ifdef HAL_SDRAM_MODULE_ENABLED + #include "stm32f4xx_hal_sdram.h" +#endif /* HAL_SDRAM_MODULE_ENABLED */ + +#ifdef HAL_HASH_MODULE_ENABLED + #include "stm32f4xx_hal_hash.h" +#endif /* HAL_HASH_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32f4xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_SMBUS_MODULE_ENABLED + #include "stm32f4xx_hal_smbus.h" +#endif /* HAL_SMBUS_MODULE_ENABLED */ + +#ifdef HAL_I2S_MODULE_ENABLED + #include "stm32f4xx_hal_i2s.h" +#endif /* HAL_I2S_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32f4xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_LTDC_MODULE_ENABLED + #include "stm32f4xx_hal_ltdc.h" +#endif /* HAL_LTDC_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32f4xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED + #include "stm32f4xx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32f4xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED + #include "stm32f4xx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SD_MODULE_ENABLED + #include "stm32f4xx_hal_sd.h" +#endif /* HAL_SD_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32f4xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32f4xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32f4xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32f4xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32f4xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32f4xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32f4xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32f4xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_HCD_MODULE_ENABLED + #include "stm32f4xx_hal_hcd.h" +#endif /* HAL_HCD_MODULE_ENABLED */ + +#ifdef HAL_DSI_MODULE_ENABLED + #include "stm32f4xx_hal_dsi.h" +#endif /* HAL_DSI_MODULE_ENABLED */ + +#ifdef HAL_QSPI_MODULE_ENABLED + #include "stm32f4xx_hal_qspi.h" +#endif /* HAL_QSPI_MODULE_ENABLED */ + +#ifdef HAL_CEC_MODULE_ENABLED + #include "stm32f4xx_hal_cec.h" +#endif /* HAL_CEC_MODULE_ENABLED */ + +#ifdef HAL_FMPI2C_MODULE_ENABLED + #include "stm32f4xx_hal_fmpi2c.h" +#endif /* HAL_FMPI2C_MODULE_ENABLED */ + +#ifdef HAL_SPDIFRX_MODULE_ENABLED + #include "stm32f4xx_hal_spdifrx.h" +#endif /* HAL_SPDIFRX_MODULE_ENABLED */ + +#ifdef HAL_DFSDM_MODULE_ENABLED + #include "stm32f4xx_hal_dfsdm.h" +#endif /* HAL_DFSDM_MODULE_ENABLED */ + +#ifdef HAL_LPTIM_MODULE_ENABLED + #include "stm32f4xx_hal_lptim.h" +#endif /* HAL_LPTIM_MODULE_ENABLED */ + +#ifdef HAL_MMC_MODULE_ENABLED + #include "stm32f4xx_hal_mmc.h" +#endif /* HAL_MMC_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t *file, uint32_t line); +#else + #define assert_param(expr) ((void)0U) +#endif /* USE_FULL_ASSERT */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F4xx_HAL_CONF_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FLY_CDY_V3/ldscript.ld b/buildroot/share/PlatformIO/variants/MARLIN_FLY_CDY_V3/ldscript.ld new file mode 100644 index 0000000000..df1ed1581a --- /dev/null +++ b/buildroot/share/PlatformIO/variants/MARLIN_FLY_CDY_V3/ldscript.ld @@ -0,0 +1,203 @@ +/* +****************************************************************************** +** +** File : LinkerScript.ld +** +** Abstract : Linker script for STM32F4x7Vx Device with +** 512/1024KByte FLASH, 192KByte RAM +** +** Set heap size, stack size and stack location according +** to application requirements. +** +** Set memory bank area and size if external memory is used. +** +** Target : STMicroelectronics STM32 +** +** Distribution: The file is distributed “as is,” without any warranty +** of any kind. +** +***************************************************************************** +** @attention +** +** Copyright (c) 2019 STMicroelectronics +** +** Redistribution and use in source and binary forms, with or without modification, +** are permitted provided that the following conditions are met: +** 1. Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright notice, +** this list of conditions and the following disclaimer in the documentation +** and/or other materials provided with the distribution. +** 3. Neither the name of STMicroelectronics nor the names of its contributors +** may be used to endorse or promote products derived from this software +** without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +** +***************************************************************************** +*/ + +/* Entry Point */ +ENTRY(Reset_Handler) + +/* Highest address of the user mode stack */ +_estack = 0x20000000 + LD_MAX_DATA_SIZE; /* end of RAM */ +/* Generate a link error if heap and stack don't fit into RAM */ +_Min_Heap_Size = 0x200; /* required amount of heap */ +_Min_Stack_Size = 0x400; /* required amount of stack */ + +/* Specify the memory areas */ +MEMORY +{ +RAM (xrw) : ORIGIN = 0x20000000, LENGTH = LD_MAX_DATA_SIZE +CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64K +FLASH (rx) : ORIGIN = 0x08000000 + LD_FLASH_OFFSET, LENGTH = LD_MAX_SIZE - LD_FLASH_OFFSET +} + +/* Define output sections */ +SECTIONS +{ + /* The startup code goes first into FLASH */ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + . = ALIGN(4); + } >FLASH + + /* The program code and other data goes into FLASH */ + .text : + { + . = ALIGN(4); + *(.text) /* .text sections (code) */ + *(.text*) /* .text* sections (code) */ + *(.glue_7) /* glue arm to thumb code */ + *(.glue_7t) /* glue thumb to arm code */ + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + . = ALIGN(4); + _etext = .; /* define a global symbols at end of code */ + } >FLASH + + /* Constant data goes into FLASH */ + .rodata : + { + . = ALIGN(4); + *(.rodata) /* .rodata sections (constants, strings, etc.) */ + *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ + . = ALIGN(4); + } >FLASH + + .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH + .ARM : { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } >FLASH + + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array*)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } >FLASH + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array*)) + PROVIDE_HIDDEN (__init_array_end = .); + } >FLASH + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT(.fini_array.*))) + KEEP (*(.fini_array*)) + PROVIDE_HIDDEN (__fini_array_end = .); + } >FLASH + + /* used by the startup to initialize data */ + _sidata = LOADADDR(.data); + + /* Initialized data sections goes into RAM, load LMA copy after code */ + .data : + { + . = ALIGN(4); + _sdata = .; /* create a global symbol at data start */ + *(.data) /* .data sections */ + *(.data*) /* .data* sections */ + + . = ALIGN(4); + _edata = .; /* define a global symbol at data end */ + } >RAM AT> FLASH + + _siccmram = LOADADDR(.ccmram); + + /* CCM-RAM section + * + * IMPORTANT NOTE! + * If initialized variables will be placed in this section, + * the startup code needs to be modified to copy the init-values. + */ + .ccmram : + { + . = ALIGN(4); + _sccmram = .; /* create a global symbol at ccmram start */ + *(.ccmram) + *(.ccmram*) + + . = ALIGN(4); + _eccmram = .; /* create a global symbol at ccmram end */ + } >CCMRAM AT> FLASH + + + /* Uninitialized data section */ + . = ALIGN(4); + .bss : + { + /* This is used by the startup in order to initialize the .bss section */ + _sbss = .; /* define a global symbol at bss start */ + __bss_start__ = _sbss; + *(.bss) + *(.bss*) + *(COMMON) + + . = ALIGN(4); + _ebss = .; /* define a global symbol at bss end */ + __bss_end__ = _ebss; + } >RAM + + /* User_heap_stack section, used to check that there is enough RAM left */ + ._user_heap_stack : + { + . = ALIGN(8); + PROVIDE ( end = . ); + PROVIDE ( _end = . ); + . = . + _Min_Heap_Size; + . = . + _Min_Stack_Size; + . = ALIGN(8); + } >RAM + + + /* Remove information from the standard libraries */ + /DISCARD/ : + { + libc.a ( * ) + libm.a ( * ) + libgcc.a ( * ) + } + + .ARM.attributes 0 : { *(.ARM.attributes) } +} diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FLY_CDY_V3/variant.cpp b/buildroot/share/PlatformIO/variants/MARLIN_FLY_CDY_V3/variant.cpp new file mode 100644 index 0000000000..3721d4f5b5 --- /dev/null +++ b/buildroot/share/PlatformIO/variants/MARLIN_FLY_CDY_V3/variant.cpp @@ -0,0 +1,275 @@ +/* + Copyright (c) 2011 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "pins_arduino.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Digital PinName array +const PinName digitalPin[] = { + PA_0, // Digital pin 0 + PA_1, // Digital pin 1 + PA_2, // Digital pin 2 + PA_3, // Digital pin 3 + PA_4, // Digital pin 4 + PA_5, // Digital pin 5 + PA_6, // Digital pin 6 + PA_7, // Digital pin 7 + PA_8, // Digital pin 8 + PA_9, // Digital pin 9 + PA_10, // Digital pin 10 + PA_11, // Digital pin 11 + PA_12, // Digital pin 12 + PA_13, // Digital pin 13 + PA_14, // Digital pin 14 + PA_15, // Digital pin 15 + + PB_0, // Digital pin 16 + PB_1, // Digital pin 17 + PB_2, // Digital pin 18 + PB_3, // Digital pin 19 + PB_4, // Digital pin 20 + PB_5, // Digital pin 21 + PB_6, // Digital pin 22 + PB_7, // Digital pin 23 + PB_8, // Digital pin 24 + PB_9, // Digital pin 25 + PB_10, // Digital pin 26 + PB_11, // Digital pin 27 + PB_12, // Digital pin 28 + PB_13, // Digital pin 29 + PB_14, // Digital pin 30 + PB_15, // Digital pin 31 + + PC_0, // Digital pin 32 + PC_1, // Digital pin 33 + PC_2, // Digital pin 34 + PC_3, // Digital pin 35 + PC_4, // Digital pin 36 + PC_5, // Digital pin 37 + PC_6, // Digital pin 38 + PC_7, // Digital pin 39 + PC_8, // Digital pin 40 + PC_9, // Digital pin 41 + PC_10, // Digital pin 42 + PC_11, // Digital pin 43 + PC_12, // Digital pin 44 + PC_13, // Digital pin 45 + PC_14, // Digital pin 46 + PC_15, // Digital pin 47 + + PD_0, // Digital pin 48 + PD_1, // Digital pin 49 + PD_2, // Digital pin 50 + PD_3, // Digital pin 51 + PD_4, // Digital pin 52 + PD_5, // Digital pin 53 + PD_6, // Digital pin 54 + PD_7, // Digital pin 55 + PD_8, // Digital pin 56 + PD_9, // Digital pin 57 + PD_10, // Digital pin 58 + PD_11, // Digital pin 59 + PD_12, // Digital pin 60 + PD_13, // Digital pin 61 + PD_14, // Digital pin 62 + PD_15, // Digital pin 63 + + PE_0, // Digital pin 64 + PE_1, // Digital pin 65 + PE_2, // Digital pin 66 + PE_3, // Digital pin 67 + PE_4, // Digital pin 68 + PE_5, // Digital pin 69 + PE_6, // Digital pin 70 + PE_7, // Digital pin 71 + PE_8, // Digital pin 72 + PE_9, // Digital pin 73 + PE_10, // Digital pin 74 + PE_11, // Digital pin 75 + PE_12, // Digital pin 76 + PE_13, // Digital pin 77 + PE_14, // Digital pin 78 + PE_15, // Digital pin 79 + + PH_0, // Digital pin 80, used by the external oscillator + PH_1 // Digital pin 81, used by the external oscillator +}; + +// Analog (Ax) pin number array +const uint32_t analogInputPin[] = { + 0, // A0, PA0 + 1, // A1, PA1 + 2, // A2, PA2 + 3, // A3, PA3 + 4, // A4, PA4 + 5, // A5, PA5 + 6, // A6, PA6 + 7, // A7, PA7 + 16, // A8, PB0 + 17, // A9, PB1 + 32, // A10, PC0 + 33, // A11, PC1 + 34, // A12, PC2 + 35, // A13, PC3 + 36, // A14, PC4 + 37 // A15, PC5 +}; + +#ifdef __cplusplus +} +#endif + +// ---------------------------------------------------------------------------- + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * @brief Configures the System clock source, PLL Multiplier and Divider factors, + * AHB/APBx prescalers and Flash settings + * @note This function should be called only once the RCC clock configuration + * is reset to the default reset state (done in SystemInit() function). + * @param None + * @retval None + */ + +/******************************************************************************/ +/* PLL (clocked by HSE) used as System clock source */ +/******************************************************************************/ +static uint8_t SetSysClock_PLL_HSE(uint8_t bypass) +{ + RCC_OscInitTypeDef RCC_OscInitStruct; + RCC_ClkInitTypeDef RCC_ClkInitStruct; + + /* The voltage scaling allows optimizing the power consumption when the device is + clocked below the maximum system frequency, to update the voltage scaling value + regarding system frequency refer to product datasheet. */ + __HAL_RCC_PWR_CLK_ENABLE(); + __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); + + // Enable HSE oscillator and activate PLL with HSE as source + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; + if (bypass == 0) { + RCC_OscInitStruct.HSEState = RCC_HSE_ON; // External 8 MHz xtal on OSC_IN/OSC_OUT + } else { + RCC_OscInitStruct.HSEState = RCC_HSE_BYPASS; // External 8 MHz clock on OSC_IN + } + + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; + RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; + RCC_OscInitStruct.PLL.PLLM = HSE_VALUE / 1000000L; // Expects an 8 MHz external clock by default. Redefine HSE_VALUE if not + RCC_OscInitStruct.PLL.PLLN = 336; // VCO output clock = 336 MHz (1 MHz * 336) + RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; // PLLCLK = 168 MHz (336 MHz / 2) + RCC_OscInitStruct.PLL.PLLQ = 7; + if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { + return 0; // FAIL + } + + // Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2 clocks dividers + RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2; + RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; + RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; // 168 MHz + RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; // 42 MHz + RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; // 84 MHz + if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK) { + return 0; // FAIL + } + + /* Output clock on MCO1 pin(PA8) for debugging purpose */ + /* + if (bypass == 0) + HAL_RCC_MCOConfig(RCC_MCO1, RCC_MCO1SOURCE_HSE, RCC_MCODIV_2); // 4 MHz + else + HAL_RCC_MCOConfig(RCC_MCO1, RCC_MCO1SOURCE_HSE, RCC_MCODIV_1); // 8 MHz + */ + + return 1; // OK +} + +/******************************************************************************/ +/* PLL (clocked by HSI) used as System clock source */ +/******************************************************************************/ +uint8_t SetSysClock_PLL_HSI(void) +{ + RCC_OscInitTypeDef RCC_OscInitStruct; + RCC_ClkInitTypeDef RCC_ClkInitStruct; + + /* The voltage scaling allows optimizing the power consumption when the device is + clocked below the maximum system frequency, to update the voltage scaling value + regarding system frequency refer to product datasheet. */ + __HAL_RCC_PWR_CLK_ENABLE(); + __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); + + // Enable HSI oscillator and activate PLL with HSI as source + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI | RCC_OSCILLATORTYPE_HSE; + RCC_OscInitStruct.HSIState = RCC_HSI_ON; + RCC_OscInitStruct.HSEState = RCC_HSE_OFF; + RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; + RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI; + RCC_OscInitStruct.PLL.PLLM = 16; // VCO input clock = 1 MHz (16 MHz / 16) + RCC_OscInitStruct.PLL.PLLN = 336; // VCO output clock = 336 MHz (1 MHz * 336) + RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; // PLLCLK = 168 MHz (336 MHz / 2) + RCC_OscInitStruct.PLL.PLLQ = 7; + if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { + return 0; // FAIL + } + + /* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2 clocks dividers */ + RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2); + RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; + RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; // 168 MHz + RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; // 42 MHz + RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; // 84 MHz + if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK) { + return 0; // FAIL + } + + /* Output clock on MCO1 pin(PA8) for debugging purpose */ + //HAL_RCC_MCOConfig(RCC_MCO1, RCC_MCO1SOURCE_HSI, RCC_MCODIV_1); // 16 MHz + + return 1; // OK +} + +WEAK void SystemClock_Config(void) +{ + /* 1- If fail try to start with HSE and external xtal */ + if (SetSysClock_PLL_HSE(0) == 0) { + /* 2- Try to start with HSE and external clock */ + if (SetSysClock_PLL_HSE(1) == 0) { + /* 3- If fail start with HSI clock */ + if (SetSysClock_PLL_HSI() == 0) { + Error_Handler(); + } + } + } + + /* Ensure CCM RAM clock is enabled */ + __HAL_RCC_CCMDATARAMEN_CLK_ENABLE(); + + /* Output clock on MCO2 pin(PC9) for debugging purpose */ + //HAL_RCC_MCOConfig(RCC_MCO2, RCC_MCO2SOURCE_SYSCLK, RCC_MCODIV_4); +} + +#ifdef __cplusplus +} +#endif diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FLY_CDY_V3/variant.h b/buildroot/share/PlatformIO/variants/MARLIN_FLY_CDY_V3/variant.h new file mode 100644 index 0000000000..d5a2db8086 --- /dev/null +++ b/buildroot/share/PlatformIO/variants/MARLIN_FLY_CDY_V3/variant.h @@ -0,0 +1,187 @@ +/* + Copyright (c) 2011 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _VARIANT_ARDUINO_STM32_ +#define _VARIANT_ARDUINO_STM32_ + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/*---------------------------------------------------------------------------- + * Pins + *----------------------------------------------------------------------------*/ + + // | DIGITAL | ANALOG IN | ANALOG OUT | UART/USART | TWI | SPI | SPECIAL | + // |---------|------------|------------|-----------------------|----------------------|-----------------------------------|-----------| +#define PA0 PIN_A0 // | 0 | A0 (ADC1) | | UART4_TX | | | | +#define PA1 PIN_A1 // | 1 | A1 (ADC1) | | UART4_RX | | | | +#define PA2 PIN_A2 // | 2 | A2 (ADC1) | | USART2_TX | | | | +#define PA3 PIN_A3 // | 3 | A3 (ADC1) | | USART2_RX | | | | +#define PA4 PIN_A4 // | 4 | A4 (ADC1) | DAC_OUT1 | | | SPI1_SS, (SPI3_SS) | | +#define PA5 PIN_A5 // | 5 | A5 (ADC1) | DAC_OUT2 | | | SPI1_SCK | | +#define PA6 PIN_A6 // | 6 | A6 (ADC1) | | | | SPI1_MISO | | +#define PA7 PIN_A7 // | 7 | A7 (ADC1) | | | | SPI1_MOSI | | +#define PA8 8 // | 8 | | | | TWI3_SCL | | | +#define PA9 9 // | 9 | | | USART1_TX | | | | +#define PA10 10 // | 10 | | | USART1_RX | | | | +#define PA11 11 // | 11 | | | | | | | +#define PA12 12 // | 12 | | | | | | | +#define PA13 13 // | 13 | | | | | | SWD_SWDIO | +#define PA14 14 // | 14 | | | | | | SWD_SWCLK | +#define PA15 15 // | 15 | | | | | SPI3_SS, (SPI1_SS) | | + // |---------|------------|------------|-----------------------|----------------------|-----------------------------------|-----------| +#define PB0 PIN_A8 // | 16 | A8 (ADC1) | | | | | | +#define PB1 PIN_A9 // | 17 | A9 (ADC1) | | | | | | +#define PB2 18 // | 18 | | | | | | BOOT1 | +#define PB3 19 // | 19 | | | | | SPI3_SCK, (SPI1_SCK) | | +#define PB4 20 // | 20 | | | | | SPI3_MISO, (SPI1_MISO) | | +#define PB5 21 // | 21 | | | | | SPI3_MOSI, (SPI1_MOSI) | | +#define PB6 22 // | 22 | | | USART1_TX | TWI1_SCL | | | +#define PB7 23 // | 23 | | | USART1_RX | TWI1_SDA | | | +#define PB8 24 // | 24 | | | | TWI1_SCL | | | +#define PB9 25 // | 25 | | | | TWI1_SDA | SPI2_SS | | +#define PB10 26 // | 26 | | | USART3_TX, (UART4_TX) | TWI2_SCL | SPI2_SCK | | +#define PB11 27 // | 27 | | | USART3_RX | TWI2_SDA | | | +#define PB12 28 // | 28 | | | | | SPI2_SS | | +#define PB13 29 // | 29 | | | | | SPI2_SCK | | +#define PB14 30 // | 30 | | | | | SPI2_MISO | | +#define PB15 31 // | 31 | | | | | SPI2_MOSI | | + // |---------|------------|------------|-----------------------|----------------------|-----------------------------------|-----------| +#define PC0 PIN_A10 // | 32 | A10 (ADC1) | | | | | | +#define PC1 PIN_A11 // | 33 | A11 (ADC1) | | | | | | +#define PC2 PIN_A12 // | 34 | A12 (ADC1) | | | | SPI2_MISO | | +#define PC3 PIN_A13 // | 35 | A13 (ADC1) | | | | SPI2_MOSI | | +#define PC4 PIN_A14 // | 36 | A14 (ADC1) | | | | | | +#define PC5 PIN_A15 // | 37 | A15 (ADC1) | | USART3_RX | | | | +#define PC6 38 // | 38 | | | USART6_TX | | | | +#define PC7 39 // | 39 | | | USART6_RX | | | | +#define PC8 40 // | 40 | | | | | | | +#define PC9 41 // | 41 | | | USART3_TX | TWI3_SDA | | | +#define PC10 42 // | 42 | | | | | SPI3_SCK | | +#define PC11 43 // | 43 | | | USART3_RX, (UART4_RX) | | SPI3_MISO | | +#define PC12 44 // | 44 | | | UART5_TX | | SPI3_MOSI | | +#define PC13 45 // | 45 | | | | | | | +#define PC14 46 // | 46 | | | | | | OSC32_IN | +#define PC15 47 // | 47 | | | | | | OSC32_OUT | + // |---------|------------|------------|-----------------------|----------------------|-----------------------------------|-----------| +#define PD0 48 // | 48 | | | | | | | +#define PD1 49 // | 49 | | | | | | | +#define PD2 50 // | 50 | | | UART5_RX | | | | +#define PD3 51 // | 51 | | | | | | | +#define PD4 52 // | 52 | | | | | | | +#define PD5 53 // | 53 | | | USART2_TX | | | | +#define PD6 54 // | 54 | | | USART2_RX | | | | +#define PD7 55 // | 55 | | | | | | | +#define PD8 56 // | 56 | | | USART3_TX | | | | +#define PD9 57 // | 57 | | | USART3_RX | | | | +#define PD10 58 // | 58 | | | | | | | +#define PD11 59 // | 59 | | | | | | | +#define PD12 60 // | 60 | | | | | | | +#define PD13 61 // | 61 | | | | | | | +#define PD14 62 // | 62 | | | | | | | +#define PD15 63 // | 63 | | | | | | | + // |---------|------------|------------|-----------------------|----------------------|-----------------------------------|-----------| +#define PE0 64 // | 64 | | | | | | | +#define PE1 65 // | 65 | | | | | | | +#define PE2 66 // | 66 | | | | | | | +#define PE3 67 // | 67 | | | | | | | +#define PE4 68 // | 68 | | | | | | | +#define PE5 69 // | 69 | | | | | | | +#define PE6 70 // | 70 | | | | | | | +#define PE7 71 // | 71 | | | | | | | +#define PE8 72 // | 72 | | | | | | | +#define PE9 73 // | 73 | | | | | | | +#define PE10 74 // | 74 | | | | | | | +#define PE11 75 // | 75 | | | | | | | +#define PE12 76 // | 76 | | | | | | | +#define PE13 77 // | 77 | | | | | | | +#define PE14 78 // | 78 | | | | | | | +#define PE15 79 // | 79 | | | | | | | + // |---------|------------|------------|-----------------------|----------------------|-----------------------------------|-----------| +#define PH0 80 // | 80 | | | | | | OSC_IN | +#define PH1 81 // | 81 | | | | | | OSC_OUT | + // |---------|------------|------------|-----------------------|----------------------|-----------------------------------|-----------| + +// This must be a literal +#define NUM_DIGITAL_PINS 82 +#define NUM_ANALOG_INPUTS 16 + + +// SPI definitions +#define PIN_SPI_SS PA4 +#define PIN_SPI_MOSI PA7 +#define PIN_SPI_MISO PA6 +#define PIN_SPI_SCK PA5 + +// Timer Definitions +// Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin +#ifndef TIMER_TONE + #define TIMER_TONE TIM6 // TIMER_TONE must be defined in this file +#endif +#ifndef TIMER_SERVO + #define TIMER_SERVO TIM7 // TIMER_SERVO must be defined in this file +#endif +#ifndef TIMER_SERIAL + #define TIMER_SERIAL TIM2 // TIMER_SERIAL must be defined in this file +#endif + +// UART Definitions +#define SERIAL_UART_INSTANCE 1 + +// Default pin used for 'Serial' instance +// Mandatory for Firmata +#define PIN_SERIAL_RX PA10 +#define PIN_SERIAL_TX PA9 + +/* Extra HAL modules */ +#ifndef HAL_DAC_MODULE_ENABLED + #define HAL_DAC_MODULE_ENABLED +#endif +#ifndef HAL_SD_MODULE_ENABLED + #define HAL_SD_MODULE_ENABLED +#endif +#ifdef __cplusplus +} // extern "C" +#endif + +/*---------------------------------------------------------------------------- + * Arduino objects - C++ only + *----------------------------------------------------------------------------*/ + +#ifdef __cplusplus + // These serial port names are intended to allow libraries and architecture-neutral + // sketches to automatically default to the correct port name for a particular type + // of use. For example, a GPS module would normally connect to SERIAL_PORT_HARDWARE_OPEN, + // the first hardware serial port whose RX/TX pins are not dedicated to another use. + // + // SERIAL_PORT_MONITOR Port which normally prints to the Arduino Serial Monitor + // + // SERIAL_PORT_USBVIRTUAL Port which is USB virtual serial + // + // SERIAL_PORT_LINUXBRIDGE Port which connects to a Linux system via Bridge library + // + // SERIAL_PORT_HARDWARE Hardware serial port, physical RX & TX pins. + // + // SERIAL_PORT_HARDWARE_OPEN Hardware serial ports which are open for use. Their RX & TX + // pins are NOT connected to anything by default. + #define SERIAL_PORT_MONITOR Serial + #define SERIAL_PORT_HARDWARE Serial1 +#endif + +#endif /* _VARIANT_ARDUINO_STM32_ */ diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FLY_D5/PeripheralPins.c b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D5/PeripheralPins.c new file mode 100644 index 0000000000..3f5a3a3743 --- /dev/null +++ b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D5/PeripheralPins.c @@ -0,0 +1,271 @@ +/* + ******************************************************************************* + * Copyright (c) 2020, STMicroelectronics + * All rights reserved. + * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ******************************************************************************* + */ +/* + * Automatically generated from STM32F072R(8-B)Tx.xml, STM32F072RBHx.xml + * STM32F072RBIx.xml + * CubeMX DB release 6.0.80 + */ + +#include "Arduino.h" +#include "PeripheralPins.h" + +/* ===== + * Notes: + * - The pins mentioned Px_y_ALTz are alternative possibilities which use other + * HW peripheral instances. You can use them the same way as any other "normal" + * pin (i.e. analogWrite(PA7_ALT1, 128);). + * + * - Commented lines are alternative possibilities which are not used per default. + * If you change them, you will have to know what you do + * ===== + */ + +//*** ADC *** + +#ifdef HAL_ADC_MODULE_ENABLED +WEAK const PinMap PinMap_ADC[] = { + {PA_0, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 0, 0)}, // ADC_IN0 + {PA_1, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 1, 0)}, // ADC_IN1 + {PA_2, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 2, 0)}, // ADC_IN2 + {PA_3, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 3, 0)}, // ADC_IN3 + {PA_4, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 4, 0)}, // ADC_IN4 + {PA_5, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 5, 0)}, // ADC_IN5 + {PA_6, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 6, 0)}, // ADC_IN6 + {PA_7, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 7, 0)}, // ADC_IN7 + {PB_0, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 8, 0)}, // ADC_IN8 + {PB_1, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 9, 0)}, // ADC_IN9 + {PC_0, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 10, 0)}, // ADC_IN10 + {PC_1, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 11, 0)}, // ADC_IN11 + {PC_2, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 12, 0)}, // ADC_IN12 + {PC_3, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 13, 0)}, // ADC_IN13 + {PC_4, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 14, 0)}, // ADC_IN14 + {PC_5, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 15, 0)}, // ADC_IN15 + {NC, NP, 0} +}; +#endif + +//*** DAC *** + +#ifdef HAL_DAC_MODULE_ENABLED +WEAK const PinMap PinMap_DAC[] = { + {PA_4, DAC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 1, 0)}, // DAC_OUT1 + {PA_5, DAC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 2, 0)}, // DAC_OUT2 + {NC, NP, 0} +}; +#endif + +//*** I2C *** + +#ifdef HAL_I2C_MODULE_ENABLED +WEAK const PinMap PinMap_I2C_SDA[] = { + {PB_7, I2C1, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF1_I2C1)}, + {PB_9, I2C1, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF1_I2C1)}, + {PB_11, I2C2, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF1_I2C2)}, + {PB_14, I2C2, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF5_I2C2)}, + {NC, NP, 0} +}; +#endif + +#ifdef HAL_I2C_MODULE_ENABLED +WEAK const PinMap PinMap_I2C_SCL[] = { + {PB_6, I2C1, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF1_I2C1)}, + {PB_8, I2C1, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF1_I2C1)}, + {PB_10, I2C2, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF1_I2C2)}, + {PB_13, I2C2, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF5_I2C2)}, + {NC, NP, 0} +}; +#endif + +//*** TIM *** + +#ifdef HAL_TIM_MODULE_ENABLED +WEAK const PinMap PinMap_TIM[] = { + {PA_0, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM2, 1, 0)}, // TIM2_CH1 + {PA_1, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM2, 2, 0)}, // TIM2_CH2 + {PA_1_ALT1, TIM15, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_TIM15, 1, 1)}, // TIM15_CH1N + {PA_2, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM2, 3, 0)}, // TIM2_CH3 + {PA_2_ALT1, TIM15, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF0_TIM15, 1, 0)}, // TIM15_CH1 + {PA_3, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM2, 4, 0)}, // TIM2_CH4 + {PA_3_ALT1, TIM15, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF0_TIM15, 2, 0)}, // TIM15_CH2 + {PA_4, TIM14, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_TIM14, 1, 0)}, // TIM14_CH1 + {PA_5, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM2, 1, 0)}, // TIM2_CH1 + {PA_6, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM3, 1, 0)}, // TIM3_CH1 + {PA_6_ALT1, TIM16, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_TIM16, 1, 0)}, // TIM16_CH1 + {PA_7, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM1, 1, 1)}, // TIM1_CH1N + {PA_7_ALT1, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM3, 2, 0)}, // TIM3_CH2 + {PA_7_ALT2, TIM14, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_TIM14, 1, 0)}, // TIM14_CH1 + {PA_7_ALT3, TIM17, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_TIM17, 1, 0)}, // TIM17_CH1 + {PA_8, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM1, 1, 0)}, // TIM1_CH1 + {PA_9, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM1, 2, 0)}, // TIM1_CH2 + {PA_10, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM1, 3, 0)}, // TIM1_CH3 + {PA_11, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM1, 4, 0)}, // TIM1_CH4 + {PA_15, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM2, 1, 0)}, // TIM2_CH1 + {PB_0, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM1, 2, 1)}, // TIM1_CH2N + {PB_0_ALT1, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM3, 3, 0)}, // TIM3_CH3 + {PB_1, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM1, 3, 1)}, // TIM1_CH3N + {PB_1_ALT1, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM3, 4, 0)}, // TIM3_CH4 + {PB_1_ALT2, TIM14, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF0_TIM14, 1, 0)}, // TIM14_CH1 + {PB_3, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM2, 2, 0)}, // TIM2_CH2 + {PB_4, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM3, 1, 0)}, // TIM3_CH1 + {PB_5, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM3, 2, 0)}, // TIM3_CH2 + {PB_6, TIM16, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM16, 1, 1)}, // TIM16_CH1N + {PB_7, TIM17, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM17, 1, 1)}, // TIM17_CH1N + {PB_8, TIM16, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM16, 1, 0)}, // TIM16_CH1 + {PB_9, TIM17, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM17, 1, 0)}, // TIM17_CH1 + {PB_10, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM2, 3, 0)}, // TIM2_CH3 + {PB_11, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM2, 4, 0)}, // TIM2_CH4 + {PB_13, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM1, 1, 1)}, // TIM1_CH1N + {PB_14, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM1, 2, 1)}, // TIM1_CH2N + {PB_14_ALT1, TIM15, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM15, 1, 0)}, // TIM15_CH1 + {PB_15, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM1, 3, 1)}, // TIM1_CH3N + {PB_15_ALT1, TIM15, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM15, 1, 1)}, // TIM15_CH1N + {PB_15_ALT2, TIM15, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM15, 2, 0)}, // TIM15_CH2 + {PC_6, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF0_TIM3, 1, 0)}, // TIM3_CH1 + {PC_7, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF0_TIM3, 2, 0)}, // TIM3_CH2 + {PC_8, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF0_TIM3, 3, 0)}, // TIM3_CH3 + {PC_9, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF0_TIM3, 4, 0)}, // TIM3_CH4 + {NC, NP, 0} +}; +#endif + +//*** UART *** + +#ifdef HAL_UART_MODULE_ENABLED +WEAK const PinMap PinMap_UART_TX[] = { + {PA_0, USART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_USART4)}, + {PA_2, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_USART2)}, + {PA_9, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_USART1)}, + {PA_14, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_USART2)}, + {PB_6, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF0_USART1)}, + {PB_10, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_USART3)}, + {PC_4, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_USART3)}, + {PC_10, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_USART3)}, + {PC_10_ALT1, USART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF0_USART4)}, + {NC, NP, 0} +}; +#endif + +#ifdef HAL_UART_MODULE_ENABLED +WEAK const PinMap PinMap_UART_RX[] = { + {PA_1, USART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_USART4)}, + {PA_3, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_USART2)}, + {PA_10, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_USART1)}, + {PA_15, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_USART2)}, + {PB_7, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF0_USART1)}, + {PB_11, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_USART3)}, + {PC_5, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_USART3)}, + {PC_11, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_USART3)}, + {PC_11_ALT1, USART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF0_USART4)}, + {NC, NP, 0} +}; +#endif + +#ifdef HAL_UART_MODULE_ENABLED +WEAK const PinMap PinMap_UART_RTS[] = { + {PA_1, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_USART2)}, + {PA_12, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_USART1)}, + {PA_15, USART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_USART4)}, + {PB_1, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_USART3)}, + {PB_14, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_USART3)}, + {PD_2, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_USART3)}, + {NC, NP, 0} +}; +#endif + +#ifdef HAL_UART_MODULE_ENABLED +WEAK const PinMap PinMap_UART_CTS[] = { + {PA_0, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_USART2)}, + {PA_6, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_USART3)}, + {PA_11, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_USART1)}, + {PB_7, USART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_USART4)}, + {PB_13, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_USART3)}, + {NC, NP, 0} +}; +#endif + +//*** SPI *** + +#ifdef HAL_SPI_MODULE_ENABLED +WEAK const PinMap PinMap_SPI_MOSI[] = { + {PA_7, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF0_SPI1)}, + {PB_5, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF0_SPI1)}, + {PB_15, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF0_SPI2)}, + {PC_3, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_SPI2)}, + {NC, NP, 0} +}; +#endif + +#ifdef HAL_SPI_MODULE_ENABLED +WEAK const PinMap PinMap_SPI_MISO[] = { + {PA_6, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF0_SPI1)}, + {PB_4, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF0_SPI1)}, + {PB_14, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF0_SPI2)}, + {PC_2, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_SPI2)}, + {NC, NP, 0} +}; +#endif + +#ifdef HAL_SPI_MODULE_ENABLED +WEAK const PinMap PinMap_SPI_SCLK[] = { + {PA_5, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF0_SPI1)}, + {PB_3, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF0_SPI1)}, + {PB_10, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + {PB_13, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF0_SPI2)}, + {NC, NP, 0} +}; +#endif + +#ifdef HAL_SPI_MODULE_ENABLED +WEAK const PinMap PinMap_SPI_SSEL[] = { + {PA_4, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF0_SPI1)}, + {PA_15, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF0_SPI1)}, + {PB_9, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + {PB_12, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF0_SPI2)}, + {NC, NP, 0} +}; +#endif + +//*** CAN *** + +#if defined(HAL_CAN_MODULE_ENABLED) || defined(HAL_CAN_LEGACY_MODULE_ENABLED) +WEAK const PinMap PinMap_CAN_RD[] = { + {PA_11, CAN1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF4_CAN)}, + {PB_8, CAN1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF4_CAN)}, + {NC, NP, 0} +}; +#endif + +#if defined(HAL_CAN_MODULE_ENABLED) || defined(HAL_CAN_LEGACY_MODULE_ENABLED) +WEAK const PinMap PinMap_CAN_TD[] = { + {PA_12, CAN1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF4_CAN)}, + {PB_9, CAN1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF4_CAN)}, + {NC, NP, 0} +}; +#endif + +//*** No ETHERNET *** + +//*** No QUADSPI *** + +//*** USB *** + +#if defined(HAL_PCD_MODULE_ENABLED) || defined(HAL_HCD_MODULE_ENABLED) +WEAK const PinMap PinMap_USB[] = { + {PA_11, USB, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, GPIO_AF_NONE)}, // USB_DM + {PA_12, USB, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, GPIO_AF_NONE)}, // USB_DP + {PA_13, USB, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_USB)}, // USB_NOE + {NC, NP, 0} +}; +#endif + +//*** No SD *** diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FLY_D5/PinNamesVar.h b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D5/PinNamesVar.h new file mode 100644 index 0000000000..4e012676ee --- /dev/null +++ b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D5/PinNamesVar.h @@ -0,0 +1,49 @@ +/* Alternate pin name */ +PA_1_ALT1 = PA_1 | ALT1, +PA_2_ALT1 = PA_2 | ALT1, +PA_3_ALT1 = PA_3 | ALT1, +PA_6_ALT1 = PA_6 | ALT1, +PA_7_ALT1 = PA_7 | ALT1, +PA_7_ALT2 = PA_7 | ALT2, +PA_7_ALT3 = PA_7 | ALT3, +PB_0_ALT1 = PB_0 | ALT1, +PB_1_ALT1 = PB_1 | ALT1, +PB_1_ALT2 = PB_1 | ALT2, +PB_14_ALT1 = PB_14 | ALT1, +PB_15_ALT1 = PB_15 | ALT1, +PB_15_ALT2 = PB_15 | ALT2, +PC_10_ALT1 = PC_10 | ALT1, +PC_11_ALT1 = PC_11 | ALT1, + +/* SYS_WKUP */ +#ifdef PWR_WAKEUP_PIN1 + SYS_WKUP1 = PA_0, +#endif +#ifdef PWR_WAKEUP_PIN2 + SYS_WKUP2 = PC_13, +#endif +#ifdef PWR_WAKEUP_PIN3 + SYS_WKUP3 = NC, +#endif +#ifdef PWR_WAKEUP_PIN4 + SYS_WKUP4 = PA_2, +#endif +#ifdef PWR_WAKEUP_PIN5 + SYS_WKUP5 = PC_5, +#endif +#ifdef PWR_WAKEUP_PIN6 + SYS_WKUP6 = PB_5, +#endif +#ifdef PWR_WAKEUP_PIN7 + SYS_WKUP7 = PB_15, +#endif +#ifdef PWR_WAKEUP_PIN8 + SYS_WKUP8 = NC, +#endif + +/* USB */ +#ifdef USBCON + USB_DM = PA_11, + USB_DP = PA_12, + USB_NOE = PA_13, +#endif diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FLY_D5/ldscript.ld b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D5/ldscript.ld new file mode 100644 index 0000000000..5eee783933 --- /dev/null +++ b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D5/ldscript.ld @@ -0,0 +1,177 @@ +/** + ****************************************************************************** + * @file LinkerScript.ld + * @author Auto-generated by STM32CubeIDE + * @brief Linker script for STM32F072CBTx Device from STM32F0 series + * 128Kbytes FLASH + * 16Kbytes RAM + * + * Set heap size, stack size and stack location according + * to application requirements. + * + * Set memory bank area and size if external memory is used + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2020 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Entry Point */ +ENTRY(Reset_Handler) + +/* Highest address of the user mode stack */ +_estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */ + +_Min_Heap_Size = 0x200; /* required amount of heap */ +_Min_Stack_Size = 0x400; /* required amount of stack */ + +/* Memories definition */ +MEMORY +{ + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 16K + FLASH (rx) : ORIGIN = 0x8000000 , LENGTH = 128K +} + +/* Sections */ +SECTIONS +{ + /* The startup code into "FLASH" Rom type memory */ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + . = ALIGN(4); + } >FLASH + + /* The program code and other data into "FLASH" Rom type memory */ + .text : + { + . = ALIGN(4); + *(.text) /* .text sections (code) */ + *(.text*) /* .text* sections (code) */ + *(.glue_7) /* glue arm to thumb code */ + *(.glue_7t) /* glue thumb to arm code */ + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + . = ALIGN(4); + _etext = .; /* define a global symbols at end of code */ + } >FLASH + + /* Constant data into "FLASH" Rom type memory */ + .rodata : + { + . = ALIGN(4); + *(.rodata) /* .rodata sections (constants, strings, etc.) */ + *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ + . = ALIGN(4); + } >FLASH + + .ARM.extab : { + . = ALIGN(4); + *(.ARM.extab* .gnu.linkonce.armextab.*) + . = ALIGN(4); + } >FLASH + + .ARM : { + . = ALIGN(4); + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + . = ALIGN(4); + } >FLASH + + .preinit_array : + { + . = ALIGN(4); + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array*)) + PROVIDE_HIDDEN (__preinit_array_end = .); + . = ALIGN(4); + } >FLASH + + .init_array : + { + . = ALIGN(4); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array*)) + PROVIDE_HIDDEN (__init_array_end = .); + . = ALIGN(4); + } >FLASH + + .fini_array : + { + . = ALIGN(4); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT(.fini_array.*))) + KEEP (*(.fini_array*)) + PROVIDE_HIDDEN (__fini_array_end = .); + . = ALIGN(4); + } >FLASH + + /* Used by the startup to initialize data */ + _sidata = LOADADDR(.data); + + /* Initialized data sections into "RAM" Ram type memory */ + .data : + { + . = ALIGN(4); + _sdata = .; /* create a global symbol at data start */ + *(.data) /* .data sections */ + *(.data*) /* .data* sections */ + *(.RamFunc) /* .RamFunc sections */ + *(.RamFunc*) /* .RamFunc* sections */ + + . = ALIGN(4); + _edata = .; /* define a global symbol at data end */ + + } >RAM AT> FLASH + + /* Uninitialized data section into "RAM" Ram type memory */ + . = ALIGN(4); + .bss : + { + /* This is used by the startup in order to initialize the .bss section */ + _sbss = .; /* define a global symbol at bss start */ + __bss_start__ = _sbss; + *(.bss) + *(.bss*) + *(COMMON) + + . = ALIGN(4); + _ebss = .; /* define a global symbol at bss end */ + __bss_end__ = _ebss; + } >RAM + + /* User_heap_stack section, used to check that there is enough "RAM" Ram type memory left */ + ._user_heap_stack : + { + . = ALIGN(8); + PROVIDE ( end = . ); + PROVIDE ( _end = . ); + . = . + _Min_Heap_Size; + . = . + _Min_Stack_Size; + . = ALIGN(8); + } >RAM + + /* Remove information from the compiler libraries */ + /DISCARD/ : + { + libc.a ( * ) + libm.a ( * ) + libgcc.a ( * ) + } + + .ARM.attributes 0 : { *(.ARM.attributes) } +} diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FLY_D5/variant_MARLIN_STM32F072.cpp b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D5/variant_MARLIN_STM32F072.cpp new file mode 100644 index 0000000000..35f0dd6a10 --- /dev/null +++ b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D5/variant_MARLIN_STM32F072.cpp @@ -0,0 +1,137 @@ +/* + ******************************************************************************* + * Copyright (c) 2020, STMicroelectronics + * All rights reserved. + * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ******************************************************************************* + */ +#if defined(STM32F072xB) +#include "pins_arduino.h" + +// Digital PinName array +const PinName digitalPin[] = { + PA_0, // D0/A0 + PA_1, // D1/A1 + PA_2, // D2/A2 + PA_3, // D3/A3 + PA_4, // D4/A4 + PA_5, // D5/A5 + PA_6, // D6/A6 + PA_7, // D7/A7 + PA_8, // D8 + PA_9, // D9 + PA_10, // D10 + PA_11, // D11 + PA_12, // D12 + PA_13, // D13 + PA_14, // D14 + PA_15, // D15 + PB_0, // D16/A8 + PB_1, // D17/A9 + PB_2, // D18 + PB_3, // D19 + PB_4, // D20 + PB_5, // D21 + PB_6, // D22 + PB_7, // D23 + PB_8, // D24 + PB_9, // D25 + PB_10, // D26 + PB_11, // D27 + PB_12, // D28 + PB_13, // D29 + PB_14, // D30 + PB_15, // D31 + PC_0, // D32/A10 + PC_1, // D33/A11 + PC_2, // D34/A12 + PC_3, // D35/A13 + PC_4, // D36/A14 + PC_5, // D37/A15 + PC_6, // D38 + PC_7, // D39 + PC_8, // D40 + PC_9, // D41 + PC_10, // D42 + PC_11, // D43 + PC_12, // D44 + PC_13, // D45 + PC_14, // D46 + PC_15, // D47 + PD_2, // D48 + PF_0, // D49 + PF_1 // D50 +}; + +// Analog (Ax) pin number array +const uint32_t analogInputPin[] = { + 0, // A0, PA0 + 1, // A1, PA1 + 2, // A2, PA2 + 3, // A3, PA3 + 4, // A4, PA4 + 5, // A5, PA5 + 6, // A6, PA6 + 7, // A7, PA7 + 16, // A8, PB0 + 17, // A9, PB1 + 32, // A10, PC0 + 33, // A11, PC1 + 34, // A12, PC2 + 35, // A13, PC3 + 36, // A14, PC4 + 37 // A15, PC5 +}; + +#ifdef __cplusplus +extern "C" { +#endif +/** + * @brief System Clock Configuration + * @param None + * @retval None + */ +WEAK void SystemClock_Config(void) +{ + RCC_OscInitTypeDef RCC_OscInitStruct = {}; + RCC_ClkInitTypeDef RCC_ClkInitStruct = {}; + RCC_PeriphCLKInitTypeDef PeriphClkInit = {}; + + /** Initializes the RCC Oscillators according to the specified parameters + * in the RCC_OscInitTypeDef structure. + */ + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI48; + RCC_OscInitStruct.HSI48State = RCC_HSI48_ON; + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; + if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { + Error_Handler(); + } + /** Initializes the CPU, AHB and APB buses clocks + */ + RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK + | RCC_CLOCKTYPE_PCLK1; + RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI48; + RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; + RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; + + if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK) { + Error_Handler(); + } + PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USB; + PeriphClkInit.UsbClockSelection = RCC_USBCLKSOURCE_HSI48; + + if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) { + Error_Handler(); + } +} +#ifdef __cplusplus +} +#endif + + +#endif /* ARDUINO_GENERIC_* */ diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FLY_D5/variant_MARLIN_STM32F072.h b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D5/variant_MARLIN_STM32F072.h new file mode 100644 index 0000000000..5bb50cd564 --- /dev/null +++ b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D5/variant_MARLIN_STM32F072.h @@ -0,0 +1,160 @@ +/* + ******************************************************************************* + * Copyright (c) 2020, STMicroelectronics + * All rights reserved. + * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ******************************************************************************* + */ +#pragma once + +/*---------------------------------------------------------------------------- + * STM32 pins number + *----------------------------------------------------------------------------*/ +#define PA0 PIN_A0 +#define PA1 PIN_A1 +#define PA2 PIN_A2 +#define PA3 PIN_A3 +#define PA4 PIN_A4 +#define PA5 PIN_A5 +#define PA6 PIN_A6 +#define PA7 PIN_A7 +#define PA8 8 +#define PA9 9 +#define PA10 10 +#define PA11 11 +#define PA12 12 +#define PA13 13 +#define PA14 14 +#define PA15 15 +#define PB0 PIN_A8 +#define PB1 PIN_A9 +#define PB2 18 +#define PB3 19 +#define PB4 20 +#define PB5 21 +#define PB6 22 +#define PB7 23 +#define PB8 24 +#define PB9 25 +#define PB10 26 +#define PB11 27 +#define PB12 28 +#define PB13 29 +#define PB14 30 +#define PB15 31 +#define PC0 PIN_A10 +#define PC1 PIN_A11 +#define PC2 PIN_A12 +#define PC3 PIN_A13 +#define PC4 PIN_A14 +#define PC5 PIN_A15 +#define PC6 38 +#define PC7 39 +#define PC8 40 +#define PC9 41 +#define PC10 42 +#define PC11 43 +#define PC12 44 +#define PC13 45 +#define PC14 46 +#define PC15 47 +#define PD2 48 +#define PF0 49 +#define PF1 50 + +// Alternate pins number +#define PA1_ALT1 (PA1 | ALT1) +#define PA2_ALT1 (PA2 | ALT1) +#define PA3_ALT1 (PA3 | ALT1) +#define PA6_ALT1 (PA6 | ALT1) +#define PA7_ALT1 (PA7 | ALT1) +#define PA7_ALT2 (PA7 | ALT2) +#define PA7_ALT3 (PA7 | ALT3) +#define PB0_ALT1 (PB0 | ALT1) +#define PB1_ALT1 (PB1 | ALT1) +#define PB1_ALT2 (PB1 | ALT2) +#define PB14_ALT1 (PB14 | ALT1) +#define PB15_ALT1 (PB15 | ALT1) +#define PB15_ALT2 (PB15 | ALT2) +#define PC10_ALT1 (PC10 | ALT1) +#define PC11_ALT1 (PC11 | ALT1) + +#define NUM_DIGITAL_PINS 51 +#define NUM_ANALOG_INPUTS 16 + + +// SPI definitions +#ifndef PIN_SPI_SS + #define PIN_SPI_SS PB12 +#endif +#ifndef PIN_SPI_MOSI + #define PIN_SPI_MOSI PB15 +#endif +#ifndef PIN_SPI_MISO + #define PIN_SPI_MISO PB14 +#endif +#ifndef PIN_SPI_SCK + #define PIN_SPI_SCK PB13 +#endif + + +// Timer Definitions +// Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin +#ifndef TIMER_TONE + #define TIMER_TONE TIM6 +#endif +#ifndef TIMER_SERVO + #define TIMER_SERVO TIM1 +#endif + +// UART Definitions +#ifndef SERIAL_UART_INSTANCE + #define SERIAL_UART_INSTANCE 1 +#endif + +// Default pin used for generic 'Serial' instance +// Mandatory for Firmata +#ifndef PIN_SERIAL_RX + #define PIN_SERIAL_RX PA10 +#endif +#ifndef PIN_SERIAL_TX + #define PIN_SERIAL_TX PA9 +#endif + +// Extra HAL modules +#if !defined(HAL_DAC_MODULE_DISABLED) + #define HAL_DAC_MODULE_ENABLED +#endif + +/*---------------------------------------------------------------------------- + * Arduino objects - C++ only + *----------------------------------------------------------------------------*/ + +#ifdef __cplusplus + // These serial port names are intended to allow libraries and architecture-neutral + // sketches to automatically default to the correct port name for a particular type + // of use. For example, a GPS module would normally connect to SERIAL_PORT_HARDWARE_OPEN, + // the first hardware serial port whose RX/TX pins are not dedicated to another use. + // + // SERIAL_PORT_MONITOR Port which normally prints to the Arduino Serial Monitor + // + // SERIAL_PORT_USBVIRTUAL Port which is USB virtual serial + // + // SERIAL_PORT_LINUXBRIDGE Port which connects to a Linux system via Bridge library + // + // SERIAL_PORT_HARDWARE Hardware serial port, physical RX & TX pins. + // + // SERIAL_PORT_HARDWARE_OPEN Hardware serial ports which are open for use. Their RX & TX + // pins are NOT connected to anything by default. + #ifndef SERIAL_PORT_MONITOR + #define SERIAL_PORT_MONITOR Serial + #endif + #ifndef SERIAL_PORT_HARDWARE + #define SERIAL_PORT_HARDWARE Serial + #endif +#endif diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FLY_D7/PeripheralPins.c b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D7/PeripheralPins.c new file mode 100644 index 0000000000..3f5a3a3743 --- /dev/null +++ b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D7/PeripheralPins.c @@ -0,0 +1,271 @@ +/* + ******************************************************************************* + * Copyright (c) 2020, STMicroelectronics + * All rights reserved. + * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ******************************************************************************* + */ +/* + * Automatically generated from STM32F072R(8-B)Tx.xml, STM32F072RBHx.xml + * STM32F072RBIx.xml + * CubeMX DB release 6.0.80 + */ + +#include "Arduino.h" +#include "PeripheralPins.h" + +/* ===== + * Notes: + * - The pins mentioned Px_y_ALTz are alternative possibilities which use other + * HW peripheral instances. You can use them the same way as any other "normal" + * pin (i.e. analogWrite(PA7_ALT1, 128);). + * + * - Commented lines are alternative possibilities which are not used per default. + * If you change them, you will have to know what you do + * ===== + */ + +//*** ADC *** + +#ifdef HAL_ADC_MODULE_ENABLED +WEAK const PinMap PinMap_ADC[] = { + {PA_0, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 0, 0)}, // ADC_IN0 + {PA_1, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 1, 0)}, // ADC_IN1 + {PA_2, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 2, 0)}, // ADC_IN2 + {PA_3, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 3, 0)}, // ADC_IN3 + {PA_4, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 4, 0)}, // ADC_IN4 + {PA_5, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 5, 0)}, // ADC_IN5 + {PA_6, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 6, 0)}, // ADC_IN6 + {PA_7, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 7, 0)}, // ADC_IN7 + {PB_0, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 8, 0)}, // ADC_IN8 + {PB_1, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 9, 0)}, // ADC_IN9 + {PC_0, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 10, 0)}, // ADC_IN10 + {PC_1, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 11, 0)}, // ADC_IN11 + {PC_2, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 12, 0)}, // ADC_IN12 + {PC_3, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 13, 0)}, // ADC_IN13 + {PC_4, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 14, 0)}, // ADC_IN14 + {PC_5, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 15, 0)}, // ADC_IN15 + {NC, NP, 0} +}; +#endif + +//*** DAC *** + +#ifdef HAL_DAC_MODULE_ENABLED +WEAK const PinMap PinMap_DAC[] = { + {PA_4, DAC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 1, 0)}, // DAC_OUT1 + {PA_5, DAC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 2, 0)}, // DAC_OUT2 + {NC, NP, 0} +}; +#endif + +//*** I2C *** + +#ifdef HAL_I2C_MODULE_ENABLED +WEAK const PinMap PinMap_I2C_SDA[] = { + {PB_7, I2C1, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF1_I2C1)}, + {PB_9, I2C1, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF1_I2C1)}, + {PB_11, I2C2, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF1_I2C2)}, + {PB_14, I2C2, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF5_I2C2)}, + {NC, NP, 0} +}; +#endif + +#ifdef HAL_I2C_MODULE_ENABLED +WEAK const PinMap PinMap_I2C_SCL[] = { + {PB_6, I2C1, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF1_I2C1)}, + {PB_8, I2C1, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF1_I2C1)}, + {PB_10, I2C2, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF1_I2C2)}, + {PB_13, I2C2, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF5_I2C2)}, + {NC, NP, 0} +}; +#endif + +//*** TIM *** + +#ifdef HAL_TIM_MODULE_ENABLED +WEAK const PinMap PinMap_TIM[] = { + {PA_0, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM2, 1, 0)}, // TIM2_CH1 + {PA_1, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM2, 2, 0)}, // TIM2_CH2 + {PA_1_ALT1, TIM15, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_TIM15, 1, 1)}, // TIM15_CH1N + {PA_2, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM2, 3, 0)}, // TIM2_CH3 + {PA_2_ALT1, TIM15, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF0_TIM15, 1, 0)}, // TIM15_CH1 + {PA_3, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM2, 4, 0)}, // TIM2_CH4 + {PA_3_ALT1, TIM15, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF0_TIM15, 2, 0)}, // TIM15_CH2 + {PA_4, TIM14, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_TIM14, 1, 0)}, // TIM14_CH1 + {PA_5, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM2, 1, 0)}, // TIM2_CH1 + {PA_6, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM3, 1, 0)}, // TIM3_CH1 + {PA_6_ALT1, TIM16, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_TIM16, 1, 0)}, // TIM16_CH1 + {PA_7, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM1, 1, 1)}, // TIM1_CH1N + {PA_7_ALT1, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM3, 2, 0)}, // TIM3_CH2 + {PA_7_ALT2, TIM14, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_TIM14, 1, 0)}, // TIM14_CH1 + {PA_7_ALT3, TIM17, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_TIM17, 1, 0)}, // TIM17_CH1 + {PA_8, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM1, 1, 0)}, // TIM1_CH1 + {PA_9, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM1, 2, 0)}, // TIM1_CH2 + {PA_10, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM1, 3, 0)}, // TIM1_CH3 + {PA_11, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM1, 4, 0)}, // TIM1_CH4 + {PA_15, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM2, 1, 0)}, // TIM2_CH1 + {PB_0, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM1, 2, 1)}, // TIM1_CH2N + {PB_0_ALT1, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM3, 3, 0)}, // TIM3_CH3 + {PB_1, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM1, 3, 1)}, // TIM1_CH3N + {PB_1_ALT1, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM3, 4, 0)}, // TIM3_CH4 + {PB_1_ALT2, TIM14, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF0_TIM14, 1, 0)}, // TIM14_CH1 + {PB_3, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM2, 2, 0)}, // TIM2_CH2 + {PB_4, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM3, 1, 0)}, // TIM3_CH1 + {PB_5, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM3, 2, 0)}, // TIM3_CH2 + {PB_6, TIM16, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM16, 1, 1)}, // TIM16_CH1N + {PB_7, TIM17, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM17, 1, 1)}, // TIM17_CH1N + {PB_8, TIM16, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM16, 1, 0)}, // TIM16_CH1 + {PB_9, TIM17, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM17, 1, 0)}, // TIM17_CH1 + {PB_10, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM2, 3, 0)}, // TIM2_CH3 + {PB_11, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM2, 4, 0)}, // TIM2_CH4 + {PB_13, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM1, 1, 1)}, // TIM1_CH1N + {PB_14, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM1, 2, 1)}, // TIM1_CH2N + {PB_14_ALT1, TIM15, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM15, 1, 0)}, // TIM15_CH1 + {PB_15, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM1, 3, 1)}, // TIM1_CH3N + {PB_15_ALT1, TIM15, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM15, 1, 1)}, // TIM15_CH1N + {PB_15_ALT2, TIM15, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM15, 2, 0)}, // TIM15_CH2 + {PC_6, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF0_TIM3, 1, 0)}, // TIM3_CH1 + {PC_7, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF0_TIM3, 2, 0)}, // TIM3_CH2 + {PC_8, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF0_TIM3, 3, 0)}, // TIM3_CH3 + {PC_9, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF0_TIM3, 4, 0)}, // TIM3_CH4 + {NC, NP, 0} +}; +#endif + +//*** UART *** + +#ifdef HAL_UART_MODULE_ENABLED +WEAK const PinMap PinMap_UART_TX[] = { + {PA_0, USART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_USART4)}, + {PA_2, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_USART2)}, + {PA_9, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_USART1)}, + {PA_14, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_USART2)}, + {PB_6, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF0_USART1)}, + {PB_10, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_USART3)}, + {PC_4, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_USART3)}, + {PC_10, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_USART3)}, + {PC_10_ALT1, USART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF0_USART4)}, + {NC, NP, 0} +}; +#endif + +#ifdef HAL_UART_MODULE_ENABLED +WEAK const PinMap PinMap_UART_RX[] = { + {PA_1, USART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_USART4)}, + {PA_3, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_USART2)}, + {PA_10, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_USART1)}, + {PA_15, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_USART2)}, + {PB_7, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF0_USART1)}, + {PB_11, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_USART3)}, + {PC_5, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_USART3)}, + {PC_11, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_USART3)}, + {PC_11_ALT1, USART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF0_USART4)}, + {NC, NP, 0} +}; +#endif + +#ifdef HAL_UART_MODULE_ENABLED +WEAK const PinMap PinMap_UART_RTS[] = { + {PA_1, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_USART2)}, + {PA_12, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_USART1)}, + {PA_15, USART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_USART4)}, + {PB_1, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_USART3)}, + {PB_14, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_USART3)}, + {PD_2, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_USART3)}, + {NC, NP, 0} +}; +#endif + +#ifdef HAL_UART_MODULE_ENABLED +WEAK const PinMap PinMap_UART_CTS[] = { + {PA_0, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_USART2)}, + {PA_6, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_USART3)}, + {PA_11, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_USART1)}, + {PB_7, USART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_USART4)}, + {PB_13, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_USART3)}, + {NC, NP, 0} +}; +#endif + +//*** SPI *** + +#ifdef HAL_SPI_MODULE_ENABLED +WEAK const PinMap PinMap_SPI_MOSI[] = { + {PA_7, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF0_SPI1)}, + {PB_5, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF0_SPI1)}, + {PB_15, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF0_SPI2)}, + {PC_3, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_SPI2)}, + {NC, NP, 0} +}; +#endif + +#ifdef HAL_SPI_MODULE_ENABLED +WEAK const PinMap PinMap_SPI_MISO[] = { + {PA_6, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF0_SPI1)}, + {PB_4, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF0_SPI1)}, + {PB_14, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF0_SPI2)}, + {PC_2, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_SPI2)}, + {NC, NP, 0} +}; +#endif + +#ifdef HAL_SPI_MODULE_ENABLED +WEAK const PinMap PinMap_SPI_SCLK[] = { + {PA_5, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF0_SPI1)}, + {PB_3, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF0_SPI1)}, + {PB_10, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + {PB_13, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF0_SPI2)}, + {NC, NP, 0} +}; +#endif + +#ifdef HAL_SPI_MODULE_ENABLED +WEAK const PinMap PinMap_SPI_SSEL[] = { + {PA_4, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF0_SPI1)}, + {PA_15, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF0_SPI1)}, + {PB_9, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + {PB_12, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF0_SPI2)}, + {NC, NP, 0} +}; +#endif + +//*** CAN *** + +#if defined(HAL_CAN_MODULE_ENABLED) || defined(HAL_CAN_LEGACY_MODULE_ENABLED) +WEAK const PinMap PinMap_CAN_RD[] = { + {PA_11, CAN1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF4_CAN)}, + {PB_8, CAN1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF4_CAN)}, + {NC, NP, 0} +}; +#endif + +#if defined(HAL_CAN_MODULE_ENABLED) || defined(HAL_CAN_LEGACY_MODULE_ENABLED) +WEAK const PinMap PinMap_CAN_TD[] = { + {PA_12, CAN1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF4_CAN)}, + {PB_9, CAN1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF4_CAN)}, + {NC, NP, 0} +}; +#endif + +//*** No ETHERNET *** + +//*** No QUADSPI *** + +//*** USB *** + +#if defined(HAL_PCD_MODULE_ENABLED) || defined(HAL_HCD_MODULE_ENABLED) +WEAK const PinMap PinMap_USB[] = { + {PA_11, USB, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, GPIO_AF_NONE)}, // USB_DM + {PA_12, USB, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, GPIO_AF_NONE)}, // USB_DP + {PA_13, USB, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_USB)}, // USB_NOE + {NC, NP, 0} +}; +#endif + +//*** No SD *** diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FLY_D7/PinNamesVar.h b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D7/PinNamesVar.h new file mode 100644 index 0000000000..4e012676ee --- /dev/null +++ b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D7/PinNamesVar.h @@ -0,0 +1,49 @@ +/* Alternate pin name */ +PA_1_ALT1 = PA_1 | ALT1, +PA_2_ALT1 = PA_2 | ALT1, +PA_3_ALT1 = PA_3 | ALT1, +PA_6_ALT1 = PA_6 | ALT1, +PA_7_ALT1 = PA_7 | ALT1, +PA_7_ALT2 = PA_7 | ALT2, +PA_7_ALT3 = PA_7 | ALT3, +PB_0_ALT1 = PB_0 | ALT1, +PB_1_ALT1 = PB_1 | ALT1, +PB_1_ALT2 = PB_1 | ALT2, +PB_14_ALT1 = PB_14 | ALT1, +PB_15_ALT1 = PB_15 | ALT1, +PB_15_ALT2 = PB_15 | ALT2, +PC_10_ALT1 = PC_10 | ALT1, +PC_11_ALT1 = PC_11 | ALT1, + +/* SYS_WKUP */ +#ifdef PWR_WAKEUP_PIN1 + SYS_WKUP1 = PA_0, +#endif +#ifdef PWR_WAKEUP_PIN2 + SYS_WKUP2 = PC_13, +#endif +#ifdef PWR_WAKEUP_PIN3 + SYS_WKUP3 = NC, +#endif +#ifdef PWR_WAKEUP_PIN4 + SYS_WKUP4 = PA_2, +#endif +#ifdef PWR_WAKEUP_PIN5 + SYS_WKUP5 = PC_5, +#endif +#ifdef PWR_WAKEUP_PIN6 + SYS_WKUP6 = PB_5, +#endif +#ifdef PWR_WAKEUP_PIN7 + SYS_WKUP7 = PB_15, +#endif +#ifdef PWR_WAKEUP_PIN8 + SYS_WKUP8 = NC, +#endif + +/* USB */ +#ifdef USBCON + USB_DM = PA_11, + USB_DP = PA_12, + USB_NOE = PA_13, +#endif diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FLY_D7/ldscript.ld b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D7/ldscript.ld new file mode 100644 index 0000000000..5eee783933 --- /dev/null +++ b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D7/ldscript.ld @@ -0,0 +1,177 @@ +/** + ****************************************************************************** + * @file LinkerScript.ld + * @author Auto-generated by STM32CubeIDE + * @brief Linker script for STM32F072CBTx Device from STM32F0 series + * 128Kbytes FLASH + * 16Kbytes RAM + * + * Set heap size, stack size and stack location according + * to application requirements. + * + * Set memory bank area and size if external memory is used + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2020 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Entry Point */ +ENTRY(Reset_Handler) + +/* Highest address of the user mode stack */ +_estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */ + +_Min_Heap_Size = 0x200; /* required amount of heap */ +_Min_Stack_Size = 0x400; /* required amount of stack */ + +/* Memories definition */ +MEMORY +{ + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 16K + FLASH (rx) : ORIGIN = 0x8000000 , LENGTH = 128K +} + +/* Sections */ +SECTIONS +{ + /* The startup code into "FLASH" Rom type memory */ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + . = ALIGN(4); + } >FLASH + + /* The program code and other data into "FLASH" Rom type memory */ + .text : + { + . = ALIGN(4); + *(.text) /* .text sections (code) */ + *(.text*) /* .text* sections (code) */ + *(.glue_7) /* glue arm to thumb code */ + *(.glue_7t) /* glue thumb to arm code */ + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + . = ALIGN(4); + _etext = .; /* define a global symbols at end of code */ + } >FLASH + + /* Constant data into "FLASH" Rom type memory */ + .rodata : + { + . = ALIGN(4); + *(.rodata) /* .rodata sections (constants, strings, etc.) */ + *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ + . = ALIGN(4); + } >FLASH + + .ARM.extab : { + . = ALIGN(4); + *(.ARM.extab* .gnu.linkonce.armextab.*) + . = ALIGN(4); + } >FLASH + + .ARM : { + . = ALIGN(4); + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + . = ALIGN(4); + } >FLASH + + .preinit_array : + { + . = ALIGN(4); + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array*)) + PROVIDE_HIDDEN (__preinit_array_end = .); + . = ALIGN(4); + } >FLASH + + .init_array : + { + . = ALIGN(4); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array*)) + PROVIDE_HIDDEN (__init_array_end = .); + . = ALIGN(4); + } >FLASH + + .fini_array : + { + . = ALIGN(4); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT(.fini_array.*))) + KEEP (*(.fini_array*)) + PROVIDE_HIDDEN (__fini_array_end = .); + . = ALIGN(4); + } >FLASH + + /* Used by the startup to initialize data */ + _sidata = LOADADDR(.data); + + /* Initialized data sections into "RAM" Ram type memory */ + .data : + { + . = ALIGN(4); + _sdata = .; /* create a global symbol at data start */ + *(.data) /* .data sections */ + *(.data*) /* .data* sections */ + *(.RamFunc) /* .RamFunc sections */ + *(.RamFunc*) /* .RamFunc* sections */ + + . = ALIGN(4); + _edata = .; /* define a global symbol at data end */ + + } >RAM AT> FLASH + + /* Uninitialized data section into "RAM" Ram type memory */ + . = ALIGN(4); + .bss : + { + /* This is used by the startup in order to initialize the .bss section */ + _sbss = .; /* define a global symbol at bss start */ + __bss_start__ = _sbss; + *(.bss) + *(.bss*) + *(COMMON) + + . = ALIGN(4); + _ebss = .; /* define a global symbol at bss end */ + __bss_end__ = _ebss; + } >RAM + + /* User_heap_stack section, used to check that there is enough "RAM" Ram type memory left */ + ._user_heap_stack : + { + . = ALIGN(8); + PROVIDE ( end = . ); + PROVIDE ( _end = . ); + . = . + _Min_Heap_Size; + . = . + _Min_Stack_Size; + . = ALIGN(8); + } >RAM + + /* Remove information from the compiler libraries */ + /DISCARD/ : + { + libc.a ( * ) + libm.a ( * ) + libgcc.a ( * ) + } + + .ARM.attributes 0 : { *(.ARM.attributes) } +} diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FLY_D7/variant_MARLIN_STM32F072.cpp b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D7/variant_MARLIN_STM32F072.cpp new file mode 100644 index 0000000000..35f0dd6a10 --- /dev/null +++ b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D7/variant_MARLIN_STM32F072.cpp @@ -0,0 +1,137 @@ +/* + ******************************************************************************* + * Copyright (c) 2020, STMicroelectronics + * All rights reserved. + * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ******************************************************************************* + */ +#if defined(STM32F072xB) +#include "pins_arduino.h" + +// Digital PinName array +const PinName digitalPin[] = { + PA_0, // D0/A0 + PA_1, // D1/A1 + PA_2, // D2/A2 + PA_3, // D3/A3 + PA_4, // D4/A4 + PA_5, // D5/A5 + PA_6, // D6/A6 + PA_7, // D7/A7 + PA_8, // D8 + PA_9, // D9 + PA_10, // D10 + PA_11, // D11 + PA_12, // D12 + PA_13, // D13 + PA_14, // D14 + PA_15, // D15 + PB_0, // D16/A8 + PB_1, // D17/A9 + PB_2, // D18 + PB_3, // D19 + PB_4, // D20 + PB_5, // D21 + PB_6, // D22 + PB_7, // D23 + PB_8, // D24 + PB_9, // D25 + PB_10, // D26 + PB_11, // D27 + PB_12, // D28 + PB_13, // D29 + PB_14, // D30 + PB_15, // D31 + PC_0, // D32/A10 + PC_1, // D33/A11 + PC_2, // D34/A12 + PC_3, // D35/A13 + PC_4, // D36/A14 + PC_5, // D37/A15 + PC_6, // D38 + PC_7, // D39 + PC_8, // D40 + PC_9, // D41 + PC_10, // D42 + PC_11, // D43 + PC_12, // D44 + PC_13, // D45 + PC_14, // D46 + PC_15, // D47 + PD_2, // D48 + PF_0, // D49 + PF_1 // D50 +}; + +// Analog (Ax) pin number array +const uint32_t analogInputPin[] = { + 0, // A0, PA0 + 1, // A1, PA1 + 2, // A2, PA2 + 3, // A3, PA3 + 4, // A4, PA4 + 5, // A5, PA5 + 6, // A6, PA6 + 7, // A7, PA7 + 16, // A8, PB0 + 17, // A9, PB1 + 32, // A10, PC0 + 33, // A11, PC1 + 34, // A12, PC2 + 35, // A13, PC3 + 36, // A14, PC4 + 37 // A15, PC5 +}; + +#ifdef __cplusplus +extern "C" { +#endif +/** + * @brief System Clock Configuration + * @param None + * @retval None + */ +WEAK void SystemClock_Config(void) +{ + RCC_OscInitTypeDef RCC_OscInitStruct = {}; + RCC_ClkInitTypeDef RCC_ClkInitStruct = {}; + RCC_PeriphCLKInitTypeDef PeriphClkInit = {}; + + /** Initializes the RCC Oscillators according to the specified parameters + * in the RCC_OscInitTypeDef structure. + */ + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI48; + RCC_OscInitStruct.HSI48State = RCC_HSI48_ON; + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; + if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { + Error_Handler(); + } + /** Initializes the CPU, AHB and APB buses clocks + */ + RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK + | RCC_CLOCKTYPE_PCLK1; + RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI48; + RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; + RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; + + if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK) { + Error_Handler(); + } + PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USB; + PeriphClkInit.UsbClockSelection = RCC_USBCLKSOURCE_HSI48; + + if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) { + Error_Handler(); + } +} +#ifdef __cplusplus +} +#endif + + +#endif /* ARDUINO_GENERIC_* */ diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FLY_D7/variant_MARLIN_STM32F072.h b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D7/variant_MARLIN_STM32F072.h new file mode 100644 index 0000000000..85fad3a5f8 --- /dev/null +++ b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D7/variant_MARLIN_STM32F072.h @@ -0,0 +1,160 @@ +/* + ******************************************************************************* + * Copyright (c) 2020, STMicroelectronics + * All rights reserved. + * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ******************************************************************************* + */ +#pragma once + +/*---------------------------------------------------------------------------- + * STM32 pins number + *----------------------------------------------------------------------------*/ +#define PA0 PIN_A0 +#define PA1 PIN_A1 +#define PA2 PIN_A2 +#define PA3 PIN_A3 +#define PA4 PIN_A4 +#define PA5 PIN_A5 +#define PA6 PIN_A6 +#define PA7 PIN_A7 +#define PA8 8 +#define PA9 9 +#define PA10 10 +#define PA11 11 +#define PA12 12 +#define PA13 13 +#define PA14 14 +#define PA15 15 +#define PB0 PIN_A8 +#define PB1 PIN_A9 +#define PB2 18 +#define PB3 19 +#define PB4 20 +#define PB5 21 +#define PB6 22 +#define PB7 23 +#define PB8 24 +#define PB9 25 +#define PB10 26 +#define PB11 27 +#define PB12 28 +#define PB13 29 +#define PB14 30 +#define PB15 31 +#define PC0 PIN_A10 +#define PC1 PIN_A11 +#define PC2 PIN_A12 +#define PC3 PIN_A13 +#define PC4 PIN_A14 +#define PC5 PIN_A15 +#define PC6 38 +#define PC7 39 +#define PC8 40 +#define PC9 41 +#define PC10 42 +#define PC11 43 +#define PC12 44 +#define PC13 45 +#define PC14 46 +#define PC15 47 +#define PD2 48 +#define PF0 49 +#define PF1 50 + +// Alternate pins number +#define PA1_ALT1 (PA1 | ALT1) +#define PA2_ALT1 (PA2 | ALT1) +#define PA3_ALT1 (PA3 | ALT1) +#define PA6_ALT1 (PA6 | ALT1) +#define PA7_ALT1 (PA7 | ALT1) +#define PA7_ALT2 (PA7 | ALT2) +#define PA7_ALT3 (PA7 | ALT3) +#define PB0_ALT1 (PB0 | ALT1) +#define PB1_ALT1 (PB1 | ALT1) +#define PB1_ALT2 (PB1 | ALT2) +#define PB14_ALT1 (PB14 | ALT1) +#define PB15_ALT1 (PB15 | ALT1) +#define PB15_ALT2 (PB15 | ALT2) +#define PC10_ALT1 (PC10 | ALT1) +#define PC11_ALT1 (PC11 | ALT1) + +#define NUM_DIGITAL_PINS 51 +#define NUM_ANALOG_INPUTS 16 + + +// SPI definitions +#ifndef PIN_SPI_SS + #define PIN_SPI_SS PB12 +#endif +#ifndef PIN_SPI_MOSI + #define PIN_SPI_MOSI PB15 +#endif +#ifndef PIN_SPI_MISO + #define PIN_SPI_MISO PB14 +#endif +#ifndef PIN_SPI_SCK + #define PIN_SPI_SCK PB13 +#endif + + +// Timer Definitions +// Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin +#ifndef TIMER_TONE + #define TIMER_TONE TIM6 +#endif +#ifndef TIMER_SERVO + #define TIMER_SERVO TIM7 +#endif + +// UART Definitions +#ifndef SERIAL_UART_INSTANCE + #define SERIAL_UART_INSTANCE 1 +#endif + +// Default pin used for generic 'Serial' instance +// Mandatory for Firmata +#ifndef PIN_SERIAL_RX + #define PIN_SERIAL_RX PA10 +#endif +#ifndef PIN_SERIAL_TX + #define PIN_SERIAL_TX PA9 +#endif + +// Extra HAL modules +#if !defined(HAL_DAC_MODULE_DISABLED) + #define HAL_DAC_MODULE_ENABLED +#endif + +/*---------------------------------------------------------------------------- + * Arduino objects - C++ only + *----------------------------------------------------------------------------*/ + +#ifdef __cplusplus + // These serial port names are intended to allow libraries and architecture-neutral + // sketches to automatically default to the correct port name for a particular type + // of use. For example, a GPS module would normally connect to SERIAL_PORT_HARDWARE_OPEN, + // the first hardware serial port whose RX/TX pins are not dedicated to another use. + // + // SERIAL_PORT_MONITOR Port which normally prints to the Arduino Serial Monitor + // + // SERIAL_PORT_USBVIRTUAL Port which is USB virtual serial + // + // SERIAL_PORT_LINUXBRIDGE Port which connects to a Linux system via Bridge library + // + // SERIAL_PORT_HARDWARE Hardware serial port, physical RX & TX pins. + // + // SERIAL_PORT_HARDWARE_OPEN Hardware serial ports which are open for use. Their RX & TX + // pins are NOT connected to anything by default. + #ifndef SERIAL_PORT_MONITOR + #define SERIAL_PORT_MONITOR Serial + #endif + #ifndef SERIAL_PORT_HARDWARE + #define SERIAL_PORT_HARDWARE Serial + #endif +#endif diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FLY_D8/PeripheralPins.c b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D8/PeripheralPins.c new file mode 100644 index 0000000000..aded6e6db3 --- /dev/null +++ b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D8/PeripheralPins.c @@ -0,0 +1,394 @@ +/* + ******************************************************************************* + * Copyright (c) 2019, STMicroelectronics + * All rights reserved. + * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ******************************************************************************* + * Automatically generated from STM32F407V(E-G)Tx.xml + */ +#include "Arduino.h" +#include "PeripheralPins.h" + +/** + * Variant for: mks_robin_pro2, mks_robin_nano_v3, Anet_ET4_OpenBLT + */ + +/* ===== + * Note: Commented lines are alternative possibilities which are not used per default. + * If you change them, you will have to know what you do + * ===== + */ + +//*** ADC *** + +#ifdef HAL_ADC_MODULE_ENABLED +WEAK const PinMap PinMap_ADC[] = { + // {PA_0, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 0, 0)}, // ADC1_IN0 + //{PA_0, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 0, 0)}, // ADC2_IN0 + //{PA_0, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 0, 0)}, // ADC3_IN0 + // {PA_1, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 1, 0)}, // ADC1_IN1 + //{PA_1, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 1, 0)}, // ADC2_IN1 + //{PA_1, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 1, 0)}, // ADC3_IN1 + // {PA_2, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 2, 0)}, // ADC1_IN2 + //{PA_2, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 2, 0)}, // ADC2_IN2 + //{PA_2, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 2, 0)}, // ADC3_IN2 + // {PA_3, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 3, 0)}, // ADC1_IN3 + //{PA_3, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 3, 0)}, // ADC2_IN3 + //{PA_3, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 3, 0)}, // ADC3_IN3 + // {PA_4, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 4, 0)}, // ADC1_IN4 + //{PA_4, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 4, 0)}, // ADC2_IN4 + // {PA_5, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 5, 0)}, // ADC1_IN5 + //{PA_5, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 5, 0)}, // ADC2_IN5 + // {PA_6, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 6, 0)}, // ADC1_IN6 + //{PA_6, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 6, 0)}, // ADC2_IN6 + // {PA_7, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 7, 0)}, // ADC1_IN7 + //{PA_7, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 7, 0)}, // ADC2_IN7 + // {PB_0, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 8, 0)}, // ADC1_IN8 + //{PB_0, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 8, 0)}, // ADC2_IN8 + // {PB_1, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 9, 0)}, // ADC1_IN9 + //{PB_1, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 9, 0)}, // ADC2_IN9 + // {PC_0, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 10, 0)}, // ADC1_IN10 + //{PC_0, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 10, 0)}, // ADC2_IN10 + //{PC_0, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 10, 0)}, // ADC3_IN10 + // {PC_1, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 11, 0)}, // ADC1_IN11 + //{PC_1, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 11, 0)}, // ADC2_IN11 + //{PC_1, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 11, 0)}, // ADC3_IN11 + {PC_2, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 12, 0)}, // ADC1_IN12 + //{PC_2, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 12, 0)}, // ADC2_IN12 + //{PC_2, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 12, 0)}, // ADC3_IN12 + {PC_3, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 13, 0)}, // ADC1_IN13 + //{PC_3, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 13, 0)}, // ADC2_IN13 + //{PC_3, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 13, 0)}, // ADC3_IN13 + {PC_4, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 14, 0)}, // ADC1_IN14 + //{PC_4, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 14, 0)}, // ADC2_IN14 + {PC_5, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 15, 0)}, // ADC1_IN15 + //{PC_5, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 15, 0)}, // ADC2_IN15 + {NC, NP, 0} +}; +#endif + +//*** DAC *** + +#ifdef HAL_DAC_MODULE_ENABLED +WEAK const PinMap PinMap_DAC[] = { + {PA_4, DAC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 1, 0)}, // DAC_OUT1 + {PA_5, DAC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 2, 0)}, // DAC_OUT2 + {NC, NP, 0} +}; +#endif + +//*** I2C *** + +#ifdef HAL_I2C_MODULE_ENABLED +WEAK const PinMap PinMap_I2C_SDA[] = { + // {PB_7, I2C1, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C1)}, + // {PB_9, I2C1, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C1)}, + {PB_11, I2C2, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C2)}, + // {PC_9, I2C3, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C3)}, + {NC, NP, 0} +}; + +WEAK const PinMap PinMap_I2C_SCL[] = { + // {PA_8, I2C3, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C3)}, + // {PB_6, I2C1, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C1)}, + // {PB_8, I2C1, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C1)}, + {PB_10, I2C2, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C2)}, + {NC, NP, 0} +}; +#endif + +//*** PWM *** + +#ifdef HAL_TIM_MODULE_ENABLED +// Some pins can perform PWM from more than one timer. These were selected to utilize as many channels as +// possible from timers which were already dedicated to PWM output. + +// TIM1 = Pins are using for OTG FS +// TIM2 = [HEATER_BED], TIM2 is used OTG HS SOF +// TIM6 = Tone +// TIM8 = [FAN0, HEATER_1] OTG HS +// TIM7 = Servo +// TIM9 = [HEATER_0, ] +// TIM1, TIM8, TIM12 = Pins are using for OTG HS +// No timer = [FAN1 ] + +WEAK const PinMap PinMap_PWM[] = { + {PA_0, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 1, 0)}, // TIM2_CH1 + //{PA_0, TIM5, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM5, 1, 0)}, // TIM5_CH1 + //{PA_1, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 2, 0)}, // TIM2_CH2 + {PA_1, TIM5, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM5, 2, 0)}, // TIM5_CH2 + //{PA_2, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 3, 0)}, // TIM2_CH3 + {PA_2, TIM5, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM5, 3, 0)}, // TIM5_CH3 + //{PA_2, TIM9, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM9, 1, 0)}, // TIM9_CH1 + //{PA_3, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 4, 0)}, // TIM2_CH4 + // {PA_3, TIM5, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM5, 4, 0)}, // TIM5_CH4 + //{PA_3, TIM9, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM9, 2, 0)}, // TIM9_CH2 + // {PA_5, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 1, 0)}, // TIM2_CH1 + //{PA_5, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 1, 1)}, // TIM8_CH1N + //{PA_6, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 1, 0)}, // TIM3_CH1 + // {PA_6, TIM13, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_TIM13, 1, 0)}, // TIM13_CH1 + //{PA_7, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 1, 1)}, // TIM1_CH1N + //{PA_7, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 2, 0)}, // TIM3_CH2 + //{PA_7, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 1, 1)}, // TIM8_CH1N + // {PA_7, TIM14, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_TIM14, 1, 0)}, // TIM14_CH1 + // {PA_8, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 1, 0)}, // TIM1_CH1 + // {PA_9, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 2, 0)}, // TIM1_CH2 + // {PA_10, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 3, 0)}, // TIM1_CH3 + //{PA_11, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 4, 0)}, // TIM1_CH4 + // {PA_15, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 1, 0)}, // TIM2_CH1 + //{PB_0, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 2, 1)}, // TIM1_CH2N + //{PB_0, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 3, 0)}, // TIM3_CH3 + // {PB_0, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 2, 1)}, // TIM8_CH2N + //{PB_1, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 3, 1)}, // TIM1_CH3N + //{PB_1, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 4, 0)}, // TIM3_CH4 + // {PB_1, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 3, 1)}, // TIM8_CH3N + // {PB_2, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 4, 0)}, // TIM2_CH4 + // {PB_3, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 2, 0)}, // TIM2_CH2 + // {PB_4, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 1, 0)}, // TIM3_CH1 + // {PB_5, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 2, 0)}, // TIM3_CH2 + // {PB_6, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 1, 0)}, // TIM4_CH1 + // {PB_7, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 2, 0)}, // TIM4_CH2 + // {PB_8, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 3, 0)}, // TIM4_CH3 + //{PB_8, TIM10, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM10, 1, 0)}, // TIM10_CH1 + //{PB_9, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 4, 0)}, // TIM4_CH4 + // {PB_9, TIM11, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM11, 1, 0)}, // TIM11_CH1 + // {PB_10, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 3, 0)}, // TIM2_CH3 + // {PB_11, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 4, 0)}, // TIM2_CH4 + // {PB_13, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 1, 1)}, // TIM1_CH1N + //{PB_14, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 2, 1)}, // TIM1_CH2N + //{PB_14, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 2, 1)}, // TIM8_CH2N + //{PB_14, TIM12, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_TIM12, 1, 0)}, // TIM12_CH1 + //{PB_15, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 3, 1)}, // TIM1_CH3N + //{PB_15, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 3, 1)}, // TIM8_CH3N + //{PB_15, TIM12, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_TIM12, 2, 0)}, // TIM12_CH2 + {PC_6, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 1, 0)}, // TIM3_CH1 + //{PC_6, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 1, 0)}, // TIM8_CH1 + //{PC_7, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 2, 0)}, // TIM3_CH2 + {PC_7, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 2, 0)}, // TIM8_CH2 + {PC_8, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 3, 0)}, // TIM3_CH3 + //{PC_8, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 3, 0)}, // TIM8_CH3 + //{PC_9, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 4, 0)}, // TIM3_CH4 + // {PC_9, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 4, 0)}, // TIM8_CH4 + {PD_12, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 1, 0)}, // TIM4_CH1 + {PD_13, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 2, 0)}, // TIM4_CH2 + {PD_14, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 3, 0)}, // TIM4_CH3 + // {PD_15, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 4, 0)}, // TIM4_CH4 + // {PE_5, TIM9, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM9, 1, 0)}, // TIM9_CH1 + // {PE_6, TIM9, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM9, 2, 0)}, // TIM9_CH2 + // {PE_8, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 1, 1)}, // TIM1_CH1N + // {PE_9, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 1, 0)}, // TIM1_CH1 + // {PE_10, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 2, 1)}, // TIM1_CH2N + // {PE_11, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 2, 0)}, // TIM1_CH2 + // {PE_12, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 3, 1)}, // TIM1_CH3N + // {PE_13, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 3, 0)}, // TIM1_CH3 + // {PE_14, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 4, 0)}, // TIM1_CH4 + {NC, NP, 0} +}; +#endif + +//*** SERIAL *** + +#ifdef HAL_UART_MODULE_ENABLED +WEAK const PinMap PinMap_UART_TX[] = { + // {PA_0, UART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART4)}, + // {PA_2, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)}, + {PA_9, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART1)}, + // {PB_6, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART1)}, + {PB_10, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + // {PC_6, USART6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_USART6)}, + // {PC_10, UART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART4)}, + // {PC_10, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + // {PC_12, UART5, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART5)}, + // {PD_5, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)}, + // {PD_8, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + {NC, NP, 0} +}; + +WEAK const PinMap PinMap_UART_RX[] = { + // {PA_1, UART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART4)}, + // {PA_3, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)}, + {PA_10, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART1)}, + // {PB_7, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART1)}, + {PB_11, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + // {PC_7, USART6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_USART6)}, + // //{PC_11, UART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART4)}, + // {PC_11, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + // {PD_2, UART5, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART5)}, + // {PD_6, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)}, + // {PD_9, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + {NC, NP, 0} +}; + +WEAK const PinMap PinMap_UART_RTS[] = { + // {PA_1, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)}, + // {PA_12, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART1)}, + // {PB_14, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + // {PD_4, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)}, + // {PD_12, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + {NC, NP, 0} +}; + +WEAK const PinMap PinMap_UART_CTS[] = { + // {PA_0, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)}, + // {PA_11, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART1)}, + // {PB_13, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + // {PD_3, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)}, + // {PD_11, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + {NC, NP, 0} +}; +#endif + +//*** SPI *** + +#ifdef HAL_SPI_MODULE_ENABLED +WEAK const PinMap PinMap_SPI_MOSI[] = { + // {PA_7, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, + {PB_5, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, + // {PB_5, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)}, + {PB_15, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + // {PC_3, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + // {PC_12, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)}, + {NC, NP, 0} +}; + +WEAK const PinMap PinMap_SPI_MISO[] = { + // {PA_6, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, + {PB_4, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, + // {PB_4, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)}, + {PB_14, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + // {PC_2, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + // {PC_11, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)}, + {NC, NP, 0} +}; + +WEAK const PinMap PinMap_SPI_SCLK[] = { + // {PA_5, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, + {PB_3, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, + // {PB_3, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)}, + // {PB_10, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + {PB_13, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + // {PC_10, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)}, + {NC, NP, 0} +}; + +WEAK const PinMap PinMap_SPI_SSEL[] = { + // {PA_4, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, + // {PA_4, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)}, + // {PA_15, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, + // {PA_15, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)}, + // {PB_9, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + // {PB_12, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + {NC, NP, 0} +}; +#endif + +//*** CAN *** + +#ifdef HAL_CAN_MODULE_ENABLED +WEAK const PinMap PinMap_CAN_RD[] = { + // {PA_11, CAN1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_CAN1)}, + // {PB_5, CAN2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_CAN2)}, + {PB_8, CAN1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_CAN1)}, + // {PB_12, CAN2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_CAN2)}, + // {PD_0, CAN1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_CAN1)}, + {NC, NP, 0} +}; + +WEAK const PinMap PinMap_CAN_TD[] = { + // {PA_12, CAN1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_CAN1)}, + // {PB_6, CAN2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_CAN2)}, + {PB_9, CAN1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_CAN1)}, + // {PB_13, CAN2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_CAN2)}, + // {PD_1, CAN1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_CAN1)}, + {NC, NP, 0} +}; +#endif + +//*** ETHERNET *** + +#ifdef HAL_ETH_MODULE_ENABLED +WEAK const PinMap PinMap_Ethernet[] = { + {PA_0, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_CRS + {PA_1, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_REF_CLK|ETH_RX_CLK + {PA_2, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_MDIO + {PA_3, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_COL + {PA_7, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_CRS_DV|ETH_RX_DV + {PB_0, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_RXD2 + {PB_1, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_RXD3 + {PB_5, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_PPS_OUT + {PB_8, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_TXD3 + {PB_10, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_RX_ER + {PB_11, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_TX_EN + {PB_12, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_TXD0 + {PB_13, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_TXD1 + {PC_1, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_MDC + {PC_2, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_TXD2 + {PC_3, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_TX_CLK + {PC_4, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_RXD0 + {PC_5, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_RXD1 + {PE_2, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_TXD3 + {NC, NP, 0} +}; +#endif + +//*** No QUADSPI *** + +//*** USB *** + +#ifdef HAL_PCD_MODULE_ENABLED +WEAK const PinMap PinMap_USB_OTG_FS[] = { + //{PA_8, USB_OTG_FS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_FS)}, // USB_OTG_FS_SOF + //{PA_9, USB_OTG_FS, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, GPIO_AF_NONE)}, // USB_OTG_FS_VBUS + //{PA_10, USB_OTG_FS, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_PULLUP, GPIO_AF10_OTG_FS)}, // USB_OTG_FS_ID + {PA_11, USB_OTG_FS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_FS)}, // USB_OTG_FS_DM + {PA_12, USB_OTG_FS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_FS)}, // USB_OTG_FS_DP + {NC, NP, 0} +}; + +WEAK const PinMap PinMap_USB_OTG_HS[] = { +#ifdef USE_USB_HS_IN_FS + //{PA_4, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_OTG_HS_FS)}, // USB_OTG_HS_SOF + //{PB_12, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_PULLUP, GPIO_AF12_OTG_HS_FS)}, // USB_OTG_HS_ID + //{PB_13, USB_OTG_HS, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, GPIO_AF_NONE)}, // USB_OTG_HS_VBUS + {PB_14, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_OTG_HS_FS)}, // USB_OTG_HS_DM + {PB_15, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_OTG_HS_FS)}, // USB_OTG_HS_DP +#else + // {PA_3, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_HS)}, // USB_OTG_HS_ULPI_D0 + // {PA_5, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_HS)}, // USB_OTG_HS_ULPI_CK + // {PB_0, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_HS)}, // USB_OTG_HS_ULPI_D1 + // {PB_1, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_HS)}, // USB_OTG_HS_ULPI_D2 + // {PB_5, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_HS)}, // USB_OTG_HS_ULPI_D7 + // {PB_10, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_HS)}, // USB_OTG_HS_ULPI_D3 + // {PB_11, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_HS)}, // USB_OTG_HS_ULPI_D4 + // {PB_12, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_HS)}, // USB_OTG_HS_ULPI_D5 + // {PB_13, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_HS)}, // USB_OTG_HS_ULPI_D6 + // {PC_0, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_HS)}, // USB_OTG_HS_ULPI_STP + // {PC_2, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_HS)}, // USB_OTG_HS_ULPI_DIR + // {PC_3, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_HS)}, // USB_OTG_HS_ULPI_NXT +#endif /* USE_USB_HS_IN_FS */ + {NC, NP, 0} +}; +#endif + +//*** SD *** + +#ifdef HAL_SD_MODULE_ENABLED +WEAK const PinMap PinMap_SD[] = { + // {PB_8, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDIO)}, // SDIO_D4 + // {PB_9, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDIO)}, // SDIO_D5 + // {PC_6, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDIO)}, // SDIO_D6 + // {PC_7, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDIO)}, // SDIO_D7 + // {PC_8, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDIO)}, // SDIO_D0 + // {PC_9, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDIO)}, // SDIO_D1 + // {PC_10, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDIO)}, // SDIO_D2 + // {PC_11, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDIO)}, // SDIO_D3 + // {PC_12, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF12_SDIO)}, // SDIO_CK + // {PD_2, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF12_SDIO)}, // SDIO_CMD + {NC, NP, 0} +}; +#endif diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FLY_D8/PinNamesVar.h b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D8/PinNamesVar.h new file mode 100644 index 0000000000..2424885937 --- /dev/null +++ b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D8/PinNamesVar.h @@ -0,0 +1,50 @@ +/* SYS_WKUP */ +#ifdef PWR_WAKEUP_PIN1 + SYS_WKUP1 = PA_0, +#endif +#ifdef PWR_WAKEUP_PIN2 + SYS_WKUP2 = NC, +#endif +#ifdef PWR_WAKEUP_PIN3 + SYS_WKUP3 = NC, +#endif +#ifdef PWR_WAKEUP_PIN4 + SYS_WKUP4 = NC, +#endif +#ifdef PWR_WAKEUP_PIN5 + SYS_WKUP5 = NC, +#endif +#ifdef PWR_WAKEUP_PIN6 + SYS_WKUP6 = NC, +#endif +#ifdef PWR_WAKEUP_PIN7 + SYS_WKUP7 = NC, +#endif +#ifdef PWR_WAKEUP_PIN8 + SYS_WKUP8 = NC, +#endif +/* USB */ +#ifdef USBCON + USB_OTG_FS_SOF = PA_8, + USB_OTG_FS_VBUS = PA_9, + USB_OTG_FS_ID = PA_10, + USB_OTG_FS_DM = PA_11, + USB_OTG_FS_DP = PA_12, + USB_OTG_HS_ULPI_D0 = PA_3, + USB_OTG_HS_SOF = PA_4, + USB_OTG_HS_ULPI_CK = PA_5, + USB_OTG_HS_ULPI_D1 = PB_0, + USB_OTG_HS_ULPI_D2 = PB_1, + USB_OTG_HS_ULPI_D7 = PB_5, + USB_OTG_HS_ULPI_D3 = PB_10, + USB_OTG_HS_ULPI_D4 = PB_11, + USB_OTG_HS_ID = PB_12, + USB_OTG_HS_ULPI_D5 = PB_12, + USB_OTG_HS_ULPI_D6 = PB_13, + USB_OTG_HS_VBUS = PB_13, + USB_OTG_HS_DM = PB_14, + USB_OTG_HS_DP = PB_15, + USB_OTG_HS_ULPI_STP = PC_0, + USB_OTG_HS_ULPI_DIR = PC_2, + USB_OTG_HS_ULPI_NXT = PC_3, +#endif diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FLY_D8/ldscript.ld b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D8/ldscript.ld new file mode 100644 index 0000000000..df1ed1581a --- /dev/null +++ b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D8/ldscript.ld @@ -0,0 +1,203 @@ +/* +****************************************************************************** +** +** File : LinkerScript.ld +** +** Abstract : Linker script for STM32F4x7Vx Device with +** 512/1024KByte FLASH, 192KByte RAM +** +** Set heap size, stack size and stack location according +** to application requirements. +** +** Set memory bank area and size if external memory is used. +** +** Target : STMicroelectronics STM32 +** +** Distribution: The file is distributed “as is,” without any warranty +** of any kind. +** +***************************************************************************** +** @attention +** +** Copyright (c) 2019 STMicroelectronics +** +** Redistribution and use in source and binary forms, with or without modification, +** are permitted provided that the following conditions are met: +** 1. Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright notice, +** this list of conditions and the following disclaimer in the documentation +** and/or other materials provided with the distribution. +** 3. Neither the name of STMicroelectronics nor the names of its contributors +** may be used to endorse or promote products derived from this software +** without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +** +***************************************************************************** +*/ + +/* Entry Point */ +ENTRY(Reset_Handler) + +/* Highest address of the user mode stack */ +_estack = 0x20000000 + LD_MAX_DATA_SIZE; /* end of RAM */ +/* Generate a link error if heap and stack don't fit into RAM */ +_Min_Heap_Size = 0x200; /* required amount of heap */ +_Min_Stack_Size = 0x400; /* required amount of stack */ + +/* Specify the memory areas */ +MEMORY +{ +RAM (xrw) : ORIGIN = 0x20000000, LENGTH = LD_MAX_DATA_SIZE +CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64K +FLASH (rx) : ORIGIN = 0x08000000 + LD_FLASH_OFFSET, LENGTH = LD_MAX_SIZE - LD_FLASH_OFFSET +} + +/* Define output sections */ +SECTIONS +{ + /* The startup code goes first into FLASH */ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + . = ALIGN(4); + } >FLASH + + /* The program code and other data goes into FLASH */ + .text : + { + . = ALIGN(4); + *(.text) /* .text sections (code) */ + *(.text*) /* .text* sections (code) */ + *(.glue_7) /* glue arm to thumb code */ + *(.glue_7t) /* glue thumb to arm code */ + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + . = ALIGN(4); + _etext = .; /* define a global symbols at end of code */ + } >FLASH + + /* Constant data goes into FLASH */ + .rodata : + { + . = ALIGN(4); + *(.rodata) /* .rodata sections (constants, strings, etc.) */ + *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ + . = ALIGN(4); + } >FLASH + + .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH + .ARM : { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } >FLASH + + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array*)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } >FLASH + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array*)) + PROVIDE_HIDDEN (__init_array_end = .); + } >FLASH + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT(.fini_array.*))) + KEEP (*(.fini_array*)) + PROVIDE_HIDDEN (__fini_array_end = .); + } >FLASH + + /* used by the startup to initialize data */ + _sidata = LOADADDR(.data); + + /* Initialized data sections goes into RAM, load LMA copy after code */ + .data : + { + . = ALIGN(4); + _sdata = .; /* create a global symbol at data start */ + *(.data) /* .data sections */ + *(.data*) /* .data* sections */ + + . = ALIGN(4); + _edata = .; /* define a global symbol at data end */ + } >RAM AT> FLASH + + _siccmram = LOADADDR(.ccmram); + + /* CCM-RAM section + * + * IMPORTANT NOTE! + * If initialized variables will be placed in this section, + * the startup code needs to be modified to copy the init-values. + */ + .ccmram : + { + . = ALIGN(4); + _sccmram = .; /* create a global symbol at ccmram start */ + *(.ccmram) + *(.ccmram*) + + . = ALIGN(4); + _eccmram = .; /* create a global symbol at ccmram end */ + } >CCMRAM AT> FLASH + + + /* Uninitialized data section */ + . = ALIGN(4); + .bss : + { + /* This is used by the startup in order to initialize the .bss section */ + _sbss = .; /* define a global symbol at bss start */ + __bss_start__ = _sbss; + *(.bss) + *(.bss*) + *(COMMON) + + . = ALIGN(4); + _ebss = .; /* define a global symbol at bss end */ + __bss_end__ = _ebss; + } >RAM + + /* User_heap_stack section, used to check that there is enough RAM left */ + ._user_heap_stack : + { + . = ALIGN(8); + PROVIDE ( end = . ); + PROVIDE ( _end = . ); + . = . + _Min_Heap_Size; + . = . + _Min_Stack_Size; + . = ALIGN(8); + } >RAM + + + /* Remove information from the standard libraries */ + /DISCARD/ : + { + libc.a ( * ) + libm.a ( * ) + libgcc.a ( * ) + } + + .ARM.attributes 0 : { *(.ARM.attributes) } +} diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FLY_D8/variant.cpp b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D8/variant.cpp new file mode 100644 index 0000000000..3721d4f5b5 --- /dev/null +++ b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D8/variant.cpp @@ -0,0 +1,275 @@ +/* + Copyright (c) 2011 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "pins_arduino.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Digital PinName array +const PinName digitalPin[] = { + PA_0, // Digital pin 0 + PA_1, // Digital pin 1 + PA_2, // Digital pin 2 + PA_3, // Digital pin 3 + PA_4, // Digital pin 4 + PA_5, // Digital pin 5 + PA_6, // Digital pin 6 + PA_7, // Digital pin 7 + PA_8, // Digital pin 8 + PA_9, // Digital pin 9 + PA_10, // Digital pin 10 + PA_11, // Digital pin 11 + PA_12, // Digital pin 12 + PA_13, // Digital pin 13 + PA_14, // Digital pin 14 + PA_15, // Digital pin 15 + + PB_0, // Digital pin 16 + PB_1, // Digital pin 17 + PB_2, // Digital pin 18 + PB_3, // Digital pin 19 + PB_4, // Digital pin 20 + PB_5, // Digital pin 21 + PB_6, // Digital pin 22 + PB_7, // Digital pin 23 + PB_8, // Digital pin 24 + PB_9, // Digital pin 25 + PB_10, // Digital pin 26 + PB_11, // Digital pin 27 + PB_12, // Digital pin 28 + PB_13, // Digital pin 29 + PB_14, // Digital pin 30 + PB_15, // Digital pin 31 + + PC_0, // Digital pin 32 + PC_1, // Digital pin 33 + PC_2, // Digital pin 34 + PC_3, // Digital pin 35 + PC_4, // Digital pin 36 + PC_5, // Digital pin 37 + PC_6, // Digital pin 38 + PC_7, // Digital pin 39 + PC_8, // Digital pin 40 + PC_9, // Digital pin 41 + PC_10, // Digital pin 42 + PC_11, // Digital pin 43 + PC_12, // Digital pin 44 + PC_13, // Digital pin 45 + PC_14, // Digital pin 46 + PC_15, // Digital pin 47 + + PD_0, // Digital pin 48 + PD_1, // Digital pin 49 + PD_2, // Digital pin 50 + PD_3, // Digital pin 51 + PD_4, // Digital pin 52 + PD_5, // Digital pin 53 + PD_6, // Digital pin 54 + PD_7, // Digital pin 55 + PD_8, // Digital pin 56 + PD_9, // Digital pin 57 + PD_10, // Digital pin 58 + PD_11, // Digital pin 59 + PD_12, // Digital pin 60 + PD_13, // Digital pin 61 + PD_14, // Digital pin 62 + PD_15, // Digital pin 63 + + PE_0, // Digital pin 64 + PE_1, // Digital pin 65 + PE_2, // Digital pin 66 + PE_3, // Digital pin 67 + PE_4, // Digital pin 68 + PE_5, // Digital pin 69 + PE_6, // Digital pin 70 + PE_7, // Digital pin 71 + PE_8, // Digital pin 72 + PE_9, // Digital pin 73 + PE_10, // Digital pin 74 + PE_11, // Digital pin 75 + PE_12, // Digital pin 76 + PE_13, // Digital pin 77 + PE_14, // Digital pin 78 + PE_15, // Digital pin 79 + + PH_0, // Digital pin 80, used by the external oscillator + PH_1 // Digital pin 81, used by the external oscillator +}; + +// Analog (Ax) pin number array +const uint32_t analogInputPin[] = { + 0, // A0, PA0 + 1, // A1, PA1 + 2, // A2, PA2 + 3, // A3, PA3 + 4, // A4, PA4 + 5, // A5, PA5 + 6, // A6, PA6 + 7, // A7, PA7 + 16, // A8, PB0 + 17, // A9, PB1 + 32, // A10, PC0 + 33, // A11, PC1 + 34, // A12, PC2 + 35, // A13, PC3 + 36, // A14, PC4 + 37 // A15, PC5 +}; + +#ifdef __cplusplus +} +#endif + +// ---------------------------------------------------------------------------- + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * @brief Configures the System clock source, PLL Multiplier and Divider factors, + * AHB/APBx prescalers and Flash settings + * @note This function should be called only once the RCC clock configuration + * is reset to the default reset state (done in SystemInit() function). + * @param None + * @retval None + */ + +/******************************************************************************/ +/* PLL (clocked by HSE) used as System clock source */ +/******************************************************************************/ +static uint8_t SetSysClock_PLL_HSE(uint8_t bypass) +{ + RCC_OscInitTypeDef RCC_OscInitStruct; + RCC_ClkInitTypeDef RCC_ClkInitStruct; + + /* The voltage scaling allows optimizing the power consumption when the device is + clocked below the maximum system frequency, to update the voltage scaling value + regarding system frequency refer to product datasheet. */ + __HAL_RCC_PWR_CLK_ENABLE(); + __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); + + // Enable HSE oscillator and activate PLL with HSE as source + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; + if (bypass == 0) { + RCC_OscInitStruct.HSEState = RCC_HSE_ON; // External 8 MHz xtal on OSC_IN/OSC_OUT + } else { + RCC_OscInitStruct.HSEState = RCC_HSE_BYPASS; // External 8 MHz clock on OSC_IN + } + + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; + RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; + RCC_OscInitStruct.PLL.PLLM = HSE_VALUE / 1000000L; // Expects an 8 MHz external clock by default. Redefine HSE_VALUE if not + RCC_OscInitStruct.PLL.PLLN = 336; // VCO output clock = 336 MHz (1 MHz * 336) + RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; // PLLCLK = 168 MHz (336 MHz / 2) + RCC_OscInitStruct.PLL.PLLQ = 7; + if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { + return 0; // FAIL + } + + // Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2 clocks dividers + RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2; + RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; + RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; // 168 MHz + RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; // 42 MHz + RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; // 84 MHz + if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK) { + return 0; // FAIL + } + + /* Output clock on MCO1 pin(PA8) for debugging purpose */ + /* + if (bypass == 0) + HAL_RCC_MCOConfig(RCC_MCO1, RCC_MCO1SOURCE_HSE, RCC_MCODIV_2); // 4 MHz + else + HAL_RCC_MCOConfig(RCC_MCO1, RCC_MCO1SOURCE_HSE, RCC_MCODIV_1); // 8 MHz + */ + + return 1; // OK +} + +/******************************************************************************/ +/* PLL (clocked by HSI) used as System clock source */ +/******************************************************************************/ +uint8_t SetSysClock_PLL_HSI(void) +{ + RCC_OscInitTypeDef RCC_OscInitStruct; + RCC_ClkInitTypeDef RCC_ClkInitStruct; + + /* The voltage scaling allows optimizing the power consumption when the device is + clocked below the maximum system frequency, to update the voltage scaling value + regarding system frequency refer to product datasheet. */ + __HAL_RCC_PWR_CLK_ENABLE(); + __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); + + // Enable HSI oscillator and activate PLL with HSI as source + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI | RCC_OSCILLATORTYPE_HSE; + RCC_OscInitStruct.HSIState = RCC_HSI_ON; + RCC_OscInitStruct.HSEState = RCC_HSE_OFF; + RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; + RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI; + RCC_OscInitStruct.PLL.PLLM = 16; // VCO input clock = 1 MHz (16 MHz / 16) + RCC_OscInitStruct.PLL.PLLN = 336; // VCO output clock = 336 MHz (1 MHz * 336) + RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; // PLLCLK = 168 MHz (336 MHz / 2) + RCC_OscInitStruct.PLL.PLLQ = 7; + if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { + return 0; // FAIL + } + + /* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2 clocks dividers */ + RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2); + RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; + RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; // 168 MHz + RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; // 42 MHz + RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; // 84 MHz + if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK) { + return 0; // FAIL + } + + /* Output clock on MCO1 pin(PA8) for debugging purpose */ + //HAL_RCC_MCOConfig(RCC_MCO1, RCC_MCO1SOURCE_HSI, RCC_MCODIV_1); // 16 MHz + + return 1; // OK +} + +WEAK void SystemClock_Config(void) +{ + /* 1- If fail try to start with HSE and external xtal */ + if (SetSysClock_PLL_HSE(0) == 0) { + /* 2- Try to start with HSE and external clock */ + if (SetSysClock_PLL_HSE(1) == 0) { + /* 3- If fail start with HSI clock */ + if (SetSysClock_PLL_HSI() == 0) { + Error_Handler(); + } + } + } + + /* Ensure CCM RAM clock is enabled */ + __HAL_RCC_CCMDATARAMEN_CLK_ENABLE(); + + /* Output clock on MCO2 pin(PC9) for debugging purpose */ + //HAL_RCC_MCOConfig(RCC_MCO2, RCC_MCO2SOURCE_SYSCLK, RCC_MCODIV_4); +} + +#ifdef __cplusplus +} +#endif diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FLY_D8/variant.h b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D8/variant.h new file mode 100644 index 0000000000..c19bc72f1e --- /dev/null +++ b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D8/variant.h @@ -0,0 +1,184 @@ +/* + Copyright (c) 2011 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _VARIANT_ARDUINO_STM32_ +#define _VARIANT_ARDUINO_STM32_ + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/*---------------------------------------------------------------------------- + * Pins + *----------------------------------------------------------------------------*/ + + // | DIGITAL | ANALOG IN | ANALOG OUT | UART/USART | TWI | SPI | SPECIAL | + // |---------|------------|------------|-----------------------|----------------------|-----------------------------------|-----------| +#define PA0 0 // | 0 | A0 (ADC1) | | UART4_TX | | | | +#define PA1 1 // | 1 | A1 (ADC1) | | UART4_RX | | | | +#define PA2 2 // | 2 | A2 (ADC1) | | USART2_TX | | | | +#define PA3 3 // | 3 | A3 (ADC1) | | USART2_RX | | | | +#define PA4 4 // | 4 | A4 (ADC1) | DAC_OUT1 | | | SPI1_SS, (SPI3_SS) | | +#define PA5 5 // | 5 | A5 (ADC1) | DAC_OUT2 | | | SPI1_SCK | | +#define PA6 6 // | 6 | A6 (ADC1) | | | | SPI1_MISO | | +#define PA7 7 // | 7 | A7 (ADC1) | | | | SPI1_MOSI | | +#define PA8 8 // | 8 | | | | TWI3_SCL | | | +#define PA9 9 // | 9 | | | USART1_TX | | | | +#define PA10 10 // | 10 | | | USART1_RX | | | | +#define PA11 11 // | 11 | | | | | | | +#define PA12 12 // | 12 | | | | | | | +#define PA13 13 // | 13 | | | | | | SWD_SWDIO | +#define PA14 14 // | 14 | | | | | | SWD_SWCLK | +#define PA15 15 // | 15 | | | | | SPI3_SS, (SPI1_SS) | | + // |---------|------------|------------|-----------------------|----------------------|-----------------------------------|-----------| +#define PB0 16 // | 16 | A8 (ADC1) | | | | | | +#define PB1 17 // | 17 | A9 (ADC1) | | | | | | +#define PB2 18 // | 18 | | | | | | BOOT1 | +#define PB3 19 // | 19 | | | | | SPI3_SCK, (SPI1_SCK) | | +#define PB4 20 // | 20 | | | | | SPI3_MISO, (SPI1_MISO) | | +#define PB5 21 // | 21 | | | | | SPI3_MOSI, (SPI1_MOSI) | | +#define PB6 22 // | 22 | | | USART1_TX | TWI1_SCL | | | +#define PB7 23 // | 23 | | | USART1_RX | TWI1_SDA | | | +#define PB8 24 // | 24 | | | | TWI1_SCL | | | +#define PB9 25 // | 25 | | | | TWI1_SDA | SPI2_SS | | +#define PB10 26 // | 26 | | | USART3_TX, (UART4_TX) | TWI2_SCL | SPI2_SCK | | +#define PB11 27 // | 27 | | | USART3_RX | TWI2_SDA | | | +#define PB12 28 // | 28 | | | | | SPI2_SS | | +#define PB13 29 // | 29 | | | | | SPI2_SCK | | +#define PB14 30 // | 30 | | | | | SPI2_MISO | | +#define PB15 31 // | 31 | | | | | SPI2_MOSI | | + // |---------|------------|------------|-----------------------|----------------------|-----------------------------------|-----------| +#define PC0 32 // | 32 | A10 (ADC1) | | | | | | +#define PC1 33 // | 33 | A11 (ADC1) | | | | | | +#define PC2 34 // | 34 | A12 (ADC1) | | | | SPI2_MISO | | +#define PC3 35 // | 35 | A13 (ADC1) | | | | SPI2_MOSI | | +#define PC4 36 // | 36 | A14 (ADC1) | | | | | | +#define PC5 37 // | 37 | A15 (ADC1) | | USART3_RX | | | | +#define PC6 38 // | 38 | | | USART6_TX | | | | +#define PC7 39 // | 39 | | | USART6_RX | | | | +#define PC8 40 // | 40 | | | | | | | +#define PC9 41 // | 41 | | | USART3_TX | TWI3_SDA | | | +#define PC10 42 // | 42 | | | | | SPI3_SCK | | +#define PC11 43 // | 43 | | | USART3_RX, (UART4_RX) | | SPI3_MISO | | +#define PC12 44 // | 44 | | | UART5_TX | | SPI3_MOSI | | +#define PC13 45 // | 45 | | | | | | | +#define PC14 46 // | 46 | | | | | | OSC32_IN | +#define PC15 47 // | 47 | | | | | | OSC32_OUT | + // |---------|------------|------------|-----------------------|----------------------|-----------------------------------|-----------| +#define PD0 48 // | 48 | | | | | | | +#define PD1 49 // | 49 | | | | | | | +#define PD2 50 // | 50 | | | UART5_RX | | | | +#define PD3 51 // | 51 | | | | | | | +#define PD4 52 // | 52 | | | | | | | +#define PD5 53 // | 53 | | | USART2_TX | | | | +#define PD6 54 // | 54 | | | USART2_RX | | | | +#define PD7 55 // | 55 | | | | | | | +#define PD8 56 // | 56 | | | USART3_TX | | | | +#define PD9 57 // | 57 | | | USART3_RX | | | | +#define PD10 58 // | 58 | | | | | | | +#define PD11 59 // | 59 | | | | | | | +#define PD12 60 // | 60 | | | | | | | +#define PD13 61 // | 61 | | | | | | | +#define PD14 62 // | 62 | | | | | | | +#define PD15 63 // | 63 | | | | | | | + // |---------|------------|------------|-----------------------|----------------------|-----------------------------------|-----------| +#define PE0 64 // | 64 | | | | | | | +#define PE1 65 // | 65 | | | | | | | +#define PE2 66 // | 66 | | | | | | | +#define PE3 67 // | 67 | | | | | | | +#define PE4 68 // | 68 | | | | | | | +#define PE5 69 // | 69 | | | | | | | +#define PE6 70 // | 70 | | | | | | | +#define PE7 71 // | 71 | | | | | | | +#define PE8 72 // | 72 | | | | | | | +#define PE9 73 // | 73 | | | | | | | +#define PE10 74 // | 74 | | | | | | | +#define PE11 75 // | 75 | | | | | | | +#define PE12 76 // | 76 | | | | | | | +#define PE13 77 // | 77 | | | | | | | +#define PE14 78 // | 78 | | | | | | | +#define PE15 79 // | 79 | | | | | | | + // |---------|------------|------------|-----------------------|----------------------|-----------------------------------|-----------| +#define PH0 80 // | 80 | | | | | | OSC_IN | +#define PH1 81 // | 81 | | | | | | OSC_OUT | + // |---------|------------|------------|-----------------------|----------------------|-----------------------------------|-----------| + +// This must be a literal +#define NUM_DIGITAL_PINS 82 +#define NUM_ANALOG_INPUTS 4 + +// SPI definitions +#define PIN_SPI_SS PB12 +#define PIN_SPI_MOSI PB15 +#define PIN_SPI_MISO PB14 +#define PIN_SPI_SCK PB13 + +// Timer Definitions +// Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin +#ifndef TIMER_TONE + #define TIMER_TONE TIM6 // TIMER_TONE must be defined in this file +#endif +#ifndef TIMER_SERVO + #define TIMER_SERVO TIM7 // TIMER_SERVO must be defined in this file +#endif +// #ifndef TIMER_SERIAL +// #define TIMER_SERIAL TIM5 // TIMER_SERIAL must be defined in this file +// #endif + +// UART Definitions +#define SERIAL_UART_INSTANCE 1 + +// Default pin used for 'Serial' instance +// Mandatory for Firmata +#define PIN_SERIAL_RX PA10 +#define PIN_SERIAL_TX PA9 + +/* Extra HAL modules */ +#ifndef HAL_DAC_MODULE_ENABLED + #define HAL_DAC_MODULE_ENABLED +#endif + +#ifdef __cplusplus +} // extern "C" +#endif + +/*---------------------------------------------------------------------------- + * Arduino objects - C++ only + *----------------------------------------------------------------------------*/ + +#ifdef __cplusplus + // These serial port names are intended to allow libraries and architecture-neutral + // sketches to automatically default to the correct port name for a particular type + // of use. For example, a GPS module would normally connect to SERIAL_PORT_HARDWARE_OPEN, + // the first hardware serial port whose RX/TX pins are not dedicated to another use. + // + // SERIAL_PORT_MONITOR Port which normally prints to the Arduino Serial Monitor + // + // SERIAL_PORT_USBVIRTUAL Port which is USB virtual serial + // + // SERIAL_PORT_LINUXBRIDGE Port which connects to a Linux system via Bridge library + // + // SERIAL_PORT_HARDWARE Hardware serial port, physical RX & TX pins. + // + // SERIAL_PORT_HARDWARE_OPEN Hardware serial ports which are open for use. Their RX & TX + // pins are NOT connected to anything by default. + #define SERIAL_PORT_MONITOR Serial + #define SERIAL_PORT_HARDWARE Serial1 +#endif + +#endif /* _VARIANT_ARDUINO_STM32_ */ diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FLY_D8_PRO/PeripheralPins.c b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D8_PRO/PeripheralPins.c new file mode 100644 index 0000000000..b0a78e5e85 --- /dev/null +++ b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D8_PRO/PeripheralPins.c @@ -0,0 +1,590 @@ +/* + ******************************************************************************* + * Copyright (c) 2020, STMicroelectronics + * All rights reserved. + * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ******************************************************************************* + */ +/* + * Automatically generated from STM32H723VEHx.xml, STM32H723VETx.xml + * STM32H723VGHx.xml, STM32H723VGTx.xml + * STM32H730VBHx.xml, STM32H730VBTx.xml + * STM32H733VGHx.xml, STM32H733VGTx.xml + * CubeMX DB release 6.0.60 + */ +#if !defined(CUSTOM_PERIPHERAL_PINS) +#include "Arduino.h" +#include "PeripheralPins.h" + +/* ===== + * Notes: + * - The pins mentioned Px_y_ALTz are alternative possibilities which use other + * HW peripheral instances. You can use them the same way as any other "normal" + * pin (i.e. analogWrite(PA7_ALT1, 128);). + * + * - Commented lines are alternative possibilities which are not used per default. + * If you change them, you will have to know what you do + * ===== + */ + +//*** ADC *** + +#ifdef HAL_ADC_MODULE_ENABLED +WEAK const PinMap PinMap_ADC[] = { + // {PA_0, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 16, 0)}, // ADC1_INP16 + // {PA_1, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 17, 0)}, // ADC1_INP17 + // {PA_2, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 14, 0)}, // ADC1_INP14 + // {PA_2_ALT1, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 14, 0)}, // ADC2_INP14 + // {PA_3, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 15, 0)}, // ADC1_INP15 + // {PA_3_ALT1, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 15, 0)}, // ADC2_INP15 + // {PA_4, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 18, 0)}, // ADC1_INP18 + // {PA_4_ALT1, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 18, 0)}, // ADC2_INP18 + // {PA_5, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 19, 0)}, // ADC1_INP19 + // {PA_5_ALT1, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 19, 0)}, // ADC2_INP19 + // {PA_6, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 3, 0)}, // ADC1_INP3 + // {PA_6_ALT1, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 3, 0)}, // ADC2_INP3 + // {PA_7, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 7, 0)}, // ADC1_INP7 + // {PA_7_ALT1, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 7, 0)}, // ADC2_INP7 + {PB_0, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 9, 0)}, // ADC1_INP9 TEMP_BED_PIN + // {PB_0_ALT1, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 9, 0)}, // ADC2_INP9 + // {PB_1, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 5, 0)}, // ADC1_INP5 + // {PB_1_ALT1, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 5, 0)}, // ADC2_INP5 + // {PC_0, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 10, 0)}, // ADC1_INP10 + // {PC_0_ALT1, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 10, 0)}, // ADC2_INP10 + // {PC_0_ALT2, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 10, 0)}, // ADC3_INP10 + // {PC_1, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 11, 0)}, // ADC1_INP11 + // {PC_1_ALT1, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 11, 0)}, // ADC2_INP11 + // {PC_1_ALT2, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 11, 0)}, // ADC3_INP11 + {PC_2_C, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 0, 0)}, // ADC3_INP0 TEMP_0_PIN + {PC_3_C, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 1, 0)}, // ADC3_INP1 TEMP_1_PIN + // {PC_4, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 4, 0)}, // ADC1_INP4 + // {PC_4_ALT1, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 4, 0)}, // ADC2_INP4 + {PC_5, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 8, 0)}, // ADC1_INP8 TEMP_2_PIN + // {PC_5_ALT1, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 8, 0)}, // ADC2_INP8 + {NC, NP, 0} +}; +#endif + +//*** DAC *** + +#ifdef HAL_DAC_MODULE_ENABLED +WEAK const PinMap PinMap_DAC[] = { + // {PA_4, DAC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 1, 0)}, // DAC1_OUT1 + // {PA_5, DAC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 2, 0)}, // DAC1_OUT2 + {NC, NP, 0} +}; +#endif + +//*** I2C *** + +#ifdef HAL_I2C_MODULE_ENABLED +WEAK const PinMap PinMap_I2C_SDA[] = { + // {PB_7, I2C1, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C1)}, + // {PB_7_ALT1, I2C4, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF6_I2C4)}, + // {PB_9, I2C1, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C1)}, + // {PB_9_ALT1, I2C4, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF6_I2C4)}, + {PB_11, I2C2, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C2)}, + // {PC_9, I2C3, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C3)}, + // {PC_9_ALT1, I2C5, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF6_I2C5)}, + // {PC_10, I2C5, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C5)}, + // {PD_13, I2C4, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C4)}, + {NC, NP, 0} +}; +#endif + +#ifdef HAL_I2C_MODULE_ENABLED +WEAK const PinMap PinMap_I2C_SCL[] = { + // {PA_8, I2C3, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C3)}, + // {PA_8_ALT1, I2C5, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF6_I2C5)}, + // {PB_6, I2C1, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C1)}, + // {PB_6_ALT1, I2C4, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF6_I2C4)}, + // {PB_8, I2C1, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C1)}, + // {PB_8_ALT1, I2C4, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF6_I2C4)}, + {PB_10, I2C2, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C2)}, + // {PC_11, I2C5, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C5)}, + // {PD_12, I2C4, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C4)}, + {NC, NP, 0} +}; +#endif + +//*** TIM *** + +#ifdef HAL_TIM_MODULE_ENABLED +WEAK const PinMap PinMap_TIM[] = { + // {PA_0, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 1, 0)}, // TIM2_CH1 + // {PA_0_ALT1, TIM5, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM5, 1, 0)}, // TIM5_CH1 + {PA_1, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 2, 0)}, // TIM2_CH2 FAN0_PIN + // {PA_1_ALT1, TIM5, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM5, 2, 0)}, // TIM5_CH2 + // {PA_1_ALT2, TIM15, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_TIM15, 1, 1)}, // TIM15_CH1N + {PA_2, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 3, 0)}, // TIM2_CH3 FAN1_PIN + // {PA_2_ALT1, TIM5, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM5, 3, 0)}, // TIM5_CH3 + // {PA_2_ALT2, TIM15, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_TIM15, 1, 0)}, // TIM15_CH1 + {PA_3, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 4, 0)}, // TIM2_CH4 FAN2_PIN + // {PA_3_ALT1, TIM5, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM5, 4, 0)}, // TIM5_CH4 + // {PA_3_ALT2, TIM15, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_TIM15, 2, 0)}, // TIM15_CH2 + // {PA_5, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 1, 0)}, // TIM2_CH1 + // {PA_5_ALT1, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 1, 1)}, // TIM8_CH1N + // {PA_6, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 1, 0)}, // TIM3_CH1 + // {PA_6_ALT1, TIM13, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_TIM13, 1, 0)}, // TIM13_CH1 + // {PA_7, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 1, 1)}, // TIM1_CH1N + // {PA_7_ALT1, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 2, 0)}, // TIM3_CH2 + // {PA_7_ALT2, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 1, 1)}, // TIM8_CH1N + // {PA_7_ALT3, TIM14, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_TIM14, 1, 0)}, // TIM14_CH1 + // {PA_8, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 1, 0)}, // TIM1_CH1 + // {PA_9, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 2, 0)}, // TIM1_CH2 + // {PA_10, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 3, 0)}, // TIM1_CH3 + // {PA_11, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 4, 0)}, // TIM1_CH4 + // {PA_15, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 1, 0)}, // TIM2_CH1 + // {PB_0, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 2, 1)}, // TIM1_CH2N + // {PB_0_ALT1, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 3, 0)}, // TIM3_CH3 + // {PB_0_ALT2, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 2, 1)}, // TIM8_CH2N + {PB_1, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 3, 1)}, // TIM1_CH3N HEATER_BED_PIN + // {PB_1_ALT1, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 4, 0)}, // TIM3_CH4 + // {PB_1_ALT2, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 3, 1)}, // TIM8_CH3N + // {PB_3, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 2, 0)}, // TIM2_CH2 + // {PB_4, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 1, 0)}, // TIM3_CH1 + // {PB_5, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 2, 0)}, // TIM3_CH2 + // {PB_6, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 1, 0)}, // TIM4_CH1 + // {PB_6_ALT1, TIM16, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM16, 1, 1)}, // TIM16_CH1N + // {PB_7, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 2, 0)}, // TIM4_CH2 + // {PB_7_ALT1, TIM17, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM17, 1, 1)}, // TIM17_CH1N + // {PB_8, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 3, 0)}, // TIM4_CH3 + // {PB_8_ALT1, TIM16, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM16, 1, 0)}, // TIM16_CH1 + // {PB_9, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 4, 0)}, // TIM4_CH4 + // {PB_9_ALT1, TIM17, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM17, 1, 0)}, // TIM17_CH1 + // {PB_10, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 3, 0)}, // TIM2_CH3 + // {PB_11, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 4, 0)}, // TIM2_CH4 + // {PB_13, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 1, 1)}, // TIM1_CH1N + // {PB_14, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 2, 1)}, // TIM1_CH2N + // {PB_14_ALT1, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 2, 1)}, // TIM8_CH2N + // {PB_14_ALT2, TIM12, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM12, 1, 0)}, // TIM12_CH1 + // {PB_15, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 3, 1)}, // TIM1_CH3N + // {PB_15_ALT1, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 3, 1)}, // TIM8_CH3N + // {PB_15_ALT2, TIM12, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM12, 2, 0)}, // TIM12_CH2 + {PC_6, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 1, 0)}, // TIM3_CH1 FAN3_PIN + // {PC_6_ALT1, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 1, 0)}, // TIM8_CH1 + {PC_7, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 2, 0)}, // TIM3_CH2 FAN4_PIN + // {PC_7_ALT1, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 2, 0)}, // TIM8_CH2 + {PC_8, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 3, 0)}, // TIM3_CH3 FAN5_PIN + // {PC_8_ALT1, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 3, 0)}, // TIM8_CH3 + // {PC_9, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 4, 0)}, // TIM3_CH4 + // {PC_9_ALT1, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 4, 0)}, // TIM8_CH4 + // {PC_12, TIM15, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM15, 1, 0)}, // TIM15_CH1 + {PD_12, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 1, 0)}, // TIM4_CH1 HEATER_0_PIN + {PD_13, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 2, 0)}, // TIM4_CH2 HEATER_1_PIN + {PD_14, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 3, 0)}, // TIM4_CH3 HEATER_2_PIN + // {PD_15, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 4, 0)}, // TIM4_CH4 + // {PE_4, TIM15, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_TIM15, 1, 1)}, // TIM15_CH1N + // {PE_5, TIM15, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_TIM15, 1, 0)}, // TIM15_CH1 + // {PE_6, TIM15, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_TIM15, 2, 0)}, // TIM15_CH2 + // {PE_8, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 1, 1)}, // TIM1_CH1N + // {PE_9, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 1, 0)}, // TIM1_CH1 + // {PE_10, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 2, 1)}, // TIM1_CH2N + // {PE_11, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 2, 0)}, // TIM1_CH2 + // {PE_12, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 3, 1)}, // TIM1_CH3N + // {PE_13, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 3, 0)}, // TIM1_CH3 + // {PE_14, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 4, 0)}, // TIM1_CH4 + {NC, NP, 0} +}; +#endif + +//*** UART *** + +#ifdef HAL_UART_MODULE_ENABLED +WEAK const PinMap PinMap_UART_TX[] = { + // {PA_0, UART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART4)}, + // {PA_2, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)}, + // {PA_9, LPUART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_LPUART)}, + {PA_9_ALT1, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART1)},// EXP2_03_PIN + // {PA_12, UART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_UART4)}, + // {PA_15, UART7, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_UART7)}, + // {PB_4, UART7, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_UART7)}, + // {PB_6, LPUART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_LPUART)}, + // {PB_6_ALT1, UART5, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF14_UART5)}, + // {PB_6_ALT2, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART1)}, + // {PB_9, UART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART4)}, + {PB_10, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + // {PB_13, UART5, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF14_UART5)}, + // {PB_14, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_USART1)}, + // {PC_6, USART6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART6)}, + // {PC_10, UART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART4)}, + // {PC_10_ALT1, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + // {PC_12, UART5, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART5)}, + // {PD_1, UART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART4)}, + // {PD_5, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)}, + // {PD_8, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + // {PD_15, UART9, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_UART9)}, + // {PE_1, UART8, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART8)}, + // {PE_3, USART10, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_USART10)}, + // {PE_8, UART7, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_UART7)}, + {NC, NP, 0} +}; +#endif + +#ifdef HAL_UART_MODULE_ENABLED +WEAK const PinMap PinMap_UART_RX[] = { + // {PA_1, UART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART4)}, + // {PA_3, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)}, + // {PA_8, UART7, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_UART7)}, + // {PA_10, LPUART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_LPUART)}, + {PA_10_ALT1, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART1)},// EXP2_05_PIN + // {PA_11, UART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_UART4)}, + // {PB_3, UART7, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_UART7)}, + // {PB_5, UART5, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF14_UART5)}, + // {PB_7, LPUART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_LPUART)}, + // {PB_7_ALT1, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART1)}, + // {PB_8, UART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART4)}, + {PB_11, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + // {PB_12, UART5, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF14_UART5)}, + // {PB_15, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_USART1)}, + // {PC_7, USART6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART6)}, + // {PC_11, UART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART4)}, + // {PC_11_ALT1, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + // {PD_0, UART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART4)}, + // {PD_2, UART5, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART5)}, + // {PD_6, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)}, + // {PD_9, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + // {PD_14, UART9, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_UART9)}, + // {PE_0, UART8, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART8)}, + // {PE_2, USART10, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_USART10)}, + // {PE_7, UART7, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_UART7)}, + {NC, NP, 0} +}; +#endif + +#ifdef HAL_UART_MODULE_ENABLED +WEAK const PinMap PinMap_UART_RTS[] = { + // {PA_1, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)}, + // {PA_12, LPUART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_LPUART)}, + // {PA_12_ALT1, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART1)}, + // {PA_15, UART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART4)}, + // {PB_14, UART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART4)}, + // {PB_14_ALT1, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + // {PC_8, UART5, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART5)}, + // {PD_4, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)}, + // {PD_12, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + // {PD_13, UART9, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_UART9)}, + // {PD_15, UART8, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART8)}, + // {PE_9, UART7, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_UART7)}, + {NC, NP, 0} +}; +#endif + +#ifdef HAL_UART_MODULE_ENABLED +WEAK const PinMap PinMap_UART_CTS[] = { + // {PA_0, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)}, + // {PA_11, LPUART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_LPUART)}, + // {PA_11_ALT1, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART1)}, + // {PB_0, UART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART4)}, + // {PB_13, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + // {PB_15, UART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART4)}, + // {PC_9, UART5, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART5)}, + // {PD_0, UART9, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_UART9)}, + // {PD_3, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)}, + // {PD_11, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + // {PD_14, UART8, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART8)}, + // {PE_10, UART7, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_UART7)}, + {NC, NP, 0} +}; +#endif + +//*** SPI *** + +#ifdef HAL_SPI_MODULE_ENABLED +WEAK const PinMap PinMap_SPI_MOSI[] = { + // {PA_7, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, + // {PA_7_ALT1, SPI6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_SPI6)}, + // {PB_2, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_SPI3)}, + {PB_5, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, // TMC_SPI_MOSI + // {PB_5_ALT1, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_SPI3)}, + // {PB_5_ALT2, SPI6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_SPI6)}, + {PB_15, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, // SD_MOSI_PIN / EXP2_06_PIN + // {PC_1, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + // {PC_3_C, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + // {PC_12, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)}, + // {PD_6, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI3)}, + // {PD_7, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, + // {PE_6, SPI4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI4)}, + // {PE_14, SPI4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI4)}, + {NC, NP, 0} +}; +#endif + +#ifdef HAL_SPI_MODULE_ENABLED +WEAK const PinMap PinMap_SPI_MISO[] = { + // {PA_6, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, + // {PA_6_ALT1, SPI6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_SPI6)}, + {PB_4, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, // TMC_SPI_MISO + // {PB_4_ALT1, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)}, + // {PB_4_ALT2, SPI6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_SPI6)}, + {PB_14, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, // SD_MISO_PIN / EXP2_01_PIN + // {PC_2_C, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + // {PC_11, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)}, + // {PE_5, SPI4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI4)}, + // {PE_13, SPI4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI4)}, + {NC, NP, 0} +}; +#endif + +#ifdef HAL_SPI_MODULE_ENABLED +WEAK const PinMap PinMap_SPI_SCLK[] = { + // {PA_5, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, + // {PA_5_ALT1, SPI6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_SPI6)}, + // {PA_9, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + // {PA_12, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + {PB_3, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, // TMC_SPI_SCK + // {PB_3_ALT1, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)}, + // {PB_3_ALT2, SPI6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_SPI6)}, + // {PB_10, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + {PB_13, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, // SD_SCK_PIN / EXP2_02_PIN + // {PC_10, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)}, + // {PC_12, SPI6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI6)}, + // {PD_3, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + // {PE_2, SPI4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI4)}, + // {PE_12, SPI4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI4)}, + {NC, NP, 0} +}; +#endif + +#ifdef HAL_SPI_MODULE_ENABLED +WEAK const PinMap PinMap_SPI_SSEL[] = { + // {PA_0, SPI6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI6)}, + // {PA_4, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, + // {PA_4_ALT1, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)}, + // {PA_4_ALT2, SPI6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_SPI6)}, + // {PA_11, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + // {PA_15, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, + // {PA_15_ALT1, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)}, + // {PA_15_ALT2, SPI6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_SPI6)}, + // {PB_4, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_SPI2)}, + // {PB_9, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + {PB_12, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, // SDSS / EXP2_04_PIN + // {PE_4, SPI4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI4)}, + // {PE_11, SPI4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI4)}, + {NC, NP, 0} +}; +#endif + +//*** FDCAN *** + +#ifdef HAL_FDCAN_MODULE_ENABLED +WEAK const PinMap PinMap_CAN_RD[] = { + // {PA_11, FDCAN1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_FDCAN1)}, + // {PB_5, FDCAN2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_FDCAN2)}, + {PB_8, FDCAN1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_FDCAN1)}, + // {PB_12, FDCAN2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_FDCAN2)}, + // {PD_0, FDCAN1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_FDCAN1)}, + // {PD_12, FDCAN3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF5_FDCAN3)}, + {NC, NP, 0} +}; +#endif + +#ifdef HAL_FDCAN_MODULE_ENABLED +WEAK const PinMap PinMap_CAN_TD[] = { + // {PA_12, FDCAN1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_FDCAN1)}, + // {PB_6, FDCAN2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_FDCAN2)}, + {PB_9, FDCAN1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_FDCAN1)}, + // {PB_13, FDCAN2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_FDCAN2)}, + // {PD_1, FDCAN1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_FDCAN1)}, + // {PD_13, FDCAN3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF5_FDCAN3)}, + {NC, NP, 0} +}; +#endif + +//*** ETHERNET *** + +#if defined(HAL_ETH_MODULE_ENABLED) || defined(HAL_ETH_LEGACY_MODULE_ENABLED) +WEAK const PinMap PinMap_Ethernet[] = { + // {PA_0, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_CRS + // {PA_1, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_REF_CLK + // {PA_1_ALT1, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_RX_CLK + // {PA_2, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_MDIO + // {PA_3, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_COL + // {PA_7, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_CRS_DV + // {PA_7_ALT1, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_RX_DV + // {PA_9, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_TX_ER + // {PB_0, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_RXD2 + // {PB_1, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_RXD3 + // {PB_2, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_TX_ER + // {PB_5, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_PPS_OUT + // {PB_8, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_TXD3 + // {PB_10, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_RX_ER + // {PB_11, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_TX_EN + // {PB_12, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_TXD0 + // {PB_13, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_TXD1 + // {PC_1, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_MDC + // {PC_2_C, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_TXD2 + // {PC_3_C, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_TX_CLK + // {PC_4, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_RXD0 + // {PC_5, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_RXD1 + // {PE_2, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_TXD3 + {NC, NP, 0} +}; +#endif + +//*** OCTOSPI *** + +#ifdef HAL_OSPI_MODULE_ENABLED +WEAK const PinMap PinMap_OCTOSPI_DATA0[] = { + // {PA_2, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO0 + // {PB_1, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO0 + // {PB_12, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO0 + // {PC_3_C, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO0 + // {PC_9, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO0 + // {PD_11, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO0 + {NC, NP, 0} +}; +#endif + +#ifdef HAL_OSPI_MODULE_ENABLED +WEAK const PinMap PinMap_OCTOSPI_DATA1[] = { + // {PB_0, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO1 + // {PC_10, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO1 + // {PD_12, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO1 + {NC, NP, 0} +}; +#endif + +#ifdef HAL_OSPI_MODULE_ENABLED +WEAK const PinMap PinMap_OCTOSPI_DATA2[] = { + // {PA_3, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO2 + // {PA_7, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO2 + // {PB_13, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO2 + // {PC_2_C, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO2 + // {PE_2, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO2 + {NC, NP, 0} +}; +#endif + +#ifdef HAL_OSPI_MODULE_ENABLED +WEAK const PinMap PinMap_OCTOSPI_DATA3[] = { + // {PA_1, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO3 + // {PA_6, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO3 + // {PD_13, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO3 + {NC, NP, 0} +}; +#endif + +#ifdef HAL_OSPI_MODULE_ENABLED +WEAK const PinMap PinMap_OCTOSPI_DATA4[] = { + // {PC_1, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO4 + // {PD_4, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO4 + // {PE_7, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO4 + {NC, NP, 0} +}; +#endif + +#ifdef HAL_OSPI_MODULE_ENABLED +WEAK const PinMap PinMap_OCTOSPI_DATA5[] = { + // {PC_2_C, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO5 + // {PD_5, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO5 + // {PE_8, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO5 + {NC, NP, 0} +}; +#endif + +#ifdef HAL_OSPI_MODULE_ENABLED +WEAK const PinMap PinMap_OCTOSPI_DATA6[] = { + // {PC_3_C, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO6 + // {PD_6, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO6 + // {PE_9, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO6 + {NC, NP, 0} +}; +#endif + +#ifdef HAL_OSPI_MODULE_ENABLED +WEAK const PinMap PinMap_OCTOSPI_DATA7[] = { + // {PD_7, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO7 + // {PE_10, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO7 + {NC, NP, 0} +}; +#endif + +#ifdef HAL_OSPI_MODULE_ENABLED +WEAK const PinMap PinMap_OCTOSPI_SCLK[] = { + // {PA_3, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_OCTOSPIM_P1)}, // OCTOSPIM_P1_CLK + // {PB_2, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_OCTOSPIM_P1)}, // OCTOSPIM_P1_CLK + {NC, NP, 0} +}; +#endif + +#ifdef HAL_OSPI_MODULE_ENABLED +WEAK const PinMap PinMap_OCTOSPI_SSEL[] = { + // {PB_6, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OCTOSPIM_P1)}, // OCTOSPIM_P1_NCS + // {PB_10, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_OCTOSPIM_P1)}, // OCTOSPIM_P1_NCS + // {PC_11, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_OCTOSPIM_P1)}, // OCTOSPIM_P1_NCS + // {PE_11, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_OCTOSPIM_P1)}, // OCTOSPIM_P1_NCS + {NC, NP, 0} +}; +#endif + +//*** USB *** + +#if defined(HAL_PCD_MODULE_ENABLED) || defined(HAL_HCD_MODULE_ENABLED) +WEAK const PinMap PinMap_USB_OTG_HS[] = { +#ifdef USE_USB_HS_IN_FS + // {PA_8, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG1_HS)}, // USB_OTG_HS_SOF + // {PA_9, USB_OTG_HS, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, GPIO_AF_NONE)}, // USB_OTG_HS_VBUS + // {PA_10, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_PULLUP, GPIO_AF10_OTG1_HS)}, // USB_OTG_HS_ID + {PA_11, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF_NONE)}, // USB_OTG_HS_DM + {PA_12, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF_NONE)}, // USB_OTG_HS_DP +#else + // {PA_3, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG1_HS)}, // USB_OTG_HS_ULPI_D0 + // {PA_5, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG1_HS)}, // USB_OTG_HS_ULPI_CK + // {PB_0, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG1_HS)}, // USB_OTG_HS_ULPI_D1 + // {PB_1, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG1_HS)}, // USB_OTG_HS_ULPI_D2 + // {PB_5, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG1_HS)}, // USB_OTG_HS_ULPI_D7 + // {PB_10, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG1_HS)}, // USB_OTG_HS_ULPI_D3 + // {PB_11, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG1_HS)}, // USB_OTG_HS_ULPI_D4 + // {PB_12, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG1_HS)}, // USB_OTG_HS_ULPI_D5 + // {PB_13, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG1_HS)}, // USB_OTG_HS_ULPI_D6 + // {PC_0, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG1_HS)}, // USB_OTG_HS_ULPI_STP + // {PC_2_C, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG1_HS)}, // USB_OTG_HS_ULPI_DIR + // {PC_3_C, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG1_HS)}, // USB_OTG_HS_ULPI_NXT +#endif /* USE_USB_HS_IN_FS */ + {NC, NP, 0} +}; +#endif + +//*** SD *** + +#ifdef HAL_SD_MODULE_ENABLED +WEAK const PinMap PinMap_SD[] = { + // {PA_0, SDMMC2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_SDMMC2)}, // SDMMC2_CMD (EXP1_08_PIN) + // {PB_3, SDMMC2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_SDMMC2)}, // SDMMC2_D2 (TMC_SPI_SCK) + // {PB_4, SDMMC2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_SDMMC2)}, // SDMMC2_D3 (TMC_SPI_MISO) + // {PB_8, SDMMC1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF7_SDMMC1)}, // SDMMC1_CKIN + // {PB_8_ALT1, SDMMC1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDMMC1)}, // SDMMC1_D4 + // {PB_8_ALT2, SDMMC2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_SDMMC2)}, // SDMMC2_D4 + // {PB_9, SDMMC1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF7_SDMMC1)}, // SDMMC1_CDIR + // {PB_9_ALT1, SDMMC1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDMMC1)}, // SDMMC1_D5 + // {PB_9_ALT2, SDMMC2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_SDMMC2)}, // SDMMC2_D5 + // {PB_13, SDMMC1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDMMC1)}, // SDMMC1_D0 (SD_SCK_PIN EXP2_02_PIN) + // {PB_14, SDMMC2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_SDMMC2)}, // SDMMC2_D0 (SD_MISO_PIN EXP2_01_PIN) + // {PB_15, SDMMC2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_SDMMC2)}, // SDMMC2_D1 (SD_MOSI_PIN EXP2_06_PIN) + // {PC_1, SDMMC2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_SDMMC2)}, // SDMMC2_CK + // {PC_4, SDMMC2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF10_SDMMC2)}, // SDMMC2_CKIN (E4_DIR_PIN) + // {PC_6, SDMMC1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF8_SDMMC1)}, // SDMMC1_D0DIR (FAN3_PIN) + // {PC_6_ALT1, SDMMC1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDMMC1)}, // SDMMC1_D6 + // {PC_6_ALT2, SDMMC2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_SDMMC2)}, // SDMMC2_D6 + // {PC_7, SDMMC1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF8_SDMMC1)}, // SDMMC1_D123DIR (FAN4_PIN) + // {PC_7_ALT1, SDMMC1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDMMC1)}, // SDMMC1_D7 + // {PC_7_ALT2, SDMMC2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_SDMMC2)}, // SDMMC2_D7 + // {PC_8, SDMMC1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDMMC1)}, // SDMMC1_D0 (FAN5_PIN) + // {PC_9, SDMMC1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDMMC1)}, // SDMMC1_D1 (X_SERIAL_TX_PIN) + // {PC_10, SDMMC1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDMMC1)}, // SDMMC1_D2 (Y_SERIAL_TX_PIN) + // {PC_11, SDMMC1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDMMC1)}, // SDMMC1_D3 (Y_DIR_PIN) + // {PC_12, SDMMC1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF12_SDMMC1)}, // SDMMC1_CK (Y_ENABLE_PIN) + // {PD_2, SDMMC1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF12_SDMMC1)}, // SDMMC1_CMD (Z_ENABLE_PIN) + // {PD_6, SDMMC2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF11_SDMMC2)}, // SDMMC2_CK (E1_CS_PIN) + // {PD_7, SDMMC2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF11_SDMMC2)}, // SDMMC2_CMD (E1_DIR_PIN) + // {NC, NP, 0} +}; +#endif + +#endif /* !CUSTOM_PERIPHERAL_PINS */ diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FLY_D8_PRO/PinNamesVar.h b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D8_PRO/PinNamesVar.h new file mode 100644 index 0000000000..3bd0ed8fcd --- /dev/null +++ b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D8_PRO/PinNamesVar.h @@ -0,0 +1,108 @@ +/* Dual pad pin name */ +PC_2_C = PC_2 | PDUAL, +PC_3_C = PC_3 | PDUAL, + +/* Alternate pin name */ +PA_0_ALT1 = PA_0 | ALT1, +PA_1_ALT1 = PA_1 | ALT1, +PA_1_ALT2 = PA_1 | ALT2, +PA_2_ALT1 = PA_2 | ALT1, +PA_2_ALT2 = PA_2 | ALT2, +PA_3_ALT1 = PA_3 | ALT1, +PA_3_ALT2 = PA_3 | ALT2, +PA_4_ALT1 = PA_4 | ALT1, +PA_4_ALT2 = PA_4 | ALT2, +PA_5_ALT1 = PA_5 | ALT1, +PA_6_ALT1 = PA_6 | ALT1, +PA_7_ALT1 = PA_7 | ALT1, +PA_7_ALT2 = PA_7 | ALT2, +PA_7_ALT3 = PA_7 | ALT3, +PA_8_ALT1 = PA_8 | ALT1, +PA_9_ALT1 = PA_9 | ALT1, +PA_10_ALT1 = PA_10 | ALT1, +PA_11_ALT1 = PA_11 | ALT1, +PA_12_ALT1 = PA_12 | ALT1, +PA_15_ALT1 = PA_15 | ALT1, +PA_15_ALT2 = PA_15 | ALT2, +PB_0_ALT1 = PB_0 | ALT1, +PB_0_ALT2 = PB_0 | ALT2, +PB_1_ALT1 = PB_1 | ALT1, +PB_1_ALT2 = PB_1 | ALT2, +PB_3_ALT1 = PB_3 | ALT1, +PB_3_ALT2 = PB_3 | ALT2, +PB_4_ALT1 = PB_4 | ALT1, +PB_4_ALT2 = PB_4 | ALT2, +PB_5_ALT1 = PB_5 | ALT1, +PB_5_ALT2 = PB_5 | ALT2, +PB_6_ALT1 = PB_6 | ALT1, +PB_6_ALT2 = PB_6 | ALT2, +PB_7_ALT1 = PB_7 | ALT1, +PB_8_ALT1 = PB_8 | ALT1, +PB_8_ALT2 = PB_8 | ALT2, +PB_9_ALT1 = PB_9 | ALT1, +PB_9_ALT2 = PB_9 | ALT2, +PB_14_ALT1 = PB_14 | ALT1, +PB_14_ALT2 = PB_14 | ALT2, +PB_15_ALT1 = PB_15 | ALT1, +PB_15_ALT2 = PB_15 | ALT2, +PC_0_ALT1 = PC_0 | ALT1, +PC_0_ALT2 = PC_0 | ALT2, +PC_1_ALT1 = PC_1 | ALT1, +PC_1_ALT2 = PC_1 | ALT2, +PC_4_ALT1 = PC_4 | ALT1, +PC_5_ALT1 = PC_5 | ALT1, +PC_6_ALT1 = PC_6 | ALT1, +PC_6_ALT2 = PC_6 | ALT2, +PC_7_ALT1 = PC_7 | ALT1, +PC_7_ALT2 = PC_7 | ALT2, +PC_8_ALT1 = PC_8 | ALT1, +PC_9_ALT1 = PC_9 | ALT1, +PC_10_ALT1 = PC_10 | ALT1, +PC_11_ALT1 = PC_11 | ALT1, + +/* SYS_WKUP */ +#ifdef PWR_WAKEUP_PIN1 + SYS_WKUP1 = PA_0, +#endif +#ifdef PWR_WAKEUP_PIN2 + SYS_WKUP2 = PA_2, +#endif +#ifdef PWR_WAKEUP_PIN3 + SYS_WKUP3 = NC, +#endif +#ifdef PWR_WAKEUP_PIN4 + SYS_WKUP4 = PC_13, +#endif +#ifdef PWR_WAKEUP_PIN5 + SYS_WKUP5 = NC, +#endif +#ifdef PWR_WAKEUP_PIN6 + SYS_WKUP6 = PC_1, +#endif +#ifdef PWR_WAKEUP_PIN7 + SYS_WKUP7 = NC, +#endif +#ifdef PWR_WAKEUP_PIN8 + SYS_WKUP8 = NC, +#endif + +/* USB */ +#ifdef USBCON + USB_OTG_HS_DM = PA_11, + USB_OTG_HS_DP = PA_12, + USB_OTG_HS_ID = PA_10, + USB_OTG_HS_SOF = PA_8, + USB_OTG_HS_ULPI_CK = PA_5, + USB_OTG_HS_ULPI_D0 = PA_3, + USB_OTG_HS_ULPI_D1 = PB_0, + USB_OTG_HS_ULPI_D2 = PB_1, + USB_OTG_HS_ULPI_D3 = PB_10, + USB_OTG_HS_ULPI_D4 = PB_11, + USB_OTG_HS_ULPI_D5 = PB_12, + USB_OTG_HS_ULPI_D6 = PB_13, + USB_OTG_HS_ULPI_D7 = PB_5, + USB_OTG_HS_ULPI_DIR = PC_2_C, + USB_OTG_HS_ULPI_NXT = PC_3_C, + USB_OTG_HS_ULPI_STP = PC_0, + USB_OTG_HS_VBUS = PA_9, +#endif diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FLY_D8_PRO/ldscript.ld b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D8_PRO/ldscript.ld new file mode 100644 index 0000000000..6322861033 --- /dev/null +++ b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D8_PRO/ldscript.ld @@ -0,0 +1,174 @@ +/* +****************************************************************************** +** +** File : LinkerScript.ld +** +** Author : STM32CubeIDE +** +** Abstract : Linker script for STM32H7 series +** 512Kbytes FLASH and 560Kbytes RAM +** +** Set heap size, stack size and stack location according +** to application requirements. +** +** Set memory bank area and size if external memory is used. +** +** Target : STMicroelectronics STM32 +** +** Distribution: The file is distributed as is, without any warranty +** of any kind. +** +***************************************************************************** +** @attention +** +** Copyright (c) 2022 STMicroelectronics. +** All rights reserved. +** +** This software is licensed under terms that can be found in the LICENSE file +** in the root directory of this software component. +** If no LICENSE file comes with this software, it is provided AS-IS. +** +**************************************************************************** +*/ + +/* Entry Point */ +ENTRY(Reset_Handler) + +/* Highest address of the user mode stack */ +_estack = ORIGIN(RAM_D1) + LENGTH(RAM_D1); /* end of RAM */ +/* Generate a link error if heap and stack don't fit into RAM */ +_Min_Heap_Size = 0x200 ; /* required amount of heap */ +_Min_Stack_Size = 0x400 ; /* required amount of stack */ + +/* Specify the memory areas */ +MEMORY +{ + ITCMRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 64K + DTCMRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K + FLASH (rx) : ORIGIN = 0x8000000 + LD_FLASH_OFFSET, LENGTH = LD_MAX_SIZE - LD_FLASH_OFFSET + RAM_D1 (xrw) : ORIGIN = 0x24000000, LENGTH = 320K + RAM_D2 (xrw) : ORIGIN = 0x30000000, LENGTH = 32K + RAM_D3 (xrw) : ORIGIN = 0x38000000, LENGTH = 16K +} + +/* Define output sections */ +SECTIONS +{ + /* The startup code goes first into FLASH */ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + . = ALIGN(4); + } >FLASH + + /* The program code and other data goes into FLASH */ + .text : + { + . = ALIGN(4); + *(.text) /* .text sections (code) */ + *(.text*) /* .text* sections (code) */ + *(.glue_7) /* glue arm to thumb code */ + *(.glue_7t) /* glue thumb to arm code */ + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + . = ALIGN(4); + _etext = .; /* define a global symbols at end of code */ + } >FLASH + + /* Constant data goes into FLASH */ + .rodata : + { + . = ALIGN(4); + *(.rodata) /* .rodata sections (constants, strings, etc.) */ + *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ + . = ALIGN(4); + } >FLASH + + .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH + .ARM : { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } >FLASH + + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array*)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } >FLASH + + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array*)) + PROVIDE_HIDDEN (__init_array_end = .); + } >FLASH + + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT(.fini_array.*))) + KEEP (*(.fini_array*)) + PROVIDE_HIDDEN (__fini_array_end = .); + } >FLASH + + /* used by the startup to initialize data */ + _sidata = LOADADDR(.data); + + /* Initialized data sections goes into RAM, load LMA copy after code */ + .data : + { + . = ALIGN(4); + _sdata = .; /* create a global symbol at data start */ + *(.data) /* .data sections */ + *(.data*) /* .data* sections */ + *(.RamFunc) /* .RamFunc sections */ + *(.RamFunc*) /* .RamFunc* sections */ + + . = ALIGN(4); + _edata = .; /* define a global symbol at data end */ + } >RAM_D1 AT> FLASH + + /* Uninitialized data section */ + . = ALIGN(4); + .bss : + { + /* This is used by the startup in order to initialize the .bss section */ + _sbss = .; /* define a global symbol at bss start */ + __bss_start__ = _sbss; + *(.bss) + *(.bss*) + *(COMMON) + + . = ALIGN(4); + _ebss = .; /* define a global symbol at bss end */ + __bss_end__ = _ebss; + } >RAM_D1 + + /* User_heap_stack section, used to check that there is enough RAM left */ + ._user_heap_stack : + { + . = ALIGN(8); + PROVIDE ( end = . ); + PROVIDE ( _end = . ); + . = . + _Min_Heap_Size; + . = . + _Min_Stack_Size; + . = ALIGN(8); + } >RAM_D1 + + /* Remove information from the standard libraries */ + /DISCARD/ : + { + libc.a ( * ) + libm.a ( * ) + libgcc.a ( * ) + } + + .ARM.attributes 0 : { *(.ARM.attributes) } +} diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FLY_D8_PRO/variant_MARLIN_STM32H723VG.cpp b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D8_PRO/variant_MARLIN_STM32H723VG.cpp new file mode 100644 index 0000000000..bfeb0f9abc --- /dev/null +++ b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D8_PRO/variant_MARLIN_STM32H723VG.cpp @@ -0,0 +1,273 @@ +/* + ******************************************************************************* + * Copyright (c) 2020-2021, STMicroelectronics + * All rights reserved. + * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ******************************************************************************* + */ +#ifdef STM32H723xx +#include "pins_arduino.h" + +// Digital PinName array +const PinName digitalPin[] = { + PA_0, // D0/A0 + PA_1, // D1/A1 + PA_2, // D2/A2 + PA_3, // D3/A3 + PA_4, // D4/A4 + PA_5, // D5/A5 + PA_6, // D6/A6 + PA_7, // D7/A7 + PA_8, // D8 + PA_9, // D9 + PA_10, // D10 + PA_11, // D11 + PA_12, // D12 + PA_13, // D13 + PA_14, // D14 + PA_15, // D15 + PB_0, // D16/A8 + PB_1, // D17/A9 + PB_2, // D18 + PB_3, // D19 + PB_4, // D20 + PB_5, // D21 + PB_6, // D22 + PB_7, // D23 + PB_8, // D24 + PB_9, // D25 + PB_10, // D26 + PB_11, // D27 + PB_12, // D28 + PB_13, // D29 + PB_14, // D30 + PB_15, // D31 + PC_0, // D32/A10 + PC_1, // D33/A11 + PC_4, // D34/A12 + PC_5, // D35/A13 + PC_6, // D36 + PC_7, // D37 + PC_8, // D38 + PC_9, // D39 + PC_10, // D40 + PC_11, // D41 + PC_12, // D42 + PC_13, // D43 + PC_14, // D44 + PC_15, // D45 + PD_0, // D46 + PD_1, // D47 + PD_2, // D48 + PD_3, // D49 + PD_4, // D50 + PD_5, // D51 + PD_6, // D52 + PD_7, // D53 + PD_8, // D54 + PD_9, // D55 + PD_10, // D56 + PD_11, // D57 + PD_12, // D58 + PD_13, // D59 + PD_14, // D60 + PD_15, // D61 + PE_0, // D62 + PE_1, // D63 + PE_2, // D64 + PE_3, // D65 + PE_4, // D66 + PE_5, // D67 + PE_6, // D68 + PE_7, // D69 + PE_8, // D70 + PE_9, // D71 + PE_10, // D72 + PE_11, // D73 + PE_12, // D74 + PE_13, // D75 + PE_14, // D76 + PE_15, // D77 + PH_0, // D78 + PH_1, // D79 + PC_2_C, // D80/A14 + PC_3_C // D81/A15 +}; + +// Analog (Ax) pin number array +const uint32_t analogInputPin[] = { + 0, // A0, PA0 + 1, // A1, PA1 + 2, // A2, PA2 + 3, // A3, PA3 + 4, // A4, PA4 + 5, // A5, PA5 + 6, // A6, PA6 + 7, // A7, PA7 + 16, // A8, PB0 + 17, // A9, PB1 + 32, // A10, PC0 + 33, // A11, PC1 + 34, // A12, PC4 + 35, // A13, PC5 + 80, // A14, PC2_C + 81 // A15, PC3_C +}; + +void MPU_Config(void) +{ + MPU_Region_InitTypeDef MPU_InitStruct = {0}; + + /* Disables the MPU */ + HAL_MPU_Disable(); + + /** Initializes and configures the Region and the memory to be protected + */ + MPU_InitStruct.Enable = MPU_REGION_ENABLE; + MPU_InitStruct.Number = MPU_REGION_NUMBER0; + MPU_InitStruct.BaseAddress = 0x0; + MPU_InitStruct.Size = MPU_REGION_SIZE_4GB; + MPU_InitStruct.SubRegionDisable = 0x87; + MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0; + MPU_InitStruct.AccessPermission = MPU_REGION_NO_ACCESS; + MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE; + MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE; + MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE; + MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE; + + HAL_MPU_ConfigRegion(&MPU_InitStruct); + /* Enables the MPU */ + HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT); + +} + +/* + * @brief System Clock Configuration + * @param None + * @retval None + */ +WEAK void SystemClock_Config(void) +{ + RCC_OscInitTypeDef RCC_OscInitStruct = {0}; + RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; + RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {}; + + MPU_Config(); + + /** Supply configuration update enable + */ + HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY); + /** Configure the main internal regulator output voltage + */ + __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE0); + + while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {} + /** Initializes the RCC Oscillators according to the specified parameters + * in the RCC_OscInitTypeDef structure. + */ + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI48 | RCC_OSCILLATORTYPE_HSE; + RCC_OscInitStruct.HSEState = RCC_HSE_ON; + RCC_OscInitStruct.HSI48State = RCC_HSI48_ON; // 48Mhz for USB + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; + RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; + RCC_OscInitStruct.PLL.PLLM = 5; // 25Mhz / 5 = 5Mhz + RCC_OscInitStruct.PLL.PLLN = 110; // 25Mhz / 5 * 110 = 550Mhz + RCC_OscInitStruct.PLL.PLLP = 1; // 550Mhz / 1 = 550Mhz + RCC_OscInitStruct.PLL.PLLQ = 10; // 550Mhz / 10 = 55Mhz + RCC_OscInitStruct.PLL.PLLR = 10; // unused + RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2; + RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE; + RCC_OscInitStruct.PLL.PLLFRACN = 0; + if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) + { + Error_Handler(); + } + /** Initializes the CPU, AHB and APB buses clocks + */ + RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK + |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2 + |RCC_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1; + RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; + RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1; + RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2; + RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2; + RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2; + RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2; + RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2; + + if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) + { + Error_Handler(); + } + + PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_USB + | RCC_PERIPHCLK_SDMMC | RCC_PERIPHCLK_ADC + | RCC_PERIPHCLK_LPUART1 | RCC_PERIPHCLK_USART16 + | RCC_PERIPHCLK_USART234578 | RCC_PERIPHCLK_I2C123 + | RCC_PERIPHCLK_I2C4 | RCC_PERIPHCLK_SPI123 + | RCC_PERIPHCLK_SPI45 | RCC_PERIPHCLK_SPI6; + + /* HSI48 used for USB 48 Mhz */ + /* PLL1 qclk also used for FMC, SDMMC, RNG, SAI */ + /* PLL2 pclk is needed for adc max 80 Mhz (p,q,r same) */ + /* PLL2 pclk also used for LP timers 2,3,4,5, SPI 1,2,3 */ + /* PLL2 qclk is needed for uart, can, spi4,5,6 80 Mhz */ + /* PLL3 r clk is needed for i2c 80 Mhz (p,q,r same) */ + PeriphClkInitStruct.PLL2.PLL2M = 15; // M DIV 15 vco 25 / 15 ~ 1.667 Mhz + PeriphClkInitStruct.PLL2.PLL2N = 96; // N MUL 96 + PeriphClkInitStruct.PLL2.PLL2P = 2; // P div 2 + PeriphClkInitStruct.PLL2.PLL2Q = 2; // Q div 2 + PeriphClkInitStruct.PLL2.PLL2R = 2; // R div 2 + // RCC_PLL1VCIRANGE_0 Clock range frequency between 1 and 2 MHz + PeriphClkInitStruct.PLL2.PLL2RGE = RCC_PLL2VCIRANGE_0; + PeriphClkInitStruct.PLL2.PLL2VCOSEL = RCC_PLL2VCOMEDIUM; + PeriphClkInitStruct.PLL2.PLL2FRACN = 0; + PeriphClkInitStruct.PLL3.PLL3M = 15; // M DIV 15 vco 25 / 15 ~ 1.667 Mhz + PeriphClkInitStruct.PLL3.PLL3N = 96; // N MUL 96 + PeriphClkInitStruct.PLL3.PLL3P = 2; // P div 2 + PeriphClkInitStruct.PLL3.PLL3Q = 2; // Q div 2 + PeriphClkInitStruct.PLL3.PLL3R = 2; // R div 2 + // RCC_PLL1VCIRANGE_0 Clock range frequency between 1 and 2 MHz + PeriphClkInitStruct.PLL3.PLL3RGE = RCC_PLL3VCIRANGE_0; + PeriphClkInitStruct.PLL3.PLL3VCOSEL = RCC_PLL3VCOMEDIUM; + PeriphClkInitStruct.PLL3.PLL3FRACN = 0; + // ADC from PLL2 pclk + PeriphClkInitStruct.AdcClockSelection = RCC_ADCCLKSOURCE_PLL2; + // USB from HSI48 + PeriphClkInitStruct.UsbClockSelection = RCC_USBCLKSOURCE_HSI48; + // SDMMC from PLL1 qclk + PeriphClkInitStruct.SdmmcClockSelection = 0; + //PeriphClkInitStruct.SdmmcClockSelection = RCC_SDMMCCLKSOURCE_PLL; + // LPUART from PLL2 qclk + PeriphClkInitStruct.Lpuart1ClockSelection = 0; + //PeriphClkInitStruct.Lpuart1ClockSelection = RCC_LPUART1CLKSOURCE_PLL2; + // USART from PLL2 qclk + PeriphClkInitStruct.Usart16ClockSelection = RCC_USART16CLKSOURCE_PLL2; + // USART from PLL2 qclk + PeriphClkInitStruct.Usart234578ClockSelection = 0; + //PeriphClkInitStruct.Usart234578ClockSelection = RCC_USART234578CLKSOURCE_PLL2; + // I2C123 from PLL3 rclk + PeriphClkInitStruct.I2c123ClockSelection = RCC_I2C123CLKSOURCE_PLL3; + // I2C4 from PLL3 rclk + PeriphClkInitStruct.I2c4ClockSelection = 0; + //PeriphClkInitStruct.I2c4ClockSelection = RCC_I2C4CLKSOURCE_PLL3; + // SPI123 from PLL2 pclk + PeriphClkInitStruct.Spi123ClockSelection = RCC_SPI123CLKSOURCE_PLL2; + // SPI45 from PLL2 qclk + PeriphClkInitStruct.Spi45ClockSelection = 0; + //PeriphClkInitStruct.Spi45ClockSelection = RCC_SPI45CLKSOURCE_PLL2; + // SPI6 from PLL2 qclk + PeriphClkInitStruct.Spi6ClockSelection = 0; + //PeriphClkInitStruct.Spi6ClockSelection = RCC_SPI6CLKSOURCE_PLL2; + + if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) { + Error_Handler(); + } +} + +#endif /* ARDUINO_GENERIC_* */ diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FLY_D8_PRO/variant_MARLIN_STM32H723VG.h b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D8_PRO/variant_MARLIN_STM32H723VG.h new file mode 100644 index 0000000000..0302c1dc12 --- /dev/null +++ b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D8_PRO/variant_MARLIN_STM32H723VG.h @@ -0,0 +1,234 @@ +/* + ******************************************************************************* + * Copyright (c) 2020, STMicroelectronics + * All rights reserved. + * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ******************************************************************************* + */ +#pragma once + +/*---------------------------------------------------------------------------- + * STM32 pins number + *----------------------------------------------------------------------------*/ +#define PA0 PIN_A0 +#define PA1 PIN_A1 +#define PA2 PIN_A2 +#define PA3 PIN_A3 +#define PA4 PIN_A4 +#define PA5 PIN_A5 +#define PA6 PIN_A6 +#define PA7 PIN_A7 +#define PA8 8 +#define PA9 9 +#define PA10 10 +#define PA11 11 +#define PA12 12 +#define PA13 13 +#define PA14 14 +#define PA15 15 +#define PB0 PIN_A8 +#define PB1 PIN_A9 +#define PB2 18 +#define PB3 19 +#define PB4 20 +#define PB5 21 +#define PB6 22 +#define PB7 23 +#define PB8 24 +#define PB9 25 +#define PB10 26 +#define PB11 27 +#define PB12 28 +#define PB13 29 +#define PB14 30 +#define PB15 31 +#define PC0 PIN_A10 +#define PC1 PIN_A11 +#define PC4 PIN_A12 +#define PC5 PIN_A13 +#define PC6 36 +#define PC7 37 +#define PC8 38 +#define PC9 39 +#define PC10 40 +#define PC11 41 +#define PC12 42 +#define PC13 43 +#define PC14 44 +#define PC15 45 +#define PD0 46 +#define PD1 47 +#define PD2 48 +#define PD3 49 +#define PD4 50 +#define PD5 51 +#define PD6 52 +#define PD7 53 +#define PD8 54 +#define PD9 55 +#define PD10 56 +#define PD11 57 +#define PD12 58 +#define PD13 59 +#define PD14 60 +#define PD15 61 +#define PE0 62 +#define PE1 63 +#define PE2 64 +#define PE3 65 +#define PE4 66 +#define PE5 67 +#define PE6 68 +#define PE7 69 +#define PE8 70 +#define PE9 71 +#define PE10 72 +#define PE11 73 +#define PE12 74 +#define PE13 75 +#define PE14 76 +#define PE15 77 +#define PH0 78 +#define PH1 79 +#define PC2_C PIN_A14 +#define PC3_C PIN_A15 +#define PC2 PC2_C +#define PC3 PC3_C + +// Alternate pins number +#define PA0_ALT1 (PA0 | ALT1) +#define PA1_ALT1 (PA1 | ALT1) +#define PA1_ALT2 (PA1 | ALT2) +#define PA2_ALT1 (PA2 | ALT1) +#define PA2_ALT2 (PA2 | ALT2) +#define PA3_ALT1 (PA3 | ALT1) +#define PA3_ALT2 (PA3 | ALT2) +#define PA4_ALT1 (PA4 | ALT1) +#define PA4_ALT2 (PA4 | ALT2) +#define PA5_ALT1 (PA5 | ALT1) +#define PA6_ALT1 (PA6 | ALT1) +#define PA7_ALT1 (PA7 | ALT1) +#define PA7_ALT2 (PA7 | ALT2) +#define PA7_ALT3 (PA7 | ALT3) +#define PA8_ALT1 (PA8 | ALT1) +#define PA9_ALT1 (PA9 | ALT1) +#define PA10_ALT1 (PA10 | ALT1) +#define PA11_ALT1 (PA11 | ALT1) +#define PA12_ALT1 (PA12 | ALT1) +#define PA15_ALT1 (PA15 | ALT1) +#define PA15_ALT2 (PA15 | ALT2) +#define PB0_ALT1 (PB0 | ALT1) +#define PB0_ALT2 (PB0 | ALT2) +#define PB1_ALT1 (PB1 | ALT1) +#define PB1_ALT2 (PB1 | ALT2) +#define PB3_ALT1 (PB3 | ALT1) +#define PB3_ALT2 (PB3 | ALT2) +#define PB4_ALT1 (PB4 | ALT1) +#define PB4_ALT2 (PB4 | ALT2) +#define PB5_ALT1 (PB5 | ALT1) +#define PB5_ALT2 (PB5 | ALT2) +#define PB6_ALT1 (PB6 | ALT1) +#define PB6_ALT2 (PB6 | ALT2) +#define PB7_ALT1 (PB7 | ALT1) +#define PB8_ALT1 (PB8 | ALT1) +#define PB8_ALT2 (PB8 | ALT2) +#define PB9_ALT1 (PB9 | ALT1) +#define PB9_ALT2 (PB9 | ALT2) +#define PB14_ALT1 (PB14 | ALT1) +#define PB14_ALT2 (PB14 | ALT2) +#define PB15_ALT1 (PB15 | ALT1) +#define PB15_ALT2 (PB15 | ALT2) +#define PC0_ALT1 (PC0 | ALT1) +#define PC0_ALT2 (PC0 | ALT2) +#define PC1_ALT1 (PC1 | ALT1) +#define PC1_ALT2 (PC1 | ALT2) +#define PC4_ALT1 (PC4 | ALT1) +#define PC5_ALT1 (PC5 | ALT1) +#define PC6_ALT1 (PC6 | ALT1) +#define PC6_ALT2 (PC6 | ALT2) +#define PC7_ALT1 (PC7 | ALT1) +#define PC7_ALT2 (PC7 | ALT2) +#define PC8_ALT1 (PC8 | ALT1) +#define PC9_ALT1 (PC9 | ALT1) +#define PC10_ALT1 (PC10 | ALT1) +#define PC11_ALT1 (PC11 | ALT1) + +#define NUM_DIGITAL_PINS 82 +#define NUM_DUALPAD_PINS 2 +#define NUM_ANALOG_INPUTS 16 +#define NUM_ANALOG_FIRST PA0 + +// SPI definitions +#ifndef PIN_SPI_SS + #define PIN_SPI_SS PB12 +#endif +#ifndef PIN_SPI_MOSI + #define PIN_SPI_MOSI PB15 +#endif +#ifndef PIN_SPI_MISO + #define PIN_SPI_MISO PB14 +#endif +#ifndef PIN_SPI_SCK + #define PIN_SPI_SCK PB13 +#endif + +// Timer Definitions +// Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin +#ifndef TIMER_TONE + #define TIMER_TONE TIM6 +#endif +#ifndef TIMER_SERVO + #define TIMER_SERVO TIM7 +#endif + +// UART Definitions +#ifndef SERIAL_UART_INSTANCE + #define SERIAL_UART_INSTANCE 1 +#endif + +// Default pin used for generic 'Serial' instance +// Mandatory for Firmata +#ifndef PIN_SERIAL_RX + #define PIN_SERIAL_RX PA10 +#endif +#ifndef PIN_SERIAL_TX + #define PIN_SERIAL_TX PA9 +#endif + +// Extra HAL modules +#ifndef HAL_SD_MODULE_DISABLED + #define HAL_SD_MODULE_ENABLED +#endif + +/*---------------------------------------------------------------------------- + * Arduino objects - C++ only + *----------------------------------------------------------------------------*/ + +#ifdef __cplusplus + // These serial port names are intended to allow libraries and architecture-neutral + // sketches to automatically default to the correct port name for a particular type + // of use. For example, a GPS module would normally connect to SERIAL_PORT_HARDWARE_OPEN, + // the first hardware serial port whose RX/TX pins are not dedicated to another use. + // + // SERIAL_PORT_MONITOR Port which normally prints to the Arduino Serial Monitor + // + // SERIAL_PORT_USBVIRTUAL Port which is USB virtual serial + // + // SERIAL_PORT_LINUXBRIDGE Port which connects to a Linux system via Bridge library + // + // SERIAL_PORT_HARDWARE Hardware serial port, physical RX & TX pins. + // + // SERIAL_PORT_HARDWARE_OPEN Hardware serial ports which are open for use. Their RX & TX + // pins are NOT connected to anything by default. + #ifndef SERIAL_PORT_MONITOR + #define SERIAL_PORT_MONITOR Serial + #endif + #ifndef SERIAL_PORT_HARDWARE + #define SERIAL_PORT_HARDWARE Serial + #endif +#endif diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FLY_F407ZG/PeripheralPins.c b/buildroot/share/PlatformIO/variants/MARLIN_FLY_F407ZG/PeripheralPins.c index f0f2c4b80c..17d2f66b75 100644 --- a/buildroot/share/PlatformIO/variants/MARLIN_FLY_F407ZG/PeripheralPins.c +++ b/buildroot/share/PlatformIO/variants/MARLIN_FLY_F407ZG/PeripheralPins.c @@ -402,3 +402,21 @@ WEAK const PinMap PinMap_USB_OTG_HS[] = { {NC, NP, 0} }; #endif + +//*** SD *** + +#ifdef HAL_SD_MODULE_ENABLED +WEAK const PinMap PinMap_SD[] = { + // {PB_8, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDIO)}, // SDIO_D4 + // {PB_9, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDIO)}, // SDIO_D5 + // {PC_6, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDIO)}, // SDIO_D6 + // {PC_7, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDIO)}, // SDIO_D7 + {PC_8, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDIO)}, // SDIO_D0 + {PC_9, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDIO)}, // SDIO_D1 + {PC_10, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDIO)}, // SDIO_D2 + {PC_11, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDIO)}, // SDIO_D3 + {PC_12, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF12_SDIO)}, // SDIO_CK + {PD_2, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF12_SDIO)}, // SDIO_CMD + {NC, NP, 0} +}; +#endif \ No newline at end of file diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FLY_SUPER8/PeripheralPins.c b/buildroot/share/PlatformIO/variants/MARLIN_FLY_SUPER8/PeripheralPins.c new file mode 100644 index 0000000000..92496e60db --- /dev/null +++ b/buildroot/share/PlatformIO/variants/MARLIN_FLY_SUPER8/PeripheralPins.c @@ -0,0 +1,422 @@ +/* + ******************************************************************************* + * Copyright (c) 2019, STMicroelectronics + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ******************************************************************************* + * Automatically generated from STM32F407Z(E-G)Tx.xml + */ +#include +#include + +/* ===== + * Note: Commented lines are alternative possibilities which are not used per default. + * If you change them, you will have to know what you do + * ===== + */ + +//*** ADC *** + +#ifdef HAL_ADC_MODULE_ENABLED +WEAK const PinMap PinMap_ADC[] = { + {PA_0, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 0, 0)}, // ADC1_IN0 + //{PA_0, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 0, 0)}, // ADC2_IN0 + //{PA_0, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 0, 0)}, // ADC3_IN0 + //{PA_1, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 1, 0)}, // ADC1_IN1 + //{PA_1, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 1, 0)}, // ADC2_IN1 + //{PA_1, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 1, 0)}, // ADC3_IN1 + //{PA_2, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 2, 0)}, // ADC1_IN2 + //{PA_2, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 2, 0)}, // ADC2_IN2 + //{PA_2, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 2, 0)}, // ADC3_IN2 + //{PA_3, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 3, 0)}, // ADC1_IN3 + //{PA_3, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 3, 0)}, // ADC2_IN3 + //{PA_3, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 3, 0)}, // ADC3_IN3 + //{PA_4, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 4, 0)}, // ADC1_IN4 + //{PA_4, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 4, 0)}, // ADC2_IN4 + //{PA_5, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 5, 0)}, // ADC1_IN5 + //{PA_5, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 5, 0)}, // ADC2_IN5 + //{PA_6, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 6, 0)}, // ADC1_IN6 + //{PA_6, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 6, 0)}, // ADC2_IN6 + //{PA_7, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 7, 0)}, // ADC1_IN7 + //{PA_7, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 7, 0)}, // ADC2_IN7 + //{PB_0, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 8, 0)}, // ADC1_IN8 + //{PB_0, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 8, 0)}, // ADC2_IN8 + //{PB_1, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 9, 0)}, // ADC1_IN9 + //{PB_1, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 9, 0)}, // ADC2_IN9 + //{PC_0, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 10, 0)}, // ADC1_IN10 + //{PC_0, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 10, 0)}, // ADC2_IN10 + {PC_0, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 10, 0)}, // ADC3_IN10 + {PC_1, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 11, 0)}, // ADC1_IN11 + //{PC_1, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 11, 0)}, // ADC2_IN11 + //{PC_1, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 11, 0)}, // ADC3_IN11 + //{PC_2, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 12, 0)}, // ADC1_IN12 + //{PC_2, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 12, 0)}, // ADC2_IN12 + //{PC_2, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 12, 0)}, // ADC3_IN12 + //{PC_3, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 13, 0)}, // ADC1_IN13 + //{PC_3, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 13, 0)}, // ADC2_IN13 + //{PC_3, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 13, 0)}, // ADC3_IN13 + //{PC_4, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 14, 0)}, // ADC1_IN14 + //{PC_4, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 14, 0)}, // ADC2_IN14 + //{PC_5, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 15, 0)}, // ADC1_IN15 + //{PC_5, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 15, 0)}, // ADC2_IN15 + {PF_3, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 9, 0)}, // ADC3_IN9 + {PF_4, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 14, 0)}, // ADC3_IN14 + {PF_5, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 15, 0)}, // ADC3_IN15 + //{PF_6, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 4, 0)}, // ADC3_IN4 + //{PF_7, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 5, 0)}, // ADC3_IN5 + //{PF_8, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 6, 0)}, // ADC3_IN6 + {PF_9, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 7, 0)}, // ADC3_IN7 + {PF_10, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 8, 0)}, // ADC3_IN8 + {NC, NP, 0} +}; +#endif + +//*** DAC *** + +#ifdef HAL_DAC_MODULE_ENABLED +WEAK const PinMap PinMap_DAC[] = { + //{PA_4, DAC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 1, 0)}, // DAC_OUT1 + //{PA_5, DAC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 2, 0)}, // DAC_OUT2 + {NC, NP, 0} +}; +#endif + +//*** I2C *** + +#ifdef HAL_I2C_MODULE_ENABLED +WEAK const PinMap PinMap_I2C_SDA[] = { + {PB_7, I2C1, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C1)}, + //{PB_9, I2C1, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C1)}, + //{PB_11, I2C2, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C2)}, + //{PC_9, I2C3, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C3)}, + //{PF_0, I2C2, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C2)}, + {NC, NP, 0} +}; + +WEAK const PinMap PinMap_I2C_SCL[] = { + //{PA_8, I2C3, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C3)}, + {PB_6, I2C1, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C1)}, + //{PB_8, I2C1, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C1)}, + //{PB_10, I2C2, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C2)}, + //{PF_1, I2C2, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C2)}, + {NC, NP, 0} +}; +#endif + +//*** PWM *** + +#ifdef HAL_TIM_MODULE_ENABLED +WEAK const PinMap PinMap_PWM[] = { + {PA_1, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 2, 0)}, // TIM2_CH2 + {PA_2, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 3, 0)}, // TIM2_CH3 + {PA_8, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 1, 0)}, // TIM1_CH1 + {PB_8, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 3, 0)}, // TIM4_CH3 + {PB_9, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 4, 0)}, // TIM4_CH4 + {PB_11, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 4, 0)}, // TIM2_CH4 + {PC_6, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 1, 0)}, // TIM3_CH1 + {PC_7, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 2, 0)}, // TIM3_CH2 + {PD_12, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 1, 0)}, // TIM4_CH1 + {PD_13, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 2, 0)}, // TIM4_CH2 + {PD_14, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 3, 0)}, // TIM4_CH3 + {PD_15, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 4, 0)}, // TIM4_CH4 + {PE_5, TIM9, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM9, 1, 0)}, // TIM9_CH1 + {PE_6, TIM9, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM9, 2, 0)}, // TIM9_CH2 + //{PE_11, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 2, 0)}, // TIM1_CH2 + //{PE_13, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 3, 0)}, // TIM1_CH3 + {PF_6, TIM10, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM10, 1, 0)}, // TIM10_CH1 + {PF_7, TIM11, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM11, 1, 0)}, // TIM11_CH1 + {PF_8, TIM13, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_TIM13, 1, 0)}, // TIM13_CH1 + {PF_9, TIM14, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_TIM14, 1, 0)}, // TIM14_CH1 + //{PA_0, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 1, 0)}, // TIM2_CH1 + //{PA_0, TIM5, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM5, 1, 0)}, // TIM5_CH1 + //{PA_1, TIM5, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM5, 2, 0)}, // TIM5_CH2 + //{PA_2, TIM5, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM5, 3, 0)}, // TIM5_CH3 + //{PA_2, TIM9, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM9, 1, 0)}, // TIM9_CH1 + //{PA_3, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 4, 0)}, // TIM2_CH4 + //{PA_3, TIM5, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM5, 4, 0)}, // TIM5_CH4 + //{PA_3, TIM9, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM9, 2, 0)}, // TIM9_CH2 + //{PA_5, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 1, 0)}, // TIM2_CH1 + //{PA_5, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 1, 1)}, // TIM8_CH1N + //{PA_6, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 1, 0)}, // TIM3_CH1 + //{PA_6, TIM13, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_TIM13, 1, 0)}, // TIM13_CH1 + //{PA_7, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 1, 1)}, // TIM1_CH1N + //{PA_7, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 2, 0)}, // TIM3_CH2 + //{PA_7, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 1, 1)}, // TIM8_CH1N + //{PA_7, TIM14, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_TIM14, 1, 0)}, // TIM14_CH1 + //{PA_9, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 2, 0)}, // TIM1_CH2 + //{PA_10, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 3, 0)}, // TIM1_CH3 + //{PA_11, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 4, 0)}, // TIM1_CH4 + //{PA_15, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 1, 0)}, // TIM2_CH1 + //{PB_0, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 2, 1)}, // TIM1_CH2N + //{PB_0, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 3, 0)}, // TIM3_CH3 + //{PB_0, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 2, 1)}, // TIM8_CH2N + //{PB_1, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 3, 1)}, // TIM1_CH3N + //{PB_1, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 4, 0)}, // TIM3_CH4 + //{PB_1, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 3, 1)}, // TIM8_CH3N + //{PB_3, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 2, 0)}, // TIM2_CH2 + //{PB_4, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 1, 0)}, // TIM3_CH1 + //{PB_5, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 2, 0)}, // TIM3_CH2 + //{PB_6, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 1, 0)}, // TIM4_CH1 + //{PB_7, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 2, 0)}, // TIM4_CH2 + //{PB_8, TIM10, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM10, 1, 0)}, // TIM10_CH1 + //{PB_9, TIM11, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM11, 1, 0)}, // TIM11_CH1 + //{PB_10, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 3, 0)}, // TIM2_CH3 + //{PB_13, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 1, 1)}, // TIM1_CH1N + //{PB_14, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 2, 1)}, // TIM1_CH2N + //{PB_14, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 2, 1)}, // TIM8_CH2N + //{PB_14, TIM12, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_TIM12, 1, 0)}, // TIM12_CH1 + //{PB_15, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 3, 1)}, // TIM1_CH3N + //{PB_15, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 3, 1)}, // TIM8_CH3N + //{PB_15, TIM12, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_TIM12, 2, 0)}, // TIM12_CH2 + //{PC_6, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 1, 0)}, // TIM8_CH1 + //{PC_7, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 2, 0)}, // TIM8_CH2 + //{PC_8, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 3, 0)}, // TIM3_CH3 + //{PC_8, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 3, 0)}, // TIM8_CH3 + //{PC_9, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 4, 0)}, // TIM3_CH4 + //{PC_9, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 4, 0)}, // TIM8_CH4 + //{PE_8, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 1, 1)}, // TIM1_CH1N + //{PE_9, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 1, 0)}, // TIM1_CH1 + //{PE_10, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 2, 1)}, // TIM1_CH2N + //{PE_12, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 3, 1)}, // TIM1_CH3N + //{PE_14, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 4, 0)}, // TIM1_CH4 + {NC, NP, 0} +}; +#endif + +//*** SERIAL *** + +#ifdef HAL_UART_MODULE_ENABLED +WEAK const PinMap PinMap_UART_TX[] = { + //{PA_0, UART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART4)}, + //{PA_2, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)}, + {PA_9, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART1)}, + //{PB_6, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART1)}, + //{PB_10, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + //{PC_6, USART6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_USART6)}, + //{PC_10, UART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART4)}, + //{PC_10, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + //{PC_12, UART5, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART5)}, + //{PD_5, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)}, + //{PD_8, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + // {PG_14, USART6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_USART6)}, + {NC, NP, 0} +}; + +WEAK const PinMap PinMap_UART_RX[] = { + //{PA_1, UART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART4)}, + //{PA_3, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)}, + {PA_10, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART1)}, + //{PB_7, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART1)}, + //{PB_11, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + //{PC_7, USART6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_USART6)}, + //{PC_11, UART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART4)}, + //{PC_11, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + //{PD_2, UART5, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART5)}, + //{PD_6, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)}, + //{PD_9, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + // {PG_9, USART6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_USART6)}, + {NC, NP, 0} +}; + +WEAK const PinMap PinMap_UART_RTS[] = { + //{PA_1, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)}, + //{PA_12, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART1)}, + //{PB_14, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + //{PD_4, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)}, + //{PD_12, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + //{PG_8, USART6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_USART6)}, + //{PG_12, USART6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_USART6)}, + {NC, NP, 0} +}; + +WEAK const PinMap PinMap_UART_CTS[] = { + //{PA_0, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)}, + //{PA_11, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART1)}, + //{PB_13, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + //{PD_3, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)}, + //{PD_11, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + //{PG_13, USART6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_USART6)}, + //{PG_15, USART6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_USART6)}, + {NC, NP, 0} +}; +#endif + +//*** SPI *** + +#ifdef HAL_SPI_MODULE_ENABLED +WEAK const PinMap PinMap_SPI_MOSI[] = { + {PA_7, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, + // {PB_5, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, + {PB_5, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)}, + {PB_15, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + // {PC_3, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + // {PC_12, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)}, + {NC, NP, 0} +}; + +WEAK const PinMap PinMap_SPI_MISO[] = { + {PA_6, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, + // {PB_4, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, + {PB_4, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)}, + {PB_14, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + // {PC_2, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + // {PC_11, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)}, + {NC, NP, 0} +}; + +WEAK const PinMap PinMap_SPI_SCLK[] = { + {PA_5, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, + // {PB_3, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, + {PB_3, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)}, + // {PB_10, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + {PB_13, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + // {PC_10, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)}, + {NC, NP, 0} +}; + +WEAK const PinMap PinMap_SPI_SSEL[] = { + {PA_4, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, + // {PA_4, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)}, + // {PA_15, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, + // {PA_15, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)}, + // {PB_9, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + // {PB_12, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + {NC, NP, 0} +}; +#endif + +//*** CAN *** + +#ifdef HAL_CAN_MODULE_ENABLED +WEAK const PinMap PinMap_CAN_RD[] = { + //{PA_11, CAN1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_CAN1)}, + //{PB_5, CAN2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_CAN2)}, + {PB_8, CAN1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_CAN1)}, + //{PB_12, CAN2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_CAN2)}, + //{PD_0, CAN1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_CAN1)}, + {NC, NP, 0} +}; + +WEAK const PinMap PinMap_CAN_TD[] = { + //{PA_12, CAN1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_CAN1)}, + //{PB_6, CAN2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_CAN2)}, + {PB_9, CAN1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_CAN1)}, + //{PB_13, CAN2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_CAN2)}, + //{PD_1, CAN1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_CAN1)}, + {NC, NP, 0} +}; +#endif + +//*** ETHERNET *** + +#ifdef HAL_ETH_MODULE_ENABLED +WEAK const PinMap PinMap_Ethernet[] = { + /* + {PA_0, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_CRS + {PA_1, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_REF_CLK|ETH_RX_CLK + {PA_2, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_MDIO + {PA_3, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_COL + {PA_7, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_CRS_DV|ETH_RX_DV + {PB_0, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_RXD2 + {PB_1, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_RXD3 + {PB_5, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_PPS_OUT + {PB_8, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_TXD3 + {PB_10, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_RX_ER + {PB_11, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_TX_EN + {PB_12, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_TXD0 + {PB_13, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_TXD1 + {PC_1, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_MDC + {PC_2, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_TXD2 + {PC_3, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_TX_CLK + {PC_4, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_RXD0 + {PC_5, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_RXD1 + {PE_2, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_TXD3 + {PG_8, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_PPS_OUT + {PG_11, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_TX_EN + {PG_13, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_TXD0 + {PG_14, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_TXD1 + {NC, NP, 0} + */ +}; +#endif + +//*** No QUADSPI *** + +//*** USB *** + +#ifdef HAL_PCD_MODULE_ENABLED +WEAK const PinMap PinMap_USB_OTG_FS[] = { + //{PA_8, USB_OTG_FS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_FS)}, // USB_OTG_FS_SOF + //{PA_9, USB_OTG_FS, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, GPIO_AF_NONE)}, // USB_OTG_FS_VBUS + //{PA_10, USB_OTG_FS, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_PULLUP, GPIO_AF10_OTG_FS)}, // USB_OTG_FS_ID + {PA_11, USB_OTG_FS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_FS)}, // USB_OTG_FS_DM + {PA_12, USB_OTG_FS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_FS)}, // USB_OTG_FS_DP + {NC, NP, 0} +}; + +WEAK const PinMap PinMap_USB_OTG_HS[] = { + /* + #ifdef USE_USB_HS_IN_FS + {PA_4, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_OTG_HS_FS)}, // USB_OTG_HS_SOF + {PB_12, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_PULLUP, GPIO_AF12_OTG_HS_FS)}, // USB_OTG_HS_ID + {PB_13, USB_OTG_HS, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, GPIO_AF_NONE)}, // USB_OTG_HS_VBUS + {PB_14, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_OTG_HS_FS)}, // USB_OTG_HS_DM + {PB_15, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_OTG_HS_FS)}, // USB_OTG_HS_DP + #else + {PA_3, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_HS)}, // USB_OTG_HS_ULPI_D0 + {PA_5, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_HS)}, // USB_OTG_HS_ULPI_CK + {PB_0, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_HS)}, // USB_OTG_HS_ULPI_D1 + {PB_1, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_HS)}, // USB_OTG_HS_ULPI_D2 + {PB_5, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_HS)}, // USB_OTG_HS_ULPI_D7 + {PB_10, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_HS)}, // USB_OTG_HS_ULPI_D3 + {PB_11, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_HS)}, // USB_OTG_HS_ULPI_D4 + {PB_12, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_HS)}, // USB_OTG_HS_ULPI_D5 + {PB_13, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_HS)}, // USB_OTG_HS_ULPI_D6 + {PC_0, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_HS)}, // USB_OTG_HS_ULPI_STP + {PC_2, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_HS)}, // USB_OTG_HS_ULPI_DIR + {PC_3, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_HS)}, // USB_OTG_HS_ULPI_NXT + #endif // USE_USB_HS_IN_FS + */ + {NC, NP, 0} +}; +#endif + +//*** SD *** + +#ifdef HAL_SD_MODULE_ENABLED +WEAK const PinMap PinMap_SD[] = { + // {PB_8, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDIO)}, // SDIO_D4 + // {PB_9, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDIO)}, // SDIO_D5 + // {PC_6, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDIO)}, // SDIO_D6 + // {PC_7, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDIO)}, // SDIO_D7 + {PC_8, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDIO)}, // SDIO_D0 + {PC_9, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDIO)}, // SDIO_D1 + {PC_10, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDIO)}, // SDIO_D2 + {PC_11, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDIO)}, // SDIO_D3 + {PC_12, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF12_SDIO)}, // SDIO_CK + {PD_2, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF12_SDIO)}, // SDIO_CMD + {NC, NP, 0} +}; +#endif \ No newline at end of file diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FLY_SUPER8/PinNamesVar.h b/buildroot/share/PlatformIO/variants/MARLIN_FLY_SUPER8/PinNamesVar.h new file mode 100644 index 0000000000..b4bb9d45f8 --- /dev/null +++ b/buildroot/share/PlatformIO/variants/MARLIN_FLY_SUPER8/PinNamesVar.h @@ -0,0 +1,50 @@ +/* SYS_WKUP */ +#ifdef PWR_WAKEUP_PIN1 + SYS_WKUP1 = PA_0, +#endif +#ifdef PWR_WAKEUP_PIN2 + SYS_WKUP2 = NC, +#endif +#ifdef PWR_WAKEUP_PIN3 + SYS_WKUP3 = NC, +#endif +#ifdef PWR_WAKEUP_PIN4 + SYS_WKUP4 = NC, +#endif +#ifdef PWR_WAKEUP_PIN5 + SYS_WKUP5 = NC, +#endif +#ifdef PWR_WAKEUP_PIN6 + SYS_WKUP6 = NC, +#endif +#ifdef PWR_WAKEUP_PIN7 + SYS_WKUP7 = NC, +#endif +#ifdef PWR_WAKEUP_PIN8 + SYS_WKUP8 = NC, +#endif +/* USB */ +#ifdef USBCON + USB_OTG_FS_SOF = PA_8, + USB_OTG_FS_VBUS = PA_9, + USB_OTG_FS_ID = PA_10, + USB_OTG_FS_DM = PA_11, + USB_OTG_FS_DP = PA_12, + USB_OTG_HS_ULPI_D0 = PA_3, + USB_OTG_HS_SOF = PA_4, + USB_OTG_HS_ULPI_CK = PA_5, + USB_OTG_HS_ULPI_D1 = PB_0, + USB_OTG_HS_ULPI_D2 = PB_1, + USB_OTG_HS_ULPI_D7 = PB_5, + USB_OTG_HS_ULPI_D3 = PB_10, + USB_OTG_HS_ULPI_D4 = PB_11, + USB_OTG_HS_ID = PB_12, + USB_OTG_HS_ULPI_D5 = PB_12, + USB_OTG_HS_ULPI_D6 = PB_13, + USB_OTG_HS_VBUS = PB_13, + USB_OTG_HS_DM = PB_14, + USB_OTG_HS_DP = PB_15, + USB_OTG_HS_ULPI_STP = PC_0, + USB_OTG_HS_ULPI_DIR = PC_2, + USB_OTG_HS_ULPI_NXT = PC_3, +#endif diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FLY_SUPER8/hal_conf_extra.h b/buildroot/share/PlatformIO/variants/MARLIN_FLY_SUPER8/hal_conf_extra.h new file mode 100644 index 0000000000..8325aba948 --- /dev/null +++ b/buildroot/share/PlatformIO/variants/MARLIN_FLY_SUPER8/hal_conf_extra.h @@ -0,0 +1,87 @@ +#pragma once + +#ifndef HAL_MODULE_ENABLED + #define HAL_MODULE_ENABLED +#endif +#ifndef HAL_ADC_MODULE_ENABLED + #define HAL_ADC_MODULE_ENABLED +#endif +#ifndef HAL_CRC_MODULE_ENABLED + #define HAL_CRC_MODULE_ENABLED +#endif +#ifndef HAL_DMA_MODULE_ENABLED + #define HAL_DMA_MODULE_ENABLED +#endif +#ifndef HAL_EXTI_MODULE_ENABLED + #define HAL_EXTI_MODULE_ENABLED // Needed for Endstop (and other external) Interrupts +#endif +#ifndef HAL_GPIO_MODULE_ENABLED + #define HAL_GPIO_MODULE_ENABLED +#endif +#ifndef HAL_I2C_MODULE_ENABLED + #define HAL_I2C_MODULE_ENABLED +#endif +#ifndef HAL_PWR_MODULE_ENABLED + #define HAL_PWR_MODULE_ENABLED +#endif +#ifndef HAL_RCC_MODULE_ENABLED + #define HAL_RCC_MODULE_ENABLED +#endif +#ifndef HAL_RTC_MODULE_ENABLED + //#define HAL_RTC_MODULE_ENABLED // Real Time Clock...do we use it? +#endif +#ifndef HAL_SPI_MODULE_ENABLED + #define HAL_SPI_MODULE_ENABLED +#endif +#ifndef HAL_TIM_MODULE_ENABLED + #define HAL_TIM_MODULE_ENABLED +#endif +#ifndef HAL_USART_MODULE_ENABLED + #define HAL_USART_MODULE_ENABLED +#endif +#ifndef HAL_CORTEX_MODULE_ENABLED + #define HAL_CORTEX_MODULE_ENABLED +#endif +#ifndef HAL_UART_MODULE_ENABLED + //#define HAL_UART_MODULE_ENABLED // by default +#endif +#ifndef HAL_PCD_MODULE_ENABLED + //#define HAL_PCD_MODULE_ENABLED // Since STM32 v3.10700.191028 this is automatically added if any type of USB is enabled (as in Arduino IDE) +#endif +#ifndef HAL_SD_MODULE_ENABLED + #define HAL_SD_MODULE_ENABLED +#endif + +//#undef HAL_SD_MODULE_ENABLED +#undef HAL_DAC_MODULE_ENABLED +#undef HAL_FLASH_MODULE_ENABLED +#undef HAL_CAN_MODULE_ENABLED +#undef HAL_CAN_LEGACY_MODULE_ENABLED +#undef HAL_CEC_MODULE_ENABLED +#undef HAL_CRYP_MODULE_ENABLED +#undef HAL_DCMI_MODULE_ENABLED +#undef HAL_DMA2D_MODULE_ENABLED +#undef HAL_ETH_MODULE_ENABLED +#undef HAL_NAND_MODULE_ENABLED +#undef HAL_NOR_MODULE_ENABLED +#undef HAL_PCCARD_MODULE_ENABLED +#undef HAL_SRAM_MODULE_ENABLED +#undef HAL_SDRAM_MODULE_ENABLED +#undef HAL_HASH_MODULE_ENABLED +#undef HAL_SMBUS_MODULE_ENABLED +#undef HAL_I2S_MODULE_ENABLED +#undef HAL_IWDG_MODULE_ENABLED +#undef HAL_LTDC_MODULE_ENABLED +#undef HAL_DSI_MODULE_ENABLED +#undef HAL_QSPI_MODULE_ENABLED +#undef HAL_RNG_MODULE_ENABLED +#undef HAL_SAI_MODULE_ENABLED +#undef HAL_IRDA_MODULE_ENABLED +#undef HAL_SMARTCARD_MODULE_ENABLED +#undef HAL_WWDG_MODULE_ENABLED +//#undef HAL_HCD_MODULE_ENABLED +#undef HAL_FMPI2C_MODULE_ENABLED +#undef HAL_SPDIFRX_MODULE_ENABLED +#undef HAL_DFSDM_MODULE_ENABLED +#undef HAL_LPTIM_MODULE_ENABLED +#undef HAL_MMC_MODULE_ENABLED diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FLY_SUPER8/ldscript.ld b/buildroot/share/PlatformIO/variants/MARLIN_FLY_SUPER8/ldscript.ld new file mode 100644 index 0000000000..cd7ccef85f --- /dev/null +++ b/buildroot/share/PlatformIO/variants/MARLIN_FLY_SUPER8/ldscript.ld @@ -0,0 +1,207 @@ +/* +***************************************************************************** +** + +** File : lscript.ld +** +** Abstract : Linker script for STM32F407(VZ)(EG)Tx Device with +** 512/1024KByte FLASH, 128KByte RAM +** +** Set heap size, stack size and stack location according +** to application requirements. +** +** Set memory bank area and size if external memory is used. +** +** Target : STMicroelectronics STM32 +** +** +** Distribution: The file is distributed as is, without any warranty +** of any kind. +** +***************************************************************************** +** @attention +** +** Copyright (c) 2014 Ac6 +** +** Redistribution and use in source and binary forms, with or without modification, +** are permitted provided that the following conditions are met: +** 1. Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright notice, +** this list of conditions and the following disclaimer in the documentation +** and/or other materials provided with the distribution. +** 3. Neither the name of Ac6 nor the names of its contributors +** may be used to endorse or promote products derived from this software +** without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +** +***************************************************************************** +*/ + +/* Entry Point */ +ENTRY(Reset_Handler) + +/* Highest address of the user mode stack */ +_estack = 0x20020000; /* end of RAM */ +/* Generate a link error if heap and stack don't fit into RAM */ +_Min_Heap_Size = 0x200;; /* required amount of heap */ +_Min_Stack_Size = 0x400;; /* required amount of stack */ + +/* Specify the memory areas */ +MEMORY +{ +RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K +CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64K +FLASH (rx) : ORIGIN = 0x8008000, LENGTH = 1024K -32K +} + +/* Define output sections */ +SECTIONS +{ + /* The startup code goes first into FLASH */ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + . = ALIGN(4); + } >FLASH + + /* The program code and other data goes into FLASH */ + .text ALIGN(4): + { + . = ALIGN(4); + *(.text) /* .text sections (code) */ + *(.text*) /* .text* sections (code) */ + *(.glue_7) /* glue arm to thumb code */ + *(.glue_7t) /* glue thumb to arm code */ + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + . = ALIGN(4); + _etext = .; /* define a global symbols at end of code */ + } >FLASH + + /* Constant data goes into FLASH */ + .rodata ALIGN(4): + { + . = ALIGN(4); + *(.rodata) /* .rodata sections (constants, strings, etc.) */ + *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ + . = ALIGN(4); + } >FLASH + + .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH + .ARM : { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } >FLASH + + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array*)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } >FLASH + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array*)) + PROVIDE_HIDDEN (__init_array_end = .); + } >FLASH + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT(.fini_array.*))) + KEEP (*(.fini_array*)) + PROVIDE_HIDDEN (__fini_array_end = .); + } >FLASH + + /* used by the startup to initialize data */ + _sidata = LOADADDR(.data); + + /* Initialized data sections goes into RAM, load LMA copy after code */ + .data : + { + . = ALIGN(4); + _sdata = .; /* create a global symbol at data start */ + *(.data) /* .data sections */ + *(.data*) /* .data* sections */ + + . = ALIGN(4); + _edata = .; /* define a global symbol at data end */ + } >RAM AT> FLASH + + _siccmram = LOADADDR(.ccmram); + + /* CCM-RAM section + * + * IMPORTANT NOTE! + * If initialized variables will be placed in this section, + * the startup code needs to be modified to copy the init-values. + */ + .ccmram : + { + . = ALIGN(4); + _sccmram = .; /* create a global symbol at ccmram start */ + *(.ccmram) + *(.ccmram*) + + . = ALIGN(4); + _eccmram = .; /* create a global symbol at ccmram end */ + } >CCMRAM AT> FLASH + + + /* Uninitialized data section */ + . = ALIGN(4); + .bss : + { + /* This is used by the startup in order to initialize the .bss section */ + _sbss = .; /* define a global symbol at bss start */ + __bss_start__ = _sbss; + *(.bss) + *(.bss*) + *(COMMON) + + . = ALIGN(4); + _ebss = .; /* define a global symbol at bss end */ + __bss_end__ = _ebss; + } >RAM + + /* User_heap_stack section, used to check that there is enough RAM left */ + ._user_heap_stack : + { + . = ALIGN(4); + PROVIDE ( end = . ); + PROVIDE ( _end = . ); + . = . + _Min_Heap_Size; + . = . + _Min_Stack_Size; + . = ALIGN(4); + } >RAM + + + /* Remove information from the standard libraries */ + /DISCARD/ : + { + libc.a ( * ) + libm.a ( * ) + libgcc.a ( * ) + } + + .ARM.attributes 0 : { *(.ARM.attributes) } +} + + diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FLY_SUPER8/variant.cpp b/buildroot/share/PlatformIO/variants/MARLIN_FLY_SUPER8/variant.cpp new file mode 100644 index 0000000000..1c7aedd9ac --- /dev/null +++ b/buildroot/share/PlatformIO/variants/MARLIN_FLY_SUPER8/variant.cpp @@ -0,0 +1,212 @@ +/* + ******************************************************************************* + * Copyright (c) 2017, STMicroelectronics + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ******************************************************************************* + */ + +#include "pins_arduino.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +const PinName digitalPin[] = { +PA_1, +PA_2, +PA_3, +PA_4, +PA_5, +PA_6, +PA_7, +PA_8, +PA_9, +PA_10, +PA_11, +PA_12, +PA_13, +PA_14, +PA_15, +PB_0, +PB_1, +PB_2, +PB_3, +PB_4, +PB_5, +PB_6, +PB_7, +PB_8, +PB_9, +PB_10, +PB_11, +PB_12, +PB_13, +PB_14, +PB_15, +PC_2, +PC_3, +PC_4, +PC_5, +PC_6, +PC_7, +PC_8, +PC_9, +PC_10, +PC_11, +PC_12, +PC_13, +PC_14, +PC_15, +PD_0, +PD_1, +PD_2, +PD_3, +PD_4, +PD_5, +PD_6, +PD_7, +PD_8, +PD_9, +PD_10, +PD_11, +PD_12, +PD_13, +PD_14, +PD_15, +PE_0, +PE_1, +PE_11, +PE_3, +PE_4, +PE_5, +PE_6, +PE_7, +PE_8, +PE_9, +PE_10, +PE_2, +PE_12, +PE_13, +PE_14, +PE_15, +PF_0, +PF_1, +PF_2, +PF_6, +PF_7, +PF_8, +PF_9, +PF_11, +PF_12, +PF_13, +PF_14, +PF_15, +PG_0, +PG_1, +PG_2, +PG_3, +PG_4, +PG_5, +PG_6, +PG_7, +PG_8, +PG_9, +PG_10, +PG_11, +PG_12, +PG_13, +PG_14, +PG_15, +PH_0, +PH_1, +PA_0, +PC_1, +PC_0, +PF_10, +PF_5, +PF_4, +PF_3, +}; + +#ifdef __cplusplus +} +#endif + +// ---------------------------------------------------------------------------- + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief System Clock Configuration + * @param None + * @retval None + */ +WEAK void SystemClock_Config(void) +{ + + RCC_OscInitTypeDef RCC_OscInitStruct; + RCC_ClkInitTypeDef RCC_ClkInitStruct; + + /**Configure the main internal regulator output voltage + */ + __HAL_RCC_PWR_CLK_ENABLE(); + + __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); + + /**Initializes the CPU, AHB and APB busses clocks + */ + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; + RCC_OscInitStruct.HSEState = RCC_HSE_ON; + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; + RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; + RCC_OscInitStruct.PLL.PLLM = 8; + RCC_OscInitStruct.PLL.PLLN = 336; + RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; + RCC_OscInitStruct.PLL.PLLQ = 7; + if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { + _Error_Handler(__FILE__, __LINE__); + } + + /**Initializes the CPU, AHB and APB busses clocks + */ + RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK + | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2; + RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; + RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; + RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; + RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; + + if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK) { + _Error_Handler(__FILE__, __LINE__); + } +} + +#ifdef __cplusplus +} +#endif diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FLY_SUPER8/variant.h b/buildroot/share/PlatformIO/variants/MARLIN_FLY_SUPER8/variant.h new file mode 100644 index 0000000000..075e9b368e --- /dev/null +++ b/buildroot/share/PlatformIO/variants/MARLIN_FLY_SUPER8/variant.h @@ -0,0 +1,233 @@ +/* + ******************************************************************************* + * Copyright (c) 2017, STMicroelectronics + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ******************************************************************************* + */ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/*---------------------------------------------------------------------------- + * Pins + *----------------------------------------------------------------------------*/ + +#define PA1 0 +#define PA2 1 +#define PA3 2 +#define PA4 3 +#define PA5 4 +#define PA6 5 +#define PA7 6 +#define PA8 7 +#define PA9 8 +#define PA10 9 +#define PA11 10 +#define PA12 11 +#define PA13 12 +#define PA14 13 +#define PA15 14 +#define PB0 15 +#define PB1 16 +#define PB2 17 +#define PB3 18 +#define PB4 19 +#define PB5 20 +#define PB6 21 +#define PB7 22 +#define PB8 23 +#define PB9 24 +#define PB10 25 +#define PB11 26 +#define PB12 27 +#define PB13 28 +#define PB14 29 +#define PB15 30 +#define PC2 31 +#define PC3 32 +#define PC4 33 +#define PC5 34 +#define PC6 35 +#define PC7 36 +#define PC8 37 +#define PC9 38 +#define PC10 39 +#define PC11 40 +#define PC12 41 +#define PC13 42 +#define PC14 43 +#define PC15 44 +#define PD0 45 +#define PD1 46 +#define PD2 47 +#define PD3 48 +#define PD4 49 +#define PD5 50 +#define PD6 51 +#define PD7 52 +#define PD8 53 +#define PD9 54 +#define PD10 55 +#define PD11 56 +#define PD12 57 +#define PD13 58 +#define PD14 59 +#define PD15 60 +#define PE0 61 +#define PE1 62 +#define PE11 63 +#define PE3 64 +#define PE4 65 +#define PE5 66 +#define PE6 67 +#define PE7 68 +#define PE8 69 +#define PE9 70 +#define PE10 71 +#define PE2 72 +#define PE12 73 +#define PE13 74 +#define PE14 75 +#define PE15 76 +#define PF0 77 +#define PF1 78 +#define PF2 79 +#define PF6 80 +#define PF7 81 +#define PF8 82 +#define PF9 83 +#define PF11 84 +#define PF12 85 +#define PF13 86 +#define PF14 87 +#define PF15 88 +#define PG0 89 +#define PG1 90 +#define PG2 91 +#define PG3 92 +#define PG4 93 +#define PG5 94 +#define PG6 95 +#define PG7 96 +#define PG8 97 +#define PG9 98 +#define PG10 99 +#define PG11 100 +#define PG12 101 +#define PG13 102 +#define PG14 103 +#define PG15 104 +#define PH0 105 +#define PH1 106 +#define PA0 107 +#define PC1 108 +#define PC0 109 +#define PF10 110 +#define PF5 111 +#define PF4 112 +#define PF3 113 + +// This must be a literal +#define NUM_DIGITAL_PINS 114 +// This must be a literal with a value less than or equal to MAX_ANALOG_INPUTS +#define NUM_ANALOG_INPUTS 7 +#define NUM_ANALOG_FIRST 107 + + +// Below SPI and I2C definitions already done in the core +// Could be redefined here if differs from the default one +// SPI Definitions +#define PIN_SPI_SS PA4 +#define PIN_SPI_MOSI PA7 +#define PIN_SPI_MISO PA6 +#define PIN_SPI_SCK PA5 + +//max6675 +//#define PIN_SPI_SS PA4 +//#define PIN_SPI_SCK PA5 +//#define PIN_SPI_MISO PA6 +//#define PIN_SPI_MOSI PA7 + +// Timer Definitions +// Do not use timer used by PWM pins when possible. See PinMap_PWM in PeripheralPins.c +#define TIMER_TONE TIM6 // TIMER_TONE must be defined in this file + +// Do not use basic timer: OC is required +#define TIMER_SERVO TIM1 // TODO: advanced-control timers don't work + +// UART Definitions +// Define here Serial instance number to map on Serial generic name +#define SERIAL_UART_INSTANCE 1 //ex: 2 for Serial2 (USART2) +// DEBUG_UART could be redefined to print on another instance than 'Serial' +//#define DEBUG_UART ((USART_TypeDef *) U(S)ARTX) // ex: USART3 +// DEBUG_UART baudrate, default: 9600 if not defined +//#define DEBUG_UART_BAUDRATE x +// DEBUG_UART Tx pin name, default: the first one found in PinMap_UART_TX for DEBUG_UART +//#define DEBUG_PINNAME_TX PX_n // PinName used for TX + +// Default pin used for 'Serial' instance (ex: ST-Link) +// Mandatory for Firmata +#define PIN_SERIAL_RX PA10 +#define PIN_SERIAL_TX PA9 + +/* Extra HAL modules */ +#ifndef HAL_DAC_MODULE_ENABLED + //#define HAL_DAC_MODULE_ENABLED +#endif +#ifndef HAL_SD_MODULE_ENABLED + #define HAL_SD_MODULE_ENABLED +#endif + +#ifdef __cplusplus +} // extern "C" +#endif + +/*---------------------------------------------------------------------------- + * Arduino objects - C++ only + *----------------------------------------------------------------------------*/ + +#ifdef __cplusplus +// These serial port names are intended to allow libraries and architecture-neutral +// sketches to automatically default to the correct port name for a particular type +// of use. For example, a GPS module would normally connect to SERIAL_PORT_HARDWARE_OPEN, +// the first hardware serial port whose RX/TX pins are not dedicated to another use. +// +// SERIAL_PORT_MONITOR Port which normally prints to the Arduino Serial Monitor +// +// SERIAL_PORT_USBVIRTUAL Port which is USB virtual serial +// +// SERIAL_PORT_LINUXBRIDGE Port which connects to a Linux system via Bridge library +// +// SERIAL_PORT_HARDWARE Hardware serial port, physical RX & TX pins. +// +// SERIAL_PORT_HARDWARE_OPEN Hardware serial ports which are open for use. Their RX & TX +// pins are NOT connected to anything by default. +#define SERIAL_PORT_MONITOR Serial +#define SERIAL_PORT_HARDWARE Serial1 + +#endif diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FLY_SUPER8_PRO/PeripheralPins.c b/buildroot/share/PlatformIO/variants/MARLIN_FLY_SUPER8_PRO/PeripheralPins.c new file mode 100644 index 0000000000..21d2c4b1fe --- /dev/null +++ b/buildroot/share/PlatformIO/variants/MARLIN_FLY_SUPER8_PRO/PeripheralPins.c @@ -0,0 +1,688 @@ +/* + ******************************************************************************* + * Copyright (c) 2020-2021, STMicroelectronics + * All rights reserved. + * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ******************************************************************************* + */ +/* + * Automatically generated from STM32H723ZETx.xml, STM32H723ZGTx.xml + * STM32H733ZGTx.xml + * CubeMX DB release 6.0.30 + */ +#if !defined(CUSTOM_PERIPHERAL_PINS) +#include "Arduino.h" +#include "PeripheralPins.h" + +/* ===== + * Notes: + * - The pins mentioned Px_y_ALTz are alternative possibilities which use other + * HW peripheral instances. You can use them the same way as any other "normal" + * pin (i.e. analogWrite(PA7_ALT1, 128);). + * + * - Commented lines are alternative possibilities which are not used per default. + * If you change them, you will have to know what you do + * ===== + */ + +//*** ADC *** + +#ifdef HAL_ADC_MODULE_ENABLED +WEAK const PinMap PinMap_ADC[] = { + // {PA_0, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 16, 0)}, // ADC1_INP16 + // {PA_1, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 17, 0)}, // ADC1_INP17 + // {PA_2, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 14, 0)}, // ADC1_INP14 + // {PA_2_ALT1, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 14, 0)}, // ADC2_INP14 + // {PA_3, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 15, 0)}, // ADC1_INP15 + // {PA_3_ALT1, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 15, 0)}, // ADC2_INP15 + // {PA_4, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 18, 0)}, // ADC1_INP18 + // {PA_4_ALT1, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 18, 0)}, // ADC2_INP18 + // {PA_5, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 19, 0)}, // ADC1_INP19 + // {PA_5_ALT1, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 19, 0)}, // ADC2_INP19 + // {PA_6, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 3, 0)}, // ADC1_INP3 + // {PA_6_ALT1, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 3, 0)}, // ADC2_INP3 + // {PA_7, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 7, 0)}, // ADC1_INP7 + // {PA_7_ALT1, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 7, 0)}, // ADC2_INP7 + // {PB_0, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 9, 0)}, // ADC1_INP9 + // {PB_0_ALT1, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 9, 0)}, // ADC2_INP9 + // {PB_1, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 5, 0)}, // ADC1_INP5 + // {PB_1_ALT1, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 5, 0)}, // ADC2_INP5 + {PC_0, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 10, 0)}, // ADC1_INP10 + // {PC_0_ALT1, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 10, 0)}, // ADC2_INP10 + // {PC_0_ALT2, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 10, 0)}, // ADC3_INP10 + {PC_1, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 11, 0)}, // ADC1_INP11 + // {PC_1_ALT1, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 11, 0)}, // ADC2_INP11 + // {PC_1_ALT2, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 11, 0)}, // ADC3_INP11 + // {PC_2_C, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 0, 0)}, // ADC3_INP0 + // {PC_3_C, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 1, 0)}, // ADC3_INP1 + // {PC_4, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 4, 0)}, // ADC1_INP4 + // {PC_4_ALT1, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 4, 0)}, // ADC2_INP4 + // {PC_5, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 8, 0)}, // ADC1_INP8 + // {PC_5_ALT1, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 8, 0)}, // ADC2_INP8 + // {PF_3, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 5, 0)}, // ADC3_INP5 + {PF_4, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 9, 0)}, // ADC3_INP9 + {PF_5, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 4, 0)}, // ADC3_INP4 + // {PF_6, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 8, 0)}, // ADC3_INP8 + // {PF_7, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 3, 0)}, // ADC3_INP3 + // {PF_8, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 7, 0)}, // ADC3_INP7 + {PF_9, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 2, 0)}, // ADC3_INP2 + {PF_10, ADC3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 6, 0)}, // ADC3_INP6 + // {PF_11, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 2, 0)}, // ADC1_INP2 + // {PF_12, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 6, 0)}, // ADC1_INP6 + // {PF_13, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 2, 0)}, // ADC2_INP2 + // {PF_14, ADC2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 6, 0)}, // ADC2_INP6 + {NC, NP, 0} +}; +#endif + +//*** DAC *** + +#ifdef HAL_DAC_MODULE_ENABLED +WEAK const PinMap PinMap_DAC[] = { + // {PA_4, DAC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 1, 0)}, // DAC1_OUT1 + // {PA_5, DAC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 2, 0)}, // DAC1_OUT2 + {NC, NP, 0} +}; +#endif + +//*** I2C *** + +#ifdef HAL_I2C_MODULE_ENABLED +WEAK const PinMap PinMap_I2C_SDA[] = { + {PB_7, I2C1, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C1)}, + // {PB_7_ALT1, I2C4, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF6_I2C4)}, + // {PB_9, I2C1, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C1)}, + // {PB_9_ALT1, I2C4, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF6_I2C4)}, + // {PB_11, I2C2, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C2)}, + // {PC_9, I2C3, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C3)}, + // {PC_9_ALT1, I2C5, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF6_I2C5)}, + // {PC_10, I2C5, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C5)}, + // {PD_13, I2C4, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C4)}, + // {PF_0, I2C2, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C2)}, + // {PF_0_ALT1, I2C5, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF6_I2C5)}, + // {PF_15, I2C4, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C4)}, + {NC, NP, 0} +}; +#endif + +#ifdef HAL_I2C_MODULE_ENABLED +WEAK const PinMap PinMap_I2C_SCL[] = { + // {PA_8, I2C3, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C3)}, + // {PA_8_ALT1, I2C5, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF6_I2C5)}, + {PB_6, I2C1, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C1)}, + // {PB_6_ALT1, I2C4, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF6_I2C4)}, + // {PB_8, I2C1, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C1)}, + // {PB_8_ALT1, I2C4, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF6_I2C4)}, + // {PB_10, I2C2, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C2)}, + // {PC_11, I2C5, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C5)}, + // {PD_12, I2C4, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C4)}, + // {PF_1, I2C2, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C2)}, + // {PF_1_ALT1, I2C5, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF6_I2C5)}, + // {PF_14, I2C4, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C4)}, + {NC, NP, 0} +}; +#endif + +//*** TIM *** + +#ifdef HAL_TIM_MODULE_ENABLED +WEAK const PinMap PinMap_TIM[] = { + // {PA_0, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 1, 0)}, // TIM2_CH1 + {PA_0_ALT1, TIM5, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM5, 1, 0)}, // TIM5_CH1 + {PA_1, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 2, 0)}, // TIM2_CH2 + // {PA_1_ALT1, TIM5, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM5, 2, 0)}, // TIM5_CH2 + // {PA_1_ALT2, TIM15, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_TIM15, 1, 1)}, // TIM15_CH1N + // {PA_2, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 3, 0)}, // TIM2_CH3 + {PA_2_ALT1, TIM5, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM5, 3, 0)}, // TIM5_CH3 + // {PA_2_ALT2, TIM15, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_TIM15, 1, 0)}, // TIM15_CH1 + // {PA_3, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 4, 0)}, // TIM2_CH4 + {PA_3_ALT1, TIM5, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM5, 4, 0)}, // TIM5_CH4 + // {PA_3_ALT2, TIM15, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_TIM15, 2, 0)}, // TIM15_CH2 + // {PA_5, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 1, 0)}, // TIM2_CH1 + // {PA_5_ALT1, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 1, 1)}, // TIM8_CH1N + // {PA_6, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 1, 0)}, // TIM3_CH1 + // {PA_6_ALT1, TIM13, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_TIM13, 1, 0)}, // TIM13_CH1 + // {PA_7, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 1, 1)}, // TIM1_CH1N + // {PA_7_ALT1, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 2, 0)}, // TIM3_CH2 + // {PA_7_ALT2, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 1, 1)}, // TIM8_CH1N + // {PA_7_ALT3, TIM14, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_TIM14, 1, 0)}, // TIM14_CH1 + // {PA_8, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 1, 0)}, // TIM1_CH1 + // {PA_9, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 2, 0)}, // TIM1_CH2 + // {PA_10, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 3, 0)}, // TIM1_CH3 + // {PA_11, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 4, 0)}, // TIM1_CH4 + {PA_15, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 1, 0)}, // TIM2_CH1 + {PB_0, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 2, 1)}, // TIM1_CH2N + // {PB_0_ALT1, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 3, 0)}, // TIM3_CH3 + // {PB_0_ALT2, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 2, 1)}, // TIM8_CH2N + {PB_1, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 3, 1)}, // TIM1_CH3N + // {PB_1_ALT1, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 4, 0)}, // TIM3_CH4 + // {PB_1_ALT2, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 3, 1)}, // TIM8_CH3N + // {PB_3, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 2, 0)}, // TIM2_CH2 + // {PB_4, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 1, 0)}, // TIM3_CH1 + // {PB_5, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 2, 0)}, // TIM3_CH2 + // {PB_6, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 1, 0)}, // TIM4_CH1 + // {PB_6_ALT1, TIM16, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM16, 1, 1)}, // TIM16_CH1N + // {PB_7, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 2, 0)}, // TIM4_CH2 + // {PB_7_ALT1, TIM17, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM17, 1, 1)}, // TIM17_CH1N + // {PB_8, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 3, 0)}, // TIM4_CH3 + // {PB_8_ALT1, TIM16, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM16, 1, 0)}, // TIM16_CH1 + // {PB_9, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 4, 0)}, // TIM4_CH4 + // {PB_9_ALT1, TIM17, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM17, 1, 0)}, // TIM17_CH1 + {PB_10, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 3, 0)}, // TIM2_CH3 + {PB_11, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 4, 0)}, // TIM2_CH4 + // {PB_13, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 1, 1)}, // TIM1_CH1N + // {PB_14, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 2, 1)}, // TIM1_CH2N + // {PB_14_ALT1, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 2, 1)}, // TIM8_CH2N + // {PB_14_ALT2, TIM12, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM12, 1, 0)}, // TIM12_CH1 + // {PB_15, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 3, 1)}, // TIM1_CH3N + // {PB_15_ALT1, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 3, 1)}, // TIM8_CH3N + // {PB_15_ALT2, TIM12, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM12, 2, 0)}, // TIM12_CH2 + // {PC_6, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 1, 0)}, // TIM3_CH1 + // {PC_6_ALT1, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 1, 0)}, // TIM8_CH1 + {PC_7, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 2, 0)}, // TIM3_CH2 + // {PC_7_ALT1, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 2, 0)}, // TIM8_CH2 + // {PC_8, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 3, 0)}, // TIM3_CH3 + // {PC_8_ALT1, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 3, 0)}, // TIM8_CH3 + // {PC_9, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 4, 0)}, // TIM3_CH4 + // {PC_9_ALT1, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 4, 0)}, // TIM8_CH4 + // {PC_12, TIM15, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM15, 1, 0)}, // TIM15_CH1 + {PD_12, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 1, 0)}, // TIM4_CH1 + // {PD_13, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 2, 0)}, // TIM4_CH2 + {PD_14, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 3, 0)}, // TIM4_CH3 + {PD_15, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 4, 0)}, // TIM4_CH4 + // {PE_4, TIM15, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_TIM15, 1, 1)}, // TIM15_CH1N + {PE_5, TIM15, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_TIM15, 1, 0)}, // TIM15_CH1 + // {PE_6, TIM15, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_TIM15, 2, 0)}, // TIM15_CH2 + // {PE_8, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 1, 1)}, // TIM1_CH1N + // {PE_9, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 1, 0)}, // TIM1_CH1 + // {PE_10, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 2, 1)}, // TIM1_CH2N + // {PE_11, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 2, 0)}, // TIM1_CH2 + // {PE_12, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 3, 1)}, // TIM1_CH3N + // {PE_13, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 3, 0)}, // TIM1_CH3 + // {PE_14, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 4, 0)}, // TIM1_CH4 + // {PF_0, TIM23, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF13_TIM23, 1, 0)}, // TIM23_CH1 + // {PF_1, TIM23, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF13_TIM23, 2, 0)}, // TIM23_CH2 + // {PF_2, TIM23, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF13_TIM23, 3, 0)}, // TIM23_CH3 + // {PF_3, TIM23, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF13_TIM23, 4, 0)}, // TIM23_CH4 + // {PF_6, TIM16, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM16, 1, 0)}, // TIM16_CH1 + {PF_6_ALT1, TIM23, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF13_TIM23, 1, 0)}, // TIM23_CH1 + {PF_7, TIM17, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM17, 1, 0)}, // TIM17_CH1 + // {PF_7_ALT1, TIM23, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF13_TIM23, 2, 0)}, // TIM23_CH2 + // {PF_8, TIM13, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_TIM13, 1, 0)}, // TIM13_CH1 + // {PF_8_ALT1, TIM16, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM16, 1, 1)}, // TIM16_CH1N + // {PF_8_ALT2, TIM23, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF13_TIM23, 3, 0)}, // TIM23_CH3 + // {PF_9, TIM14, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_TIM14, 1, 0)}, // TIM14_CH1 + // {PF_9_ALT1, TIM17, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM17, 1, 1)}, // TIM17_CH1N + // {PF_9_ALT2, TIM23, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF13_TIM23, 4, 0)}, // TIM23_CH4 + // {PF_11, TIM24, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF14_TIM24, 1, 0)}, // TIM24_CH1 + // {PF_12, TIM24, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF14_TIM24, 2, 0)}, // TIM24_CH2 + // {PF_13, TIM24, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF14_TIM24, 3, 0)}, // TIM24_CH3 + // {PF_14, TIM24, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF14_TIM24, 4, 0)}, // TIM24_CH4 + // {PG_12, TIM23, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF13_TIM23, 1, 0)}, // TIM23_CH1 + // {PG_13, TIM23, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF13_TIM23, 2, 0)}, // TIM23_CH2 + // {PG_14, TIM23, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF13_TIM23, 3, 0)}, // TIM23_CH3 + {NC, NP, 0} +}; +#endif + +//*** UART *** + +#ifdef HAL_UART_MODULE_ENABLED +WEAK const PinMap PinMap_UART_TX[] = { + // {PA_0, UART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART4)}, + // {PA_2, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)}, + // {PA_9, LPUART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_LPUART)}, + {PA_9_ALT1, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART1)}, + // {PA_12, UART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_UART4)}, + // {PA_15, UART7, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_UART7)}, + // {PB_4, UART7, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_UART7)}, + // {PB_6, LPUART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_LPUART)}, + // {PB_6_ALT1, UART5, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF14_UART5)}, + // {PB_6_ALT2, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART1)}, + // {PB_9, UART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART4)}, + // {PB_10, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + // {PB_13, UART5, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF14_UART5)}, + // {PB_14, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_USART1)}, + // {PC_6, USART6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART6)}, + // {PC_10, UART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART4)}, + // {PC_10_ALT1, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + // {PC_12, UART5, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART5)}, + // {PD_1, UART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART4)}, + // {PD_5, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)}, + // {PD_8, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + // {PD_15, UART9, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_UART9)}, + // {PE_1, UART8, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART8)}, + // {PE_3, USART10, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_USART10)}, + // {PE_8, UART7, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_UART7)}, + // {PF_7, UART7, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_UART7)}, + // {PG_1, UART9, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_UART9)}, + // {PG_12, USART10, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_USART10)}, + // {PG_14, USART6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART6)}, + {NC, NP, 0} +}; +#endif + +#ifdef HAL_UART_MODULE_ENABLED +WEAK const PinMap PinMap_UART_RX[] = { + // {PA_1, UART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART4)}, + // {PA_3, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)}, + // {PA_8, UART7, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_UART7)}, + // {PA_10, LPUART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_LPUART)}, + {PA_10_ALT1, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART1)}, + // {PA_11, UART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_UART4)}, + // {PB_3, UART7, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_UART7)}, + // {PB_5, UART5, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF14_UART5)}, + // {PB_7, LPUART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_LPUART)}, + // {PB_7_ALT1, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART1)}, + // {PB_8, UART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART4)}, + // {PB_11, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + // {PB_12, UART5, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF14_UART5)}, + // {PB_15, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_USART1)}, + // {PC_7, USART6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART6)}, + // {PC_11, UART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART4)}, + // {PC_11_ALT1, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + // {PD_0, UART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART4)}, + // {PD_2, UART5, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART5)}, + // {PD_6, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)}, + // {PD_9, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + // {PD_14, UART9, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_UART9)}, + // {PE_0, UART8, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART8)}, + // {PE_2, USART10, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_USART10)}, + // {PE_7, UART7, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_UART7)}, + // {PF_6, UART7, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_UART7)}, + // {PG_0, UART9, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_UART9)}, + // {PG_9, USART6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART6)}, + // {PG_11, USART10, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_USART10)}, + {NC, NP, 0} +}; +#endif + +#ifdef HAL_UART_MODULE_ENABLED +WEAK const PinMap PinMap_UART_RTS[] = { + // {PA_1, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)}, + // {PA_12, LPUART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_LPUART)}, + // {PA_12_ALT1, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART1)}, + // {PA_15, UART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART4)}, + // {PB_14, UART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART4)}, + // {PB_14_ALT1, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + // {PC_8, UART5, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART5)}, + // {PD_4, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)}, + // {PD_12, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + // {PD_13, UART9, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_UART9)}, + // {PD_15, UART8, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART8)}, + // {PE_9, UART7, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_UART7)}, + // {PF_8, UART7, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_UART7)}, + // {PG_8, USART6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART6)}, + // {PG_12, USART6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART6)}, + // {PG_14, USART10, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_USART10)}, + {NC, NP, 0} +}; +#endif + +#ifdef HAL_UART_MODULE_ENABLED +WEAK const PinMap PinMap_UART_CTS[] = { + // {PA_0, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)}, + // {PA_11, LPUART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_LPUART)}, + // {PA_11_ALT1, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART1)}, + // {PB_0, UART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART4)}, + // {PB_13, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + // {PB_15, UART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART4)}, + // {PC_9, UART5, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART5)}, + // {PD_0, UART9, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_UART9)}, + // {PD_3, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)}, + // {PD_11, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART3)}, + // {PD_14, UART8, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART8)}, + // {PE_10, UART7, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_UART7)}, + // {PF_9, UART7, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_UART7)}, + // {PG_13, USART10, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_USART10)}, + // {PG_13_ALT1, USART6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART6)}, + // {PG_15, USART6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART6)}, + {NC, NP, 0} +}; +#endif + +//*** SPI *** + +#ifdef HAL_SPI_MODULE_ENABLED +WEAK const PinMap PinMap_SPI_MOSI[] = { + {PA_7, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, + // {PA_7_ALT1, SPI6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_SPI6)}, + // {PB_2, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_SPI3)}, + // {PB_5, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, + {PB_5_ALT1, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_SPI3)}, + // {PB_5_ALT2, SPI6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_SPI6)}, + {PB_15, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + // {PC_1, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + // {PC_3_C, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + // {PC_12, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)}, + // {PD_6, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI3)}, + // {PD_7, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, + // {PE_6, SPI4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI4)}, + // {PE_14, SPI4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI4)}, + // {PF_9, SPI5, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI5)}, + // {PF_11, SPI5, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI5)}, + // {PG_14, SPI6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI6)}, + {NC, NP, 0} +}; +#endif + +#ifdef HAL_SPI_MODULE_ENABLED +WEAK const PinMap PinMap_SPI_MISO[] = { + {PA_6, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, + // {PA_6_ALT1, SPI6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_SPI6)}, + // {PB_4, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, + {PB_4_ALT1, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)}, + // {PB_4_ALT2, SPI6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_SPI6)}, + {PB_14, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + // {PC_2_C, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + // {PC_11, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)}, + // {PE_5, SPI4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI4)}, + // {PE_13, SPI4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI4)}, + // {PF_8, SPI5, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI5)}, + // {PG_9, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, + // {PG_12, SPI6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI6)}, + {NC, NP, 0} +}; +#endif + +#ifdef HAL_SPI_MODULE_ENABLED +WEAK const PinMap PinMap_SPI_SCLK[] = { + {PA_5, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, + // {PA_5_ALT1, SPI6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_SPI6)}, + // {PA_9, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + // {PA_12, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + // {PB_3, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, + {PB_3_ALT1, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)}, + // {PB_3_ALT2, SPI6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_SPI6)}, + // {PB_10, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + {PB_13, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + // {PC_10, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)}, + // {PC_12, SPI6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI6)}, + // {PD_3, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + // {PE_2, SPI4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI4)}, + // {PE_12, SPI4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI4)}, + // {PF_7, SPI5, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI5)}, + // {PG_11, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, + // {PG_13, SPI6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI6)}, + {NC, NP, 0} +}; +#endif + +#ifdef HAL_SPI_MODULE_ENABLED +WEAK const PinMap PinMap_SPI_SSEL[] = { + // {PA_0, SPI6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI6)}, + {PA_4, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, + // {PA_4_ALT1, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)}, + // {PA_4_ALT2, SPI6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_SPI6)}, + // {PA_11, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + // {PA_15, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, + // {PA_15_ALT1, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)}, + // {PA_15_ALT2, SPI6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_SPI6)}, + // {PB_4, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_SPI2)}, + // {PB_9, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + // {PB_12, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, + // {PE_4, SPI4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI4)}, + // {PE_11, SPI4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI4)}, + // {PF_6, SPI5, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI5)}, + // {PG_8, SPI6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI6)}, + // {PG_10, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, + {NC, NP, 0} +}; +#endif + +//*** FDCAN *** + +#ifdef HAL_FDCAN_MODULE_ENABLED +WEAK const PinMap PinMap_CAN_RD[] = { + // {PA_11, FDCAN1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_FDCAN1)}, + // {PB_5, FDCAN2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_FDCAN2)}, + {PB_8, FDCAN1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_FDCAN1)}, + // {PB_12, FDCAN2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_FDCAN2)}, + // {PD_0, FDCAN1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_FDCAN1)}, + // {PD_12, FDCAN3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF5_FDCAN3)}, + // {PF_6, FDCAN3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF2_FDCAN3)}, + // {PG_10, FDCAN3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF2_FDCAN3)}, + {NC, NP, 0} +}; +#endif + +#ifdef HAL_FDCAN_MODULE_ENABLED +WEAK const PinMap PinMap_CAN_TD[] = { + // {PA_12, FDCAN1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_FDCAN1)}, + // {PB_6, FDCAN2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_FDCAN2)}, + {PB_9, FDCAN1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_FDCAN1)}, + // {PB_13, FDCAN2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_FDCAN2)}, + // {PD_1, FDCAN1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_FDCAN1)}, + // {PD_13, FDCAN3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF5_FDCAN3)}, + // {PF_7, FDCAN3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF2_FDCAN3)}, + // {PG_9, FDCAN3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF2_FDCAN3)}, + {NC, NP, 0} +}; +#endif + +//*** ETHERNET *** + +#ifdef HAL_ETH_MODULE_ENABLED +WEAK const PinMap PinMap_Ethernet[] = { + // {PA_0, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_CRS + // {PA_1, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_REF_CLK + // {PA_1_ALT1, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_RX_CLK + // {PA_2, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_MDIO + // {PA_3, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_COL + // {PA_7, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_CRS_DV + // {PA_7_ALT1, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_RX_DV + // {PA_9, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_TX_ER + // {PB_0, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_RXD2 + // {PB_1, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_RXD3 + // {PB_2, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_TX_ER + // {PB_5, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_PPS_OUT + // {PB_8, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_TXD3 + // {PB_10, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_RX_ER + // {PB_11, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_TX_EN + // {PB_12, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_TXD0 + // {PB_13, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_TXD1 + // {PC_1, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_MDC + // {PC_2_C, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_TXD2 + // {PC_3_C, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_TX_CLK + // {PC_4, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_RXD0 + // {PC_5, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_RXD1 + // {PE_2, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_TXD3 + // {PG_8, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_PPS_OUT + // {PG_11, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_TX_EN + // {PG_12, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_TXD1 + // {PG_13, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_TXD0 + // {PG_14, ETH, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_ETH)}, // ETH_TXD1 + {NC, NP, 0} +}; +#endif + +//*** OCTOSPI *** + +#ifdef HAL_OSPI_MODULE_ENABLED +WEAK const PinMap PinMap_OCTOSPI_DATA0[] = { + // {PA_2, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO0 + // {PB_1, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO0 + // {PB_12, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO0 + // {PC_3_C, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO0 + // {PC_9, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO0 + // {PD_11, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO0 + // {PF_0, OCTOSPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_OCTOSPIM_P2)}, // OCTOSPIM_P2_IO0 + // {PF_8, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO0 + {NC, NP, 0} +}; +#endif + +#ifdef HAL_OSPI_MODULE_ENABLED +WEAK const PinMap PinMap_OCTOSPI_DATA1[] = { + // {PB_0, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO1 + // {PC_10, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO1 + // {PD_12, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO1 + // {PF_1, OCTOSPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_OCTOSPIM_P2)}, // OCTOSPIM_P2_IO1 + // {PF_9, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO1 + {NC, NP, 0} +}; +#endif + +#ifdef HAL_OSPI_MODULE_ENABLED +WEAK const PinMap PinMap_OCTOSPI_DATA2[] = { + // {PA_3, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO2 + // {PA_7, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO2 + // {PB_13, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO2 + // {PC_2_C, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO2 + // {PE_2, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO2 + // {PF_2, OCTOSPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_OCTOSPIM_P2)}, // OCTOSPIM_P2_IO2 + // {PF_7, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO2 + {NC, NP, 0} +}; +#endif + +#ifdef HAL_OSPI_MODULE_ENABLED +WEAK const PinMap PinMap_OCTOSPI_DATA3[] = { + // {PA_1, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO3 + // {PA_6, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO3 + // {PD_13, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO3 + // {PF_3, OCTOSPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_OCTOSPIM_P2)}, // OCTOSPIM_P2_IO3 + // {PF_6, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO3 + {NC, NP, 0} +}; +#endif + +#ifdef HAL_OSPI_MODULE_ENABLED +WEAK const PinMap PinMap_OCTOSPI_DATA4[] = { + // {PC_1, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO4 + // {PD_4, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO4 + // {PE_7, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO4 + // {PG_0, OCTOSPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_OCTOSPIM_P2)}, // OCTOSPIM_P2_IO4 + {NC, NP, 0} +}; +#endif + +#ifdef HAL_OSPI_MODULE_ENABLED +WEAK const PinMap PinMap_OCTOSPI_DATA5[] = { + // {PC_2_C, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO5 + // {PD_5, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO5 + // {PE_8, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO5 + // {PG_1, OCTOSPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_OCTOSPIM_P2)}, // OCTOSPIM_P2_IO5 + {NC, NP, 0} +}; +#endif + +#ifdef HAL_OSPI_MODULE_ENABLED +WEAK const PinMap PinMap_OCTOSPI_DATA6[] = { + // {PC_3_C, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO6 + // {PD_6, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO6 + // {PE_9, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO6 + // {PG_9, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO6 + // {PG_10, OCTOSPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_OCTOSPIM_P2)}, // OCTOSPIM_P2_IO6 + {NC, NP, 0} +}; +#endif + +#ifdef HAL_OSPI_MODULE_ENABLED +WEAK const PinMap PinMap_OCTOSPI_DATA7[] = { + // {PD_7, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO7 + // {PE_10, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO7 + // {PG_11, OCTOSPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_OCTOSPIM_P2)}, // OCTOSPIM_P2_IO7 + // {PG_14, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_OCTOSPIM_P1)}, // OCTOSPIM_P1_IO7 + {NC, NP, 0} +}; +#endif + +#ifdef HAL_OSPI_MODULE_ENABLED +WEAK const PinMap PinMap_OCTOSPI_SCLK[] = { + // {PA_3, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_OCTOSPIM_P1)}, // OCTOSPIM_P1_CLK + // {PB_2, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_OCTOSPIM_P1)}, // OCTOSPIM_P1_CLK + // {PF_4, OCTOSPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_OCTOSPIM_P2)}, // OCTOSPIM_P2_CLK + // {PF_10, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_OCTOSPIM_P1)}, // OCTOSPIM_P1_CLK + {NC, NP, 0} +}; +#endif + +#ifdef HAL_OSPI_MODULE_ENABLED +WEAK const PinMap PinMap_OCTOSPI_SSEL[] = { + // {PB_6, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OCTOSPIM_P1)}, // OCTOSPIM_P1_NCS + // {PB_10, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_OCTOSPIM_P1)}, // OCTOSPIM_P1_NCS + // {PC_11, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_OCTOSPIM_P1)}, // OCTOSPIM_P1_NCS + // {PE_11, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_OCTOSPIM_P1)}, // OCTOSPIM_P1_NCS + // {PG_6, OCTOSPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OCTOSPIM_P1)}, // OCTOSPIM_P1_NCS + // {PG_12, OCTOSPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_OCTOSPIM_P2)}, // OCTOSPIM_P2_NCS + {NC, NP, 0} +}; +#endif + +//*** USB *** + +#if defined(HAL_PCD_MODULE_ENABLED) || defined(HAL_HCD_MODULE_ENABLED) +WEAK const PinMap PinMap_USB_OTG_HS[] = { +#ifdef USE_USB_HS_IN_FS + // {PA_8, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG1_HS)}, // USB_OTG_HS_SOF + // {PA_9, USB_OTG_HS, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, GPIO_AF_NONE)}, // USB_OTG_HS_VBUS + // {PA_10, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_PULLUP, GPIO_AF10_OTG1_HS)}, // USB_OTG_HS_ID + {PA_11, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF_NONE)}, // USB_OTG_HS_DM + {PA_12, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF_NONE)}, // USB_OTG_HS_DP +#else + // {PA_3, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG1_HS)}, // USB_OTG_HS_ULPI_D0 + // {PA_5, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG1_HS)}, // USB_OTG_HS_ULPI_CK + // {PB_0, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG1_HS)}, // USB_OTG_HS_ULPI_D1 + // {PB_1, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG1_HS)}, // USB_OTG_HS_ULPI_D2 + // {PB_5, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG1_HS)}, // USB_OTG_HS_ULPI_D7 + // {PB_10, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG1_HS)}, // USB_OTG_HS_ULPI_D3 + // {PB_11, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG1_HS)}, // USB_OTG_HS_ULPI_D4 + // {PB_12, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG1_HS)}, // USB_OTG_HS_ULPI_D5 + // {PB_13, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG1_HS)}, // USB_OTG_HS_ULPI_D6 + // {PC_0, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG1_HS)}, // USB_OTG_HS_ULPI_STP + // {PC_2_C, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG1_HS)}, // USB_OTG_HS_ULPI_DIR + // {PC_3_C, USB_OTG_HS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG1_HS)}, // USB_OTG_HS_ULPI_NXT +#endif /* USE_USB_HS_IN_FS */ + {NC, NP, 0} +}; +#endif + +//*** SD *** + +#ifdef HAL_SD_MODULE_ENABLED +WEAK const PinMap PinMap_SD[] = { + {PA_0, SDMMC2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_SDMMC2)}, // SDMMC2_CMD + {PB_3, SDMMC2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_SDMMC2)}, // SDMMC2_D2 + {PB_4, SDMMC2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_SDMMC2)}, // SDMMC2_D3 + {PB_8, SDMMC1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF7_SDMMC1)}, // SDMMC1_CKIN + {PB_8_ALT1, SDMMC1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDMMC1)}, // SDMMC1_D4 + {PB_8_ALT2, SDMMC2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_SDMMC2)}, // SDMMC2_D4 + {PB_9, SDMMC1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF7_SDMMC1)}, // SDMMC1_CDIR + {PB_9_ALT1, SDMMC1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDMMC1)}, // SDMMC1_D5 + {PB_9_ALT2, SDMMC2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_SDMMC2)}, // SDMMC2_D5 + {PB_13, SDMMC1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDMMC1)}, // SDMMC1_D0 + {PB_14, SDMMC2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_SDMMC2)}, // SDMMC2_D0 + {PB_15, SDMMC2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_SDMMC2)}, // SDMMC2_D1 + {PC_1, SDMMC2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_SDMMC2)}, // SDMMC2_CK + {PC_4, SDMMC2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF10_SDMMC2)}, // SDMMC2_CKIN + {PC_6, SDMMC1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF8_SDMMC1)}, // SDMMC1_D0DIR + {PC_6_ALT1, SDMMC1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDMMC1)}, // SDMMC1_D6 + {PC_6_ALT2, SDMMC2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_SDMMC2)}, // SDMMC2_D6 + {PC_7, SDMMC1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF8_SDMMC1)}, // SDMMC1_D123DIR + {PC_7_ALT1, SDMMC1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDMMC1)}, // SDMMC1_D7 + {PC_7_ALT2, SDMMC2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_SDMMC2)}, // SDMMC2_D7 + {PC_8, SDMMC1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDMMC1)}, // SDMMC1_D0 + {PC_9, SDMMC1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDMMC1)}, // SDMMC1_D1 + {PC_10, SDMMC1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDMMC1)}, // SDMMC1_D2 + {PC_11, SDMMC1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDMMC1)}, // SDMMC1_D3 + {PC_12, SDMMC1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF12_SDMMC1)}, // SDMMC1_CK + {PD_2, SDMMC1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF12_SDMMC1)}, // SDMMC1_CMD + {PD_6, SDMMC2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF11_SDMMC2)}, // SDMMC2_CK + {PD_7, SDMMC2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF11_SDMMC2)}, // SDMMC2_CMD + {PG_9, SDMMC2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_SDMMC2)}, // SDMMC2_D0 + {PG_10, SDMMC2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_SDMMC2)}, // SDMMC2_D1 + {PG_11, SDMMC2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_SDMMC2)}, // SDMMC2_D2 + {PG_12, SDMMC2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_SDMMC2)}, // SDMMC2_D3 + {PG_13, SDMMC2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_SDMMC2)}, // SDMMC2_D6 + {PG_14, SDMMC2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_SDMMC2)}, // SDMMC2_D7 + {NC, NP, 0} +}; +#endif + +#endif /* !CUSTOM_PERIPHERAL_PINS */ diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FLY_SUPER8_PRO/PinNamesVar.h b/buildroot/share/PlatformIO/variants/MARLIN_FLY_SUPER8_PRO/PinNamesVar.h new file mode 100644 index 0000000000..ad9d80a625 --- /dev/null +++ b/buildroot/share/PlatformIO/variants/MARLIN_FLY_SUPER8_PRO/PinNamesVar.h @@ -0,0 +1,117 @@ +/* Dual pad pin name */ +PC_2_C = PC_2 | PDUAL, +PC_3_C = PC_3 | PDUAL, + +/* Alternate pin name */ +PA_0_ALT1 = PA_0 | ALT1, +PA_1_ALT1 = PA_1 | ALT1, +PA_1_ALT2 = PA_1 | ALT2, +PA_2_ALT1 = PA_2 | ALT1, +PA_2_ALT2 = PA_2 | ALT2, +PA_3_ALT1 = PA_3 | ALT1, +PA_3_ALT2 = PA_3 | ALT2, +PA_4_ALT1 = PA_4 | ALT1, +PA_4_ALT2 = PA_4 | ALT2, +PA_5_ALT1 = PA_5 | ALT1, +PA_6_ALT1 = PA_6 | ALT1, +PA_7_ALT1 = PA_7 | ALT1, +PA_7_ALT2 = PA_7 | ALT2, +PA_7_ALT3 = PA_7 | ALT3, +PA_8_ALT1 = PA_8 | ALT1, +PA_9_ALT1 = PA_9 | ALT1, +PA_10_ALT1 = PA_10 | ALT1, +PA_11_ALT1 = PA_11 | ALT1, +PA_12_ALT1 = PA_12 | ALT1, +PA_15_ALT1 = PA_15 | ALT1, +PA_15_ALT2 = PA_15 | ALT2, +PB_0_ALT1 = PB_0 | ALT1, +PB_0_ALT2 = PB_0 | ALT2, +PB_1_ALT1 = PB_1 | ALT1, +PB_1_ALT2 = PB_1 | ALT2, +PB_3_ALT1 = PB_3 | ALT1, +PB_3_ALT2 = PB_3 | ALT2, +PB_4_ALT1 = PB_4 | ALT1, +PB_4_ALT2 = PB_4 | ALT2, +PB_5_ALT1 = PB_5 | ALT1, +PB_5_ALT2 = PB_5 | ALT2, +PB_6_ALT1 = PB_6 | ALT1, +PB_6_ALT2 = PB_6 | ALT2, +PB_7_ALT1 = PB_7 | ALT1, +PB_8_ALT1 = PB_8 | ALT1, +PB_8_ALT2 = PB_8 | ALT2, +PB_9_ALT1 = PB_9 | ALT1, +PB_9_ALT2 = PB_9 | ALT2, +PB_14_ALT1 = PB_14 | ALT1, +PB_14_ALT2 = PB_14 | ALT2, +PB_15_ALT1 = PB_15 | ALT1, +PB_15_ALT2 = PB_15 | ALT2, +PC_0_ALT1 = PC_0 | ALT1, +PC_0_ALT2 = PC_0 | ALT2, +PC_1_ALT1 = PC_1 | ALT1, +PC_1_ALT2 = PC_1 | ALT2, +PC_4_ALT1 = PC_4 | ALT1, +PC_5_ALT1 = PC_5 | ALT1, +PC_6_ALT1 = PC_6 | ALT1, +PC_6_ALT2 = PC_6 | ALT2, +PC_7_ALT1 = PC_7 | ALT1, +PC_7_ALT2 = PC_7 | ALT2, +PC_8_ALT1 = PC_8 | ALT1, +PC_9_ALT1 = PC_9 | ALT1, +PC_10_ALT1 = PC_10 | ALT1, +PC_11_ALT1 = PC_11 | ALT1, +PF_0_ALT1 = PF_0 | ALT1, +PF_1_ALT1 = PF_1 | ALT1, +PF_6_ALT1 = PF_6 | ALT1, +PF_7_ALT1 = PF_7 | ALT1, +PF_8_ALT1 = PF_8 | ALT1, +PF_8_ALT2 = PF_8 | ALT2, +PF_9_ALT1 = PF_9 | ALT1, +PF_9_ALT2 = PF_9 | ALT2, +PG_13_ALT1 = PG_13 | ALT1, + +/* SYS_WKUP */ +#ifdef PWR_WAKEUP_PIN1 + SYS_WKUP1 = PA_0, +#endif +#ifdef PWR_WAKEUP_PIN2 + SYS_WKUP2 = PA_2, +#endif +#ifdef PWR_WAKEUP_PIN3 + SYS_WKUP3 = NC, +#endif +#ifdef PWR_WAKEUP_PIN4 + SYS_WKUP4 = PC_13, +#endif +#ifdef PWR_WAKEUP_PIN5 + SYS_WKUP5 = NC, +#endif +#ifdef PWR_WAKEUP_PIN6 + SYS_WKUP6 = PC_1, +#endif +#ifdef PWR_WAKEUP_PIN7 + SYS_WKUP7 = NC, +#endif +#ifdef PWR_WAKEUP_PIN8 + SYS_WKUP8 = NC, +#endif + +/* USB */ +#ifdef USBCON + USB_OTG_HS_DM = PA_11, + USB_OTG_HS_DP = PA_12, + USB_OTG_HS_ID = PA_10, + USB_OTG_HS_SOF = PA_8, + USB_OTG_HS_ULPI_CK = PA_5, + USB_OTG_HS_ULPI_D0 = PA_3, + USB_OTG_HS_ULPI_D1 = PB_0, + USB_OTG_HS_ULPI_D2 = PB_1, + USB_OTG_HS_ULPI_D3 = PB_10, + USB_OTG_HS_ULPI_D4 = PB_11, + USB_OTG_HS_ULPI_D5 = PB_12, + USB_OTG_HS_ULPI_D6 = PB_13, + USB_OTG_HS_ULPI_D7 = PB_5, + USB_OTG_HS_ULPI_DIR = PC_2_C, + USB_OTG_HS_ULPI_NXT = PC_3_C, + USB_OTG_HS_ULPI_STP = PC_0, + USB_OTG_HS_VBUS = PA_9, +#endif diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FLY_SUPER8_PRO/ldscript.ld b/buildroot/share/PlatformIO/variants/MARLIN_FLY_SUPER8_PRO/ldscript.ld new file mode 100644 index 0000000000..6322861033 --- /dev/null +++ b/buildroot/share/PlatformIO/variants/MARLIN_FLY_SUPER8_PRO/ldscript.ld @@ -0,0 +1,174 @@ +/* +****************************************************************************** +** +** File : LinkerScript.ld +** +** Author : STM32CubeIDE +** +** Abstract : Linker script for STM32H7 series +** 512Kbytes FLASH and 560Kbytes RAM +** +** Set heap size, stack size and stack location according +** to application requirements. +** +** Set memory bank area and size if external memory is used. +** +** Target : STMicroelectronics STM32 +** +** Distribution: The file is distributed as is, without any warranty +** of any kind. +** +***************************************************************************** +** @attention +** +** Copyright (c) 2022 STMicroelectronics. +** All rights reserved. +** +** This software is licensed under terms that can be found in the LICENSE file +** in the root directory of this software component. +** If no LICENSE file comes with this software, it is provided AS-IS. +** +**************************************************************************** +*/ + +/* Entry Point */ +ENTRY(Reset_Handler) + +/* Highest address of the user mode stack */ +_estack = ORIGIN(RAM_D1) + LENGTH(RAM_D1); /* end of RAM */ +/* Generate a link error if heap and stack don't fit into RAM */ +_Min_Heap_Size = 0x200 ; /* required amount of heap */ +_Min_Stack_Size = 0x400 ; /* required amount of stack */ + +/* Specify the memory areas */ +MEMORY +{ + ITCMRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 64K + DTCMRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K + FLASH (rx) : ORIGIN = 0x8000000 + LD_FLASH_OFFSET, LENGTH = LD_MAX_SIZE - LD_FLASH_OFFSET + RAM_D1 (xrw) : ORIGIN = 0x24000000, LENGTH = 320K + RAM_D2 (xrw) : ORIGIN = 0x30000000, LENGTH = 32K + RAM_D3 (xrw) : ORIGIN = 0x38000000, LENGTH = 16K +} + +/* Define output sections */ +SECTIONS +{ + /* The startup code goes first into FLASH */ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + . = ALIGN(4); + } >FLASH + + /* The program code and other data goes into FLASH */ + .text : + { + . = ALIGN(4); + *(.text) /* .text sections (code) */ + *(.text*) /* .text* sections (code) */ + *(.glue_7) /* glue arm to thumb code */ + *(.glue_7t) /* glue thumb to arm code */ + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + . = ALIGN(4); + _etext = .; /* define a global symbols at end of code */ + } >FLASH + + /* Constant data goes into FLASH */ + .rodata : + { + . = ALIGN(4); + *(.rodata) /* .rodata sections (constants, strings, etc.) */ + *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ + . = ALIGN(4); + } >FLASH + + .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH + .ARM : { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } >FLASH + + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array*)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } >FLASH + + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array*)) + PROVIDE_HIDDEN (__init_array_end = .); + } >FLASH + + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT(.fini_array.*))) + KEEP (*(.fini_array*)) + PROVIDE_HIDDEN (__fini_array_end = .); + } >FLASH + + /* used by the startup to initialize data */ + _sidata = LOADADDR(.data); + + /* Initialized data sections goes into RAM, load LMA copy after code */ + .data : + { + . = ALIGN(4); + _sdata = .; /* create a global symbol at data start */ + *(.data) /* .data sections */ + *(.data*) /* .data* sections */ + *(.RamFunc) /* .RamFunc sections */ + *(.RamFunc*) /* .RamFunc* sections */ + + . = ALIGN(4); + _edata = .; /* define a global symbol at data end */ + } >RAM_D1 AT> FLASH + + /* Uninitialized data section */ + . = ALIGN(4); + .bss : + { + /* This is used by the startup in order to initialize the .bss section */ + _sbss = .; /* define a global symbol at bss start */ + __bss_start__ = _sbss; + *(.bss) + *(.bss*) + *(COMMON) + + . = ALIGN(4); + _ebss = .; /* define a global symbol at bss end */ + __bss_end__ = _ebss; + } >RAM_D1 + + /* User_heap_stack section, used to check that there is enough RAM left */ + ._user_heap_stack : + { + . = ALIGN(8); + PROVIDE ( end = . ); + PROVIDE ( _end = . ); + . = . + _Min_Heap_Size; + . = . + _Min_Stack_Size; + . = ALIGN(8); + } >RAM_D1 + + /* Remove information from the standard libraries */ + /DISCARD/ : + { + libc.a ( * ) + libm.a ( * ) + libgcc.a ( * ) + } + + .ARM.attributes 0 : { *(.ARM.attributes) } +} diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FLY_SUPER8_PRO/variant_MARLIN_STM32H723ZG.cpp b/buildroot/share/PlatformIO/variants/MARLIN_FLY_SUPER8_PRO/variant_MARLIN_STM32H723ZG.cpp new file mode 100644 index 0000000000..4506cf5ce6 --- /dev/null +++ b/buildroot/share/PlatformIO/variants/MARLIN_FLY_SUPER8_PRO/variant_MARLIN_STM32H723ZG.cpp @@ -0,0 +1,317 @@ +/* + ******************************************************************************* + * Copyright (c) 2020-2021, STMicroelectronics + * All rights reserved. + * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ******************************************************************************* + */ +#if defined(STM32H723xx) +#include "pins_arduino.h" + +// Digital PinName array +const PinName digitalPin[] = { + PA_0, // D0/A0 + PA_1, // D1/A1 + PA_2, // D2/A2 + PA_3, // D3/A3 + PA_4, // D4/A4 + PA_5, // D5/A5 + PA_6, // D6/A6 + PA_7, // D7/A7 + PA_8, // D8 + PA_9, // D9 + PA_10, // D10 + PA_11, // D11 + PA_12, // D12 + PA_13, // D13 + PA_14, // D14 + PA_15, // D15 + PB_0, // D16/A8 + PB_1, // D17/A9 + PB_2, // D18 + PB_3, // D19 + PB_4, // D20 + PB_5, // D21 + PB_6, // D22 + PB_7, // D23 + PB_8, // D24 + PB_9, // D25 + PB_10, // D26 + PB_11, // D27 + PB_12, // D28 + PB_13, // D29 + PB_14, // D30 + PB_15, // D31 + PC_0, // D32/A10 + PC_1, // D33/A11 + PC_4, // D34/A12 + PC_5, // D35/A13 + PC_6, // D36 + PC_7, // D37 + PC_8, // D38 + PC_9, // D39 + PC_10, // D40 + PC_11, // D41 + PC_12, // D42 + PC_13, // D43 + PC_14, // D44 + PC_15, // D45 + PD_0, // D46 + PD_1, // D47 + PD_2, // D48 + PD_3, // D49 + PD_4, // D50 + PD_5, // D51 + PD_6, // D52 + PD_7, // D53 + PD_8, // D54 + PD_9, // D55 + PD_10, // D56 + PD_11, // D57 + PD_12, // D58 + PD_13, // D59 + PD_14, // D60 + PD_15, // D61 + PE_0, // D62 + PE_1, // D63 + PE_2, // D64 + PE_3, // D65 + PE_4, // D66 + PE_5, // D67 + PE_6, // D68 + PE_7, // D69 + PE_8, // D70 + PE_9, // D71 + PE_10, // D72 + PE_11, // D73 + PE_12, // D74 + PE_13, // D75 + PE_14, // D76 + PE_15, // D77 + PF_0, // D78 + PF_1, // D79 + PF_2, // D80 + PF_3, // D81/A14 + PF_4, // D82/A15 + PF_5, // D83/A16 + PF_6, // D84/A17 + PF_7, // D85/A18 + PF_8, // D86/A19 + PF_9, // D87/A20 + PF_10, // D88/A21 + PF_11, // D89/A22 + PF_12, // D90/A23 + PF_13, // D91/A24 + PF_14, // D92/A25 + PF_15, // D93 + PG_0, // D94 + PG_1, // D95 + PG_2, // D96 + PG_3, // D97 + PG_4, // D98 + PG_5, // D99 + PG_6, // D100 + PG_7, // D101 + PG_8, // D102 + PG_9, // D103 + PG_10, // D104 + PG_11, // D105 + PG_12, // D106 + PG_13, // D107 + PG_14, // D108 + PG_15, // D109 + PH_0, // D110 + PH_1, // D111 + PC_2_C, // D112/A26 + PC_3_C // D113/A27 +}; + +// Analog (Ax) pin number array +const uint32_t analogInputPin[] = { + 0, // A0, PA0 + 1, // A1, PA1 + 2, // A2, PA2 + 3, // A3, PA3 + 4, // A4, PA4 + 5, // A5, PA5 + 6, // A6, PA6 + 7, // A7, PA7 + 16, // A8, PB0 + 17, // A9, PB1 + 32, // A10, PC0 + 33, // A11, PC1 + 34, // A12, PC4 + 35, // A13, PC5 + 81, // A14, PF3 + 82, // A15, PF4 + 83, // A16, PF5 + 84, // A17, PF6 + 85, // A18, PF7 + 86, // A19, PF8 + 87, // A20, PF9 + 88, // A21, PF10 + 89, // A22, PF11 + 90, // A23, PF12 + 91, // A24, PF13 + 92, // A25, PF14 + 112, // A26, PC2_C + 113 // A27, PC3_C +}; + +void MPU_Config(void) +{ + MPU_Region_InitTypeDef MPU_InitStruct = {0}; + + /* Disables the MPU */ + HAL_MPU_Disable(); + + /** Initializes and configures the Region and the memory to be protected + */ + MPU_InitStruct.Enable = MPU_REGION_ENABLE; + MPU_InitStruct.Number = MPU_REGION_NUMBER0; + MPU_InitStruct.BaseAddress = 0x0; + MPU_InitStruct.Size = MPU_REGION_SIZE_4GB; + MPU_InitStruct.SubRegionDisable = 0x87; + MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0; + MPU_InitStruct.AccessPermission = MPU_REGION_NO_ACCESS; + MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE; + MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE; + MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE; + MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE; + + HAL_MPU_ConfigRegion(&MPU_InitStruct); + /* Enables the MPU */ + HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT); + +} + +/* + * @brief System Clock Configuration + * @param None + * @retval None + */ +WEAK void SystemClock_Config(void) +{ + RCC_OscInitTypeDef RCC_OscInitStruct = {0}; + RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; + RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {}; + + MPU_Config(); + + /** Supply configuration update enable + */ + HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY); + /** Configure the main internal regulator output voltage + */ + __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE0); + + while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {} + /** Initializes the RCC Oscillators according to the specified parameters + * in the RCC_OscInitTypeDef structure. + */ + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI48 | RCC_OSCILLATORTYPE_HSE; + RCC_OscInitStruct.HSEState = RCC_HSE_ON; + RCC_OscInitStruct.HSI48State = RCC_HSI48_ON; // 48Mhz for USB + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; + RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; + RCC_OscInitStruct.PLL.PLLM = 5; // 25Mhz / 5 = 5Mhz + RCC_OscInitStruct.PLL.PLLN = 110; // 25Mhz / 5 * 110 = 550Mhz + RCC_OscInitStruct.PLL.PLLP = 1; // 550Mhz / 1 = 550Mhz + RCC_OscInitStruct.PLL.PLLQ = 10; // 550Mhz / 10 = 55Mhz + RCC_OscInitStruct.PLL.PLLR = 10; // unused + RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2; + RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE; + RCC_OscInitStruct.PLL.PLLFRACN = 0; + if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) + { + Error_Handler(); + } + /** Initializes the CPU, AHB and APB buses clocks + */ + RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK + |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2 + |RCC_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1; + RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; + RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1; + RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2; + RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2; + RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2; + RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2; + RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2; + + if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) + { + Error_Handler(); + } + + PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_USB + | RCC_PERIPHCLK_SDMMC | RCC_PERIPHCLK_ADC + | RCC_PERIPHCLK_LPUART1 | RCC_PERIPHCLK_USART16 + | RCC_PERIPHCLK_USART234578 | RCC_PERIPHCLK_I2C123 + | RCC_PERIPHCLK_I2C4 | RCC_PERIPHCLK_SPI123 + | RCC_PERIPHCLK_SPI45 | RCC_PERIPHCLK_SPI6; + + /* HSI48 used for USB 48 Mhz */ + /* PLL1 qclk also used for FMC, SDMMC, RNG, SAI */ + /* PLL2 pclk is needed for adc max 80 Mhz (p,q,r same) */ + /* PLL2 pclk also used for LP timers 2,3,4,5, SPI 1,2,3 */ + /* PLL2 qclk is needed for uart, can, spi4,5,6 80 Mhz */ + /* PLL3 r clk is needed for i2c 80 Mhz (p,q,r same) */ + PeriphClkInitStruct.PLL2.PLL2M = 15; // M DIV 15 vco 25 / 15 ~ 1.667 Mhz + PeriphClkInitStruct.PLL2.PLL2N = 96; // N MUL 96 + PeriphClkInitStruct.PLL2.PLL2P = 2; // P div 2 + PeriphClkInitStruct.PLL2.PLL2Q = 2; // Q div 2 + PeriphClkInitStruct.PLL2.PLL2R = 2; // R div 2 + // RCC_PLL1VCIRANGE_0 Clock range frequency between 1 and 2 MHz + PeriphClkInitStruct.PLL2.PLL2RGE = RCC_PLL2VCIRANGE_0; + PeriphClkInitStruct.PLL2.PLL2VCOSEL = RCC_PLL2VCOMEDIUM; + PeriphClkInitStruct.PLL2.PLL2FRACN = 0; + PeriphClkInitStruct.PLL3.PLL3M = 15; // M DIV 15 vco 25 / 15 ~ 1.667 Mhz + PeriphClkInitStruct.PLL3.PLL3N = 96; // N MUL 96 + PeriphClkInitStruct.PLL3.PLL3P = 2; // P div 2 + PeriphClkInitStruct.PLL3.PLL3Q = 2; // Q div 2 + PeriphClkInitStruct.PLL3.PLL3R = 2; // R div 2 + // RCC_PLL1VCIRANGE_0 Clock range frequency between 1 and 2 MHz + PeriphClkInitStruct.PLL3.PLL3RGE = RCC_PLL3VCIRANGE_0; + PeriphClkInitStruct.PLL3.PLL3VCOSEL = RCC_PLL3VCOMEDIUM; + PeriphClkInitStruct.PLL3.PLL3FRACN = 0; + // ADC from PLL2 pclk + PeriphClkInitStruct.AdcClockSelection = RCC_ADCCLKSOURCE_PLL2; + // USB from HSI48 + PeriphClkInitStruct.UsbClockSelection = RCC_USBCLKSOURCE_HSI48; + // SDMMC from PLL1 qclk + PeriphClkInitStruct.SdmmcClockSelection = 0; + //PeriphClkInitStruct.SdmmcClockSelection = RCC_SDMMCCLKSOURCE_PLL; + // LPUART from PLL2 qclk + PeriphClkInitStruct.Lpuart1ClockSelection = 0; + //PeriphClkInitStruct.Lpuart1ClockSelection = RCC_LPUART1CLKSOURCE_PLL2; + // USART from PLL2 qclk + PeriphClkInitStruct.Usart16ClockSelection = RCC_USART16CLKSOURCE_PLL2; + // USART from PLL2 qclk + PeriphClkInitStruct.Usart234578ClockSelection = 0; + //PeriphClkInitStruct.Usart234578ClockSelection = RCC_USART234578CLKSOURCE_PLL2; + // I2C123 from PLL3 rclk + PeriphClkInitStruct.I2c123ClockSelection = RCC_I2C123CLKSOURCE_PLL3; + // I2C4 from PLL3 rclk + PeriphClkInitStruct.I2c4ClockSelection = 0; + //PeriphClkInitStruct.I2c4ClockSelection = RCC_I2C4CLKSOURCE_PLL3; + // SPI123 from PLL2 pclk + PeriphClkInitStruct.Spi123ClockSelection = RCC_SPI123CLKSOURCE_PLL2; + // SPI45 from PLL2 qclk + PeriphClkInitStruct.Spi45ClockSelection = 0; + //PeriphClkInitStruct.Spi45ClockSelection = RCC_SPI45CLKSOURCE_PLL2; + // SPI6 from PLL2 qclk + PeriphClkInitStruct.Spi6ClockSelection = 0; + //PeriphClkInitStruct.Spi6ClockSelection = RCC_SPI6CLKSOURCE_PLL2; + + if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) { + Error_Handler(); + } +} + +#endif /* ARDUINO_GENERIC_* */ diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FLY_SUPER8_PRO/variant_MARLIN_STM32H723ZG.h b/buildroot/share/PlatformIO/variants/MARLIN_FLY_SUPER8_PRO/variant_MARLIN_STM32H723ZG.h new file mode 100644 index 0000000000..8e208e3b26 --- /dev/null +++ b/buildroot/share/PlatformIO/variants/MARLIN_FLY_SUPER8_PRO/variant_MARLIN_STM32H723ZG.h @@ -0,0 +1,273 @@ +/* + ******************************************************************************* + * Copyright (c) 2020-2021, STMicroelectronics + * All rights reserved. + * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ******************************************************************************* + */ +#pragma once + +/*---------------------------------------------------------------------------- + * STM32 pins number + *----------------------------------------------------------------------------*/ +#define PA0 PIN_A0 +#define PA1 PIN_A1 +#define PA2 PIN_A2 +#define PA3 PIN_A3 +#define PA4 PIN_A4 +#define PA5 PIN_A5 +#define PA6 PIN_A6 +#define PA7 PIN_A7 +#define PA8 8 +#define PA9 9 +#define PA10 10 +#define PA11 11 +#define PA12 12 +#define PA13 13 +#define PA14 14 +#define PA15 15 +#define PB0 PIN_A8 +#define PB1 PIN_A9 +#define PB2 18 +#define PB3 19 +#define PB4 20 +#define PB5 21 +#define PB6 22 +#define PB7 23 +#define PB8 24 +#define PB9 25 +#define PB10 26 +#define PB11 27 +#define PB12 28 +#define PB13 29 +#define PB14 30 +#define PB15 31 +#define PC0 PIN_A10 +#define PC1 PIN_A11 +#define PC4 PIN_A12 +#define PC5 PIN_A13 +#define PC6 36 +#define PC7 37 +#define PC8 38 +#define PC9 39 +#define PC10 40 +#define PC11 41 +#define PC12 42 +#define PC13 43 +#define PC14 44 +#define PC15 45 +#define PD0 46 +#define PD1 47 +#define PD2 48 +#define PD3 49 +#define PD4 50 +#define PD5 51 +#define PD6 52 +#define PD7 53 +#define PD8 54 +#define PD9 55 +#define PD10 56 +#define PD11 57 +#define PD12 58 +#define PD13 59 +#define PD14 60 +#define PD15 61 +#define PE0 62 +#define PE1 63 +#define PE2 64 +#define PE3 65 +#define PE4 66 +#define PE5 67 +#define PE6 68 +#define PE7 69 +#define PE8 70 +#define PE9 71 +#define PE10 72 +#define PE11 73 +#define PE12 74 +#define PE13 75 +#define PE14 76 +#define PE15 77 +#define PF0 78 +#define PF1 79 +#define PF2 80 +#define PF3 PIN_A14 +#define PF4 PIN_A15 +#define PF5 PIN_A16 +#define PF6 PIN_A17 +#define PF7 PIN_A18 +#define PF8 PIN_A19 +#define PF9 PIN_A20 +#define PF10 PIN_A21 +#define PF11 PIN_A22 +#define PF12 PIN_A23 +#define PF13 PIN_A24 +#define PF14 PIN_A25 +#define PF15 93 +#define PG0 94 +#define PG1 95 +#define PG2 96 +#define PG3 97 +#define PG4 98 +#define PG5 99 +#define PG6 100 +#define PG7 101 +#define PG8 102 +#define PG9 103 +#define PG10 104 +#define PG11 105 +#define PG12 106 +#define PG13 107 +#define PG14 108 +#define PG15 109 +#define PH0 110 +#define PH1 111 +#define PC2_C PIN_A26 +#define PC3_C PIN_A27 + +// Alternate pins number +#define PA0_ALT1 (PA0 | ALT1) +#define PA1_ALT1 (PA1 | ALT1) +#define PA1_ALT2 (PA1 | ALT2) +#define PA2_ALT1 (PA2 | ALT1) +#define PA2_ALT2 (PA2 | ALT2) +#define PA3_ALT1 (PA3 | ALT1) +#define PA3_ALT2 (PA3 | ALT2) +#define PA4_ALT1 (PA4 | ALT1) +#define PA4_ALT2 (PA4 | ALT2) +#define PA5_ALT1 (PA5 | ALT1) +#define PA6_ALT1 (PA6 | ALT1) +#define PA7_ALT1 (PA7 | ALT1) +#define PA7_ALT2 (PA7 | ALT2) +#define PA7_ALT3 (PA7 | ALT3) +#define PA8_ALT1 (PA8 | ALT1) +#define PA9_ALT1 (PA9 | ALT1) +#define PA10_ALT1 (PA10 | ALT1) +#define PA11_ALT1 (PA11 | ALT1) +#define PA12_ALT1 (PA12 | ALT1) +#define PA15_ALT1 (PA15 | ALT1) +#define PA15_ALT2 (PA15 | ALT2) +#define PB0_ALT1 (PB0 | ALT1) +#define PB0_ALT2 (PB0 | ALT2) +#define PB1_ALT1 (PB1 | ALT1) +#define PB1_ALT2 (PB1 | ALT2) +#define PB3_ALT1 (PB3 | ALT1) +#define PB3_ALT2 (PB3 | ALT2) +#define PB4_ALT1 (PB4 | ALT1) +#define PB4_ALT2 (PB4 | ALT2) +#define PB5_ALT1 (PB5 | ALT1) +#define PB5_ALT2 (PB5 | ALT2) +#define PB6_ALT1 (PB6 | ALT1) +#define PB6_ALT2 (PB6 | ALT2) +#define PB7_ALT1 (PB7 | ALT1) +#define PB8_ALT1 (PB8 | ALT1) +#define PB8_ALT2 (PB8 | ALT2) +#define PB9_ALT1 (PB9 | ALT1) +#define PB9_ALT2 (PB9 | ALT2) +#define PB14_ALT1 (PB14 | ALT1) +#define PB14_ALT2 (PB14 | ALT2) +#define PB15_ALT1 (PB15 | ALT1) +#define PB15_ALT2 (PB15 | ALT2) +#define PC0_ALT1 (PC0 | ALT1) +#define PC0_ALT2 (PC0 | ALT2) +#define PC1_ALT1 (PC1 | ALT1) +#define PC1_ALT2 (PC1 | ALT2) +#define PC4_ALT1 (PC4 | ALT1) +#define PC5_ALT1 (PC5 | ALT1) +#define PC6_ALT1 (PC6 | ALT1) +#define PC6_ALT2 (PC6 | ALT2) +#define PC7_ALT1 (PC7 | ALT1) +#define PC7_ALT2 (PC7 | ALT2) +#define PC8_ALT1 (PC8 | ALT1) +#define PC9_ALT1 (PC9 | ALT1) +#define PC10_ALT1 (PC10 | ALT1) +#define PC11_ALT1 (PC11 | ALT1) +#define PF0_ALT1 (PF0 | ALT1) +#define PF1_ALT1 (PF1 | ALT1) +#define PF6_ALT1 (PF6 | ALT1) +#define PF7_ALT1 (PF7 | ALT1) +#define PF8_ALT1 (PF8 | ALT1) +#define PF8_ALT2 (PF8 | ALT2) +#define PF9_ALT1 (PF9 | ALT1) +#define PF9_ALT2 (PF9 | ALT2) +#define PG13_ALT1 (PG13 | ALT1) + +#define NUM_DIGITAL_PINS 114 +#define NUM_DUALPAD_PINS 2 +#define NUM_ANALOG_INPUTS 28 +#define NUM_ANALOG_FIRST PA0 + +// SPI definitions +#ifndef PIN_SPI_SS + #define PIN_SPI_SS PA4 +#endif +#ifndef PIN_SPI_MOSI + #define PIN_SPI_MOSI PA7 +#endif +#ifndef PIN_SPI_MISO + #define PIN_SPI_MISO PA6 +#endif +#ifndef PIN_SPI_SCK + #define PIN_SPI_SCK PA5 +#endif + +// Timer Definitions +// Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin +#ifndef TIMER_TONE + #define TIMER_TONE TIM6 +#endif +#ifndef TIMER_SERVO + #define TIMER_SERVO TIM7 +#endif + +// UART Definitions +#ifndef SERIAL_UART_INSTANCE + #define SERIAL_UART_INSTANCE 1 +#endif + +// Default pin used for generic 'Serial' instance +// Mandatory for Firmata +#ifndef PIN_SERIAL_RX + #define PIN_SERIAL_RX PA10 +#endif +#ifndef PIN_SERIAL_TX + #define PIN_SERIAL_TX PA9 +#endif + +// Extra HAL modules +#ifndef HAL_SD_MODULE_DISABLED + #define HAL_SD_MODULE_ENABLED +#endif + +/*---------------------------------------------------------------------------- + * Arduino objects - C++ only + *----------------------------------------------------------------------------*/ + +#ifdef __cplusplus + // These serial port names are intended to allow libraries and architecture-neutral + // sketches to automatically default to the correct port name for a particular type + // of use. For example, a GPS module would normally connect to SERIAL_PORT_HARDWARE_OPEN, + // the first hardware serial port whose RX/TX pins are not dedicated to another use. + // + // SERIAL_PORT_MONITOR Port which normally prints to the Arduino Serial Monitor + // + // SERIAL_PORT_USBVIRTUAL Port which is USB virtual serial + // + // SERIAL_PORT_LINUXBRIDGE Port which connects to a Linux system via Bridge library + // + // SERIAL_PORT_HARDWARE Hardware serial port, physical RX & TX pins. + // + // SERIAL_PORT_HARDWARE_OPEN Hardware serial ports which are open for use. Their RX & TX + // pins are NOT connected to anything by default. + #ifndef SERIAL_PORT_MONITOR + #define SERIAL_PORT_MONITOR Serial + #endif + #ifndef SERIAL_PORT_HARDWARE + #define SERIAL_PORT_HARDWARE Serial + #endif +#endif diff --git a/ini/stm32f0.ini b/ini/stm32f0.ini index d23ee2a603..a684b98871 100644 --- a/ini/stm32f0.ini +++ b/ini/stm32f0.ini @@ -49,3 +49,33 @@ build_flags = ${common_stm32.build_flags} -DHAL_PCD_MODULE_ENABLED -DDISABLE_GENERIC_SERIALUSB -DHAL_UART_MODULE_ENABLED build_src_filter = ${common.default_src_filter} + - + +# +# FLY D5 (STM32F072RB) +# +[env:FLY_D5] +platform = ststm32 +extends = stm32_variant +board = marlin_STM32F072 +board_build.variant = MARLIN_FLY_D5 +platform_packages = framework-arduinoststm32@4.20500.230714 + framework-cmsis@2.50700.210515 + toolchain-gccarmnoneeabi@1.100301.220327 +build_flags = ${stm32_variant.build_flags} + -DTIMER_SERIAL=TIM2 +upload_protocol = stlink + +# +# FLY D7 (STM32F072RB) +# +[env:FLY_D7] +platform = ststm32 +extends = stm32_variant +board = marlin_STM32F072 +board_build.variant = MARLIN_FLY_D7 +platform_packages = framework-arduinoststm32@4.20500.230714 + framework-cmsis@2.50700.210515 + toolchain-gccarmnoneeabi@1.100301.220327 +build_flags = ${stm32_variant.build_flags} + -DTIMER_SERIAL=TIM2 +upload_protocol = dfu diff --git a/ini/stm32f1.ini b/ini/stm32f1.ini index 96699d954d..ed60983a23 100644 --- a/ini/stm32f1.ini +++ b/ini/stm32f1.ini @@ -121,8 +121,8 @@ debug_tool = stlink extends = stm32_variant board_build.variant = MARLIN_F103Rx board_build.offset = 0x7000 -board_build.rename = firmware-{date}-{time}.bin board_upload.offset_address = 0x08007000 +board_build.rename = firmware-{date}-{time}.bin build_flags = ${stm32_variant.build_flags} -DMCU_STM32F103RE -DHAL_SD_MODULE_ENABLED -DSS_TIMER=4 -DTIMER_SERVO=TIM5 @@ -467,8 +467,8 @@ build_flags = ${env:chitu_f103.build_flags} -DCHITU_V5_Z_MIN_BUGFIX [ZONESTAR_ZM3E] extends = stm32_variant platform_packages = ${stm_flash_drive.platform_packages} -board_upload.offset_address = 0x08005000 board_build.offset = 0x5000 +board_upload.offset_address = 0x08005000 board_upload.maximum_size = 237568 extra_scripts = ${stm32_variant.extra_scripts} build_flags = ${stm32_variant.build_flags} ${USBD_CDC_MSC.build_flags} diff --git a/ini/stm32f4.ini b/ini/stm32f4.ini index 8b9c45d38a..76d9b1a12f 100644 --- a/ini/stm32f4.ini +++ b/ini/stm32f4.ini @@ -64,6 +64,40 @@ board_build.offset = 0x8000 board_build.offset_address = 0x08008000 upload_protocol = dfu +# +# FLY_D8 +# +[env:FLY_D8] +extends = stm32_variant +platform_packages = platformio/tool-dfuutil@~1.11.0 +board = marlin_STM32F407VGT6_CCM +board_build.variant = MARLIN_FLY_D8 +upload_protocol = dfu +board_build.offset = 0x0000 +board_upload.offset_address = 0x08000000 + +# +# FLY SUPER8 +# +[env:FLY_SUPER8] +extends = stm32_variant +platform_packages = platformio/tool-dfuutil@~1.11.0 +board = marlin_STM32F407ZGT6 +board_build.variant = MARLIN_FLY_SUPER8 +board_build.offset = 0x8000 +upload_protocol = dfu + +# +# FLY CDY V3 +# +[env:FLY_CDY_V3] +extends = stm32_variant +platform_packages = platformio/tool-dfuutil@~1.11.0 +board = marlin_STM32F407VGT6_CCM +board_build.variant = MARLIN_FLY_CDY_V3 +board_build.offset = 0x8000 +upload_protocol = dfu + # # FYSETC S6 (STM32F446RET6 ARM Cortex-M4) # diff --git a/ini/stm32h7.ini b/ini/stm32h7.ini index e5392464db..0bc35352cf 100644 --- a/ini/stm32h7.ini +++ b/ini/stm32h7.ini @@ -137,3 +137,38 @@ board = marlin_STM32H723ZE [env:STM32H723ZG_btt] extends = STM32H723Zx_btt board = marlin_STM32H723ZG + +# +# FLY D8 PRO +# +[env:FLY_D8_PRO] +extends = stm32_variant +platform = ststm32@15.4.1 +platform_packages = framework-arduinoststm32@~4.20200.220530 +board = marlin_STM32H723VG +board_build.variant = MARLIN_FLY_D8_PRO +board_build.offset = 0x0000 +board_upload.offset_address = 0x08000000 +build_flags = ${stm32_variant.build_flags} + -DRCC_PERIPHCLK_I2C35=RCC_PERIPHCLK_I2C5 + -DTIMER_SERVO=TIM5 -DTIMER_TONE=TIM2 + -DUSE_USB_HS -DUSE_USB_HS_IN_FS + -DD_CACHE_DISABLED +upload_protocol = dfu + +# +# FLY SUPER8 PRO +# +[env:FLY_SUPER8_PRO] +extends = stm32_variant +platform = ststm32@15.4.1 +platform_packages = framework-arduinoststm32@~4.20200.220530 +board = marlin_STM32H723ZG +board_build.variant = MARLIN_FLY_SUPER8_PRO +board_build.offset = 0x20000 +board_upload.offset_address = 0x08020000 +build_flags = ${stm32_variant.build_flags} + -DRCC_PERIPHCLK_I2C35=RCC_PERIPHCLK_I2C5 + -DUSE_USB_HS -DUSE_USB_HS_IN_FS + -DD_CACHE_DISABLED +upload_protocol = dfu From caf5d5b1343077ff9c4a0cccbaefb4462ed01311 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Wed, 5 Mar 2025 06:09:08 +0000 Subject: [PATCH 093/787] [cron] Bump distribution date (2025-03-05) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 1efacafd64..6110d29cd6 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-03-02" +//#define STRING_DISTRIBUTION_DATE "2025-03-05" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 53d34487fa..a07fba14e7 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-03-02" + #define STRING_DISTRIBUTION_DATE "2025-03-05" #endif /** From 97a7c2160ea63be28d891cb69a8dc1cac9311eb9 Mon Sep 17 00:00:00 2001 From: narno2202 <130909513+narno2202@users.noreply.github.com> Date: Fri, 7 Mar 2025 02:43:02 +0100 Subject: [PATCH 094/787] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20FT=20Motion:=20Fil?= =?UTF-8?q?l=20window=20in=20makeVector=20(#27718)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/module/ft_motion.cpp | 206 ++++++++++++++++---------------- 1 file changed, 104 insertions(+), 102 deletions(-) diff --git a/Marlin/src/module/ft_motion.cpp b/Marlin/src/module/ft_motion.cpp index 5044814373..3877df983d 100644 --- a/Marlin/src/module/ft_motion.cpp +++ b/Marlin/src/module/ft_motion.cpp @@ -578,115 +578,117 @@ void FTMotion::loadBlockData(block_t * const current_block) { // Generate data points of the trajectory. void FTMotion::makeVector() { - float accel_k = 0.0f; // (mm/s^2) Acceleration K factor - float tau = (makeVector_idx + 1) * (FTM_TS); // (s) Time since start of block - float dist = 0.0f; // (mm) Distance traveled - - if (makeVector_idx < N1) { - // Acceleration phase - dist = (f_s * tau) + (0.5f * accel_P * sq(tau)); // (mm) Distance traveled for acceleration phase since start of block - accel_k = accel_P; // (mm/s^2) Acceleration K factor from Accel phase - } - else if (makeVector_idx < (N1 + N2)) { - // Coasting phase - dist = s_1e + F_P * (tau - N1 * (FTM_TS)); // (mm) Distance traveled for coasting phase since start of block - //accel_k = 0.0f; - } - else { - // Deceleration phase - tau -= (N1 + N2) * (FTM_TS); // (s) Time since start of decel phase - dist = s_2e + F_P * tau + 0.5f * decel_P * sq(tau); // (mm) Distance traveled for deceleration phase since start of block - accel_k = decel_P; // (mm/s^2) Acceleration K factor from Decel phase - } - - #define _SET_TRAJ(q) traj.q[makeVector_batchIdx] = startPosn.q + ratio.q * dist; - LOGICAL_AXIS_MAP_LC(_SET_TRAJ); - - #if HAS_EXTRUDERS - if (cfg.linearAdvEna) { - float dedt_adj = (traj.e[makeVector_batchIdx] - e_raw_z1) * (FTM_FS); - if (ratio.e > 0.0f) dedt_adj += accel_k * cfg.linearAdvK * 0.0001f; - - e_raw_z1 = traj.e[makeVector_batchIdx]; - e_advanced_z1 += dedt_adj * (FTM_TS); - traj.e[makeVector_batchIdx] = e_advanced_z1; + do { + float accel_k = 0.0f; // (mm/s^2) Acceleration K factor + float tau = (makeVector_idx + 1) * (FTM_TS); // (s) Time since start of block + float dist = 0.0f; // (mm) Distance traveled + + if (makeVector_idx < N1) { + // Acceleration phase + dist = (f_s * tau) + (0.5f * accel_P * sq(tau)); // (mm) Distance traveled for acceleration phase since start of block + accel_k = accel_P; // (mm/s^2) Acceleration K factor from Accel phase } - #endif - - // Update shaping parameters if needed. - - switch (cfg.dynFreqMode) { - - #if HAS_DYNAMIC_FREQ_MM - case dynFreqMode_Z_BASED: { - static float oldz = 0.0f; - const float z = traj.z[makeVector_batchIdx]; - if (z != oldz) { // Only update if Z changed. - oldz = z; + else if (makeVector_idx < (N1 + N2)) { + // Coasting phase + dist = s_1e + F_P * (tau - N1 * (FTM_TS)); // (mm) Distance traveled for coasting phase since start of block + //accel_k = 0.0f; + } + else { + // Deceleration phase + tau -= (N1 + N2) * (FTM_TS); // (s) Time since start of decel phase + dist = s_2e + F_P * tau + 0.5f * decel_P * sq(tau); // (mm) Distance traveled for deceleration phase since start of block + accel_k = decel_P; // (mm/s^2) Acceleration K factor from Decel phase + } + + #define _SET_TRAJ(q) traj.q[makeVector_batchIdx] = startPosn.q + ratio.q * dist; + LOGICAL_AXIS_MAP_LC(_SET_TRAJ); + + #if HAS_EXTRUDERS + if (cfg.linearAdvEna) { + float dedt_adj = (traj.e[makeVector_batchIdx] - e_raw_z1) * (FTM_FS); + if (ratio.e > 0.0f) dedt_adj += accel_k * cfg.linearAdvK * 0.0001f; + + e_raw_z1 = traj.e[makeVector_batchIdx]; + e_advanced_z1 += dedt_adj * (FTM_TS); + traj.e[makeVector_batchIdx] = e_advanced_z1; + } + #endif + + // Update shaping parameters if needed. + + switch (cfg.dynFreqMode) { + + #if HAS_DYNAMIC_FREQ_MM + case dynFreqMode_Z_BASED: { + static float oldz = 0.0f; + const float z = traj.z[makeVector_batchIdx]; + if (z != oldz) { // Only update if Z changed. + oldz = z; + #if HAS_X_AXIS + const float xf = cfg.baseFreq.x + cfg.dynFreqK.x * z; + shaping.x.set_axis_shaping_N(cfg.shaper.x, _MAX(xf, FTM_MIN_SHAPE_FREQ), cfg.zeta.x); + #endif + #if HAS_Y_AXIS + const float yf = cfg.baseFreq.y + cfg.dynFreqK.y * z; + shaping.y.set_axis_shaping_N(cfg.shaper.y, _MAX(yf, FTM_MIN_SHAPE_FREQ), cfg.zeta.y); + #endif + } + } break; + #endif + + #if HAS_DYNAMIC_FREQ_G + case dynFreqMode_MASS_BASED: + // Update constantly. The optimization done for Z value makes + // less sense for E, as E is expected to constantly change. #if HAS_X_AXIS - const float xf = cfg.baseFreq.x + cfg.dynFreqK.x * z; - shaping.x.set_axis_shaping_N(cfg.shaper.x, _MAX(xf, FTM_MIN_SHAPE_FREQ), cfg.zeta.x); + shaping.x.set_axis_shaping_N(cfg.shaper.x, cfg.baseFreq.x + cfg.dynFreqK.x * traj.e[makeVector_batchIdx], cfg.zeta.x); #endif #if HAS_Y_AXIS - const float yf = cfg.baseFreq.y + cfg.dynFreqK.y * z; - shaping.y.set_axis_shaping_N(cfg.shaper.y, _MAX(yf, FTM_MIN_SHAPE_FREQ), cfg.zeta.y); + shaping.y.set_axis_shaping_N(cfg.shaper.y, cfg.baseFreq.y + cfg.dynFreqK.y * traj.e[makeVector_batchIdx], cfg.zeta.y); #endif + break; + #endif + + default: break; + } + + // Apply shaping if active on each axis + #if HAS_FTM_SHAPING + #if HAS_X_AXIS + if (shaping.x.ena) { + shaping.x.d_zi[shaping.zi_idx] = traj.x[makeVector_batchIdx]; + traj.x[makeVector_batchIdx] *= shaping.x.Ai[0]; + for (uint32_t i = 1U; i <= shaping.x.max_i; i++) { + const uint32_t udiffx = shaping.zi_idx - shaping.x.Ni[i]; + traj.x[makeVector_batchIdx] += shaping.x.Ai[i] * shaping.x.d_zi[shaping.x.Ni[i] > shaping.zi_idx ? (FTM_ZMAX) + udiffx : udiffx]; + } } - } break; - #endif - - #if HAS_DYNAMIC_FREQ_G - case dynFreqMode_MASS_BASED: - // Update constantly. The optimization done for Z value makes - // less sense for E, as E is expected to constantly change. - #if HAS_X_AXIS - shaping.x.set_axis_shaping_N(cfg.shaper.x, cfg.baseFreq.x + cfg.dynFreqK.x * traj.e[makeVector_batchIdx], cfg.zeta.x); - #endif - #if HAS_Y_AXIS - shaping.y.set_axis_shaping_N(cfg.shaper.y, cfg.baseFreq.y + cfg.dynFreqK.y * traj.e[makeVector_batchIdx], cfg.zeta.y); - #endif - break; - #endif - - default: break; - } - - // Apply shaping if active on each axis - #if HAS_FTM_SHAPING - #if HAS_X_AXIS - if (shaping.x.ena) { - shaping.x.d_zi[shaping.zi_idx] = traj.x[makeVector_batchIdx]; - traj.x[makeVector_batchIdx] *= shaping.x.Ai[0]; - for (uint32_t i = 1U; i <= shaping.x.max_i; i++) { - const uint32_t udiffx = shaping.zi_idx - shaping.x.Ni[i]; - traj.x[makeVector_batchIdx] += shaping.x.Ai[i] * shaping.x.d_zi[shaping.x.Ni[i] > shaping.zi_idx ? (FTM_ZMAX) + udiffx : udiffx]; + #endif + + #if HAS_Y_AXIS + if (shaping.y.ena) { + shaping.y.d_zi[shaping.zi_idx] = traj.y[makeVector_batchIdx]; + traj.y[makeVector_batchIdx] *= shaping.y.Ai[0]; + for (uint32_t i = 1U; i <= shaping.y.max_i; i++) { + const uint32_t udiffy = shaping.zi_idx - shaping.y.Ni[i]; + traj.y[makeVector_batchIdx] += shaping.y.Ai[i] * shaping.y.d_zi[shaping.y.Ni[i] > shaping.zi_idx ? (FTM_ZMAX) + udiffy : udiffy]; + } } - } - #endif - - #if HAS_Y_AXIS - if (shaping.y.ena) { - shaping.y.d_zi[shaping.zi_idx] = traj.y[makeVector_batchIdx]; - traj.y[makeVector_batchIdx] *= shaping.y.Ai[0]; - for (uint32_t i = 1U; i <= shaping.y.max_i; i++) { - const uint32_t udiffy = shaping.zi_idx - shaping.y.Ni[i]; - traj.y[makeVector_batchIdx] += shaping.y.Ai[i] * shaping.y.d_zi[shaping.y.Ni[i] > shaping.zi_idx ? (FTM_ZMAX) + udiffy : udiffy]; - } - } - #endif - if (++shaping.zi_idx == (FTM_ZMAX)) shaping.zi_idx = 0; - #endif // HAS_FTM_SHAPING - - // Filled up the queue with regular and shaped steps - if (++makeVector_batchIdx == FTM_WINDOW_SIZE) { - makeVector_batchIdx = BATCH_SIDX_IN_WINDOW; - batchRdy = true; - } - - if (++makeVector_idx == max_intervals) { - blockProcRdy = false; - makeVector_idx = 0; - } + #endif + if (++shaping.zi_idx == (FTM_ZMAX)) shaping.zi_idx = 0; + #endif // HAS_FTM_SHAPING + + // Filled up the queue with regular and shaped steps + if (++makeVector_batchIdx == FTM_WINDOW_SIZE) { + makeVector_batchIdx = BATCH_SIDX_IN_WINDOW; + batchRdy = true; + } + + if (++makeVector_idx == max_intervals) { + blockProcRdy = false; + makeVector_idx = 0; + } + } while (blockProcRdy && !batchRdy); } /** From e02de3a2566fe5abccc0b65cad41c8b40608ca75 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Fri, 7 Mar 2025 06:09:07 +0000 Subject: [PATCH 095/787] [cron] Bump distribution date (2025-03-07) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 6110d29cd6..9a2197239c 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-03-05" +//#define STRING_DISTRIBUTION_DATE "2025-03-07" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index a07fba14e7..a12898c281 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-03-05" + #define STRING_DISTRIBUTION_DATE "2025-03-07" #endif /** From 126e78dcce797b8a1725707c0cd14bc5d9a98118 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sun, 9 Mar 2025 15:41:13 -0500 Subject: [PATCH 096/787] =?UTF-8?q?=F0=9F=90=9B=20Fix=20quoted=20string=20?= =?UTF-8?q?value=20detection?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/gcode/parser.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/src/gcode/parser.h b/Marlin/src/gcode/parser.h index c2fe6880ed..401548b309 100644 --- a/Marlin/src/gcode/parser.h +++ b/Marlin/src/gcode/parser.h @@ -146,7 +146,7 @@ public: if (b) { if (param[ind]) { char * const ptr = command_ptr + param[ind]; - value_ptr = valid_number(ptr) ? ptr : nullptr; + value_ptr = (valid_number(ptr) || TERN0(GCODE_QUOTED_STRINGS, *(ptr - 1) == '"')) ? ptr : nullptr; } else value_ptr = nullptr; From 07b979012a5db096ff724d935b7d8fa468879cdc Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sun, 9 Mar 2025 15:51:39 -0500 Subject: [PATCH 097/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Pro?= =?UTF-8?q?be=20Wizard=20comments?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/lcd/menu/menu_probe_offset.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/Marlin/src/lcd/menu/menu_probe_offset.cpp b/Marlin/src/lcd/menu/menu_probe_offset.cpp index fe1f726ced..ee3689aac2 100644 --- a/Marlin/src/lcd/menu/menu_probe_offset.cpp +++ b/Marlin/src/lcd/menu/menu_probe_offset.cpp @@ -41,9 +41,10 @@ void _goto_manual_move_z(const_float_t); -// Global storage +// Global storage - TODO: Keep wizard/process data in a 'ui.scratch' union. float z_offset_backup, calculated_z_offset, z_offset_ref; +// "Done" - Set the offset, re-enable leveling, go back to the previous screen. void set_offset_and_go_back(const_float_t z) { probe.offset.z = z; SET_SOFT_ENDSTOP_LOOSE(false); @@ -51,6 +52,10 @@ void set_offset_and_go_back(const_float_t z) { ui.goto_previous_screen_no_defer(); } +/** + * @fn probe_offset_wizard_menu + * @brief Display a menu to Move Z, Cancel, or signal Done + */ void probe_offset_wizard_menu() { START_MENU(); calculated_z_offset = probe.offset.z + current_position.z - z_offset_ref; @@ -88,6 +93,16 @@ void probe_offset_wizard_menu() { END_MENU(); } +/** + * @fn prepare_for_probe_offset_wizard + * @brief Prepare the Probe Offset Wizard to do user interaction. + * @description + * 1. Probe a defined point (or the center) for an initial Probe Reference Z (relative to the homed Z0). + * (When homing with the probe, this Z0 is suspect until 'M851 Z' is properly tuned. + * When homing with a Z endstop Z0 is suspect until M206 is properly tuned.) + * 2. Stow the probe and move the nozzle over the probed point. + * 3. Go to the probe_offset_wizard_menu() screen for Z position adjustment to acquire Z0. + */ void prepare_for_probe_offset_wizard() { #if defined(PROBE_OFFSET_WIZARD_XY_POS) || !HOMING_Z_WITH_PROBE if (ui.should_draw()) MenuItem_static::draw(1, GET_TEXT_F(MSG_PROBE_WIZARD_PROBING)); @@ -126,6 +141,8 @@ void prepare_for_probe_offset_wizard() { ui.defer_status_screen(); } +// Set up the wizard, initiate homing with "Homing XYZ" message. +// When homing is completed go to prepare_for_probe_offset_wizard(). void goto_probe_offset_wizard() { ui.defer_status_screen(); set_all_unhomed(); @@ -146,6 +163,7 @@ void goto_probe_offset_wizard() { // Home all axes queue.inject_P(G28_STR); + // Show "Homing XYZ" display until homing completes ui.goto_screen([]{ _lcd_draw_homing(); if (all_axes_homed()) { From ee35929b61fcf3568cb8d83bfb36c9721fdcda2e Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Mon, 10 Mar 2025 00:25:20 +0000 Subject: [PATCH 098/787] [cron] Bump distribution date (2025-03-10) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 9a2197239c..57052419cd 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-03-07" +//#define STRING_DISTRIBUTION_DATE "2025-03-10" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index a12898c281..59c33ace52 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-03-07" + #define STRING_DISTRIBUTION_DATE "2025-03-10" #endif /** From d9229ff3557808fbebdfd63927cbdc33e807b75d Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Mon, 10 Mar 2025 19:01:37 -0500 Subject: [PATCH 099/787] =?UTF-8?q?=F0=9F=94=A8=20Fix=20CONFIG=5FEXPORT=20?= =?UTF-8?q?1,=20(embed=20=3D=20101)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Followup to #27628 See #27612 --- buildroot/share/PlatformIO/scripts/signature.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/buildroot/share/PlatformIO/scripts/signature.py b/buildroot/share/PlatformIO/scripts/signature.py index a5c92cff17..5cda69d89b 100755 --- a/buildroot/share/PlatformIO/scripts/signature.py +++ b/buildroot/share/PlatformIO/scripts/signature.py @@ -195,9 +195,9 @@ def compute_build_signature(env): # Get the CONFIG_EXPORT value and do an extended dump if > 100 # For example, CONFIG_EXPORT 102 will make a 'config.ini' with a [config:] group for each schema @section - config_dump = tryint('CONFIG_EXPORT') + config_dump = 101 if is_embed else tryint('CONFIG_EXPORT') extended_dump = config_dump > 100 - if extended_dump: config_dump -= 100 + config_dump %= 100 # Get the schema class for exports that require it if config_dump in (3, 4) or (extended_dump and config_dump in (2, 5)): @@ -451,7 +451,7 @@ f'''# # Produce a JSON file for CONFIGURATION_EMBEDDING or CONFIG_EXPORT == 1 or 101 # Skip if an identical JSON file was already present. # - if not same_hash and (config_dump == 1 or is_embed): + if not same_hash and config_dump == 1: with marlin_json.open('w') as outfile: json_data = {} @@ -468,12 +468,11 @@ f'''# json_data[header][s][name] = c['value'] else: for header in real_config: - json_data[header] = {} conf = real_config[header] #print(f"real_config[{header}]", conf) for name in conf: if name in ignore: continue - json_data[header][name] = conf[name]['value'] + json_data[name] = conf[name]['value'] json_data['__INITIAL_HASH'] = hashes From e6ccf3b72bb399123a4069a1b39f2cb5f2440bda Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Tue, 11 Mar 2025 00:28:55 +0000 Subject: [PATCH 100/787] [cron] Bump distribution date (2025-03-11) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 57052419cd..88dc0e3556 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-03-10" +//#define STRING_DISTRIBUTION_DATE "2025-03-11" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 59c33ace52..6d867bfe41 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-03-10" + #define STRING_DISTRIBUTION_DATE "2025-03-11" #endif /** From 953b6844cac78b3a84a0a4647ae9d08edd88bb42 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Mon, 10 Mar 2025 22:12:21 -0500 Subject: [PATCH 101/787] =?UTF-8?q?=F0=9F=93=9D=20Config=20comments=20with?= =?UTF-8?q?=20units?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/Configuration_adv.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 6e64112786..ad62cc06cc 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -2008,7 +2008,7 @@ #if IS_U8GLIB_ST7920 // Enable this option and reduce the value to optimize screen updates. // The normal delay is 10µs. Use the lowest value that still gives a reliable display. - //#define DOGM_SPI_DELAY_US 5 + //#define DOGM_SPI_DELAY_US 5 // (µs) Delay after each SPI transfer //#define LIGHTWEIGHT_UI #if ENABLED(LIGHTWEIGHT_UI) @@ -2261,7 +2261,7 @@ // ADC Button Debounce // #if HAS_ADC_BUTTONS - #define ADC_BUTTON_DEBOUNCE_DELAY 16 // Increase if buttons bounce or repeat too fast + #define ADC_BUTTON_DEBOUNCE_DELAY 16 // (count) Increase if buttons bounce or repeat too fast #endif // @section safety @@ -2302,7 +2302,7 @@ //#define DOUBLECLICK_FOR_Z_BABYSTEPPING // Double-click on the Status Screen for Z Babystepping. #if ENABLED(DOUBLECLICK_FOR_Z_BABYSTEPPING) - #define DOUBLECLICK_MAX_INTERVAL 1250 // Maximum interval between clicks, in milliseconds. + #define DOUBLECLICK_MAX_INTERVAL 1250 // (ms) Maximum interval between clicks. // Note: Extra time may be added to mitigate controller latency. //#define MOVE_Z_WHEN_IDLE // Jump to the move Z menu on double-click when printer is idle. #if ENABLED(MOVE_Z_WHEN_IDLE) From d74ee8ccc4398508bf2be296b9606289b2162769 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Wed, 12 Mar 2025 00:28:38 +0000 Subject: [PATCH 102/787] [cron] Bump distribution date (2025-03-12) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 88dc0e3556..bc0f6cf36e 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-03-11" +//#define STRING_DISTRIBUTION_DATE "2025-03-12" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 6d867bfe41..3edafa18df 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-03-11" + #define STRING_DISTRIBUTION_DATE "2025-03-12" #endif /** From 01990f2bf4ec8f528437d7f0008423b14ca31e5f Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Wed, 12 Mar 2025 17:28:22 -0500 Subject: [PATCH 103/787] =?UTF-8?q?=F0=9F=93=9D=20Document=20planner=20mod?= =?UTF-8?q?ifier=20methods?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/feature/twibus.h | 4 ++-- Marlin/src/lcd/menu/menu_probe_offset.cpp | 2 +- Marlin/src/module/planner.h | 18 ++++++++++++++++-- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/Marlin/src/feature/twibus.h b/Marlin/src/feature/twibus.h index de23abbed5..b438d10a33 100644 --- a/Marlin/src/feature/twibus.h +++ b/Marlin/src/feature/twibus.h @@ -64,7 +64,7 @@ class TWIBus { private: /** * @brief Number of bytes on buffer - * @description Number of bytes in the buffer waiting to be flushed to the bus + * @details Number of bytes in the buffer waiting to be flushed to the bus */ uint8_t buffer_s = 0; @@ -77,7 +77,7 @@ class TWIBus { public: /** * @brief Target device address - * @description The target device address. Persists until changed. + * @details The target device address. Persists until changed. */ uint8_t addr = 0; diff --git a/Marlin/src/lcd/menu/menu_probe_offset.cpp b/Marlin/src/lcd/menu/menu_probe_offset.cpp index ee3689aac2..a0b7c2bed4 100644 --- a/Marlin/src/lcd/menu/menu_probe_offset.cpp +++ b/Marlin/src/lcd/menu/menu_probe_offset.cpp @@ -96,7 +96,7 @@ void probe_offset_wizard_menu() { /** * @fn prepare_for_probe_offset_wizard * @brief Prepare the Probe Offset Wizard to do user interaction. - * @description + * @details * 1. Probe a defined point (or the center) for an initial Probe Reference Z (relative to the homed Z0). * (When homing with the probe, this Z0 is suspect until 'M851 Z' is properly tuned. * When homing with a Z endstop Z0 is suspect until M206 is properly tuned.) diff --git a/Marlin/src/module/planner.h b/Marlin/src/module/planner.h index 53717ca0a7..b2df5824de 100644 --- a/Marlin/src/module/planner.h +++ b/Marlin/src/module/planner.h @@ -782,13 +782,27 @@ class Planner { #endif #if HAS_POSITION_MODIFIERS - FORCE_INLINE static void apply_modifiers(xyze_pos_t &pos, bool leveling=ENABLED(PLANNER_LEVELING)) { + /** + * @brief Apply Skew, Leveling, and Retraction modifiers to the given cartesian position. + * @details By default leveling is only applied if the planner is the leveling handler (i.e., PLANNER_LEVELING). + * + * @param pos The position to modify + * @param leveling Optional bool whether to include the leveling modifier + */ + FORCE_INLINE static void apply_modifiers(xyze_pos_t &pos, const bool leveling=ENABLED(PLANNER_LEVELING)) { TERN_(SKEW_CORRECTION, skew(pos)); if (leveling) apply_leveling(pos); TERN_(FWRETRACT, apply_retract(pos)); } - FORCE_INLINE static void unapply_modifiers(xyze_pos_t &pos, bool leveling=ENABLED(PLANNER_LEVELING)) { + /** + * @brief Un-apply Skew, Leveling, and Retraction modifiers to the given cartesian position. + * @details By default leveling is only un-applied if the planner is the leveling handler (i.e., PLANNER_LEVELING). + * + * @param pos The position to un-modify + * @param leveling Optional bool whether to include the leveling modifier + */ + FORCE_INLINE static void unapply_modifiers(xyze_pos_t &pos, const bool leveling=ENABLED(PLANNER_LEVELING)) { TERN_(FWRETRACT, unapply_retract(pos)); if (leveling) unapply_leveling(pos); TERN_(SKEW_CORRECTION, unskew(pos)); From 5766dc0ece17ff67b30da1dc1efc6f55d9515e3a Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Thu, 13 Mar 2025 00:29:12 +0000 Subject: [PATCH 104/787] [cron] Bump distribution date (2025-03-13) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index bc0f6cf36e..b7759c5e65 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-03-12" +//#define STRING_DISTRIBUTION_DATE "2025-03-13" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 3edafa18df..958bf98148 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-03-12" + #define STRING_DISTRIBUTION_DATE "2025-03-13" #endif /** From 4cf4647c9acb17afadb712152a0243ac11576122 Mon Sep 17 00:00:00 2001 From: ellensp <530024+ellensp@users.noreply.github.com> Date: Thu, 13 Mar 2025 14:35:12 +1300 Subject: [PATCH 105/787] =?UTF-8?q?=F0=9F=94=A7=20More=20serial=20ports=20?= =?UTF-8?q?for=20Teensy=20HALs=20(#27736)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Followup to #27648 Co-authored-by: Scott Lahteine --- Marlin/src/HAL/TEENSY31_32/HAL.cpp | 16 +++++++++++++--- Marlin/src/HAL/TEENSY35_36/HAL.cpp | 15 +++++++++++++-- Marlin/src/HAL/TEENSY40_41/HAL.cpp | 20 +++++++++++--------- 3 files changed, 37 insertions(+), 14 deletions(-) diff --git a/Marlin/src/HAL/TEENSY31_32/HAL.cpp b/Marlin/src/HAL/TEENSY31_32/HAL.cpp index 2892368967..f54025991d 100644 --- a/Marlin/src/HAL/TEENSY31_32/HAL.cpp +++ b/Marlin/src/HAL/TEENSY31_32/HAL.cpp @@ -37,10 +37,20 @@ #define _IMPLEMENT_SERIAL(X) DefaultSerial##X MSerial##X(false, Serial##X) #define IMPLEMENT_SERIAL(X) _IMPLEMENT_SERIAL(X) -#if WITHIN(SERIAL_PORT, 0, 3) +#if WITHIN(SERIAL_PORT, SERIAL_INDEX_MIN, SERIAL_INDEX_MAX) IMPLEMENT_SERIAL(SERIAL_PORT); -#else - #error "SERIAL_PORT must be from 0 to 3." +#endif +#if defined(SERIAL_PORT_2) && WITHIN(SERIAL_PORT_2, SERIAL_INDEX_MIN, SERIAL_INDEX_MAX) + IMPLEMENT_SERIAL(SERIAL_PORT_2); +#endif +#if defined(SERIAL_PORT_3) && WITHIN(SERIAL_PORT_3, SERIAL_INDEX_MIN, SERIAL_INDEX_MAX) + IMPLEMENT_SERIAL(SERIAL_PORT_3); +#endif +#if defined(MMU_SERIAL_PORT) && WITHIN(MMU_SERIAL_PORT, SERIAL_INDEX_MIN, SERIAL_INDEX_MAX) + IMPLEMENT_SERIAL(MMU_SERIAL_PORT); +#endif +#if defined(LCD_SERIAL_PORT) && WITHIN(LCD_SERIAL_PORT, SERIAL_INDEX_MIN, SERIAL_INDEX_MAX) + IMPLEMENT_SERIAL(LCD_SERIAL_PORT); #endif USBSerialType USBSerial(false, SerialUSB); diff --git a/Marlin/src/HAL/TEENSY35_36/HAL.cpp b/Marlin/src/HAL/TEENSY35_36/HAL.cpp index bc02ac1c45..f41582be30 100644 --- a/Marlin/src/HAL/TEENSY35_36/HAL.cpp +++ b/Marlin/src/HAL/TEENSY35_36/HAL.cpp @@ -37,10 +37,21 @@ #define _IMPLEMENT_SERIAL(X) DefaultSerial##X MSerial##X(false, Serial##X) #define IMPLEMENT_SERIAL(X) _IMPLEMENT_SERIAL(X) -#if WITHIN(SERIAL_PORT, 0, 3) +#if WITHIN(SERIAL_PORT, SERIAL_INDEX_MIN, SERIAL_INDEX_MAX) IMPLEMENT_SERIAL(SERIAL_PORT); #endif - +#if defined(SERIAL_PORT_2) && WITHIN(SERIAL_PORT_2, SERIAL_INDEX_MIN, SERIAL_INDEX_MAX) + IMPLEMENT_SERIAL(SERIAL_PORT_2); +#endif +#if defined(SERIAL_PORT_3) && WITHIN(SERIAL_PORT_3, SERIAL_INDEX_MIN, SERIAL_INDEX_MAX) + IMPLEMENT_SERIAL(SERIAL_PORT_3); +#endif +#if defined(MMU_SERIAL_PORT) && WITHIN(MMU_SERIAL_PORT, SERIAL_INDEX_MIN, SERIAL_INDEX_MAX) + IMPLEMENT_SERIAL(MMU_SERIAL_PORT); +#endif +#if defined(LCD_SERIAL_PORT) && WITHIN(LCD_SERIAL_PORT, SERIAL_INDEX_MIN, SERIAL_INDEX_MAX) + IMPLEMENT_SERIAL(LCD_SERIAL_PORT); +#endif USBSerialType USBSerial(false, SerialUSB); // ------------------------ diff --git a/Marlin/src/HAL/TEENSY40_41/HAL.cpp b/Marlin/src/HAL/TEENSY40_41/HAL.cpp index d40f620c81..1f27a283f7 100644 --- a/Marlin/src/HAL/TEENSY40_41/HAL.cpp +++ b/Marlin/src/HAL/TEENSY40_41/HAL.cpp @@ -39,18 +39,20 @@ #define _IMPLEMENT_SERIAL(X) DefaultSerial##X MSerial##X(false, Serial##X) #define IMPLEMENT_SERIAL(X) _IMPLEMENT_SERIAL(X) -#if WITHIN(SERIAL_PORT, 0, 8) +#if WITHIN(SERIAL_PORT, SERIAL_INDEX_MIN, SERIAL_INDEX_MAX) IMPLEMENT_SERIAL(SERIAL_PORT); #endif -#ifdef SERIAL_PORT_2 - #if WITHIN(SERIAL_PORT_2, 0, 8) - IMPLEMENT_SERIAL(SERIAL_PORT_2); - #endif +#if defined(SERIAL_PORT_2) && WITHIN(SERIAL_PORT_2, SERIAL_INDEX_MIN, SERIAL_INDEX_MAX) + IMPLEMENT_SERIAL(SERIAL_PORT_2); #endif -#ifdef SERIAL_PORT_3 - #if WITHIN(SERIAL_PORT_3, 0, 8) - IMPLEMENT_SERIAL(SERIAL_PORT_3); - #endif +#if defined(SERIAL_PORT_3) && WITHIN(SERIAL_PORT_3, SERIAL_INDEX_MIN, SERIAL_INDEX_MAX) + IMPLEMENT_SERIAL(SERIAL_PORT_3); +#endif +#if defined(MMU_SERIAL_PORT) && WITHIN(MMU_SERIAL_PORT, SERIAL_INDEX_MIN, SERIAL_INDEX_MAX) + IMPLEMENT_SERIAL(MMU_SERIAL_PORT); +#endif +#if defined(LCD_SERIAL_PORT) && WITHIN(LCD_SERIAL_PORT, SERIAL_INDEX_MIN, SERIAL_INDEX_MAX) + IMPLEMENT_SERIAL(LCD_SERIAL_PORT); #endif USBSerialType USBSerial(false, SerialUSB); From 0fa3d2642aa6fc329fcb507b5bf32b040c4e201d Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Thu, 13 Mar 2025 17:19:23 -0500 Subject: [PATCH 106/787] =?UTF-8?q?=E2=9C=A8=20MIN=5FPOWER=20(#27742)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Followup to #14746 Co-authored-by: mikeshub <2420379+mikeshub@users.noreply.github.com> --- Marlin/Configuration.h | 1 + Marlin/src/inc/Conditionals-1-axes.h | 3 +++ Marlin/src/module/temperature.h | 8 ++++---- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 77a9176115..f804dc605a 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -695,6 +695,7 @@ #define PID_K1 0.95 // Smoothing factor within any PID loop #if ENABLED(PIDTEMP) + //#define MIN_POWER 0 //#define PID_DEBUG // Print PID debug data to the serial port. Use 'M303 D' to toggle activation. //#define PID_PARAMS_PER_HOTEND // Use separate PID parameters for each extruder (useful for mismatched extruders) // Set/get with G-code: M301 E[extruder number, 0-2] diff --git a/Marlin/src/inc/Conditionals-1-axes.h b/Marlin/src/inc/Conditionals-1-axes.h index 5f8dad37b0..e55f69c797 100644 --- a/Marlin/src/inc/Conditionals-1-axes.h +++ b/Marlin/src/inc/Conditionals-1-axes.h @@ -189,6 +189,9 @@ #ifndef HOTEND_OVERSHOOT #define HOTEND_OVERSHOOT 15 #endif + #ifndef MIN_POWER + #define MIN_POWER 0 + #endif #else #undef MPCTEMP #undef PIDTEMP diff --git a/Marlin/src/module/temperature.h b/Marlin/src/module/temperature.h index ffc86eb4e5..27e28f07a8 100644 --- a/Marlin/src/module/temperature.h +++ b/Marlin/src/module/temperature.h @@ -367,13 +367,13 @@ typedef struct { float p, i, d, c, f; } raw_pidcf_t; typedef #if ALL(PID_EXTRUSION_SCALING, PID_FAN_SCALING) - PIDCF_t<0, PID_MAX, LPQ_MAX_LEN, PID_FAN_SCALING_MIN_SPEED, PID_FAN_SCALING_LIN_FACTOR> + PIDCF_t #elif ENABLED(PID_EXTRUSION_SCALING) - PIDC_t<0, PID_MAX, LPQ_MAX_LEN> + PIDC_t #elif ENABLED(PID_FAN_SCALING) - PIDF_t<0, PID_MAX, PID_FAN_SCALING_MIN_SPEED, PID_FAN_SCALING_LIN_FACTOR> + PIDF_t #else - PID_t<0, PID_MAX> + PID_t #endif hotend_pid_t; From f0bd400002317b2f7a17288cd16d9ffea43c3db1 Mon Sep 17 00:00:00 2001 From: ellensp <530024+ellensp@users.noreply.github.com> Date: Fri, 14 Mar 2025 11:21:28 +1300 Subject: [PATCH 107/787] =?UTF-8?q?=F0=9F=A9=B9=F0=9F=94=A7=20Fix=20LCD=5F?= =?UTF-8?q?LANGUAGE=20for=20HD44780=20(#27729)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/inc/Conditionals-2-LCD.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/src/inc/Conditionals-2-LCD.h b/Marlin/src/inc/Conditionals-2-LCD.h index 97f1cbd9c5..40f18c406a 100644 --- a/Marlin/src/inc/Conditionals-2-LCD.h +++ b/Marlin/src/inc/Conditionals-2-LCD.h @@ -649,7 +649,7 @@ #if !HAS_MARLINUI_HD44780 #undef LCD_INFO_SCREEN_STYLE #endif -#if NONE(HAS_MARLINUI_U8GLIB, HAS_TFT_LVGL_UI, TFT_COLOR_UI, DGUS_LCD_UI_E3S1PRO) +#if NONE(HAS_MARLINUI_HD44780, HAS_MARLINUI_U8GLIB, HAS_TFT_LVGL_UI, TFT_COLOR_UI, DGUS_LCD_UI_E3S1PRO) #undef LCD_LANGUAGE #endif #if DISABLED(MPC_AUTOTUNE) From 9e30173b13a8a23f9eefc797fa1908c9bfd96b8f Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Fri, 14 Mar 2025 00:28:40 +0000 Subject: [PATCH 108/787] [cron] Bump distribution date (2025-03-14) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index b7759c5e65..b0bbd83206 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-03-13" +//#define STRING_DISTRIBUTION_DATE "2025-03-14" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 958bf98148..189d9a1e2e 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-03-13" + #define STRING_DISTRIBUTION_DATE "2025-03-14" #endif /** From 78f871567f56cc73f5b5ed2f5cb4740e93d392e1 Mon Sep 17 00:00:00 2001 From: Keith Bennett <13375512+thisiskeithb@users.noreply.github.com> Date: Fri, 14 Mar 2025 11:11:45 -0700 Subject: [PATCH 109/787] =?UTF-8?q?=F0=9F=94=A8=20Rename=20FYSETC=20S6/Spi?= =?UTF-8?q?der=20envs=20(#27122)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci-build-tests.yml | 2 +- Marlin/src/pins/pins.h | 8 ++++---- buildroot/bin/mftest | 2 +- ...c_s6.json => marlin_STM32F446VE_fysetc.json} | 6 +++--- .../PeripheralPins.c | 0 .../PinNamesVar.h | 0 .../ldscript.ld | 0 .../variant.cpp | 0 .../variant.h | 0 .../tests/{FYSETC_S6 => STM32F446VE_fysetc} | 10 +++++----- ini/renamed.ini | 6 ++++++ ini/stm32f4.ini | 17 ++++++++++------- 12 files changed, 30 insertions(+), 21 deletions(-) rename buildroot/share/PlatformIO/boards/{marlin_fysetc_s6.json => marlin_STM32F446VE_fysetc.json} (85%) rename buildroot/share/PlatformIO/variants/{MARLIN_FYSETC_S6 => MARLIN_F446VE_FYSETC}/PeripheralPins.c (100%) rename buildroot/share/PlatformIO/variants/{MARLIN_FYSETC_S6 => MARLIN_F446VE_FYSETC}/PinNamesVar.h (100%) rename buildroot/share/PlatformIO/variants/{MARLIN_FYSETC_S6 => MARLIN_F446VE_FYSETC}/ldscript.ld (100%) rename buildroot/share/PlatformIO/variants/{MARLIN_FYSETC_S6 => MARLIN_F446VE_FYSETC}/variant.cpp (100%) rename buildroot/share/PlatformIO/variants/{MARLIN_FYSETC_S6 => MARLIN_F446VE_FYSETC}/variant.h (100%) rename buildroot/tests/{FYSETC_S6 => STM32F446VE_fysetc} (66%) diff --git a/.github/workflows/ci-build-tests.yml b/.github/workflows/ci-build-tests.yml index 3dabf82f46..320cda5b18 100644 --- a/.github/workflows/ci-build-tests.yml +++ b/.github/workflows/ci-build-tests.yml @@ -113,7 +113,7 @@ jobs: - BTT_GTR_V1_0 - BTT_SKR_PRO - FLYF407ZG - - FYSETC_S6 + - STM32F446VE_fysetc - LERDGEK - LERDGEX - mks_robin_pro2 diff --git a/Marlin/src/pins/pins.h b/Marlin/src/pins/pins.h index 4e36558ef8..01ff13f8c2 100644 --- a/Marlin/src/pins/pins.h +++ b/Marlin/src/pins/pins.h @@ -786,13 +786,13 @@ #elif MB(LERDGE_X) #include "stm32f4/pins_LERDGE_X.h" // STM32F4 env:LERDGEX env:LERDGEX_usb_flash_drive #elif MB(FYSETC_S6) - #include "stm32f4/pins_FYSETC_S6.h" // STM32F4 env:FYSETC_S6 env:FYSETC_S6_8000 + #include "stm32f4/pins_FYSETC_S6.h" // STM32F4 env:STM32F446VE_fysetc env:STM32F446VE_fysetc_32k_bootloader #elif MB(FYSETC_S6_V2_0) - #include "stm32f4/pins_FYSETC_S6_V2_0.h" // STM32F4 env:FYSETC_S6 env:FYSETC_S6_8000 + #include "stm32f4/pins_FYSETC_S6_V2_0.h" // STM32F4 env:STM32F446VE_fysetc env:STM32F446VE_fysetc_32k_bootloader #elif MB(FYSETC_SPIDER) - #include "stm32f4/pins_FYSETC_SPIDER.h" // STM32F4 env:FYSETC_S6 env:FYSETC_S6_8000 + #include "stm32f4/pins_FYSETC_SPIDER.h" // STM32F4 env:STM32F446VE_fysetc env:STM32F446VE_fysetc_32k_bootloader #elif MB(FYSETC_SPIDER_V2_2) - #include "stm32f4/pins_FYSETC_SPIDER_V2_2.h" // STM32F4 env:FYSETC_S6 env:FYSETC_S6_8000 + #include "stm32f4/pins_FYSETC_SPIDER_V2_2.h" // STM32F4 env:STM32F446VE_fysetc_32k_bootloader #elif MB(FLYF407ZG) #include "stm32f4/pins_FLYF407ZG.h" // STM32F4 env:FLYF407ZG #elif MB(MKS_ROBIN2) diff --git a/buildroot/bin/mftest b/buildroot/bin/mftest index 3dd54b2bf6..9b6dfb465d 100755 --- a/buildroot/bin/mftest +++ b/buildroot/bin/mftest @@ -134,7 +134,7 @@ lp9|lpc9) TESTENV='LPC1769' ;; f1) TESTENV='STM32F103RE' ;; f4) TESTENV='STM32F4' ;; f7) TESTENV='STM32F7' ;; - s6) TESTENV='FYSETC_S6' ;; + s6) TESTENV='STM32F446VE_fysetc' ;; teensy) TESTENV='teensy31' ;; t31) TESTENV='teensy31' ;; t32) TESTENV='teensy31' ;; diff --git a/buildroot/share/PlatformIO/boards/marlin_fysetc_s6.json b/buildroot/share/PlatformIO/boards/marlin_STM32F446VE_fysetc.json similarity index 85% rename from buildroot/share/PlatformIO/boards/marlin_fysetc_s6.json rename to buildroot/share/PlatformIO/boards/marlin_STM32F446VE_fysetc.json index 286e46ffbd..bbeefdf977 100644 --- a/buildroot/share/PlatformIO/boards/marlin_fysetc_s6.json +++ b/buildroot/share/PlatformIO/boards/marlin_STM32F446VE_fysetc.json @@ -3,14 +3,14 @@ "cpu": "cortex-m4", "extra_flags": "-DSTM32F446xx", "f_cpu": "180000000L", - "mcu": "stm32f446ret6", - "variant": "MARLIN_FYSETC_S6" + "mcu": "stm32f446vet6", + "variant": "MARLIN_F446VE_FYSETC" }, "connectivity": [ "can" ], "debug": { - "jlink_device": "STM32F446RE", + "jlink_device": "STM32F446VE", "openocd_target": "stm32f4x", "svd_path": "STM32F446x.svd" }, diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FYSETC_S6/PeripheralPins.c b/buildroot/share/PlatformIO/variants/MARLIN_F446VE_FYSETC/PeripheralPins.c similarity index 100% rename from buildroot/share/PlatformIO/variants/MARLIN_FYSETC_S6/PeripheralPins.c rename to buildroot/share/PlatformIO/variants/MARLIN_F446VE_FYSETC/PeripheralPins.c diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FYSETC_S6/PinNamesVar.h b/buildroot/share/PlatformIO/variants/MARLIN_F446VE_FYSETC/PinNamesVar.h similarity index 100% rename from buildroot/share/PlatformIO/variants/MARLIN_FYSETC_S6/PinNamesVar.h rename to buildroot/share/PlatformIO/variants/MARLIN_F446VE_FYSETC/PinNamesVar.h diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FYSETC_S6/ldscript.ld b/buildroot/share/PlatformIO/variants/MARLIN_F446VE_FYSETC/ldscript.ld similarity index 100% rename from buildroot/share/PlatformIO/variants/MARLIN_FYSETC_S6/ldscript.ld rename to buildroot/share/PlatformIO/variants/MARLIN_F446VE_FYSETC/ldscript.ld diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FYSETC_S6/variant.cpp b/buildroot/share/PlatformIO/variants/MARLIN_F446VE_FYSETC/variant.cpp similarity index 100% rename from buildroot/share/PlatformIO/variants/MARLIN_FYSETC_S6/variant.cpp rename to buildroot/share/PlatformIO/variants/MARLIN_F446VE_FYSETC/variant.cpp diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FYSETC_S6/variant.h b/buildroot/share/PlatformIO/variants/MARLIN_F446VE_FYSETC/variant.h similarity index 100% rename from buildroot/share/PlatformIO/variants/MARLIN_FYSETC_S6/variant.h rename to buildroot/share/PlatformIO/variants/MARLIN_F446VE_FYSETC/variant.h diff --git a/buildroot/tests/FYSETC_S6 b/buildroot/tests/STM32F446VE_fysetc similarity index 66% rename from buildroot/tests/FYSETC_S6 rename to buildroot/tests/STM32F446VE_fysetc index 9043b7b6e3..bdc51e43ca 100755 --- a/buildroot/tests/FYSETC_S6 +++ b/buildroot/tests/STM32F446VE_fysetc @@ -1,16 +1,16 @@ #!/usr/bin/env bash # -# Build tests for FYSETC_S6 +# Build tests for STM32F446VE_fysetc # # exit on first failure set -e -# Build examples +# Build basic FYSETC S6 configuration restore_configs -use_example_configs FYSETC/S6 -opt_enable MEATPACK_ON_SERIAL_PORT_1 -opt_set Y_DRIVER_TYPE TMC2209 Z_DRIVER_TYPE TMC2130 +opt_set MOTHERBOARD BOARD_FYSETC_S6_V2_0 SERIAL_PORT -1 BAUDRATE 115200 TEMP_SENSOR_BED 0 \ + DEFAULT_AXIS_STEPS_PER_UNIT '{ 80, 80, 400, 400 }' Y_DRIVER_TYPE TMC2209 Z_DRIVER_TYPE TMC2130 +opt_enable MEATPACK_ON_SERIAL_PORT_1 EEPROM_SETTINGS SDSUPPORT exec_test $1 $2 "FYSETC S6 Example" "$3" # diff --git a/ini/renamed.ini b/ini/renamed.ini index f39cbec6ad..4f9ce0793d 100644 --- a/ini/renamed.ini +++ b/ini/renamed.ini @@ -140,3 +140,9 @@ extends = renamed [env:BIGTREE_SKR_2_F429_USB_debug] ;=> STM32F429VG_btt_USB_debug extends = renamed + +[env:FYSETC_S6] ;=> STM32F446VE_fysetc +extends = renamed + +[env:FYSETC_S6_8000] ;=> STM32F446VE_fysetc_32k_bootloader +extends = renamed diff --git a/ini/stm32f4.ini b/ini/stm32f4.ini index 76d9b1a12f..0e9dc9102a 100644 --- a/ini/stm32f4.ini +++ b/ini/stm32f4.ini @@ -99,12 +99,12 @@ board_build.offset = 0x8000 upload_protocol = dfu # -# FYSETC S6 (STM32F446RET6 ARM Cortex-M4) +# FYSETC S6 / Spider V1.x/2.x/3.x with 64k bootloader (STM32F446VET6 ARM Cortex-M4) # -[env:FYSETC_S6] +[env:STM32F446VE_fysetc] extends = stm32_variant platform_packages = platformio/tool-dfuutil@~1.11.0 -board = marlin_fysetc_s6 +board = marlin_STM32F446VE_fysetc board_build.offset = 0x10000 board_upload.offset_address = 0x08010000 build_flags = ${stm32_variant.build_flags} -DHAL_PCD_MODULE_ENABLED @@ -113,11 +113,14 @@ upload_protocol = dfu upload_command = dfu-util -a 0 -s 0x08010000:leave -D "$SOURCE" # -# FYSETC S6 new bootloader +# FYSETC S6 / Spider V1.x/2.x/3.x with 32k bootloader +# All S6 & Spider (V2.2+) boards made after 2021/06/23 use this bootloader +# S6 - https://github.com/FYSETC/FYSETC-S6/tree/main/bootloader +# Spider - https://github.com/FYSETC/FYSETC-SPIDER/tree/main/bootloader # -[env:FYSETC_S6_8000] -extends = env:FYSETC_S6 -board = marlin_fysetc_s6 +[env:STM32F446VE_fysetc_32k_bootloader] +extends = env:STM32F446VE_fysetc +board = marlin_STM32F446VE_fysetc board_build.offset = 0x8000 board_upload.offset_address = 0x08008000 upload_command = dfu-util -a 0 -s 0x08008000:leave -D "$SOURCE" From 6ba08130f05ed0cee0037812f4d1addaec822d42 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Sat, 15 Mar 2025 00:28:35 +0000 Subject: [PATCH 110/787] [cron] Bump distribution date (2025-03-15) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index b0bbd83206..46d3eca6f7 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-03-14" +//#define STRING_DISTRIBUTION_DATE "2025-03-15" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 189d9a1e2e..bc51577643 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-03-14" + #define STRING_DISTRIBUTION_DATE "2025-03-15" #endif /** From 3827ceaf66a09a33c27c89f2488b7fb31321aa6e Mon Sep 17 00:00:00 2001 From: "Marcio T." Date: Sat, 15 Mar 2025 16:31:32 -0600 Subject: [PATCH 111/787] =?UTF-8?q?=F0=9F=A9=B9=20Fix=20color=20game=20com?= =?UTF-8?q?pile=20(#27721)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/lcd/dogm/game.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/src/lcd/dogm/game.cpp b/Marlin/src/lcd/dogm/game.cpp index 70e8783b49..e49f9198e7 100644 --- a/Marlin/src/lcd/dogm/game.cpp +++ b/Marlin/src/lcd/dogm/game.cpp @@ -31,8 +31,8 @@ void MarlinGame::frame_start() { void MarlinGame::frame_end() {} -void MarlinGame::set_color(const color color) { - switch (color) { +void MarlinGame::set_color(const color clr) { + switch (clr) { default: case color::WHITE: u8g.setColorIndex(1); break; case color::BLACK: u8g.setColorIndex(0); break; From fb4d465360990013858c9ba97cc6a3e236f97644 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Sun, 16 Mar 2025 00:32:26 +0000 Subject: [PATCH 112/787] [cron] Bump distribution date (2025-03-16) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 46d3eca6f7..a8330b0054 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-03-15" +//#define STRING_DISTRIBUTION_DATE "2025-03-16" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index bc51577643..7d3ef7cdac 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-03-15" + #define STRING_DISTRIBUTION_DATE "2025-03-16" #endif /** From 82d3d78e3190ea314f1f1f59f9a0c3acf64a59c3 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Mon, 10 Mar 2025 01:11:20 -0500 Subject: [PATCH 113/787] =?UTF-8?q?=F0=9F=94=A7=20BOARD=5FLCD=5FSERIAL=5FP?= =?UTF-8?q?ORT?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/inc/Warnings.cpp | 7 +++++++ Marlin/src/pins/hc32f4/pins_AQUILA_101.h | 2 ++ Marlin/src/pins/lpc1769/pins_BTT_SKR_E3_TURBO.h | 2 ++ Marlin/src/pins/ramps/pins_PANOWIN_CUTLASS.h | 2 ++ Marlin/src/pins/ramps/pins_RAMPS.h | 2 ++ Marlin/src/pins/stm32f1/pins_BTT_SKR_MINI_E3_common.h | 2 ++ Marlin/src/pins/stm32f1/pins_CREALITY_CR4NS.h | 2 ++ Marlin/src/pins/stm32f1/pins_CREALITY_V24S1_301.h | 2 ++ Marlin/src/pins/stm32f1/pins_CREALITY_V423.h | 2 ++ Marlin/src/pins/stm32f1/pins_MKS_ROBIN.h | 2 ++ Marlin/src/pins/stm32f4/pins_BTT_OCTOPUS_V1_1.h | 2 ++ Marlin/src/pins/stm32f4/pins_BTT_SKR_MINI_E3_V3_0_1.h | 2 ++ Marlin/src/pins/stm32f4/pins_CREALITY_CR4NTXXC10.h | 2 ++ Marlin/src/pins/stm32f4/pins_CREALITY_F401.h | 2 ++ Marlin/src/pins/stm32f4/pins_MKS_MONSTER8_V1.h | 2 ++ Marlin/src/pins/stm32g0/pins_BTT_SKR_MINI_E3_V3_0.h | 6 ++++-- Marlin/src/pins/stm32h7/pins_BTT_SKR_V3_0_common.h | 2 ++ 17 files changed, 41 insertions(+), 2 deletions(-) diff --git a/Marlin/src/inc/Warnings.cpp b/Marlin/src/inc/Warnings.cpp index a6ea570030..df2279a08b 100644 --- a/Marlin/src/inc/Warnings.cpp +++ b/Marlin/src/inc/Warnings.cpp @@ -925,3 +925,10 @@ #if ALL(PELTIER_BED, PIDTEMPBED) #warning "PELTIER_BED with PIDTEMPBED requires extra circuitry. Use with caution." #endif + +/** + * Board recommended LCD_SERIAL_PORT + */ +#if LCD_IS_SERIAL_HOST && defined(BOARD_LCD_SERIAL_PORT) && LCD_SERIAL_PORT != BOARD_LCD_SERIAL_PORT && DISABLED(NO_LCD_SERIAL_PORT_WARNING) + #warning "LCD_SERIAL_PORT overrides the default (BOARD_LCD_SERIAL_PORT)." +#endif diff --git a/Marlin/src/pins/hc32f4/pins_AQUILA_101.h b/Marlin/src/pins/hc32f4/pins_AQUILA_101.h index 8c3ce10c6d..dd8488de64 100644 --- a/Marlin/src/pins/hc32f4/pins_AQUILA_101.h +++ b/Marlin/src/pins/hc32f4/pins_AQUILA_101.h @@ -37,6 +37,8 @@ #define DEFAULT_MACHINE_NAME "Aquila" #endif +#define BOARD_LCD_SERIAL_PORT 1 + // // Onboard crystal oscillator // diff --git a/Marlin/src/pins/lpc1769/pins_BTT_SKR_E3_TURBO.h b/Marlin/src/pins/lpc1769/pins_BTT_SKR_E3_TURBO.h index 98da81781e..03394b02ba 100644 --- a/Marlin/src/pins/lpc1769/pins_BTT_SKR_E3_TURBO.h +++ b/Marlin/src/pins/lpc1769/pins_BTT_SKR_E3_TURBO.h @@ -34,6 +34,8 @@ #define USES_DIAG_JUMPERS +#define BOARD_LCD_SERIAL_PORT 1 + // Onboard I2C EEPROM #define I2C_EEPROM #define MARLIN_EEPROM_SIZE 0x1000U // 4K (AT24C32) diff --git a/Marlin/src/pins/ramps/pins_PANOWIN_CUTLASS.h b/Marlin/src/pins/ramps/pins_PANOWIN_CUTLASS.h index 11451e95a4..51da658365 100755 --- a/Marlin/src/pins/ramps/pins_PANOWIN_CUTLASS.h +++ b/Marlin/src/pins/ramps/pins_PANOWIN_CUTLASS.h @@ -38,6 +38,8 @@ #define DEFAULT_MACHINE_NAME "Panowin F1" #endif +#define BOARD_LCD_SERIAL_PORT 2 + // // Limit Switches // diff --git a/Marlin/src/pins/ramps/pins_RAMPS.h b/Marlin/src/pins/ramps/pins_RAMPS.h index e40415c826..e033cfd060 100644 --- a/Marlin/src/pins/ramps/pins_RAMPS.h +++ b/Marlin/src/pins/ramps/pins_RAMPS.h @@ -59,6 +59,8 @@ #define BOARD_INFO_NAME "RAMPS 1.4" #endif +#define BOARD_LCD_SERIAL_PORT 2 + // // Servos // diff --git a/Marlin/src/pins/stm32f1/pins_BTT_SKR_MINI_E3_common.h b/Marlin/src/pins/stm32f1/pins_BTT_SKR_MINI_E3_common.h index 6b6aec5197..77a80d36e1 100644 --- a/Marlin/src/pins/stm32f1/pins_BTT_SKR_MINI_E3_common.h +++ b/Marlin/src/pins/stm32f1/pins_BTT_SKR_MINI_E3_common.h @@ -38,6 +38,8 @@ #define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE // 2K #endif +#define BOARD_LCD_SERIAL_PORT 1 + // // Servos // diff --git a/Marlin/src/pins/stm32f1/pins_CREALITY_CR4NS.h b/Marlin/src/pins/stm32f1/pins_CREALITY_CR4NS.h index 95bd5e98ff..7d19aec51d 100644 --- a/Marlin/src/pins/stm32f1/pins_CREALITY_CR4NS.h +++ b/Marlin/src/pins/stm32f1/pins_CREALITY_CR4NS.h @@ -41,6 +41,8 @@ #endif #define BOARD_WEBSITE_URL "www.creality.com" +#define BOARD_LCD_SERIAL_PORT 2 + // // EEPROM // diff --git a/Marlin/src/pins/stm32f1/pins_CREALITY_V24S1_301.h b/Marlin/src/pins/stm32f1/pins_CREALITY_V24S1_301.h index 584d7661f8..916db4e596 100644 --- a/Marlin/src/pins/stm32f1/pins_CREALITY_V24S1_301.h +++ b/Marlin/src/pins/stm32f1/pins_CREALITY_V24S1_301.h @@ -44,6 +44,8 @@ #define DEFAULT_MACHINE_NAME "Ender-3 S1" #endif +#define BOARD_LCD_SERIAL_PORT 2 + // // Servos // diff --git a/Marlin/src/pins/stm32f1/pins_CREALITY_V423.h b/Marlin/src/pins/stm32f1/pins_CREALITY_V423.h index c174b0e56e..e8ffca6a5b 100644 --- a/Marlin/src/pins/stm32f1/pins_CREALITY_V423.h +++ b/Marlin/src/pins/stm32f1/pins_CREALITY_V423.h @@ -28,6 +28,8 @@ #define BOARD_INFO_NAME "Creality v4.2.3" #define DEFAULT_MACHINE_NAME "Creality3D" +#define BOARD_LCD_SERIAL_PORT 2 + // // Heaters // diff --git a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN.h b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN.h index ff438418fe..f081dad4cb 100644 --- a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN.h +++ b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN.h @@ -58,6 +58,8 @@ #define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE // 2K #endif +#define BOARD_LCD_SERIAL_PORT 2 + // // Servos // diff --git a/Marlin/src/pins/stm32f4/pins_BTT_OCTOPUS_V1_1.h b/Marlin/src/pins/stm32f4/pins_BTT_OCTOPUS_V1_1.h index e9de6d8176..21c93b8f31 100644 --- a/Marlin/src/pins/stm32f4/pins_BTT_OCTOPUS_V1_1.h +++ b/Marlin/src/pins/stm32f4/pins_BTT_OCTOPUS_V1_1.h @@ -23,6 +23,8 @@ #define BOARD_INFO_NAME "BTT OCTOPUS V1.1" +#define BOARD_LCD_SERIAL_PORT 1 + // // Temperature Sensors // diff --git a/Marlin/src/pins/stm32f4/pins_BTT_SKR_MINI_E3_V3_0_1.h b/Marlin/src/pins/stm32f4/pins_BTT_SKR_MINI_E3_V3_0_1.h index 0582cdff61..ca1adec5d7 100644 --- a/Marlin/src/pins/stm32f4/pins_BTT_SKR_MINI_E3_V3_0_1.h +++ b/Marlin/src/pins/stm32f4/pins_BTT_SKR_MINI_E3_V3_0_1.h @@ -52,6 +52,8 @@ #define MARLIN_EEPROM_SIZE 0x1000U // 4K #endif +#define BOARD_LCD_SERIAL_PORT 1 + // // Servos // diff --git a/Marlin/src/pins/stm32f4/pins_CREALITY_CR4NTXXC10.h b/Marlin/src/pins/stm32f4/pins_CREALITY_CR4NTXXC10.h index 3b22085b3d..71ee1b84dc 100644 --- a/Marlin/src/pins/stm32f4/pins_CREALITY_CR4NTXXC10.h +++ b/Marlin/src/pins/stm32f4/pins_CREALITY_CR4NTXXC10.h @@ -48,6 +48,8 @@ //#undef DISABLE_DEBUG // DISABLE_(DEBUG|JTAG) is not supported for STM32F4. //#define DISABLE_JTAG +#define BOARD_LCD_SERIAL_PORT 2 + // // EEPROM // diff --git a/Marlin/src/pins/stm32f4/pins_CREALITY_F401.h b/Marlin/src/pins/stm32f4/pins_CREALITY_F401.h index 757dde06c9..eecb5c8bc3 100644 --- a/Marlin/src/pins/stm32f4/pins_CREALITY_F401.h +++ b/Marlin/src/pins/stm32f4/pins_CREALITY_F401.h @@ -47,6 +47,8 @@ // 32Mb FLASH //#define SPI_FLASH_CS ? +#define BOARD_LCD_SERIAL_PORT 2 + // // Servos // diff --git a/Marlin/src/pins/stm32f4/pins_MKS_MONSTER8_V1.h b/Marlin/src/pins/stm32f4/pins_MKS_MONSTER8_V1.h index a8d0be3ca6..758690ee80 100644 --- a/Marlin/src/pins/stm32f4/pins_MKS_MONSTER8_V1.h +++ b/Marlin/src/pins/stm32f4/pins_MKS_MONSTER8_V1.h @@ -23,6 +23,8 @@ #define BOARD_INFO_NAME "MKS Monster8 V1" +#define BOARD_LCD_SERIAL_PORT 1 + // // Limit Switches // diff --git a/Marlin/src/pins/stm32g0/pins_BTT_SKR_MINI_E3_V3_0.h b/Marlin/src/pins/stm32g0/pins_BTT_SKR_MINI_E3_V3_0.h index 121dbac336..c7130564ef 100644 --- a/Marlin/src/pins/stm32g0/pins_BTT_SKR_MINI_E3_V3_0.h +++ b/Marlin/src/pins/stm32g0/pins_BTT_SKR_MINI_E3_V3_0.h @@ -34,8 +34,6 @@ // Ignore temp readings during development. //#define BOGUS_TEMPERATURE_GRACE_PERIOD 2000 -#define LED_PIN PD8 - // Onboard I2C EEPROM #if ANY(NO_EEPROM_SELECTED, I2C_EEPROM) #undef NO_EEPROM_SELECTED @@ -46,6 +44,10 @@ #define MARLIN_EEPROM_SIZE 0x1000U // 4K #endif +#define BOARD_LCD_SERIAL_PORT 1 + +#define LED_PIN PD8 + // // Servos // diff --git a/Marlin/src/pins/stm32h7/pins_BTT_SKR_V3_0_common.h b/Marlin/src/pins/stm32h7/pins_BTT_SKR_V3_0_common.h index 87afd7bb16..7456236669 100644 --- a/Marlin/src/pins/stm32h7/pins_BTT_SKR_V3_0_common.h +++ b/Marlin/src/pins/stm32h7/pins_BTT_SKR_V3_0_common.h @@ -41,6 +41,8 @@ #define USES_DIAG_JUMPERS +#define BOARD_LCD_SERIAL_PORT 1 + // Onboard I2C EEPROM #if ANY(NO_EEPROM_SELECTED, I2C_EEPROM) #undef NO_EEPROM_SELECTED From 434bf81f8e98a8ede3576ad9fcc36b7f3cfe6fff Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sun, 16 Mar 2025 00:36:22 -0500 Subject: [PATCH 114/787] =?UTF-8?q?=F0=9F=A9=B9=20Fix=20max=20Y/Z=20endsto?= =?UTF-8?q?p=20pins=20on=20GMARSH=20X6=20REV1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/pins/lpc1768/pins_GMARSH_X6_REV1.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/src/pins/lpc1768/pins_GMARSH_X6_REV1.h b/Marlin/src/pins/lpc1768/pins_GMARSH_X6_REV1.h index 4cb8a01a20..6329c506a0 100644 --- a/Marlin/src/pins/lpc1768/pins_GMARSH_X6_REV1.h +++ b/Marlin/src/pins/lpc1768/pins_GMARSH_X6_REV1.h @@ -50,9 +50,9 @@ #define X_MIN_PIN P0_00 #define X_MAX_PIN P0_01 #define Y_MIN_PIN P0_10 -#define Y_MAX_PIN P0_21 +#define Y_MAX_PIN P0_11 #define Z_MIN_PIN P2_13 -#define Z_MAX_PIN P2_22 +#define Z_MAX_PIN P2_12 // // Steppers From b954959f55d86e0feff045a561f70524bb260bc8 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sun, 16 Mar 2025 03:24:00 -0500 Subject: [PATCH 115/787] =?UTF-8?q?=E2=9C=A8=20M550=20CONFIGURABLE=5FMACHI?= =?UTF-8?q?NE=5FNAME=20(#27731)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/Configuration.h | 1 + Marlin/Configuration_adv.h | 2 +- Marlin/src/MarlinCore.cpp | 8 ++ Marlin/src/MarlinCore.h | 4 + Marlin/src/core/language.h | 1 + Marlin/src/core/mstring.h | 3 + Marlin/src/gcode/config/M550.cpp | 59 ++++++++++++++ Marlin/src/gcode/control/M80_M81.cpp | 8 +- Marlin/src/gcode/gcode.cpp | 4 + Marlin/src/gcode/gcode.h | 5 ++ Marlin/src/gcode/host/M16.cpp | 2 +- Marlin/src/inc/Conditionals-2-LCD.h | 16 +++- Marlin/src/inc/SanityCheck.h | 4 + .../src/lcd/e3v2/marlinui/lcdprint_dwin.cpp | 2 +- .../ftdi_eve_touch_ui/ftdi_eve_extui.cpp | 2 +- .../extui/ia_creality/ia_creality_extui.cpp | 10 ++- .../lcd/extui/ia_creality/ia_creality_rts.cpp | 7 +- Marlin/src/lcd/extui/nextion/nextion_tft.cpp | 72 ++++++++--------- .../src/lcd/extui/nextion/nextion_tft_defs.h | 18 +++-- Marlin/src/lcd/extui/ui_api.cpp | 8 +- Marlin/src/lcd/extui/ui_api.h | 3 +- Marlin/src/lcd/language/language_an.h | 2 +- Marlin/src/lcd/language/language_bg.h | 2 +- Marlin/src/lcd/language/language_ca.h | 2 +- Marlin/src/lcd/language/language_cz.h | 2 +- Marlin/src/lcd/language/language_da.h | 2 +- Marlin/src/lcd/language/language_de.h | 2 +- Marlin/src/lcd/language/language_el.h | 2 +- Marlin/src/lcd/language/language_el_gr.h | 2 +- Marlin/src/lcd/language/language_en.h | 2 +- Marlin/src/lcd/language/language_es.h | 2 +- Marlin/src/lcd/language/language_eu.h | 2 +- Marlin/src/lcd/language/language_fi.h | 2 +- Marlin/src/lcd/language/language_fr.h | 2 +- Marlin/src/lcd/language/language_fr_na.h | 2 +- Marlin/src/lcd/language/language_gl.h | 2 +- Marlin/src/lcd/language/language_hr.h | 2 +- Marlin/src/lcd/language/language_hu.h | 2 +- Marlin/src/lcd/language/language_it.h | 2 +- Marlin/src/lcd/language/language_jp_kana.h | 2 +- Marlin/src/lcd/language/language_ko_KR.h | 2 +- Marlin/src/lcd/language/language_nl.h | 2 +- Marlin/src/lcd/language/language_pl.h | 2 +- Marlin/src/lcd/language/language_pt.h | 2 +- Marlin/src/lcd/language/language_pt_br.h | 2 +- Marlin/src/lcd/language/language_ro.h | 2 +- Marlin/src/lcd/language/language_ru.h | 2 +- Marlin/src/lcd/language/language_sk.h | 2 +- Marlin/src/lcd/language/language_sv.h | 2 +- Marlin/src/lcd/language/language_tr.h | 2 +- Marlin/src/lcd/language/language_uk.h | 2 +- Marlin/src/lcd/language/language_vi.h | 2 +- Marlin/src/lcd/language/language_zh_CN.h | 2 +- Marlin/src/lcd/language/language_zh_TW.h | 2 +- Marlin/src/lcd/lcdprint.cpp | 71 +--------------- Marlin/src/lcd/lcdprint.h | 31 +------ Marlin/src/lcd/marlinui.cpp | 80 +++++++++++++++++-- Marlin/src/lcd/marlinui.h | 36 ++++++--- Marlin/src/lcd/menu/menu_info.cpp | 10 ++- Marlin/src/lcd/menu/menu_item.h | 24 ++++-- Marlin/src/lcd/utf8.cpp | 4 - Marlin/src/module/settings.cpp | 26 ++++++ buildroot/tests/ARMED | 2 +- buildroot/tests/SAMD21_minitronics20 | 3 +- ini/features.ini | 1 + 65 files changed, 367 insertions(+), 226 deletions(-) create mode 100644 Marlin/src/gcode/config/M550.cpp diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index f804dc605a..e9dc6f0fd1 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -129,6 +129,7 @@ // Name displayed in the LCD "Ready" message and Info menu //#define CUSTOM_MACHINE_NAME "3D Printer" +//#define CONFIGURABLE_MACHINE_NAME // Add G-code M550 to set/report the machine name // Printer's unique ID, used by some programs to differentiate between machines. // Choose your own or use a service like https://www.uuidgenerator.net/version4 diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index ad62cc06cc..ff85b6c0e3 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -2227,7 +2227,7 @@ // Developer menu (accessed by touching "About Printer" copyright text) //#define TOUCH_UI_DEVELOPER_MENU -#endif +#endif // TOUCH_UI_FTDI_EVE // // Classic UI Options diff --git a/Marlin/src/MarlinCore.cpp b/Marlin/src/MarlinCore.cpp index bdcabca980..689f71f8e5 100644 --- a/Marlin/src/MarlinCore.cpp +++ b/Marlin/src/MarlinCore.cpp @@ -271,6 +271,10 @@ PGMSTR(M112_KILL_STR, "M112 Shutdown"); +#if ENABLED(CONFIGURABLE_MACHINE_NAME) + MString<64> machine_name; +#endif + MarlinState marlin_state = MarlinState::MF_INITIALIZING; // For M109 and M190, this flag may be cleared (by M108) to exit the wait loop @@ -1363,6 +1367,10 @@ void setup() { SETUP_RUN(settings.first_load()); // Load data from EEPROM if available (or use defaults) // This also updates variables in the planner, elsewhere + #if ENABLED(CONFIGURABLE_MACHINE_NAME) + SETUP_RUN(ui.reset_status(false)); // machine_name Initialized by settings.load() + #endif + #if ENABLED(PROBE_TARE) SETUP_RUN(probe.tare_init()); #endif diff --git a/Marlin/src/MarlinCore.h b/Marlin/src/MarlinCore.h index 9cf74de2c6..ecab0e3630 100644 --- a/Marlin/src/MarlinCore.h +++ b/Marlin/src/MarlinCore.h @@ -41,6 +41,10 @@ inline void idle_no_sleep() { idle(true); } void kill(FSTR_P const lcd_error=nullptr, FSTR_P const lcd_component=nullptr, const bool steppers_off=false); void minkill(const bool steppers_off=false); +#if ENABLED(CONFIGURABLE_MACHINE_NAME) + extern MString<64> machine_name; +#endif + // Global State of the firmware enum class MarlinState : uint8_t { MF_INITIALIZING = 0, diff --git a/Marlin/src/core/language.h b/Marlin/src/core/language.h index f64c7513df..dddc00dba8 100644 --- a/Marlin/src/core/language.h +++ b/Marlin/src/core/language.h @@ -88,6 +88,7 @@ #undef MACHINE_NAME #define MACHINE_NAME DEFAULT_MACHINE_NAME #endif +#define MACHINE_NAME_SUBST TERN(CONFIGURABLE_MACHINE_NAME, "$", MACHINE_NAME) #define MARLIN_WEBSITE_URL "marlinfw.org" diff --git a/Marlin/src/core/mstring.h b/Marlin/src/core/mstring.h index b405262d30..e3fb78c50e 100644 --- a/Marlin/src/core/mstring.h +++ b/Marlin/src/core/mstring.h @@ -298,6 +298,9 @@ public: MString& clear() { return set(); } MString& eol() { return append('\n'); } MString& trunc(const int &i) { if (i <= SIZE) str[i] = '\0'; debug(F("trunc")); return *this; } + MString& ltrim() { char *s = str; while (*s == ' ') ++s; if (s != str) strcpy(str, s); return *this; } + MString& rtrim() { int s = length(); while (s && str[s - 1] == ' ') --s; str[s] = '\0'; return *this; } + MString& trim() { return rtrim().ltrim(); } // Truncate on a Unicode boundary MString& utrunc(const int &n=SIZE) { diff --git a/Marlin/src/gcode/config/M550.cpp b/Marlin/src/gcode/config/M550.cpp new file mode 100644 index 0000000000..6ff0c506de --- /dev/null +++ b/Marlin/src/gcode/config/M550.cpp @@ -0,0 +1,59 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "../../inc/MarlinConfig.h" + +#if ENABLED(CONFIGURABLE_MACHINE_NAME) + +#include "../gcode.h" +#include "../../MarlinCore.h" +#include "../../lcd/marlinui.h" + +/** + * M550: Set machine name + * + * Parameters: + * P "" Set the name using the 'P' parameter (RepRapFirmware) + * "" Set the name using the "string" parameter + */ +void GcodeSuite::M550() { + bool did_set = true; + + if (parser.seenval('P')) + machine_name = parser.value_string(); + else if (TERN(GCODE_QUOTED_STRINGS, false, parser.seen('P'))) + machine_name = parser.string_arg[0] == 'P' ? &parser.string_arg[1] : parser.string_arg; + else if (parser.string_arg && parser.string_arg[0]) + machine_name = parser.string_arg; + else + did_set = false; + + if (did_set) { + machine_name.trim(); + ui.reset_status(false); + } + else + SERIAL_ECHOLNPGM("RepRap name: ", &machine_name); + +} + +#endif // CONFIGURABLE_MACHINE_NAME diff --git a/Marlin/src/gcode/control/M80_M81.cpp b/Marlin/src/gcode/control/M80_M81.cpp index 8a52d49d9a..a37b0af680 100644 --- a/Marlin/src/gcode/control/M80_M81.cpp +++ b/Marlin/src/gcode/control/M80_M81.cpp @@ -38,7 +38,7 @@ #include "../../feature/powerloss.h" #endif -#if HAS_SUICIDE +#if ANY(HAS_SUICIDE, CONFIGURABLE_MACHINE_NAME) #include "../../MarlinCore.h" #endif @@ -92,7 +92,11 @@ void GcodeSuite::M81() { safe_delay(1000); // Wait 1 second before switching off - LCD_MESSAGE_F(MACHINE_NAME " " STR_OFF "."); + #if ENABLED(CONFIGURABLE_MACHINE_NAME) + ui.set_status(&MString<30>(&machine_name, ' ', F(STR_OFF), '.')); + #else + LCD_MESSAGE_F(MACHINE_NAME " " STR_OFF "."); + #endif bool delayed_power_off = false; diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp index 9fed4dcada..881149fb52 100644 --- a/Marlin/src/gcode/gcode.cpp +++ b/Marlin/src/gcode/gcode.cpp @@ -947,6 +947,10 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) { case 540: M540(); break; // M540: Set abort on endstop hit for SD printing #endif + #if ENABLED(CONFIGURABLE_MACHINE_NAME) + case 550: M550(); break; // M550: Set machine name + #endif + #if HAS_ETHERNET case 552: M552(); break; // M552: Set IP address case 553: M553(); break; // M553: Set gateway diff --git a/Marlin/src/gcode/gcode.h b/Marlin/src/gcode/gcode.h index 589cd2bc48..e86a58d85d 100644 --- a/Marlin/src/gcode/gcode.h +++ b/Marlin/src/gcode/gcode.h @@ -261,6 +261,7 @@ * M512 - Set/Change/Remove Password (Requires PASSWORD_CHANGE_GCODE) * M524 - Abort the current SD print job started with M24. (Requires SDSUPPORT) * M540 - Enable/disable SD card abort on endstop hit: "M540 S". (Requires SD_ABORT_ON_ENDSTOP_HIT) + * M550 - Set the machine name: "M550 P". (Requires CONFIGURABLE_MACHINE_NAME) * M552 - Get or set IP address. Enable/disable network interface. (Requires enabled Ethernet port) * M553 - Get or set IP netmask. (Requires enabled Ethernet port) * M554 - Get or set IP gateway. (Requires enabled Ethernet port) @@ -1128,6 +1129,10 @@ private: static void M540(); #endif + #if ENABLED(CONFIGURABLE_MACHINE_NAME) + static void M550(); + #endif + #if HAS_ETHERNET static void M552(); static void M552_report(); diff --git a/Marlin/src/gcode/host/M16.cpp b/Marlin/src/gcode/host/M16.cpp index 07b0c5ef57..fc41ba3322 100644 --- a/Marlin/src/gcode/host/M16.cpp +++ b/Marlin/src/gcode/host/M16.cpp @@ -33,7 +33,7 @@ */ void GcodeSuite::M16() { - if (strcmp_P(parser.string_arg, PSTR(MACHINE_NAME))) + if (TERN(CONFIGURABLE_MACHINE_NAME, strcmp(parser.string_arg, machine_name), strcmp_P(parser.string_arg, PSTR(MACHINE_NAME)))) kill(GET_TEXT_F(MSG_KILL_EXPECTED_PRINTER)); } diff --git a/Marlin/src/inc/Conditionals-2-LCD.h b/Marlin/src/inc/Conditionals-2-LCD.h index 40f18c406a..8c818864a0 100644 --- a/Marlin/src/inc/Conditionals-2-LCD.h +++ b/Marlin/src/inc/Conditionals-2-LCD.h @@ -615,12 +615,20 @@ #define HAS_STATUS_MESSAGE 1 #endif -#if HAS_WIRED_LCD && !HAS_GRAPHICAL_TFT && !IS_DWIN_MARLINUI - #define HAS_LCDPRINT 1 +#if ANY(HAS_WIRED_LCD, DWIN_LCD_PROUI) + #if ENABLED(STATUS_MESSAGE_SCROLLING) + #define MAX_MESSAGE_SIZE _MAX(LONG_FILENAME_LENGTH, MAX_LANG_CHARSIZE * (LCD_WIDTH)) + #else + #define MAX_MESSAGE_SIZE (MAX_LANG_CHARSIZE * (LCD_WIDTH)) + #endif +#elif HAS_STATUS_MESSAGE + #define MAX_MESSAGE_SIZE 63 +#else + #define MAX_MESSAGE_SIZE 1 #endif -#if HAS_DISPLAY || HAS_LCDPRINT - #define HAS_UTF8_UTILS 1 +#if HAS_WIRED_LCD && !HAS_GRAPHICAL_TFT && !IS_DWIN_MARLINUI + #define HAS_LCDPRINT 1 #endif #if IS_ULTIPANEL && DISABLED(NO_LCD_MENUS) diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index 76b9c136d0..e07fa78173 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -4507,6 +4507,10 @@ static_assert(WITHIN(MULTISTEPPING_LIMIT, 1, 128) && IS_POWER_OF_2(MULTISTEPPING #error "Only enable ULTIPANEL_FEEDMULTIPLY or ULTIPANEL_FLOWPERCENT, but not both." #endif +#if ENABLED(CONFIGURABLE_MACHINE_NAME) && DISABLED(GCODE_QUOTED_STRINGS) + #error "CONFIGURABLE_MACHINE_NAME requires GCODE_QUOTED_STRINGS." +#endif + // Misc. Cleanup #undef _TEST_PWM #undef _NUM_AXES_STR diff --git a/Marlin/src/lcd/e3v2/marlinui/lcdprint_dwin.cpp b/Marlin/src/lcd/e3v2/marlinui/lcdprint_dwin.cpp index 9fa75a700b..d13ec2e779 100644 --- a/Marlin/src/lcd/e3v2/marlinui/lcdprint_dwin.cpp +++ b/Marlin/src/lcd/e3v2/marlinui/lcdprint_dwin.cpp @@ -107,7 +107,7 @@ int lcd_put_u8str_max_P(PGM_P utf8_pstr, const pixel_len_t max_length) { return lcd_put_u8str_max_cb(utf8_pstr, read_byte_rom, max_length); } -lcd_uint_t lcd_put_u8str_P(PGM_P const ptpl, const int8_t ind, const char * const cstr/*=nullptr*/, FSTR_P const fstr/*=nullptr*/, const lcd_uint_t maxlen/*=LCD_WIDTH*/) { +lcd_uint_t lcd_put_u8str_P(PGM_P const ptpl, const int8_t ind, const char * const cstr/*=nullptr*/, FSTR_P const fstr/*=nullptr*/, const lcd_uint_t maxlen/*=MAX_MESSAGE_SIZE*/) { dwin_string.set(ptpl, ind, cstr, fstr); dwin_string.truncate(maxlen); dwinDrawString(dwin_font.solid, dwin_font.index, dwin_font.fg, dwin_font.bg, cursor.x, cursor.y, dwin_string.string()); diff --git a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_extui.cpp b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_extui.cpp index 0035ee66fe..c26a809037 100644 --- a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_extui.cpp +++ b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_extui.cpp @@ -74,7 +74,7 @@ namespace ExtUI { void onMinTempError(const heater_id_t header_id) {} void onMaxTempError(const heater_id_t header_id) {} - void onStatusChanged(const char *lcd_msg) { StatusScreen::setStatusMessage(lcd_msg); } + void onStatusChanged(const char * const lcd_msg) { StatusScreen::setStatusMessage(lcd_msg); } void onPrintTimerStarted() { InterfaceSoundsScreen::playEventSound(InterfaceSoundsScreen::PRINTING_STARTED); diff --git a/Marlin/src/lcd/extui/ia_creality/ia_creality_extui.cpp b/Marlin/src/lcd/extui/ia_creality/ia_creality_extui.cpp index 0a1c3f6e2c..4a1d49a020 100644 --- a/Marlin/src/lcd/extui/ia_creality/ia_creality_extui.cpp +++ b/Marlin/src/lcd/extui/ia_creality/ia_creality_extui.cpp @@ -252,9 +252,15 @@ void onUserConfirmRequired(const int icon, FSTR_P const fstr, FSTR_P const fBtn) } #endif -void onStatusChanged(const char *const statMsg) { - for (int16_t j = 0; j < 20; j++) // Clear old message +static constexpr int16_t STATUS_MESSAGE_SIZE = 20; + +void clearStatus() { + for (int16_t j = 0; j < STATUS_MESSAGE_SIZE; j++) // Clear old message rts.sendData(' ', StatusMessageString + j); +} + +void onStatusChanged(const char * const statMsg) { + clearStatus(); rts.sendData(statMsg, StatusMessageString); } diff --git a/Marlin/src/lcd/extui/ia_creality/ia_creality_rts.cpp b/Marlin/src/lcd/extui/ia_creality/ia_creality_rts.cpp index 84df4f5871..660d7faed7 100644 --- a/Marlin/src/lcd/extui/ia_creality/ia_creality_rts.cpp +++ b/Marlin/src/lcd/extui/ia_creality/ia_creality_rts.cpp @@ -99,7 +99,12 @@ void RTS::onStartup() { sendData(StartSoundSet, SoundAddr); delay_ms(400); // Delay to allow screen to configure - onStatusChanged(MACHINE_NAME " Ready"); + #if ENABLED(CONFIGURABLE_MACHINE_NAME) + const MString<32> ready(message_string, " Ready"); + onStatusChanged(ready); + #else + onStatusChanged(F(MACHINE_NAME " Ready")); + #endif sendData(100, FeedrateDisplay); diff --git a/Marlin/src/lcd/extui/nextion/nextion_tft.cpp b/Marlin/src/lcd/extui/nextion/nextion_tft.cpp index 9ebd783124..53af67f3d9 100644 --- a/Marlin/src/lcd/extui/nextion/nextion_tft.cpp +++ b/Marlin/src/lcd/extui/nextion/nextion_tft.cpp @@ -63,12 +63,16 @@ void NextionTFT::startup() { delay_ms(100); SEND_VAL("tmppage.connected", 1); - SEND_VALasTXT("tmppage.marlin", SHORT_BUILD_VERSION); - SEND_VALasTXT("tmppage.compiled", __DATE__ " / " __TIME__); + SEND_TXT("tmppage.marlin", SHORT_BUILD_VERSION); + SEND_TXT("tmppage.compiled", __DATE__ " / " __TIME__); SEND_VALasTXT("tmppage.extruder", EXTRUDERS); - SEND_VALasTXT("tmppage.printer", MACHINE_NAME); - SEND_VALasTXT("tmppage.author", STRING_CONFIG_H_AUTHOR); - SEND_VALasTXT("tmppage.released", STRING_DISTRIBUTION_DATE); + #if ENABLED(CONFIGURABLE_MACHINE_NAME) + SEND_VALasTXT("tmppage.printer", &machine_name); + #else + SEND_TXT("tmppage.printer", MACHINE_NAME); + #endif + SEND_TXT("tmppage.author", STRING_CONFIG_H_AUTHOR); + SEND_TXT("tmppage.released", STRING_DISTRIBUTION_DATE); SEND_VALasTXT("tmppage.bedx", X_BED_SIZE); SEND_VALasTXT("tmppage.bedy", Y_BED_SIZE); SEND_VALasTXT("tmppage.bedz", Z_MAX_POS); @@ -222,12 +226,16 @@ void NextionTFT::panelInfo(uint8_t req) { case 2: // Printer Info if (!isPrinting()) { SEND_VAL("tmppage.connected", 1); - SEND_VALasTXT("tmppage.marlin", SHORT_BUILD_VERSION); - SEND_VALasTXT("tmppage.compiled", __DATE__ " / " __TIME__); + SEND_TXT("tmppage.marlin", SHORT_BUILD_VERSION); + SEND_TXT("tmppage.compiled", __DATE__ " / " __TIME__); SEND_VALasTXT("tmppage.extruder", EXTRUDERS); - SEND_VALasTXT("tmppage.printer", MACHINE_NAME); - SEND_VALasTXT("tmppage.author", STRING_CONFIG_H_AUTHOR); - SEND_VALasTXT("tmppage.released", STRING_DISTRIBUTION_DATE); + #if ENABLED(CONFIGURABLE_MACHINE_NAME) + SEND_VALasTXT("tmppage.printer", &machine_name); + #else + SEND_TXT("tmppage.printer", MACHINE_NAME); + #endif + SEND_TXT("tmppage.author", STRING_CONFIG_H_AUTHOR); + SEND_TXT("tmppage.released", STRING_DISTRIBUTION_DATE); SEND_VALasTXT("tmppage.bedx", X_BED_SIZE); SEND_VALasTXT("tmppage.bedy", Y_BED_SIZE); SEND_VALasTXT("tmppage.bedz", Z_MAX_POS); @@ -430,59 +438,43 @@ void NextionTFT::panelInfo(uint8_t req) { case 36: // Endstop Info #if X_HOME_TO_MIN - SEND_VALasTXT("x1", READ(X_MIN_PIN) == X_MIN_ENDSTOP_HIT_STATE ? "triggered" : "open"); + SEND_TXT_F("x1", READ(X_MIN_PIN) == X_MIN_ENDSTOP_HIT_STATE ? F("triggered") : F("open")); #elif X_HOME_TO_MAX - SEND_VALasTXT("x2", READ(X_MAX_PIN) == X_MAX_ENDSTOP_HIT_STATE ? "triggered" : "open"); + SEND_TXT_F("x2", READ(X_MAX_PIN) == X_MAX_ENDSTOP_HIT_STATE ? F("triggered") : F("open")); #endif #if Y_HOME_TO_MIN - SEND_VALasTXT("y1", READ(Y_MIN_PIN) == Y_MIN_ENDSTOP_HIT_STATE ? "triggered" : "open"); + SEND_TXT_F("y1", READ(Y_MIN_PIN) == Y_MIN_ENDSTOP_HIT_STATE ? F("triggered") : F("open")); #elif Y_HOME_TO_MAX - SEND_VALasTXT("y2", READ(X_MAX_PIN) == Y_MAX_ENDSTOP_HIT_STATE ? "triggered" : "open"); + SEND_TXT_F("y2", READ(X_MAX_PIN) == Y_MAX_ENDSTOP_HIT_STATE ? F("triggered") : F("open")); #endif #if Z_HOME_TO_MIN - SEND_VALasTXT("z1", READ(Z_MIN_PIN) == Z_MIN_ENDSTOP_HIT_STATE ? "triggered" : "open"); + SEND_TXT_F("z1", READ(Z_MIN_PIN) == Z_MIN_ENDSTOP_HIT_STATE ? F("triggered") : F("open")); #elif Z_HOME_TO_MAX - SEND_VALasTXT("z2", READ(Z_MAX_PIN) == Z_MAX_ENDSTOP_HIT_STATE ? "triggered" : "open"); + SEND_TXT_F("z2", READ(Z_MAX_PIN) == Z_MAX_ENDSTOP_HIT_STATE ? F("triggered") : F("open")); #endif #if USE_Z2_MIN - SEND_VALasTXT("z2", READ(Z2_MIN_PIN) == Z2_MIN_ENDSTOP_HIT_STATE ? "triggered" : "open"); + SEND_TXT_F("z2", READ(Z2_MIN_PIN) == Z2_MIN_ENDSTOP_HIT_STATE ? F("triggered") : F("open")); #elif USE_Z2_MAX - SEND_VALasTXT("z2", READ(Z2_MAX_PIN) == Z2_MAX_ENDSTOP_HIT_STATE ? "triggered" : "open"); + SEND_TXT_F("z2", READ(Z2_MAX_PIN) == Z2_MAX_ENDSTOP_HIT_STATE ? F("triggered") : F("open")); #endif #if HAS_BED_PROBE - //SEND_VALasTXT("bltouch", PROBE_TRIGGERED() ? "triggered" : "open"); + //SEND_TXT_F("bltouch", PROBE_TRIGGERED() ? F("triggered") : F("open")); #else SEND_NA("bltouch"); #endif break; case 37: // PID - #if ENABLED(PIDTEMP) - #define SEND_PID_INFO_0(A, B) SEND_VALasTXT(A, getPID_K##B(E0)) - #else - #define SEND_PID_INFO_0(A, B) SEND_NA(A) - #endif + #define SEND_PID_INFO_0(A, B) TERN(PIDTEMP, SEND_VALasTXT(A, getPID_K##B(E0)), SEND_NA(A)) #if ALL(PIDTEMP, HAS_MULTI_EXTRUDER) #define SEND_PID_INFO_1(A, B) SEND_VALasTXT(A, getPID_K##B(E1)) #else #define SEND_PID_INFO_1(A, B) SEND_NA(A) #endif - #if ENABLED(PIDTEMPBED) - #define SEND_PID_INFO_BED(A, B) SEND_VALasTXT(A, getBedPID_K##B()) - #else - #define SEND_PID_INFO_BED(A, B) SEND_NA(A) - #endif - SEND_PID_INFO_0("p0", p); - SEND_PID_INFO_0("i0", i); - SEND_PID_INFO_0("d0", d); - - SEND_PID_INFO_1("p1", p); - SEND_PID_INFO_1("i1", i); - SEND_PID_INFO_1("d1", d); - - SEND_PID_INFO_BED("hbp", p); - SEND_PID_INFO_BED("hbi", i); - SEND_PID_INFO_BED("hbd", d); + #define SEND_PID_INFO_BED(A, B) TERN(PIDTEMPBED, SEND_VALasTXT(A, getBedPID_K##B()), SEND_NA(A)) + SEND_PID_INFO_0("p0", p); SEND_PID_INFO_0("i0", i); SEND_PID_INFO_0("d0", d); + SEND_PID_INFO_1("p1", p); SEND_PID_INFO_1("i1", i); SEND_PID_INFO_1("d1", d); + SEND_PID_INFO_BED("hbp", p); SEND_PID_INFO_BED("hbi", i); SEND_PID_INFO_BED("hbd", d); break; } } diff --git a/Marlin/src/lcd/extui/nextion/nextion_tft_defs.h b/Marlin/src/lcd/extui/nextion/nextion_tft_defs.h index 061d29559c..e376e34e2b 100644 --- a/Marlin/src/lcd/extui/nextion/nextion_tft_defs.h +++ b/Marlin/src/lcd/extui/nextion/nextion_tft_defs.h @@ -54,10 +54,14 @@ // TFT panel commands #define msg_welcome MACHINE_NAME " Ready." -#define SEND_TEMP(x,y,t,z) (nextion.tftSend(F(x)), nextion.tftSend(F(".txt=\"")), LCD_SERIAL.print(y), nextion.tftSend(F(t)), LCD_SERIAL.print(z), nextion.tftSend(F("\"\xFF\xFF\xFF"))) -#define SEND_VAL(x,y) (nextion.tftSend(F(x)), nextion.tftSend(F(".val=")), LCD_SERIAL.print(y), nextion.tftSend(F("\xFF\xFF\xFF"))) -#define SEND_TXT(x,y) (nextion.tftSend(F(x)), nextion.tftSend(F(".txt=\"")), nextion.tftSend(F(y)), nextion.tftSend(F("\"\xFF\xFF\xFF"))) -#define SEND_TXT_F(x,y) (nextion.tftSend(F(x)), nextion.tftSend(F(".txt=\"")), nextion.tftSend(y), nextion.tftSend(F("\"\xFF\xFF\xFF"))) -#define SEND_VALasTXT(x,y) (nextion.tftSend(F(x)), nextion.tftSend(F(".txt=\"")), LCD_SERIAL.print(y), nextion.tftSend(F("\"\xFF\xFF\xFF"))) -#define SEND_TXT_END(x) (nextion.tftSend(F(x)), nextion.tftSend(F("\xFF\xFF\xFF"))) -#define SEND_PCO2(x,y,z) (nextion.tftSend(F(x)), LCD_SERIAL.print(y), nextion.tftSend(F(".pco=")), nextion.tftSend(F(z)), nextion.tftSend(F("\xFF\xFF\xFF"))) +#define TXT_OPEN() nextion.tftSend(F(".txt=\"")) +#define TXT_CLOSE() nextion.tftSend(F("\"\xFF\xFF\xFF")) +#define VAL_OPEN() nextion.tftSend(F(".val=")) +#define VAL_CLOSE() nextion.tftSend(F("\xFF\xFF\xFF")) +#define SEND_TEMP(x,y,t,z) (nextion.tftSend(F(x)), TXT_OPEN(), LCD_SERIAL.print(y), nextion.tftSend(F(t)), LCD_SERIAL.print(z), TXT_CLOSE()) // XXX.txt="YYYTTTZZZ" +#define SEND_VAL(x,y) (nextion.tftSend(F(x)), VAL_OPEN(), LCD_SERIAL.print(y), VAL_CLOSE()) // XXX.val=YYY +#define SEND_TXT(x,y) (nextion.tftSend(F(x)), TXT_OPEN(), nextion.tftSend(F(y)), TXT_CLOSE()) // XXX.txt="YYY" +#define SEND_TXT_F(x,y) (nextion.tftSend(F(x)), TXT_OPEN(), nextion.tftSend(y), TXT_CLOSE()) // XXX.txt="YYY" +#define SEND_VALasTXT(x,y) (nextion.tftSend(F(x)), TXT_OPEN(), LCD_SERIAL.print(y), TXT_CLOSE()) // XXX.txt="YYY" +#define SEND_TXT_END(x) (nextion.tftSend(F(x)), VAL_CLOSE()) // XXX +#define SEND_PCO2(x,y,z) (nextion.tftSend(F(x)), LCD_SERIAL.print(y), nextion.tftSend(F(".pco=")), nextion.tftSend(F(z)), VAL_CLOSE()) // XXXYYY.pco=ZZZ diff --git a/Marlin/src/lcd/extui/ui_api.cpp b/Marlin/src/lcd/extui/ui_api.cpp index 4a6f594066..a53b5f5dba 100644 --- a/Marlin/src/lcd/extui/ui_api.cpp +++ b/Marlin/src/lcd/extui/ui_api.cpp @@ -1213,13 +1213,13 @@ namespace ExtUI { #endif } - void onStatusChanged(FSTR_P const fstr) { + void onStatusChanged_P(PGM_P const pstr) { #ifdef __AVR__ - char msg[strlen_P(FTOP(fstr)) + 1]; - strcpy_P(msg, FTOP(fstr)); + char msg[strlen_P(pstr) + 1]; + strcpy_P(msg, pstr); onStatusChanged(msg); #else - onStatusChanged(FTOP(fstr)); + onStatusChanged(pstr); #endif } diff --git a/Marlin/src/lcd/extui/ui_api.h b/Marlin/src/lcd/extui/ui_api.h index 8404033b7b..2676d72aea 100644 --- a/Marlin/src/lcd/extui/ui_api.h +++ b/Marlin/src/lcd/extui/ui_api.h @@ -530,8 +530,9 @@ namespace ExtUI { void onPauseMode(const PauseMessage message, const PauseMode mode=PAUSE_MODE_SAME, const uint8_t extruder=active_extruder); #endif + void onStatusChanged_P(PGM_P const msg); + inline void onStatusChanged(FSTR_P const fstr) { onStatusChanged_P(FTOP(fstr)); } void onStatusChanged(const char * const msg); - void onStatusChanged(FSTR_P const fstr); void onHomingStart(); void onHomingDone(); diff --git a/Marlin/src/lcd/language/language_an.h b/Marlin/src/lcd/language/language_an.h index c51891f6ec..095a3440aa 100644 --- a/Marlin/src/lcd/language/language_an.h +++ b/Marlin/src/lcd/language/language_an.h @@ -37,7 +37,7 @@ namespace LanguageNarrow_an { constexpr uint8_t CHARSIZE = 1; LSTR LANGUAGE = _UxGT("Aragonese"); - LSTR WELCOME_MSG = MACHINE_NAME _UxGT(" parada."); + LSTR WELCOME_MSG = MACHINE_NAME_SUBST _UxGT(" parada."); LSTR MSG_MEDIA_INSERTED = _UxGT("Tarcheta mesa"); LSTR MSG_MEDIA_REMOVED = _UxGT("Tarcheta sacada"); LSTR MSG_LCD_ENDSTOPS = _UxGT("Endstops"); // Max length 8 characters diff --git a/Marlin/src/lcd/language/language_bg.h b/Marlin/src/lcd/language/language_bg.h index 3722dba3ad..4eef867826 100644 --- a/Marlin/src/lcd/language/language_bg.h +++ b/Marlin/src/lcd/language/language_bg.h @@ -36,7 +36,7 @@ namespace LanguageNarrow_bg { constexpr uint8_t CHARSIZE = 2; LSTR LANGUAGE = _UxGT("Bulgarian"); - LSTR WELCOME_MSG = MACHINE_NAME _UxGT(" Готов."); + LSTR WELCOME_MSG = MACHINE_NAME_SUBST _UxGT(" Готов."); LSTR MSG_MEDIA_INSERTED = _UxGT("Картата е поставена"); LSTR MSG_MEDIA_REMOVED = _UxGT("Картата е извадена"); LSTR MSG_MAIN_MENU = _UxGT("Меню"); diff --git a/Marlin/src/lcd/language/language_ca.h b/Marlin/src/lcd/language/language_ca.h index da784bc342..fa74f255aa 100644 --- a/Marlin/src/lcd/language/language_ca.h +++ b/Marlin/src/lcd/language/language_ca.h @@ -33,7 +33,7 @@ namespace LanguageNarrow_ca { constexpr uint8_t CHARSIZE = 2; LSTR LANGUAGE = _UxGT("Catalan"); - LSTR WELCOME_MSG = MACHINE_NAME _UxGT(" preparada."); + LSTR WELCOME_MSG = MACHINE_NAME_SUBST _UxGT(" preparada."); LSTR MSG_MEDIA_INSERTED = _UxGT("Targeta detectada."); LSTR MSG_MEDIA_REMOVED = _UxGT("Targeta extreta."); LSTR MSG_LCD_ENDSTOPS = _UxGT("Endstops"); diff --git a/Marlin/src/lcd/language/language_cz.h b/Marlin/src/lcd/language/language_cz.h index e54a69ec83..814c9ffde8 100644 --- a/Marlin/src/lcd/language/language_cz.h +++ b/Marlin/src/lcd/language/language_cz.h @@ -41,7 +41,7 @@ namespace LanguageNarrow_cz { constexpr uint8_t CHARSIZE = 2; LSTR LANGUAGE = _UxGT("Czech"); - LSTR WELCOME_MSG = MACHINE_NAME _UxGT(" připraven."); + LSTR WELCOME_MSG = MACHINE_NAME_SUBST _UxGT(" připraven."); LSTR MSG_YES = _UxGT("ANO"); LSTR MSG_NO = _UxGT("NE"); LSTR MSG_BACK = _UxGT("Zpět"); diff --git a/Marlin/src/lcd/language/language_da.h b/Marlin/src/lcd/language/language_da.h index c348db0918..35083aa01f 100644 --- a/Marlin/src/lcd/language/language_da.h +++ b/Marlin/src/lcd/language/language_da.h @@ -36,7 +36,7 @@ namespace LanguageNarrow_da { constexpr uint8_t CHARSIZE = 2; LSTR LANGUAGE = _UxGT("Danish"); - LSTR WELCOME_MSG = MACHINE_NAME _UxGT(" er klar"); + LSTR WELCOME_MSG = MACHINE_NAME_SUBST _UxGT(" er klar"); LSTR MSG_MEDIA_INSERTED = _UxGT("Kort isat"); LSTR MSG_MEDIA_REMOVED = _UxGT("Kort fjernet"); LSTR MSG_MAIN_MENU = _UxGT("Menu"); diff --git a/Marlin/src/lcd/language/language_de.h b/Marlin/src/lcd/language/language_de.h index e469a594ca..edc3d4361d 100644 --- a/Marlin/src/lcd/language/language_de.h +++ b/Marlin/src/lcd/language/language_de.h @@ -34,7 +34,7 @@ namespace LanguageNarrow_de { constexpr uint8_t CHARSIZE = 2; LSTR LANGUAGE = _UxGT("Deutsch"); - LSTR WELCOME_MSG = MACHINE_NAME _UxGT(" bereit"); + LSTR WELCOME_MSG = MACHINE_NAME_SUBST _UxGT(" bereit"); LSTR MSG_YES = _UxGT("JA"); LSTR MSG_NO = _UxGT("NEIN"); LSTR MSG_HIGH = _UxGT("HOCH"); diff --git a/Marlin/src/lcd/language/language_el.h b/Marlin/src/lcd/language/language_el.h index b100f31781..85de0f0751 100644 --- a/Marlin/src/lcd/language/language_el.h +++ b/Marlin/src/lcd/language/language_el.h @@ -36,7 +36,7 @@ namespace LanguageNarrow_el { constexpr uint8_t CHARSIZE = 2; LSTR LANGUAGE = _UxGT("Greek (Greece)"); - LSTR WELCOME_MSG = MACHINE_NAME _UxGT(" έτοιμος."); + LSTR WELCOME_MSG = MACHINE_NAME_SUBST _UxGT(" έτοιμος."); LSTR MSG_YES = _UxGT("ΝΑΙ"); LSTR MSG_NO = _UxGT("ΟΧΙ"); LSTR MSG_BACK = _UxGT("Πίσω"); diff --git a/Marlin/src/lcd/language/language_el_gr.h b/Marlin/src/lcd/language/language_el_gr.h index caef745a0e..65b2da5ee3 100644 --- a/Marlin/src/lcd/language/language_el_gr.h +++ b/Marlin/src/lcd/language/language_el_gr.h @@ -36,7 +36,7 @@ namespace LanguageNarrow_el_gr { constexpr uint8_t CHARSIZE = 2; LSTR LANGUAGE = _UxGT("Greek (Greece)"); - LSTR WELCOME_MSG = MACHINE_NAME _UxGT(" έτοιμο."); + LSTR WELCOME_MSG = MACHINE_NAME_SUBST _UxGT(" έτοιμο."); LSTR MSG_MEDIA_INSERTED = _UxGT("Εισαγωγή κάρτας"); LSTR MSG_MEDIA_REMOVED = _UxGT("Αφαίρεση κάρτας"); LSTR MSG_LCD_ENDSTOPS = _UxGT("Endstops"); // Max length 8 characters diff --git a/Marlin/src/lcd/language/language_en.h b/Marlin/src/lcd/language/language_en.h index 3575e40bea..307ff2590e 100644 --- a/Marlin/src/lcd/language/language_en.h +++ b/Marlin/src/lcd/language/language_en.h @@ -69,7 +69,7 @@ namespace LanguageNarrow_en { LSTR LANGUAGE = _UxGT("English"); // These strings should be translated - LSTR WELCOME_MSG = MACHINE_NAME _UxGT(" Ready."); + LSTR WELCOME_MSG = MACHINE_NAME_SUBST _UxGT(" Ready."); LSTR MSG_YES = _UxGT("YES"); LSTR MSG_NO = _UxGT("NO"); LSTR MSG_HIGH = _UxGT("HIGH"); diff --git a/Marlin/src/lcd/language/language_es.h b/Marlin/src/lcd/language/language_es.h index 06e3c753be..1c7d5199d3 100644 --- a/Marlin/src/lcd/language/language_es.h +++ b/Marlin/src/lcd/language/language_es.h @@ -36,7 +36,7 @@ namespace LanguageNarrow_es { constexpr uint8_t CHARSIZE = 2; LSTR LANGUAGE = _UxGT("Spanish"); - LSTR WELCOME_MSG = MACHINE_NAME _UxGT(" Lista"); + LSTR WELCOME_MSG = MACHINE_NAME_SUBST _UxGT(" Lista"); LSTR MSG_YES = _UxGT("SI"); LSTR MSG_NO = _UxGT("NO"); LSTR MSG_BACK = _UxGT("Atrás"); diff --git a/Marlin/src/lcd/language/language_eu.h b/Marlin/src/lcd/language/language_eu.h index df6e6395d1..561de0b8e6 100644 --- a/Marlin/src/lcd/language/language_eu.h +++ b/Marlin/src/lcd/language/language_eu.h @@ -37,7 +37,7 @@ namespace LanguageNarrow_eu { constexpr uint8_t CHARSIZE = 1; LSTR LANGUAGE = _UxGT("Basque-Euskera"); - LSTR WELCOME_MSG = MACHINE_NAME _UxGT(" prest."); + LSTR WELCOME_MSG = MACHINE_NAME_SUBST _UxGT(" prest."); LSTR MSG_BACK = _UxGT("Atzera"); LSTR MSG_MEDIA_INSERTED = _UxGT("Txartela sartuta"); LSTR MSG_MEDIA_REMOVED = _UxGT("Txartela kenduta"); diff --git a/Marlin/src/lcd/language/language_fi.h b/Marlin/src/lcd/language/language_fi.h index e6de9369b1..7b3f0f6082 100644 --- a/Marlin/src/lcd/language/language_fi.h +++ b/Marlin/src/lcd/language/language_fi.h @@ -36,7 +36,7 @@ namespace LanguageNarrow_fi { constexpr uint8_t CHARSIZE = 2; LSTR LANGUAGE = _UxGT("Finnish"); - LSTR WELCOME_MSG = MACHINE_NAME _UxGT(" valmis."); + LSTR WELCOME_MSG = MACHINE_NAME_SUBST _UxGT(" valmis."); LSTR MSG_MEDIA_INSERTED = _UxGT("Kortti asetettu"); LSTR MSG_MEDIA_REMOVED = _UxGT("Kortti poistettu"); LSTR MSG_MAIN_MENU = _UxGT("Palaa"); diff --git a/Marlin/src/lcd/language/language_fr.h b/Marlin/src/lcd/language/language_fr.h index 2a65cd2671..b499b32f7b 100644 --- a/Marlin/src/lcd/language/language_fr.h +++ b/Marlin/src/lcd/language/language_fr.h @@ -36,7 +36,7 @@ namespace LanguageNarrow_fr { constexpr uint8_t CHARSIZE = 2; LSTR LANGUAGE = _UxGT("Français"); - LSTR WELCOME_MSG = MACHINE_NAME _UxGT(" prête."); + LSTR WELCOME_MSG = MACHINE_NAME_SUBST _UxGT(" prête."); LSTR MSG_YES = _UxGT("Oui"); LSTR MSG_NO = _UxGT("Non"); LSTR MSG_BACK = _UxGT("Retour"); diff --git a/Marlin/src/lcd/language/language_fr_na.h b/Marlin/src/lcd/language/language_fr_na.h index 0aad606af5..995a5ecd27 100644 --- a/Marlin/src/lcd/language/language_fr_na.h +++ b/Marlin/src/lcd/language/language_fr_na.h @@ -36,7 +36,7 @@ namespace LanguageNarrow_fr_na { LSTR LANGUAGE = _UxGT("Francais"); - LSTR WELCOME_MSG = MACHINE_NAME _UxGT(" prete."); + LSTR WELCOME_MSG = MACHINE_NAME_SUBST _UxGT(" prete."); LSTR MSG_YES = _UxGT("Oui"); LSTR MSG_NO = _UxGT("Non"); LSTR MSG_BACK = _UxGT("Retour"); diff --git a/Marlin/src/lcd/language/language_gl.h b/Marlin/src/lcd/language/language_gl.h index ada1fd2fa2..37c1aa292a 100644 --- a/Marlin/src/lcd/language/language_gl.h +++ b/Marlin/src/lcd/language/language_gl.h @@ -38,7 +38,7 @@ namespace LanguageNarrow_gl { constexpr uint8_t CHARSIZE = 1; LSTR LANGUAGE = _UxGT("Galician"); - LSTR WELCOME_MSG = MACHINE_NAME _UxGT(" lista."); + LSTR WELCOME_MSG = MACHINE_NAME_SUBST _UxGT(" lista."); LSTR MSG_YES = _UxGT("SI"); LSTR MSG_NO = _UxGT("NON"); LSTR MSG_BACK = _UxGT("Atrás"); diff --git a/Marlin/src/lcd/language/language_hr.h b/Marlin/src/lcd/language/language_hr.h index 9f259693e7..5f60b000e3 100644 --- a/Marlin/src/lcd/language/language_hr.h +++ b/Marlin/src/lcd/language/language_hr.h @@ -36,7 +36,7 @@ namespace LanguageNarrow_hr { constexpr uint8_t CHARSIZE = 2; LSTR LANGUAGE = _UxGT("Croatian"); - LSTR WELCOME_MSG = MACHINE_NAME _UxGT(" spreman."); + LSTR WELCOME_MSG = MACHINE_NAME_SUBST _UxGT(" spreman."); LSTR MSG_MEDIA_INSERTED = _UxGT("SD kartica umetnuta"); LSTR MSG_MEDIA_REMOVED = _UxGT("SD kartica uklonjena"); LSTR MSG_LCD_ENDSTOPS = _UxGT("Endstops"); // Max length 8 characters diff --git a/Marlin/src/lcd/language/language_hu.h b/Marlin/src/lcd/language/language_hu.h index 2f744abc6f..d987416269 100644 --- a/Marlin/src/lcd/language/language_hu.h +++ b/Marlin/src/lcd/language/language_hu.h @@ -39,7 +39,7 @@ namespace LanguageNarrow_hu { constexpr uint8_t CHARSIZE = 2; LSTR LANGUAGE = _UxGT("Magyar"); - LSTR WELCOME_MSG = MACHINE_NAME _UxGT(" Kész."); + LSTR WELCOME_MSG = MACHINE_NAME_SUBST _UxGT(" Kész."); LSTR MSG_YES = _UxGT("IGEN"); LSTR MSG_NO = _UxGT("NEM"); LSTR MSG_BACK = _UxGT("Vissza"); diff --git a/Marlin/src/lcd/language/language_it.h b/Marlin/src/lcd/language/language_it.h index 13a6f88a01..0a7302b0f8 100644 --- a/Marlin/src/lcd/language/language_it.h +++ b/Marlin/src/lcd/language/language_it.h @@ -46,7 +46,7 @@ namespace LanguageNarrow_it { constexpr uint8_t CHARSIZE = 1; LSTR LANGUAGE = _UxGT("Italiano"); - LSTR WELCOME_MSG = MACHINE_NAME _UxGT(" pronta."); + LSTR WELCOME_MSG = MACHINE_NAME_SUBST _UxGT(" pronta."); LSTR MSG_YES = _UxGT("Si"); LSTR MSG_NO = _UxGT("No"); LSTR MSG_HIGH = _UxGT("ALTO"); diff --git a/Marlin/src/lcd/language/language_jp_kana.h b/Marlin/src/lcd/language/language_jp_kana.h index cbc680460a..ae88b1d968 100644 --- a/Marlin/src/lcd/language/language_jp_kana.h +++ b/Marlin/src/lcd/language/language_jp_kana.h @@ -41,7 +41,7 @@ namespace LanguageNarrow_jp_kana { // This translation can be improved by using the full charset of unicode codeblock U+30A0 to U+30FF. // 片仮名表示定義 - LSTR WELCOME_MSG = MACHINE_NAME _UxGT(" ジュンビカンリョウ"); + LSTR WELCOME_MSG = MACHINE_NAME_SUBST _UxGT(" ジュンビカンリョウ"); LSTR MSG_MEDIA_INSERTED = _UxGT("メディアガソウニュウサレマシタ"); // "Card inserted" LSTR MSG_MEDIA_REMOVED = _UxGT("メディアガアリマセン"); // "Card removed" LSTR MSG_RELEASE_MEDIA = _UxGT("メディアノトリダシ"); diff --git a/Marlin/src/lcd/language/language_ko_KR.h b/Marlin/src/lcd/language/language_ko_KR.h index f1eece315c..d5410cadf5 100644 --- a/Marlin/src/lcd/language/language_ko_KR.h +++ b/Marlin/src/lcd/language/language_ko_KR.h @@ -33,7 +33,7 @@ namespace LanguageNarrow_ko_KR { constexpr uint8_t CHARSIZE = 1; LSTR LANGUAGE = _UxGT("Korean"); - LSTR WELCOME_MSG = MACHINE_NAME _UxGT(" 준비."); + LSTR WELCOME_MSG = MACHINE_NAME_SUBST _UxGT(" 준비."); LSTR MSG_BACK = _UxGT("뒤로"); LSTR MSG_MEDIA_INSERTED = _UxGT("카드 삽입됨"); LSTR MSG_MEDIA_REMOVED = _UxGT("카드 제거됨"); diff --git a/Marlin/src/lcd/language/language_nl.h b/Marlin/src/lcd/language/language_nl.h index f47bc053b8..e99417a2dc 100644 --- a/Marlin/src/lcd/language/language_nl.h +++ b/Marlin/src/lcd/language/language_nl.h @@ -37,7 +37,7 @@ namespace LanguageNarrow_nl { constexpr uint8_t CHARSIZE = 1; LSTR LANGUAGE = _UxGT("Dutch"); - LSTR WELCOME_MSG = MACHINE_NAME _UxGT(" gereed."); + LSTR WELCOME_MSG = MACHINE_NAME_SUBST _UxGT(" gereed."); LSTR MSG_BACK = _UxGT("Terug"); LSTR MSG_MEDIA_INSERTED = _UxGT("Kaart ingestoken"); LSTR MSG_MEDIA_REMOVED = _UxGT("Kaart verwijderd"); diff --git a/Marlin/src/lcd/language/language_pl.h b/Marlin/src/lcd/language/language_pl.h index 087a26967d..07573bb2d8 100644 --- a/Marlin/src/lcd/language/language_pl.h +++ b/Marlin/src/lcd/language/language_pl.h @@ -44,7 +44,7 @@ namespace LanguageNarrow_pl { constexpr uint8_t CHARSIZE = 2; LSTR LANGUAGE = _UxGT("Polski"); - LSTR WELCOME_MSG = MACHINE_NAME _UxGT(" gotowy."); + LSTR WELCOME_MSG = MACHINE_NAME_SUBST _UxGT(" gotowy."); LSTR MSG_YES = _UxGT("TAK"); LSTR MSG_NO = _UxGT("NIE"); LSTR MSG_BACK = _UxGT("Wstecz"); diff --git a/Marlin/src/lcd/language/language_pt.h b/Marlin/src/lcd/language/language_pt.h index 8f9745c04b..62799fc9a5 100644 --- a/Marlin/src/lcd/language/language_pt.h +++ b/Marlin/src/lcd/language/language_pt.h @@ -37,7 +37,7 @@ namespace LanguageNarrow_pt { constexpr uint8_t CHARSIZE = 2; LSTR LANGUAGE = _UxGT("Portuguese"); - LSTR WELCOME_MSG = MACHINE_NAME _UxGT(" pronta."); + LSTR WELCOME_MSG = MACHINE_NAME_SUBST _UxGT(" pronta."); LSTR MSG_MEDIA_INSERTED = _UxGT("Cartão inserido"); LSTR MSG_MEDIA_REMOVED = _UxGT("Cartão removido"); LSTR MSG_MAIN_MENU = _UxGT("Menu principal"); diff --git a/Marlin/src/lcd/language/language_pt_br.h b/Marlin/src/lcd/language/language_pt_br.h index 4908986bdb..8d5a608d00 100644 --- a/Marlin/src/lcd/language/language_pt_br.h +++ b/Marlin/src/lcd/language/language_pt_br.h @@ -34,7 +34,7 @@ namespace LanguageNarrow_pt_br { constexpr uint8_t CHARSIZE = 2; LSTR LANGUAGE = _UxGT("Portuguese (BR)"); - LSTR WELCOME_MSG = MACHINE_NAME _UxGT(" pronto."); + LSTR WELCOME_MSG = MACHINE_NAME_SUBST _UxGT(" pronto."); LSTR MSG_YES = _UxGT("SIM"); LSTR MSG_NO = _UxGT("NÃO"); LSTR MSG_BACK = _UxGT("Voltar"); diff --git a/Marlin/src/lcd/language/language_ro.h b/Marlin/src/lcd/language/language_ro.h index 15278a43e7..ff82bb39ba 100644 --- a/Marlin/src/lcd/language/language_ro.h +++ b/Marlin/src/lcd/language/language_ro.h @@ -35,7 +35,7 @@ namespace LanguageNarrow_ro { constexpr uint8_t CHARSIZE = 2; LSTR LANGUAGE = _UxGT("Romanian"); - LSTR WELCOME_MSG = MACHINE_NAME _UxGT(" Pregatit."); + LSTR WELCOME_MSG = MACHINE_NAME_SUBST _UxGT(" Pregatit."); LSTR MSG_YES = _UxGT("DA"); LSTR MSG_NO = _UxGT("NU"); LSTR MSG_BACK = _UxGT("Inapoi"); diff --git a/Marlin/src/lcd/language/language_ru.h b/Marlin/src/lcd/language/language_ru.h index a8d862e889..6b3fbebd08 100644 --- a/Marlin/src/lcd/language/language_ru.h +++ b/Marlin/src/lcd/language/language_ru.h @@ -35,7 +35,7 @@ namespace LanguageNarrow_ru { constexpr uint8_t CHARSIZE = 2; LSTR LANGUAGE = _UxGT("Russian"); - LSTR WELCOME_MSG = MACHINE_NAME _UxGT(" Готов."); + LSTR WELCOME_MSG = MACHINE_NAME_SUBST _UxGT(" Готов."); LSTR MSG_YES = _UxGT("Да"); LSTR MSG_NO = _UxGT("Нет"); LSTR MSG_BACK = _UxGT("Назад"); diff --git a/Marlin/src/lcd/language/language_sk.h b/Marlin/src/lcd/language/language_sk.h index 30a8076d39..32683cf2ed 100644 --- a/Marlin/src/lcd/language/language_sk.h +++ b/Marlin/src/lcd/language/language_sk.h @@ -47,7 +47,7 @@ namespace LanguageNarrow_sk { constexpr uint8_t CHARSIZE = 2; LSTR LANGUAGE = _UxGT("Slovenčina"); - LSTR WELCOME_MSG = MACHINE_NAME _UxGT(" pripravená."); + LSTR WELCOME_MSG = MACHINE_NAME_SUBST _UxGT(" pripravená."); LSTR MSG_YES = _UxGT("ÁNO"); LSTR MSG_NO = _UxGT("NIE"); LSTR MSG_HIGH = _UxGT("VYSOKÁ"); diff --git a/Marlin/src/lcd/language/language_sv.h b/Marlin/src/lcd/language/language_sv.h index b7702a7985..8827252132 100644 --- a/Marlin/src/lcd/language/language_sv.h +++ b/Marlin/src/lcd/language/language_sv.h @@ -36,7 +36,7 @@ namespace LanguageNarrow_sv { constexpr uint8_t CHARSIZE = 2; LSTR LANGUAGE = _UxGT("Swedish"); - LSTR WELCOME_MSG = MACHINE_NAME _UxGT(" Redo."); + LSTR WELCOME_MSG = MACHINE_NAME_SUBST _UxGT(" Redo."); LSTR MSG_YES = _UxGT("JA"); LSTR MSG_NO = _UxGT("NEJ"); LSTR MSG_BACK = _UxGT("Bakåt"); diff --git a/Marlin/src/lcd/language/language_tr.h b/Marlin/src/lcd/language/language_tr.h index 2055713eeb..baebbe9d1e 100644 --- a/Marlin/src/lcd/language/language_tr.h +++ b/Marlin/src/lcd/language/language_tr.h @@ -45,7 +45,7 @@ namespace LanguageNarrow_tr { LSTR LANGUAGE = _UxGT("Turkish"); // These strings should be translated - LSTR WELCOME_MSG = MACHINE_NAME _UxGT(" Hazır."); + LSTR WELCOME_MSG = MACHINE_NAME_SUBST _UxGT(" Hazır."); LSTR MSG_YES = _UxGT("EVET"); LSTR MSG_NO = _UxGT("HAYIR"); LSTR MSG_HIGH = _UxGT("YÜKSEK"); diff --git a/Marlin/src/lcd/language/language_uk.h b/Marlin/src/lcd/language/language_uk.h index 0add5acc3e..104d7f1ecf 100644 --- a/Marlin/src/lcd/language/language_uk.h +++ b/Marlin/src/lcd/language/language_uk.h @@ -36,7 +36,7 @@ namespace LanguageNarrow_uk { constexpr uint8_t CHARSIZE = 2; LSTR LANGUAGE = _UxGT("Ukrainian"); - LSTR WELCOME_MSG = MACHINE_NAME _UxGT(" Готовий."); + LSTR WELCOME_MSG = MACHINE_NAME_SUBST _UxGT(" Готовий."); LSTR MSG_YES = _UxGT("ТАК"); LSTR MSG_NO = _UxGT("НІ"); LSTR MSG_BACK = _UxGT("Назад"); diff --git a/Marlin/src/lcd/language/language_vi.h b/Marlin/src/lcd/language/language_vi.h index fda9b65367..d1e98637b9 100644 --- a/Marlin/src/lcd/language/language_vi.h +++ b/Marlin/src/lcd/language/language_vi.h @@ -33,7 +33,7 @@ namespace LanguageNarrow_vi { constexpr uint8_t CHARSIZE = 2; LSTR LANGUAGE = _UxGT("Vietnamese"); - LSTR WELCOME_MSG = MACHINE_NAME _UxGT(" Sẵn sàng."); // Ready + LSTR WELCOME_MSG = MACHINE_NAME_SUBST _UxGT(" Sẵn sàng."); // Ready LSTR MSG_BACK = _UxGT("Trở lại"); // Back LSTR MSG_MEDIA_ABORTING = _UxGT("Đang hủy bỏ..."); LSTR MSG_MEDIA_INSERTED = _UxGT("Phương tiện được cắm vào"); // Media inserted diff --git a/Marlin/src/lcd/language/language_zh_CN.h b/Marlin/src/lcd/language/language_zh_CN.h index 13c49fa9f1..eb6a973205 100644 --- a/Marlin/src/lcd/language/language_zh_CN.h +++ b/Marlin/src/lcd/language/language_zh_CN.h @@ -33,7 +33,7 @@ namespace LanguageNarrow_zh_CN { constexpr uint8_t CHARSIZE = 3; LSTR LANGUAGE = _UxGT("Simplified Chinese"); - LSTR WELCOME_MSG = MACHINE_NAME _UxGT("已就绪."); // " ready." + LSTR WELCOME_MSG = MACHINE_NAME_SUBST _UxGT("已就绪."); // " ready." LSTR MSG_MARLIN = _UxGT("马林"); LSTR MSG_YES = _UxGT("是"); LSTR MSG_NO = _UxGT("否"); diff --git a/Marlin/src/lcd/language/language_zh_TW.h b/Marlin/src/lcd/language/language_zh_TW.h index c705d126cb..63e386a06f 100644 --- a/Marlin/src/lcd/language/language_zh_TW.h +++ b/Marlin/src/lcd/language/language_zh_TW.h @@ -33,7 +33,7 @@ namespace LanguageNarrow_zh_TW { constexpr uint8_t CHARSIZE = 3; LSTR LANGUAGE = _UxGT("Traditional Chinese"); - LSTR WELCOME_MSG = MACHINE_NAME _UxGT("已就緒."); // " ready." + LSTR WELCOME_MSG = MACHINE_NAME_SUBST _UxGT("已就緒."); // " ready." LSTR MSG_YES = _UxGT("是"); // "YES" LSTR MSG_NO = _UxGT("否"); // "NO" LSTR MSG_BACK = _UxGT("返回"); // "Back" diff --git a/Marlin/src/lcd/lcdprint.cpp b/Marlin/src/lcd/lcdprint.cpp index 475664f45a..5cfa042d0c 100644 --- a/Marlin/src/lcd/lcdprint.cpp +++ b/Marlin/src/lcd/lcdprint.cpp @@ -31,75 +31,6 @@ #include "marlinui.h" #include "lcdprint.h" -/** - * expand_u8str_P - * - * Expand a string with optional substitutions: - * - * $ displays the clipped string given by fstr or cstr - * { displays '0'....'10' for indexes 0 - 10 - * ~ displays '1'....'11' for indexes 0 - 10 - * * displays 'E1'...'E11' for indexes 0 - 10 (By default. Uses LCD_FIRST_TOOL) - * @ displays an axis name such as XYZUVW, or E for an extruder - * - * Return the number of characters emitted - */ -lcd_uint_t expand_u8str_P(char * const outstr, PGM_P const ptpl, const int8_t ind, const char *cstr/*=nullptr*/, FSTR_P const fstr/*=nullptr*/, const lcd_uint_t maxlen/*=LCD_WIDTH*/) { - const uint8_t *p = (uint8_t*)ptpl; - char *o = outstr; - int8_t n = maxlen; - while (n > 0) { - lchar_t wc; - uint8_t *psc = (uint8_t *)p; - p = get_utf8_value_cb(p, read_byte_rom, wc); - if (!wc) break; - if (wc == '{' || wc == '~' || wc == '*') { - if (ind >= 0) { - if (wc == '*') { *o++ = 'E'; n--; } - if (n) { - int8_t inum = ind + ((wc == '{') ? 0 : LCD_FIRST_TOOL); - if (inum >= 10) { - *o++ = ('0' + (inum / 10)); n--; - inum %= 10; - } - if (n) { *o++ = '0' + inum; n--; } - } - } - else { - PGM_P const b = ind == -2 ? GET_TEXT(MSG_CHAMBER) : GET_TEXT(MSG_BED); - strlcpy_P(o, b, n + 1); - n -= utf8_strlen(o); - o += strlen(o); - } - if (n > 0) { - strlcpy_P(o, (PGM_P)p, n + 1); - n -= utf8_strlen(o); - o += strlen(o); - break; - } - } - else if (wc == '$' && fstr) { - strlcpy_P(o, FTOP(fstr), n + 1); - n -= utf8_strlen(o); - o += strlen(o); - } - else if (wc == '$' && cstr) { - strlcpy(o, cstr, n + 1); - n -= utf8_strlen(o); - o += strlen(o); - } - else { - if (wc == '@') - *o++ = AXIS_CHAR(ind); - else - while (psc != p) *o++ = read_byte_rom(psc++); - *o = '\0'; - n--; - } - } - return maxlen - n; -} - /** * lcd_put_u8str_P * @@ -113,7 +44,7 @@ lcd_uint_t expand_u8str_P(char * const outstr, PGM_P const ptpl, const int8_t in * * Return the number of characters emitted */ -lcd_uint_t lcd_put_u8str_P(PGM_P const ptpl, const int8_t ind, const char *cstr/*=nullptr*/, FSTR_P const fstr/*=nullptr*/, const lcd_uint_t maxlen/*=LCD_WIDTH*/) { +lcd_uint_t lcd_put_u8str_P(PGM_P const ptpl, const int8_t ind, const char *cstr/*=nullptr*/, FSTR_P const fstr/*=nullptr*/, const lcd_uint_t maxlen/*=MAX_MESSAGE_SIZE*/) { char estr[maxlen * LANG_CHARSIZE + 2]; const lcd_uint_t outlen = expand_u8str_P(estr, ptpl, ind, cstr, fstr, maxlen); lcd_put_u8str_max(estr, maxlen * (MENU_FONT_WIDTH)); diff --git a/Marlin/src/lcd/lcdprint.h b/Marlin/src/lcd/lcdprint.h index a93e3adc6b..ef50fb823e 100644 --- a/Marlin/src/lcd/lcdprint.h +++ b/Marlin/src/lcd/lcdprint.h @@ -200,29 +200,6 @@ inline int lcd_put_u8str(const lcd_uint_t col, const lcd_uint_t row, FSTR_P cons return lcd_put_u8str_P(col, row, FTOP(fstr)); } -/** - * @brief Expand a string with optional substitution - * @details Expand a string with optional substitutions: - * $ : the clipped string given by fstr or cstr - * { : '0'....'10' for indexes 0 - 10 - * ~ : '1'....'11' for indexes 0 - 10 - * * : 'E1'...'E11' for indexes 0 - 10 (By default. Uses LCD_FIRST_TOOL) - * @ : an axis name such as XYZUVW, or E for an extruder - * - * @param *outstr The output destination buffer - * @param ptpl A ROM string (template) - * @param ind An index value to use for = ~ * substitution - * @param cstr An SRAM C-string to use for $ substitution - * @param fstr A ROM F-string to use for $ substitution - * @param maxlen The maximum size of the string (in pixels on GLCD) - * @return the output width (in pixels on GLCD) - */ -lcd_uint_t expand_u8str_P(char * const outstr, PGM_P const ptpl, const int8_t ind, const char *cstr=nullptr, FSTR_P const fstr=nullptr, const lcd_uint_t maxlen=LCD_WIDTH); - -inline lcd_uint_t expand_u8str(char * const outstr, FSTR_P const ftpl, const int8_t ind, const char *cstr=nullptr, FSTR_P const fstr=nullptr, const lcd_uint_t maxlen=LCD_WIDTH) { - return expand_u8str_P(outstr, FTOP(ftpl), ind, cstr, fstr, maxlen); -} - /** * @brief Draw a string with optional substitution * @details Print a string with optional substitutions: @@ -239,8 +216,8 @@ inline lcd_uint_t expand_u8str(char * const outstr, FSTR_P const ftpl, const int * @param maxlen The maximum size of the string (in pixels on GLCD) * @return the output width (in pixels on GLCD) */ -lcd_uint_t lcd_put_u8str_P(PGM_P const ptpl, const int8_t ind, const char *cstr=nullptr, FSTR_P const fstr=nullptr, const lcd_uint_t maxlen=LCD_WIDTH); -inline lcd_uint_t lcd_put_u8str_P(const lcd_uint_t col, const lcd_uint_t row, PGM_P const ptpl, const int8_t ind, const char *cstr=nullptr, FSTR_P const fstr=nullptr, const lcd_uint_t maxlen=LCD_WIDTH) { +lcd_uint_t lcd_put_u8str_P(PGM_P const ptpl, const int8_t ind, const char *cstr=nullptr, FSTR_P const fstr=nullptr, const lcd_uint_t maxlen=MAX_MESSAGE_SIZE); +inline lcd_uint_t lcd_put_u8str_P(const lcd_uint_t col, const lcd_uint_t row, PGM_P const ptpl, const int8_t ind, const char *cstr=nullptr, FSTR_P const fstr=nullptr, const lcd_uint_t maxlen=MAX_MESSAGE_SIZE) { lcd_moveto(col, row); return lcd_put_u8str_P(ptpl, ind, cstr, fstr, maxlen); } @@ -255,14 +232,14 @@ inline lcd_uint_t lcd_put_u8str_P(const lcd_uint_t col, const lcd_uint_t row, PG * @param maxlen The maximum size of the string (in pixels on GLCD) * @return the output width (in pixels on GLCD) */ -inline lcd_uint_t lcd_put_u8str(FSTR_P const ftpl, const int8_t ind, const char *cstr=nullptr, FSTR_P const fstr=nullptr, const lcd_uint_t maxlen=LCD_WIDTH) { +inline lcd_uint_t lcd_put_u8str(FSTR_P const ftpl, const int8_t ind, const char *cstr=nullptr, FSTR_P const fstr=nullptr, const lcd_uint_t maxlen=MAX_MESSAGE_SIZE) { return lcd_put_u8str_P(FTOP(ftpl), ind, cstr, fstr, maxlen); } /** * @param col * @param row */ -inline lcd_uint_t lcd_put_u8str(const lcd_uint_t col, const lcd_uint_t row, FSTR_P const ftpl, const int8_t ind, const char *cstr=nullptr, FSTR_P const fstr=nullptr, const lcd_uint_t maxlen=LCD_WIDTH) { +inline lcd_uint_t lcd_put_u8str(const lcd_uint_t col, const lcd_uint_t row, FSTR_P const ftpl, const int8_t ind, const char *cstr=nullptr, FSTR_P const fstr=nullptr, const lcd_uint_t maxlen=MAX_MESSAGE_SIZE) { return lcd_put_u8str_P(col, row, FTOP(ftpl), ind, cstr, fstr, maxlen); } diff --git a/Marlin/src/lcd/marlinui.cpp b/Marlin/src/lcd/marlinui.cpp index 2282cb5ee4..e8946edb28 100644 --- a/Marlin/src/lcd/marlinui.cpp +++ b/Marlin/src/lcd/marlinui.cpp @@ -22,7 +22,7 @@ #include "../inc/MarlinConfig.h" -#include "../MarlinCore.h" // for printingIsPaused +#include "../MarlinCore.h" // for printingIsPaused, machine_name #include "../gcode/parser.h" // for axis_is_rotational, using_inch_units #if HAS_LED_POWEROFF_TIMEOUT || ALL(HAS_WIRED_LCD, PRINTER_EVENT_LEDS) || (HAS_BACKLIGHT_TIMEOUT && defined(NEOPIXEL_BKGD_INDEX_FIRST)) @@ -72,7 +72,7 @@ constexpr uint8_t epps = ENCODER_PULSES_PER_STEP; #if ENABLED(STATUS_MESSAGE_SCROLLING) uint8_t MarlinUI::status_scroll_offset; // = 0 #endif - MString MarlinUI::status_message; + MString MarlinUI::status_message; uint8_t MarlinUI::alert_level; // = 0 #if HAS_STATUS_MESSAGE_TIMEOUT millis_t MarlinUI::status_message_expire_ms; // = 0 @@ -1462,6 +1462,62 @@ void MarlinUI::host_notify(const char * const cstr) { #include +uint8_t expand_u8str_P(char * const outstr, PGM_P const ptpl, const int8_t ind, const char *cstr/*=nullptr*/, FSTR_P const fstr/*=nullptr*/, const uint8_t maxlen/*=MAX_MESSAGE_SIZE*/) { + const uint8_t *p = (uint8_t*)ptpl; + char *o = outstr; + int8_t n = maxlen; + while (n > 0) { + lchar_t wc; + uint8_t *psc = (uint8_t *)p; + p = get_utf8_value_cb(p, read_byte_rom, wc); + if (!wc) break; + if (wc == '{' || wc == '~' || wc == '*') { + if (ind >= 0) { + if (wc == '*') { *o++ = 'E'; n--; } + if (n) { + int8_t inum = ind + ((wc == '{') ? 0 : LCD_FIRST_TOOL); + if (inum >= 10) { + *o++ = ('0' + (inum / 10)); n--; + inum %= 10; + } + if (n) { *o++ = '0' + inum; n--; } + } + } + else { + PGM_P const b = ind == -2 ? GET_TEXT(MSG_CHAMBER) : GET_TEXT(MSG_BED); + strlcpy_P(o, b, n + 1); + n -= utf8_strlen(o); + o += strlen(o); + } + if (n > 0) { + strlcpy_P(o, (PGM_P)p, n + 1); + n -= utf8_strlen(o); + o += strlen(o); + break; + } + } + else if (wc == '$' && fstr) { + strlcpy_P(o, FTOP(fstr), n + 1); + n -= utf8_strlen(o); + o += strlen(o); + } + else if (wc == '$' && cstr) { + strlcpy(o, cstr, n + 1); + n -= utf8_strlen(o); + o += strlen(o); + } + else { + if (wc == '@') + *o++ = AXIS_CHAR(ind); + else + while (psc != p) *o++ = read_byte_rom(psc++); + *o = '\0'; + n--; + } + } + return maxlen - n; +} + #if HAS_STATUS_MESSAGE #if ENABLED(EXTENSIBLE_UI) @@ -1492,7 +1548,16 @@ void MarlinUI::host_notify(const char * const cstr) { else if (print_job_timer.needsService(3)) msg = F("> " SERVICE_NAME_3 "!"); #endif - else if (!no_welcome) msg = GET_TEXT_F(WELCOME_MSG); + else if (!no_welcome) { + #if ENABLED(CONFIGURABLE_MACHINE_NAME) + char new_status[MAX_MESSAGE_SIZE + 1]; + expand_u8str_P(new_status, GET_TEXT(WELCOME_MSG), 0, &machine_name); + _set_status_and_level(new_status, -1); + return; + #else + msg = GET_TEXT_F(WELCOME_MSG); + #endif + } else if (ENABLED(STATUS_DO_CLEAR_EMPTY)) msg = F(""); @@ -1528,7 +1593,7 @@ void MarlinUI::host_notify(const char * const cstr) { MString<30> msg; pgm ? msg.set_P(ustr) : msg.set(ustr); - status_message.set(&msg).utrunc(MAX_MESSAGE_LENGTH); + status_message.set(&msg).utrunc(MAX_MESSAGE_SIZE); finish_status(level > 0); // Persist if the status has a level } @@ -1546,7 +1611,7 @@ void MarlinUI::host_notify(const char * const cstr) { pgm ? host_notify_P(ustr) : host_notify(ustr); // Remove the last partial Unicode glyph, if any - (pgm ? status_message.set_P(ustr) : status_message.set(ustr)).utrunc(MAX_MESSAGE_LENGTH); + (pgm ? status_message.set_P(ustr) : status_message.set(ustr)).utrunc(MAX_MESSAGE_SIZE); finish_status(persist); } @@ -1574,7 +1639,7 @@ void MarlinUI::host_notify(const char * const cstr) { va_list args; va_start(args, pfmt); - vsnprintf_P(status_message, MAX_MESSAGE_LENGTH, pfmt, args); + vsnprintf_P(status_message, MAX_MESSAGE_SIZE, pfmt, args); va_end(args); host_notify(status_message); @@ -1865,6 +1930,7 @@ void MarlinUI::host_notify(const char * const cstr) { #endif // HAS_MEDIA #if HAS_MARLINUI_MENU + void MarlinUI::reset_settings() { settings.reset(); completion_feedback(); @@ -1886,7 +1952,7 @@ void MarlinUI::host_notify(const char * const cstr) { } #endif -#endif +#endif // HAS_MARLINUI_MENU #if ENABLED(EEPROM_SETTINGS) diff --git a/Marlin/src/lcd/marlinui.h b/Marlin/src/lcd/marlinui.h index 3c4f28c93e..a47096a3bf 100644 --- a/Marlin/src/lcd/marlinui.h +++ b/Marlin/src/lcd/marlinui.h @@ -369,17 +369,7 @@ public: #if HAS_STATUS_MESSAGE - #if ANY(HAS_WIRED_LCD, DWIN_LCD_PROUI) - #if ENABLED(STATUS_MESSAGE_SCROLLING) - #define MAX_MESSAGE_LENGTH _MAX(LONG_FILENAME_LENGTH, MAX_LANG_CHARSIZE * 2 * (LCD_WIDTH)) - #else - #define MAX_MESSAGE_LENGTH (MAX_LANG_CHARSIZE * (LCD_WIDTH)) - #endif - #else - #define MAX_MESSAGE_LENGTH 63 - #endif - - static MString status_message; + static MString status_message; static uint8_t alert_level; // Higher levels block lower levels #if HAS_STATUS_MESSAGE_TIMEOUT @@ -410,7 +400,6 @@ public: #else - #define MAX_MESSAGE_LENGTH 1 static constexpr bool has_status() { return false; } static bool set_alert_level(int8_t) { return false; } @@ -912,6 +901,29 @@ private: #endif }; +/** + * @brief Expand a string with optional substitution + * @details Expand a string with optional substitutions: + * $ : the clipped string given by fstr or cstr + * { : '0'....'10' for indexes 0 - 10 + * ~ : '1'....'11' for indexes 0 - 10 + * * : 'E1'...'E11' for indexes 0 - 10 (By default. Uses LCD_FIRST_TOOL) + * @ : an axis name such as XYZUVW, or E for an extruder + * + * @param *outstr The output destination buffer + * @param ptpl A ROM string (template) + * @param ind An index value to use for = ~ * substitution + * @param cstr An SRAM C-string to use for $ substitution + * @param fstr A ROM F-string to use for $ substitution + * @param maxlen The maximum size of the string (in pixels on GLCD) + * @return the output width (in pixels on GLCD) + */ +uint8_t expand_u8str_P(char * const outstr, PGM_P const ptpl, const int8_t ind, const char *cstr=nullptr, FSTR_P const fstr=nullptr, const uint8_t maxlen=MAX_MESSAGE_SIZE); + +inline uint8_t expand_u8str(char * const outstr, FSTR_P const ftpl, const int8_t ind, const char *cstr=nullptr, FSTR_P const fstr=nullptr, const uint8_t maxlen=MAX_MESSAGE_SIZE) { + return expand_u8str_P(outstr, FTOP(ftpl), ind, cstr, fstr, maxlen); +} + #define LCD_MESSAGE_F(S) ui.set_status(F(S)) #define LCD_MESSAGE(M) ui.set_status(GET_TEXT_F(M)) #define LCD_MESSAGE_MIN(M) ui.set_min_status(GET_TEXT_F(M)) diff --git a/Marlin/src/lcd/menu/menu_info.cpp b/Marlin/src/lcd/menu/menu_info.cpp index 1df70ba802..31d83bd873 100644 --- a/Marlin/src/lcd/menu/menu_info.cpp +++ b/Marlin/src/lcd/menu/menu_info.cpp @@ -30,6 +30,10 @@ #include "menu_item.h" +#if ENABLED(CONFIGURABLE_MACHINE_NAME) + #include "../../MarlinCore.h" +#endif + #if HAS_GAMES #include "game/game.h" #endif @@ -246,7 +250,11 @@ void menu_info_board() { STATIC_ITEM(MSG_MARLIN, SS_DEFAULT|SS_INVERT); // Marlin STATIC_ITEM_F(F(SHORT_BUILD_VERSION)); // x.x.x-Branch STATIC_ITEM_F(F(STRING_DISTRIBUTION_DATE)); // YYYY-MM-DD HH:MM - STATIC_ITEM_F(F(MACHINE_NAME), SS_DEFAULT|SS_INVERT); // My3DPrinter + #if ENABLED(CONFIGURABLE_MACHINE_NAME) + STATIC_ITEM_C(&machine_name, SS_DEFAULT|SS_INVERT); // My3DPrinter + #else + STATIC_ITEM_F(F(MACHINE_NAME), SS_DEFAULT|SS_INVERT); // My3DPrinter + #endif STATIC_ITEM_F(F(WEBSITE_URL)); // www.my3dprinter.com PSTRING_ITEM(MSG_INFO_EXTRUDERS, STRINGIFY(EXTRUDERS), SS_CENTER); // Extruders: 2 #if HAS_LEVELING diff --git a/Marlin/src/lcd/menu/menu_item.h b/Marlin/src/lcd/menu/menu_item.h index 661deeb4e7..d81b1a8843 100644 --- a/Marlin/src/lcd/menu/menu_item.h +++ b/Marlin/src/lcd/menu/menu_item.h @@ -358,20 +358,24 @@ class MenuItem_bool : public MenuEditItemBase { // STATIC_ITEM draws a styled string with no highlight. // Parameters: label [, style [, char *value] ] -#define STATIC_ITEM_INNER_F(FLABEL, V...) do{ \ +#define STATIC_SKIP() do{ \ if (_skipStatic && encoderLine <= _thisItemNr) { \ ui.encoderPosition += ENCODER_STEPS_PER_MENU_ITEM; \ ++encoderLine; \ } \ - if (ui.should_draw()) \ - MenuItem_static::draw(_lcdLineNr, FLABEL, ##V); \ -} while(0) +}while(0) + +#define STATIC_ITEM_INNER_F(FLABEL, V...) do{ \ + STATIC_SKIP(); \ + if (ui.should_draw()) \ + MenuItem_static::draw(_lcdLineNr, FLABEL, ##V); \ +}while(0) #define STATIC_ITEM_F(FLABEL, V...) do{ \ if (MY_LINE()) \ STATIC_ITEM_INNER_F(FLABEL, ##V); \ NEXT_ITEM(); \ -} while(0) +}while(0) #define STATIC_ITEM_N_F(N, FLABEL, V...) do{ \ if (MY_LINE()) { \ @@ -381,6 +385,16 @@ class MenuItem_bool : public MenuEditItemBase { NEXT_ITEM(); \ }while(0) +#define STATIC_ITEM_N_F_C(N, FLABEL, CSTR, V...) do{ \ + if (MY_LINE()) { \ + MenuItemBase::init(N, CSTR); \ + STATIC_ITEM_INNER_F(FLABEL, ##V); \ + } \ + NEXT_ITEM(); \ +}while(0) + +#define STATIC_ITEM_C(CSTR, V...) STATIC_ITEM_N_F_C(0, F("$"), CSTR, ##V) + // PSTRING_ITEM is like STATIC_ITEM // but also takes a PSTR and style. diff --git a/Marlin/src/lcd/utf8.cpp b/Marlin/src/lcd/utf8.cpp index d9dd53e953..2fe6c14490 100644 --- a/Marlin/src/lcd/utf8.cpp +++ b/Marlin/src/lcd/utf8.cpp @@ -31,8 +31,6 @@ #include "../inc/MarlinConfigPre.h" -#if HAS_UTF8_UTILS - #include "../inc/MarlinConfig.h" #if HAS_WIRED_LCD @@ -204,5 +202,3 @@ uint8_t utf8_byte_pos_by_char_num(const char *pstart, const uint8_t charnum) { uint8_t utf8_byte_pos_by_char_num_P(PGM_P pstart, const uint8_t charnum) { return utf8_byte_pos_by_char_num_cb(pstart, read_byte_rom, charnum); } - -#endif // HAS_UTF8_UTILS diff --git a/Marlin/src/module/settings.cpp b/Marlin/src/module/settings.cpp index c156bfeaca..485d01066a 100644 --- a/Marlin/src/module/settings.cpp +++ b/Marlin/src/module/settings.cpp @@ -570,6 +570,13 @@ typedef struct SettingsDataStruct { uint8_t caselight_brightness; // M355 P #endif + // + // CONFIGURABLE_MACHINE_NAME + // + #if ENABLED(CONFIGURABLE_MACHINE_NAME) + MString<64> machine_name; // M550 P + #endif + // // PASSWORD_FEATURE // @@ -1686,6 +1693,13 @@ void MarlinSettings::postprocess() { EEPROM_WRITE(caselight.brightness); #endif + // + // CONFIGURABLE_MACHINE_NAME + // + #if ENABLED(CONFIGURABLE_MACHINE_NAME) + EEPROM_WRITE(machine_name); + #endif + // // Password feature // @@ -2810,6 +2824,13 @@ void MarlinSettings::postprocess() { EEPROM_READ(caselight.brightness); #endif + // + // CONFIGURABLE_MACHINE_NAME + // + #if ENABLED(CONFIGURABLE_MACHINE_NAME) + EEPROM_READ(machine_name); + #endif + // // Password feature // @@ -3399,6 +3420,11 @@ void MarlinSettings::reset() { // TERN_(CASELIGHT_USES_BRIGHTNESS, caselight.brightness = CASE_LIGHT_DEFAULT_BRIGHTNESS); + // + // CONFIGURABLE_MACHINE_NAME + // + TERN_(CONFIGURABLE_MACHINE_NAME, machine_name = PSTR(MACHINE_NAME)); + // // TOUCH_SCREEN_CALIBRATION // diff --git a/buildroot/tests/ARMED b/buildroot/tests/ARMED index e47e101d47..1ac016bc68 100755 --- a/buildroot/tests/ARMED +++ b/buildroot/tests/ARMED @@ -12,5 +12,5 @@ set -e restore_configs use_example_configs ArmEd opt_set X_DRIVER_TYPE TMC2130 Y_DRIVER_TYPE TMC2208 -opt_enable LASER_SYNCHRONOUS_M106_M107 +opt_enable CONFIGURABLE_MACHINE_NAME GCODE_QUOTED_STRINGS LASER_SYNCHRONOUS_M106_M107 exec_test $1 $2 "ArmEd Example Configuration with mixed TMC Drivers" "$3" diff --git a/buildroot/tests/SAMD21_minitronics20 b/buildroot/tests/SAMD21_minitronics20 index fb23e90be7..77404290a9 100755 --- a/buildroot/tests/SAMD21_minitronics20 +++ b/buildroot/tests/SAMD21_minitronics20 @@ -20,9 +20,10 @@ opt_set MOTHERBOARD BOARD_MINITRONICS20 SERIAL_PORT -1 \ opt_enable ENDSTOP_INTERRUPTS_FEATURE BLTOUCH Z_MIN_PROBE_REPEATABILITY_TEST \ FILAMENT_RUNOUT_SENSOR G26_MESH_VALIDATION MESH_EDIT_GFX_OVERLAY Z_SAFE_HOMING \ EEPROM_SETTINGS NOZZLE_PARK_FEATURE SDSUPPORT SD_CHECK_AND_RETRY \ - REPRAPWORLD_GRAPHICAL_LCD ADAPTIVE_STEP_SMOOTHING \ + REPRAPWORLD_GRAPHICAL_LCD ADAPTIVE_STEP_SMOOTHING LCD_INFO_MENU \ STATUS_MESSAGE_SCROLLING SET_PROGRESS_MANUALLY SHOW_REMAINING_TIME SET_REMAINING_TIME \ LONG_FILENAME_HOST_SUPPORT CUSTOM_FIRMWARE_UPLOAD M20_TIMESTAMP_SUPPORT \ + CONFIGURABLE_MACHINE_NAME GCODE_QUOTED_STRINGS \ SCROLL_LONG_FILENAMES BABYSTEPPING DOUBLECLICK_FOR_Z_BABYSTEPPING \ MOVE_Z_WHEN_IDLE BABYSTEP_ZPROBE_OFFSET BABYSTEP_GFX_OVERLAY \ LIN_ADVANCE ADVANCED_PAUSE_FEATURE PARK_HEAD_ON_PAUSE MONITOR_DRIVER_STATUS diff --git a/ini/features.ini b/ini/features.ini index a21c36b27e..49e0c5054e 100644 --- a/ini/features.ini +++ b/ini/features.ini @@ -295,6 +295,7 @@ PIDTEMPBED = build_src_filter=+ PIDTEMPCHAMBER = build_src_filter=+ SD_ABORT_ON_ENDSTOP_HIT = build_src_filter=+ +CONFIGURABLE_MACHINE_NAME = build_src_filter=+ BAUD_RATE_GCODE = build_src_filter=+ HAS_SMART_EFF_MOD = build_src_filter=+ COOLANT_CONTROL|AIR_ASSIST = build_src_filter=+ From da0bef50e168a028f60b39e3ed6591d371ce3862 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Mon, 17 Mar 2025 00:30:31 +0000 Subject: [PATCH 116/787] [cron] Bump distribution date (2025-03-17) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index a8330b0054..a8be38fe31 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-03-16" +//#define STRING_DISTRIBUTION_DATE "2025-03-17" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 7d3ef7cdac..c9db7e51b9 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-03-16" + #define STRING_DISTRIBUTION_DATE "2025-03-17" #endif /** From 28548efa751db0937997e2416856d501d92e57f0 Mon Sep 17 00:00:00 2001 From: ellensp <530024+ellensp@users.noreply.github.com> Date: Tue, 18 Mar 2025 06:54:21 +1300 Subject: [PATCH 117/787] =?UTF-8?q?=F0=9F=9A=B8=20Improve=20TFT=20touch=20?= =?UTF-8?q?calibrate=20(#26200)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/lcd/dogm/u8g/u8g_dev_tft_upscale_from_128x64.cpp | 1 + Marlin/src/lcd/language/language_en.h | 9 +++++---- Marlin/src/lcd/tft/ui_common.cpp | 5 +++++ 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Marlin/src/lcd/dogm/u8g/u8g_dev_tft_upscale_from_128x64.cpp b/Marlin/src/lcd/dogm/u8g/u8g_dev_tft_upscale_from_128x64.cpp index 73b35b0ec2..e458c8e4c4 100644 --- a/Marlin/src/lcd/dogm/u8g/u8g_dev_tft_upscale_from_128x64.cpp +++ b/Marlin/src/lcd/dogm/u8g/u8g_dev_tft_upscale_from_128x64.cpp @@ -542,6 +542,7 @@ U8G_PB_DEV(u8g_dev_tft_320x240_upscale_from_128x64, WIDTH, HEIGHT, PAGE_HEIGHT, tftio.set_window(TFT_PIXEL_OFFSET_X, TFT_PIXEL_OFFSET_Y, X_HI, Y_HI); do { set_font(FONT_MENU); + lcd_put_u8str(0, 7, GET_TEXT_F(MSG_TOUCH_CALIBRATION)); lcd_put_u8str(0, LCD_PIXEL_HEIGHT / 2, str); } while (u8g.nextPage()); drawing_screen = false; diff --git a/Marlin/src/lcd/language/language_en.h b/Marlin/src/lcd/language/language_en.h index 307ff2590e..b033dc3c74 100644 --- a/Marlin/src/lcd/language/language_en.h +++ b/Marlin/src/lcd/language/language_en.h @@ -924,10 +924,11 @@ namespace LanguageNarrow_en { LSTR MSG_SOUND = _UxGT("Sound"); - LSTR MSG_TOP_LEFT = _UxGT("Top Left"); - LSTR MSG_BOTTOM_LEFT = _UxGT("Bottom Left"); - LSTR MSG_TOP_RIGHT = _UxGT("Top Right"); - LSTR MSG_BOTTOM_RIGHT = _UxGT("Bottom Right"); + LSTR MSG_TOP_LEFT = _UxGT("Touch Top Left"); + LSTR MSG_BOTTOM_LEFT = _UxGT("Touch Bottom Left"); + LSTR MSG_TOP_RIGHT = _UxGT("Touch Top Right"); + LSTR MSG_BOTTOM_RIGHT = _UxGT("Touch Bottom Right"); + LSTR MSG_TOUCH_CALIBRATION = _UxGT("Touch Calibration"); LSTR MSG_CALIBRATION_COMPLETED = _UxGT("Calibration Completed"); LSTR MSG_CALIBRATION_FAILED = _UxGT("Calibration Failed"); diff --git a/Marlin/src/lcd/tft/ui_common.cpp b/Marlin/src/lcd/tft/ui_common.cpp index e71a74247b..6d59e0ce8b 100644 --- a/Marlin/src/lcd/tft/ui_common.cpp +++ b/Marlin/src/lcd/tft/ui_common.cpp @@ -487,6 +487,11 @@ void MarlinUI::clear_for_drawing() { clear_lcd(); } touch.clear(); if (stage < CALIBRATION_SUCCESS) { + tft_string.set(GET_TEXT(MSG_TOUCH_CALIBRATION)); + tft.canvas(0, 0, TFT_WIDTH, tft_string.font_height()); + tft.set_background(COLOR_BACKGROUND); + tft.add_text(tft_string.center(TFT_WIDTH), 0, COLOR_MENU_TEXT, tft_string); + switch (stage) { case CALIBRATION_TOP_LEFT: tft_string.set(GET_TEXT(MSG_TOP_LEFT)); break; case CALIBRATION_TOP_RIGHT: tft_string.set(GET_TEXT(MSG_TOP_RIGHT)); break; From 2d6454b3521b8af11912d942cf006726a307cb44 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Mon, 17 Mar 2025 15:06:35 -0500 Subject: [PATCH 118/787] =?UTF-8?q?=F0=9F=A9=B9=20Update=20some=20SD=20SS?= =?UTF-8?q?=20pins?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Followup to #27650 --- Marlin/src/pins/stm32f0/pins_FLY_D5.h | 2 +- Marlin/src/pins/stm32f0/pins_FLY_DP5.h | 2 +- Marlin/src/pins/stm32f4/pins_FLY_CDY_V3.h | 2 +- Marlin/src/pins/stm32f4/pins_FLY_D8.h | 2 +- Marlin/src/pins/stm32f4/pins_FLY_SUPER8.h | 2 +- Marlin/src/pins/stm32f4/pins_MKS_NEPTUNE_3.h | 2 +- Marlin/src/pins/stm32f4/pins_MKS_NEPTUNE_X_common.h | 2 +- Marlin/src/pins/stm32h7/pins_FLY_D8_PRO.h | 2 +- Marlin/src/pins/stm32h7/pins_FLY_SUPER8_PRO.h | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Marlin/src/pins/stm32f0/pins_FLY_D5.h b/Marlin/src/pins/stm32f0/pins_FLY_D5.h index b75a5a62ac..c98dcb0b7e 100644 --- a/Marlin/src/pins/stm32f0/pins_FLY_D5.h +++ b/Marlin/src/pins/stm32f0/pins_FLY_D5.h @@ -173,7 +173,7 @@ #define SD_SCK_PIN EXP2_02_PIN #define SD_MISO_PIN EXP2_01_PIN #define SD_MOSI_PIN EXP2_06_PIN - #define SDSS EXP2_04_PIN + #define SD_SS_PIN EXP2_04_PIN #define SD_DETECT_PIN EXP2_07_PIN #endif diff --git a/Marlin/src/pins/stm32f0/pins_FLY_DP5.h b/Marlin/src/pins/stm32f0/pins_FLY_DP5.h index d3c7b50e45..f66187a646 100644 --- a/Marlin/src/pins/stm32f0/pins_FLY_DP5.h +++ b/Marlin/src/pins/stm32f0/pins_FLY_DP5.h @@ -180,7 +180,7 @@ #define SD_SCK_PIN EXP2_02_PIN #define SD_MISO_PIN EXP2_01_PIN #define SD_MOSI_PIN EXP2_06_PIN - #define SDSS EXP2_04_PIN + #define SD_SS_PIN EXP2_04_PIN #define SD_DETECT_PIN EXP2_07_PIN #endif diff --git a/Marlin/src/pins/stm32f4/pins_FLY_CDY_V3.h b/Marlin/src/pins/stm32f4/pins_FLY_CDY_V3.h index 44843da5bd..a7383967b2 100644 --- a/Marlin/src/pins/stm32f4/pins_FLY_CDY_V3.h +++ b/Marlin/src/pins/stm32f4/pins_FLY_CDY_V3.h @@ -199,7 +199,7 @@ #define SD_SCK_PIN EXP2_02_PIN #define SD_MISO_PIN EXP2_01_PIN #define SD_MOSI_PIN EXP2_06_PIN - #define SDSS EXP2_04_PIN + #define SD_SS_PIN EXP2_04_PIN #define SD_DETECT_PIN EXP2_07_PIN #endif diff --git a/Marlin/src/pins/stm32f4/pins_FLY_D8.h b/Marlin/src/pins/stm32f4/pins_FLY_D8.h index 974595c559..ada7c2a853 100644 --- a/Marlin/src/pins/stm32f4/pins_FLY_D8.h +++ b/Marlin/src/pins/stm32f4/pins_FLY_D8.h @@ -211,7 +211,7 @@ #define SD_SCK_PIN EXP2_02_PIN #define SD_MISO_PIN EXP2_01_PIN #define SD_MOSI_PIN EXP2_06_PIN - #define SDSS EXP2_04_PIN + #define SD_SS_PIN EXP2_04_PIN #define SD_DETECT_PIN EXP2_07_PIN #endif diff --git a/Marlin/src/pins/stm32f4/pins_FLY_SUPER8.h b/Marlin/src/pins/stm32f4/pins_FLY_SUPER8.h index 3ce5790fb8..9440758c45 100644 --- a/Marlin/src/pins/stm32f4/pins_FLY_SUPER8.h +++ b/Marlin/src/pins/stm32f4/pins_FLY_SUPER8.h @@ -220,7 +220,7 @@ #define SD_SCK_PIN EXP2_02_PIN #define SD_MISO_PIN EXP2_01_PIN #define SD_MOSI_PIN EXP2_06_PIN - #define SDSS EXP2_04_PIN + #define SD_SS_PIN EXP2_04_PIN #define SD_DETECT_PIN EXP2_07_PIN #endif diff --git a/Marlin/src/pins/stm32f4/pins_MKS_NEPTUNE_3.h b/Marlin/src/pins/stm32f4/pins_MKS_NEPTUNE_3.h index 2ee641d1c5..8df334d740 100644 --- a/Marlin/src/pins/stm32f4/pins_MKS_NEPTUNE_3.h +++ b/Marlin/src/pins/stm32f4/pins_MKS_NEPTUNE_3.h @@ -131,7 +131,7 @@ #if SD_CONNECTION_IS(ONBOARD) #define ENABLE_SPI3 #define SD_SS_PIN -1 - #define SDSS PB12 + #define SD_SS_PIN PB12 #define SD_SCK_PIN PB13 #define SD_MISO_PIN PB14 #define SD_MOSI_PIN PB15 diff --git a/Marlin/src/pins/stm32f4/pins_MKS_NEPTUNE_X_common.h b/Marlin/src/pins/stm32f4/pins_MKS_NEPTUNE_X_common.h index 627e14faf3..7d1d7943cf 100644 --- a/Marlin/src/pins/stm32f4/pins_MKS_NEPTUNE_X_common.h +++ b/Marlin/src/pins/stm32f4/pins_MKS_NEPTUNE_X_common.h @@ -250,7 +250,7 @@ #if SD_CONNECTION_IS(ONBOARD) #define ENABLE_SPI3 #define SD_SS_PIN -1 - #define SDSS PC9 + #define SD_SS_PIN PC9 #define SD_SCK_PIN PC10 #define SD_MISO_PIN PC11 #define SD_MOSI_PIN PC12 diff --git a/Marlin/src/pins/stm32h7/pins_FLY_D8_PRO.h b/Marlin/src/pins/stm32h7/pins_FLY_D8_PRO.h index 9b7cfb32c1..ab032a21a9 100644 --- a/Marlin/src/pins/stm32h7/pins_FLY_D8_PRO.h +++ b/Marlin/src/pins/stm32h7/pins_FLY_D8_PRO.h @@ -212,7 +212,7 @@ #define SD_SCK_PIN EXP2_02_PIN #define SD_MISO_PIN EXP2_01_PIN #define SD_MOSI_PIN EXP2_06_PIN - #define SDSS EXP2_04_PIN + #define SD_SS_PIN EXP2_04_PIN #define SD_DETECT_PIN EXP2_07_PIN #endif diff --git a/Marlin/src/pins/stm32h7/pins_FLY_SUPER8_PRO.h b/Marlin/src/pins/stm32h7/pins_FLY_SUPER8_PRO.h index 4e19a0e05f..60af38a03b 100644 --- a/Marlin/src/pins/stm32h7/pins_FLY_SUPER8_PRO.h +++ b/Marlin/src/pins/stm32h7/pins_FLY_SUPER8_PRO.h @@ -220,7 +220,7 @@ #define SD_SCK_PIN EXP2_02_PIN #define SD_MISO_PIN EXP2_01_PIN #define SD_MOSI_PIN EXP2_06_PIN - #define SDSS EXP2_04_PIN + #define SD_SS_PIN EXP2_04_PIN #define SD_DETECT_PIN EXP2_07_PIN #endif From e8c03630516023a1d7be57f05fad35a219ab5299 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Mon, 17 Mar 2025 15:19:21 -0500 Subject: [PATCH 119/787] =?UTF-8?q?=F0=9F=8E=A8=20cosmetics?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/module/ft_motion.cpp | 26 +++++++++---------- Marlin/src/module/motion.cpp | 4 +-- .../variants/MARLIN_FLY_D5/ldscript.ld | 2 +- .../variants/MARLIN_FLY_D7/ldscript.ld | 2 +- .../MARLIN_FLY_D8_PRO/PeripheralPins.c | 4 +-- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/Marlin/src/module/ft_motion.cpp b/Marlin/src/module/ft_motion.cpp index 3877df983d..88d2fb60b3 100644 --- a/Marlin/src/module/ft_motion.cpp +++ b/Marlin/src/module/ft_motion.cpp @@ -582,7 +582,7 @@ void FTMotion::makeVector() { float accel_k = 0.0f; // (mm/s^2) Acceleration K factor float tau = (makeVector_idx + 1) * (FTM_TS); // (s) Time since start of block float dist = 0.0f; // (mm) Distance traveled - + if (makeVector_idx < N1) { // Acceleration phase dist = (f_s * tau) + (0.5f * accel_P * sq(tau)); // (mm) Distance traveled for acceleration phase since start of block @@ -599,25 +599,25 @@ void FTMotion::makeVector() { dist = s_2e + F_P * tau + 0.5f * decel_P * sq(tau); // (mm) Distance traveled for deceleration phase since start of block accel_k = decel_P; // (mm/s^2) Acceleration K factor from Decel phase } - + #define _SET_TRAJ(q) traj.q[makeVector_batchIdx] = startPosn.q + ratio.q * dist; LOGICAL_AXIS_MAP_LC(_SET_TRAJ); - + #if HAS_EXTRUDERS if (cfg.linearAdvEna) { float dedt_adj = (traj.e[makeVector_batchIdx] - e_raw_z1) * (FTM_FS); if (ratio.e > 0.0f) dedt_adj += accel_k * cfg.linearAdvK * 0.0001f; - + e_raw_z1 = traj.e[makeVector_batchIdx]; e_advanced_z1 += dedt_adj * (FTM_TS); traj.e[makeVector_batchIdx] = e_advanced_z1; } #endif - + // Update shaping parameters if needed. - + switch (cfg.dynFreqMode) { - + #if HAS_DYNAMIC_FREQ_MM case dynFreqMode_Z_BASED: { static float oldz = 0.0f; @@ -635,7 +635,7 @@ void FTMotion::makeVector() { } } break; #endif - + #if HAS_DYNAMIC_FREQ_G case dynFreqMode_MASS_BASED: // Update constantly. The optimization done for Z value makes @@ -648,10 +648,10 @@ void FTMotion::makeVector() { #endif break; #endif - + default: break; } - + // Apply shaping if active on each axis #if HAS_FTM_SHAPING #if HAS_X_AXIS @@ -664,7 +664,7 @@ void FTMotion::makeVector() { } } #endif - + #if HAS_Y_AXIS if (shaping.y.ena) { shaping.y.d_zi[shaping.zi_idx] = traj.y[makeVector_batchIdx]; @@ -677,13 +677,13 @@ void FTMotion::makeVector() { #endif if (++shaping.zi_idx == (FTM_ZMAX)) shaping.zi_idx = 0; #endif // HAS_FTM_SHAPING - + // Filled up the queue with regular and shaped steps if (++makeVector_batchIdx == FTM_WINDOW_SIZE) { makeVector_batchIdx = BATCH_SIDX_IN_WINDOW; batchRdy = true; } - + if (++makeVector_idx == max_intervals) { blockProcRdy = false; makeVector_idx = 0; diff --git a/Marlin/src/module/motion.cpp b/Marlin/src/module/motion.cpp index dc218290a0..6a039c8ab9 100644 --- a/Marlin/src/module/motion.cpp +++ b/Marlin/src/module/motion.cpp @@ -2626,7 +2626,7 @@ void prepare_line_to_destination() { default: return; } - // Phase distance to nearest home phase position when moving in the backout direction from endstop(may be negative). + // Phase distance to nearest home phase position when moving in the backout direction from endstop (may be negative). int16_t phaseDelta = (home_phase[axis] - phaseCurrent) * stepperBackoutDir; // Check if home distance within endstop assumed repeatability noise of .05mm and warn. @@ -2638,7 +2638,7 @@ void prepare_line_to_destination() { // Skip to next if target position is behind current. So it only moves away from endstop. if (phaseDelta < 0) phaseDelta += 1024; - // Convert TMC µsteps(phase) to whole Marlin µsteps to effector backout direction to mm + // Convert TMC µsteps (phase) to whole Marlin µsteps to effector backout direction to mm const float mmDelta = int16_t(phaseDelta / phasePerUStep) * effectorBackoutDir * planner.mm_per_step[axis]; // Optional debug messages diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FLY_D5/ldscript.ld b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D5/ldscript.ld index 5eee783933..e86d8aa274 100644 --- a/buildroot/share/PlatformIO/variants/MARLIN_FLY_D5/ldscript.ld +++ b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D5/ldscript.ld @@ -37,7 +37,7 @@ _Min_Stack_Size = 0x400; /* required amount of stack */ MEMORY { RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 16K - FLASH (rx) : ORIGIN = 0x8000000 , LENGTH = 128K + FLASH (rx) : ORIGIN = 0x8000000 , LENGTH = 128K } /* Sections */ diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FLY_D7/ldscript.ld b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D7/ldscript.ld index 5eee783933..e86d8aa274 100644 --- a/buildroot/share/PlatformIO/variants/MARLIN_FLY_D7/ldscript.ld +++ b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D7/ldscript.ld @@ -37,7 +37,7 @@ _Min_Stack_Size = 0x400; /* required amount of stack */ MEMORY { RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 16K - FLASH (rx) : ORIGIN = 0x8000000 , LENGTH = 128K + FLASH (rx) : ORIGIN = 0x8000000 , LENGTH = 128K } /* Sections */ diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FLY_D8_PRO/PeripheralPins.c b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D8_PRO/PeripheralPins.c index b0a78e5e85..f71d59c6f5 100644 --- a/buildroot/share/PlatformIO/variants/MARLIN_FLY_D8_PRO/PeripheralPins.c +++ b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D8_PRO/PeripheralPins.c @@ -199,7 +199,7 @@ WEAK const PinMap PinMap_TIM[] = { WEAK const PinMap PinMap_UART_TX[] = { // {PA_0, UART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART4)}, // {PA_2, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)}, - // {PA_9, LPUART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_LPUART)}, + // {PA_9, LPUART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_LPUART)}, {PA_9_ALT1, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART1)},// EXP2_03_PIN // {PA_12, UART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_UART4)}, // {PA_15, UART7, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_UART7)}, @@ -231,7 +231,7 @@ WEAK const PinMap PinMap_UART_RX[] = { // {PA_1, UART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART4)}, // {PA_3, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)}, // {PA_8, UART7, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_UART7)}, - // {PA_10, LPUART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_LPUART)}, + // {PA_10, LPUART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_LPUART)}, {PA_10_ALT1, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART1)},// EXP2_05_PIN // {PA_11, UART4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_UART4)}, // {PB_3, UART7, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF11_UART7)}, From e11a5ee717e35136afe23715fa04f3b63c1917b3 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Mon, 17 Mar 2025 16:04:42 -0500 Subject: [PATCH 120/787] =?UTF-8?q?=F0=9F=93=9D=20Some=20config=20comment?= =?UTF-8?q?=20updates?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Andrew <18502096+classicrocker883@users.noreply.github.com> --- Marlin/Configuration.h | 52 +++++++++++++++++++-------------- Marlin/Configuration_adv.h | 59 ++++++++++++++++++++------------------ 2 files changed, 61 insertions(+), 50 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index e9dc6f0fd1..6e16dc5caf 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -2899,13 +2899,15 @@ // //#define MAKEBOARD_MINI_2_LINE_DISPLAY_1602 -// -// ANET and Tronxy 20x4 Controller -// -//#define ZONESTAR_LCD // Requires ADC_KEYPAD_PIN to be assigned to an analog pin. - // This LCD is known to be susceptible to electrical interference - // which scrambles the display. Pressing any button clears it up. - // This is a LCD2004 display with 5 analog buttons. +/** + * ANET and Tronxy 20x4 Controller + * LCD2004 display with 5 analog buttons. + * + * NOTE: Requires ADC_KEYPAD_PIN to be assigned to an analog pin. + * This LCD is known to be susceptible to electrical interference which + * scrambles the display. Press any button to clear it up. + */ +//#define ZONESTAR_LCD // // Generic 16x2, 16x4, 20x2, or 20x4 character-based LCD. @@ -3542,22 +3544,26 @@ // :[1,2,3,4,5,6,7,8] //#define NUM_M106_FANS 1 -// Use software PWM to drive the fan, as for the heaters. This uses a very low frequency -// which is not as annoying as with the hardware PWM. On the other hand, if this frequency -// is too low, you should also increment SOFT_PWM_SCALE. +/** + * Use software PWM to drive the fan, as for the heaters. This uses a very low frequency + * which is not as annoying as with the hardware PWM. On the other hand, if this frequency + * is too low, you should also increment SOFT_PWM_SCALE. + */ //#define FAN_SOFT_PWM -// Incrementing this by 1 will double the software PWM frequency, -// affecting heaters, and the fan if FAN_SOFT_PWM is enabled. -// However, control resolution will be halved for each increment; -// at zero value, there are 128 effective control positions. -// :[0,1,2,3,4,5,6,7] +/** + * Incrementing this by 1 will double the software PWM frequency, affecting heaters, and + * the fan if FAN_SOFT_PWM is enabled. However, control resolution will be halved for each + * increment; at zero value, there are 128 effective control positions. + * :[0,1,2,3,4,5,6,7] + */ #define SOFT_PWM_SCALE 0 -// If SOFT_PWM_SCALE is set to a value higher than 0, dithering can -// be used to mitigate the associated resolution loss. If enabled, -// some of the PWM cycles are stretched so on average the desired -// duty cycle is attained. +/** + * If SOFT_PWM_SCALE is set to a value higher than 0, dithering can be used to mitigate the + * associated resolution loss. If enabled, some of the PWM cycles are stretched so on average + * the desired duty cycle is attained. + */ //#define SOFT_PWM_DITHER // @section extras @@ -3567,9 +3573,11 @@ // @section lights -// Temperature status LEDs that display the hotend and bed temperature. -// If all hotends, bed temperature, and target temperature are under 54C -// then the BLUE led is on. Otherwise the RED led is on. (1C hysteresis) +/** + * Temperature status LEDs that display the hotend and bed temperature. + * If all hotends, bed temperature, and target temperature are under 54C + * the BLUE led is on. Otherwise the RED led is on. (1C hysteresis) + */ //#define TEMP_STAT_LEDS // Support for BlinkM/CyzRgb diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index ff85b6c0e3..45ba05cbba 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -1419,24 +1419,24 @@ #define MICROSTEP_MODES { 16, 16, 16, 16, 16, 16 } // [1,2,4,8,16] /** - * @section stepper motor current + * @section stepper motor current * - * Some boards have a means of setting the stepper motor current via firmware. + * Some boards have a means of setting the stepper motor current via firmware. * - * The power on motor currents are set by: - * PWM_MOTOR_CURRENT - used by MINIRAMBO & ULTIMAIN_2 - * known compatible chips: A4982 - * DIGIPOT_MOTOR_CURRENT - used by BQ_ZUM_MEGA_3D, RAMBO & SCOOVO_X9H - * known compatible chips: AD5206 - * DAC_MOTOR_CURRENT_DEFAULT - used by PRINTRBOARD_REVF & RIGIDBOARD_V2 - * known compatible chips: MCP4728 - * DIGIPOT_I2C_MOTOR_CURRENTS - used by 5DPRINT, AZTEEG_X3_PRO, AZTEEG_X5_MINI_WIFI, MIGHTYBOARD_REVE - * known compatible chips: MCP4451, MCP4018 + * The power on motor currents are set by: + * PWM_MOTOR_CURRENT - used by MINIRAMBO & ULTIMAIN_2 + * known compatible chips: A4982 + * DIGIPOT_MOTOR_CURRENT - used by BQ_ZUM_MEGA_3D, RAMBO & SCOOVO_X9H + * known compatible chips: AD5206 + * DAC_MOTOR_CURRENT_DEFAULT - used by PRINTRBOARD_REVF & RIGIDBOARD_V2 + * known compatible chips: MCP4728 + * DIGIPOT_I2C_MOTOR_CURRENTS - used by 5DPRINT, AZTEEG_X3_PRO, AZTEEG_X5_MINI_WIFI, MIGHTYBOARD_REVE + * known compatible chips: MCP4451, MCP4018 * - * Motor currents can also be set by M907 - M910 and by the LCD. - * M907 - applies to all. - * M908 - BQ_ZUM_MEGA_3D, RAMBO, PRINTRBOARD_REVF, RIGIDBOARD_V2 & SCOOVO_X9H - * M909, M910 & LCD - only PRINTRBOARD_REVF & RIGIDBOARD_V2 + * Motor currents can also be set by M907 - M910 and by the LCD. + * M907 - applies to all. + * M908 - BQ_ZUM_MEGA_3D, RAMBO, PRINTRBOARD_REVF, RIGIDBOARD_V2 & SCOOVO_X9H + * M909, M910 & LCD - only PRINTRBOARD_REVF & RIGIDBOARD_V2 */ //#define PWM_MOTOR_CURRENT { 1300, 1300, 1250 } // Values in milliamps //#define DIGIPOT_MOTOR_CURRENT { 135,135,135,135,135 } // Values 0-255 (RAMBO 135 = ~0.75A, 185 = ~1A) @@ -2634,19 +2634,23 @@ #define MAX_CMD_SIZE 96 #define BUFSIZE 4 -// Transmission to Host Buffer Size -// To save 386 bytes of flash (and TX_BUFFER_SIZE+3 bytes of RAM) set to 0. -// To buffer a simple "ok" you need 4 bytes. -// For ADVANCED_OK (M105) you need 32 bytes. -// For debug-echo: 128 bytes for the optimal speed. -// Other output doesn't need to be that speedy. -// :[0, 2, 4, 8, 16, 32, 64, 128, 256] +/** + * Host Transmit Buffer Size + * - Costs 386 bytes of flash and TX_BUFFER_SIZE+3 bytes of SRAM (if not 0). + * - 4 bytes required to buffer a simple "ok". + * - 32 bytes for ADVANCED_OK (M105). + * - 128 bytes for the optimal speed of 'debug-echo:' + * - Other output doesn't need to be that speedy. + * :[0, 2, 4, 8, 16, 32, 64, 128, 256] + */ #define TX_BUFFER_SIZE 0 -// Host Receive Buffer Size -// Without XON/XOFF flow control (see SERIAL_XON_XOFF below) 32 bytes should be enough. -// To use flow control, set this buffer size to at least 1024 bytes. -// :[0, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048] +/** + * Host Receive Buffer Size + * Without XON/XOFF flow control (see SERIAL_XON_XOFF below) 32 bytes should be enough. + * To use flow control, set this buffer size to at least 1024 bytes. + * :[0, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048] + */ //#define RX_BUFFER_SIZE 1024 #if RX_BUFFER_SIZE >= 1024 @@ -3913,7 +3917,7 @@ /** * Extra options for the M114 "Current Position" report */ -//#define M114_DETAIL // Use 'M114` for details to check planner calculations +//#define M114_DETAIL // Use 'M114 D' for details to check planner calculations //#define M114_REALTIME // Real current position based on forward kinematics //#define M114_LEGACY // M114 used to synchronize on every call. Enable if needed. @@ -3960,7 +3964,6 @@ * Spend 28 bytes of SRAM to optimize the G-code parser */ #define FASTER_GCODE_PARSER - #if ENABLED(FASTER_GCODE_PARSER) //#define GCODE_QUOTED_STRINGS // Support for quoted string parameters #endif From 0d87dd9d51d857048ba251ffa22d47a1b2ab2deb Mon Sep 17 00:00:00 2001 From: David Buezas Date: Mon, 17 Mar 2025 22:27:51 +0100 Subject: [PATCH 121/787] =?UTF-8?q?=E2=9C=A8=20LCD=5FDOUBLE=5FBUFFER=20(#2?= =?UTF-8?q?6713)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/Configuration_adv.h | 4 ++++ Marlin/src/lcd/dogm/marlinui_DOGM.h | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 45ba05cbba..7cc54b2a96 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -1619,6 +1619,10 @@ //#define SOUND_MENU_ITEM // Add a mute option to the LCD menu #define SOUND_ON_DEFAULT // Buzzer/speaker default enabled state + #if ENABLED(U8GLIB_SSD1309) + //#define LCD_DOUBLE_BUFFER // Optimize display updates. Costs ~1K of SRAM. + #endif + #if HAS_WIRED_LCD //#define DOUBLE_LCD_FRAMERATE // Not recommended for slow boards. #endif diff --git a/Marlin/src/lcd/dogm/marlinui_DOGM.h b/Marlin/src/lcd/dogm/marlinui_DOGM.h index d3f38cd619..ac65eab7de 100644 --- a/Marlin/src/lcd/dogm/marlinui_DOGM.h +++ b/Marlin/src/lcd/dogm/marlinui_DOGM.h @@ -201,7 +201,7 @@ // Generic support for SSD1309 OLED I2C LCDs - #define U8G_CLASS U8GLIB_SSD1309_128X64 + #define U8G_CLASS TERN(LCD_DOUBLE_BUFFER, U8GLIB_SSD1309_128X64_F, U8GLIB_SSD1309_128X64) #define U8G_PARAM (U8G_I2C_OPT_NONE | U8G_I2C_OPT_FAST) // I2C #elif ENABLED(U8GLIB_SSD1306) From 2f4f2bce15a63fe2b2280b43744176695ece4490 Mon Sep 17 00:00:00 2001 From: Andrew <18502096+classicrocker883@users.noreply.github.com> Date: Mon, 17 Mar 2025 19:04:59 -0400 Subject: [PATCH 122/787] =?UTF-8?q?=F0=9F=94=A8=20PowerShell=20compatibili?= =?UTF-8?q?ty=20(#27720)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ftdi_eve_lib/scripts/svg2cpp.py | 2 +- buildroot/bin/config.py | 12 ++++++------ buildroot/share/PlatformIO/scripts/config.py | 12 ++++++------ buildroot/share/PlatformIO/scripts/mc-apply.py | 8 ++++---- .../share/PlatformIO/scripts/preflight-checks.py | 2 +- buildroot/share/PlatformIO/scripts/schema.py | 2 +- buildroot/share/scripts/pinsformat.py | 4 ++-- buildroot/share/scripts/validate_boards.py | 4 ++-- 8 files changed, 23 insertions(+), 23 deletions(-) diff --git a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/scripts/svg2cpp.py b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/scripts/svg2cpp.py index f505636c86..3b26cc4e47 100755 --- a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/scripts/svg2cpp.py +++ b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/scripts/svg2cpp.py @@ -296,7 +296,7 @@ if __name__ == "__main__": parser.add_argument('--layer', help='only include layers which have this string in their names') args = parser.parse_args() - f = open(args.filename, "r") + f = open(args.filename, "r", encoding='utf-8') data = f.read() # First pass to grab viewbox diff --git a/buildroot/bin/config.py b/buildroot/bin/config.py index 980c6ecc65..8d6cc5891a 100755 --- a/buildroot/bin/config.py +++ b/buildroot/bin/config.py @@ -16,7 +16,7 @@ def set(file_path, define_name, value): Returns True if the define was found and replaced, False otherwise. ''' # Read the contents of the file - with open(file_path, 'r') as f: + with open(file_path, 'r', encoding='utf-8') as f: content = f.readlines() modified = False @@ -32,7 +32,7 @@ def set(file_path, define_name, value): # Write the modified content back to the file only if changes were made if modified: - with open(file_path, 'w') as f: + with open(file_path, 'w', encoding='utf-8') as f: f.writelines(content) return True @@ -42,7 +42,7 @@ def add(file_path, define_name, value=""): ''' Insert a define on the first blank line in a file. ''' - with open(file_path, 'r') as f: + with open(file_path, 'r', encoding='utf-8') as f: content = f.readlines() # Prepend a space to the value if it's not empty @@ -59,7 +59,7 @@ def add(file_path, define_name, value=""): # If no blank line is found, append to the end content.append(f"#define {define_name}{value}\n") - with open(file_path, 'w') as f: + with open(file_path, 'w', encoding='utf-8') as f: f.writelines(content) def enable(file_path, define_name, enable=True): @@ -68,7 +68,7 @@ def enable(file_path, define_name, enable=True): Returns True if the define was found, False otherwise. ''' # Read the contents of the file - with open(file_path, 'r') as f: + with open(file_path, 'r', encoding='utf-8') as f: content = f.readlines() # Prepare the regex @@ -96,7 +96,7 @@ def enable(file_path, define_name, enable=True): # Write the modified content back to the file only if changes were made if modified: - with open(file_path, 'w') as f: + with open(file_path, 'w', encoding='utf-8') as f: f.writelines(content) return found diff --git a/buildroot/share/PlatformIO/scripts/config.py b/buildroot/share/PlatformIO/scripts/config.py index 980c6ecc65..8d6cc5891a 100755 --- a/buildroot/share/PlatformIO/scripts/config.py +++ b/buildroot/share/PlatformIO/scripts/config.py @@ -16,7 +16,7 @@ def set(file_path, define_name, value): Returns True if the define was found and replaced, False otherwise. ''' # Read the contents of the file - with open(file_path, 'r') as f: + with open(file_path, 'r', encoding='utf-8') as f: content = f.readlines() modified = False @@ -32,7 +32,7 @@ def set(file_path, define_name, value): # Write the modified content back to the file only if changes were made if modified: - with open(file_path, 'w') as f: + with open(file_path, 'w', encoding='utf-8') as f: f.writelines(content) return True @@ -42,7 +42,7 @@ def add(file_path, define_name, value=""): ''' Insert a define on the first blank line in a file. ''' - with open(file_path, 'r') as f: + with open(file_path, 'r', encoding='utf-8') as f: content = f.readlines() # Prepend a space to the value if it's not empty @@ -59,7 +59,7 @@ def add(file_path, define_name, value=""): # If no blank line is found, append to the end content.append(f"#define {define_name}{value}\n") - with open(file_path, 'w') as f: + with open(file_path, 'w', encoding='utf-8') as f: f.writelines(content) def enable(file_path, define_name, enable=True): @@ -68,7 +68,7 @@ def enable(file_path, define_name, enable=True): Returns True if the define was found, False otherwise. ''' # Read the contents of the file - with open(file_path, 'r') as f: + with open(file_path, 'r', encoding='utf-8') as f: content = f.readlines() # Prepare the regex @@ -96,7 +96,7 @@ def enable(file_path, define_name, enable=True): # Write the modified content back to the file only if changes were made if modified: - with open(file_path, 'w') as f: + with open(file_path, 'w', encoding='utf-8') as f: f.writelines(content) return found diff --git a/buildroot/share/PlatformIO/scripts/mc-apply.py b/buildroot/share/PlatformIO/scripts/mc-apply.py index 52d2ad6387..4f341b0065 100755 --- a/buildroot/share/PlatformIO/scripts/mc-apply.py +++ b/buildroot/share/PlatformIO/scripts/mc-apply.py @@ -25,7 +25,7 @@ def report_version(conf): print(k + ': ' + v) def write_opt_file(conf, outpath='Marlin/apply_config.sh'): - with open(outpath, 'w') as outfile: + with open(outpath, 'w', encoding='utf-8') as outfile: for key, val in conf.items(): if key in ('__INITIAL_HASH', 'VERSION'): continue @@ -49,7 +49,7 @@ def write_opt_file(conf, outpath='Marlin/apply_config.sh'): def back_up_config(name): # Back up the existing file before modifying it conf_path = 'Marlin/' + name - with open(conf_path, 'r') as f: + with open(conf_path, 'r', encoding='utf-8') as f: # Write a filename.bak#.ext retaining the original extension parts = conf_path.split('.') nr = '' @@ -59,7 +59,7 @@ def back_up_config(name): nr = 1 if nr == '' else nr + 1 continue - with open(bak_path, 'w') as b: + with open(bak_path, 'w', encoding='utf-8') as b: b.writelines(f.readlines()) break @@ -83,7 +83,7 @@ def main(): args = parser.parse_args() try: - infile = open(args.config_file, 'r') + infile = open(args.config_file, 'r', encoding='utf-8') except: print(f'No {args.config_file} found.') sys.exit(1) diff --git a/buildroot/share/PlatformIO/scripts/preflight-checks.py b/buildroot/share/PlatformIO/scripts/preflight-checks.py index 7ccf86c486..94b39927e0 100644 --- a/buildroot/share/PlatformIO/scripts/preflight-checks.py +++ b/buildroot/share/PlatformIO/scripts/preflight-checks.py @@ -78,7 +78,7 @@ if pioutil.is_pio_build(): modified_text = text.replace("BOTH(", "ALL(").replace("EITHER(", "ANY(") if text != modified_text: conf_modified = True - with open(conf_path, 'w') as file: + with open(conf_path, 'w', encoding="utf8") as file: file.write(modified_text) if conf_modified: diff --git a/buildroot/share/PlatformIO/scripts/schema.py b/buildroot/share/PlatformIO/scripts/schema.py index d23e5c4716..fcfae998c4 100755 --- a/buildroot/share/PlatformIO/scripts/schema.py +++ b/buildroot/share/PlatformIO/scripts/schema.py @@ -70,7 +70,7 @@ def group_options(schema): def load_boards(): bpath = Path("Marlin/src/core/boards.h") if bpath.is_file(): - with bpath.open() as bfile: + with bpath.open(encoding='utf-8') as bfile: boards = [] for line in bfile: if line.startswith("#define BOARD_"): diff --git a/buildroot/share/scripts/pinsformat.py b/buildroot/share/scripts/pinsformat.py index 0260d3174e..c1d88934b7 100755 --- a/buildroot/share/scripts/pinsformat.py +++ b/buildroot/share/scripts/pinsformat.py @@ -71,7 +71,7 @@ def format_pins(argv): file_text = sys.stdin.read() else: # Open and read the file src_file - with open(src_file, 'r') as rf: file_text = rf.read() + with open(src_file, 'r', encoding='utf-8') as rf: file_text = rf.read() if len(file_text) == 0: print('No text to process') @@ -80,7 +80,7 @@ def format_pins(argv): # Read from file or STDIN until it terminates filtered = process_text(file_text) if dst_file: - with open(dst_file, 'w') as wf: wf.write(filtered) + with open(dst_file, 'w', encoding='utf-8') as wf: wf.write(filtered) else: print(filtered) diff --git a/buildroot/share/scripts/validate_boards.py b/buildroot/share/scripts/validate_boards.py index 8d5650d6c6..0e4ae3351a 100755 --- a/buildroot/share/scripts/validate_boards.py +++ b/buildroot/share/scripts/validate_boards.py @@ -40,7 +40,7 @@ def boards_checks(argv): logmsg('Checking boards file:', src_file) # Open the file - with open(src_file, 'r') as f: + with open(src_file, 'r', encoding='utf-8') as f: lines = f.readlines() # Get the board names and numbers @@ -85,7 +85,7 @@ def boards_checks(argv): # Validate that pins.h has all the boards mentioned in it # pins_boards = [] - with open('Marlin/src/pins/pins.h', 'r') as f: + with open('Marlin/src/pins/pins.h', 'r', encoding='utf-8') as f: lines = f.readlines() if_count = 0 for line in lines: From 0a07bba213424fc8841bb803e697b830c861df4e Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Tue, 18 Mar 2025 00:28:49 +0000 Subject: [PATCH 123/787] [cron] Bump distribution date (2025-03-18) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index a8be38fe31..6f5abc50e1 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-03-17" +//#define STRING_DISTRIBUTION_DATE "2025-03-18" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index c9db7e51b9..a36c00865f 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-03-17" + #define STRING_DISTRIBUTION_DATE "2025-03-18" #endif /** From 367cea0d0dfdf71464faf1422f46417388139306 Mon Sep 17 00:00:00 2001 From: InsanityAutomation <38436470+InsanityAutomation@users.noreply.github.com> Date: Mon, 17 Mar 2025 22:35:20 -0400 Subject: [PATCH 124/787] =?UTF-8?q?=F0=9F=9A=B8=20Chamber=20Preheat=20comp?= =?UTF-8?q?letion=20(#26864)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Followup to #21156 Co-authored-by: Scott Lahteine --- Marlin/src/gcode/lcd/M145.cpp | 5 +++ Marlin/src/gcode/temp/M141_M191.cpp | 9 ++++- Marlin/src/lcd/extui/ui_api.cpp | 3 ++ Marlin/src/lcd/extui/ui_api.h | 3 ++ Marlin/src/lcd/language/language_en.h | 3 ++ Marlin/src/lcd/marlinui.cpp | 8 ++--- Marlin/src/lcd/marlinui.h | 3 ++ Marlin/src/lcd/menu/menu_configuration.cpp | 3 ++ Marlin/src/lcd/menu/menu_temperature.cpp | 39 +++++++++++++--------- Marlin/src/module/settings.cpp | 10 ++++-- Marlin/src/module/temperature.h | 2 +- 11 files changed, 64 insertions(+), 24 deletions(-) diff --git a/Marlin/src/gcode/lcd/M145.cpp b/Marlin/src/gcode/lcd/M145.cpp index 3cc6130dfd..a0aa340d0d 100644 --- a/Marlin/src/gcode/lcd/M145.cpp +++ b/Marlin/src/gcode/lcd/M145.cpp @@ -37,6 +37,7 @@ * S * H * B + * C * F */ void GcodeSuite::M145() { @@ -53,6 +54,10 @@ void GcodeSuite::M145() { if (parser.seenval('B')) mat.bed_temp = constrain(parser.value_int(), BED_MINTEMP, BED_MAX_TARGET); #endif + #if HAS_HEATED_CHAMBER + if (parser.seenval('C')) + mat.chamber_temp = constrain(parser.value_int(), CHAMBER_MINTEMP, CHAMBER_MAX_TARGET); + #endif #if HAS_FAN if (parser.seenval('F')) mat.fan_speed = constrain(parser.value_int(), 0, 255); diff --git a/Marlin/src/gcode/temp/M141_M191.cpp b/Marlin/src/gcode/temp/M141_M191.cpp index 81a078318a..3364fbc22e 100644 --- a/Marlin/src/gcode/temp/M141_M191.cpp +++ b/Marlin/src/gcode/temp/M141_M191.cpp @@ -39,9 +39,16 @@ */ void GcodeSuite::M141() { if (DEBUGGING(DRYRUN)) return; + // Accept 'I' if temperature presets are defined + #if HAS_PREHEAT + if (parser.seenval('I')) { + const uint8_t index = parser.value_byte(); + thermalManager.setTargetChamber(ui.material_preset[_MIN(index, PREHEAT_COUNT - 1)].chamber_temp); + return; + } + #endif if (parser.seenval('S')) { thermalManager.setTargetChamber(parser.value_celsius()); - #if ENABLED(PRINTJOB_TIMER_AUTOSTART) /** * Stop the timer at the end of print. Hotend, bed target, and chamber diff --git a/Marlin/src/lcd/extui/ui_api.cpp b/Marlin/src/lcd/extui/ui_api.cpp index a53b5f5dba..5b6caf378a 100644 --- a/Marlin/src/lcd/extui/ui_api.cpp +++ b/Marlin/src/lcd/extui/ui_api.cpp @@ -811,6 +811,9 @@ namespace ExtUI { #if HAS_HEATED_BED uint16_t getMaterial_preset_B(const uint16_t index) { return ui.material_preset[index].bed_temp; } #endif + #if HAS_HEATED_CHAMBER + uint16_t getMaterial_preset_C(const uint16_t index) { return ui.material_preset[index].chamber_temp; } + #endif #endif feedRate_t getFeedrate_mm_s() { return feedrate_mm_s; } diff --git a/Marlin/src/lcd/extui/ui_api.h b/Marlin/src/lcd/extui/ui_api.h index 2676d72aea..dfe393e39a 100644 --- a/Marlin/src/lcd/extui/ui_api.h +++ b/Marlin/src/lcd/extui/ui_api.h @@ -214,6 +214,9 @@ namespace ExtUI { #if HAS_HEATED_BED uint16_t getMaterial_preset_B(const uint16_t); #endif + #if HAS_HEATED_CHAMBER + uint16_t getMaterial_preset_C(const uint16_t); + #endif #endif // IDEX Machine Mode diff --git a/Marlin/src/lcd/language/language_en.h b/Marlin/src/lcd/language/language_en.h index b033dc3c74..6076c6fb30 100644 --- a/Marlin/src/lcd/language/language_en.h +++ b/Marlin/src/lcd/language/language_en.h @@ -155,6 +155,7 @@ namespace LanguageNarrow_en { LSTR MSG_PREHEAT_M_END_E = _UxGT("Preheat $ End ~"); LSTR MSG_PREHEAT_M_ALL = _UxGT("Preheat $ All"); LSTR MSG_PREHEAT_M_BEDONLY = _UxGT("Preheat $ Bed"); + LSTR MSG_PREHEAT_M_CHAMBER = _UxGT("Preheat $ Chmb"); LSTR MSG_PREHEAT_M_SETTINGS = _UxGT("Preheat $ Conf"); LSTR MSG_PREHEAT_HOTEND = _UxGT("Preheat Hotend"); @@ -1109,6 +1110,8 @@ namespace LanguageWide_en { LSTR MSG_HOMING_FEEDRATE_Y = _UxGT("Y Homing Feedrate"); LSTR MSG_HOMING_FEEDRATE_Z = _UxGT("Z Homing Feedrate"); LSTR MSG_EEPROM_INITIALIZED = _UxGT("Default Settings Restored"); + LSTR MSG_PREHEAT_M_CHAMBER = _UxGT("Preheat $ Chamber"); + LSTR MSG_PREHEAT_M_SETTINGS = _UxGT("Preheat $ Config"); #endif } diff --git a/Marlin/src/lcd/marlinui.cpp b/Marlin/src/lcd/marlinui.cpp index e8946edb28..bd974d8d0a 100644 --- a/Marlin/src/lcd/marlinui.cpp +++ b/Marlin/src/lcd/marlinui.cpp @@ -150,10 +150,10 @@ constexpr uint8_t epps = ENCODER_PULSES_PER_STEP; void MarlinUI::apply_preheat(const uint8_t m, const uint8_t pmask, const uint8_t e/*=active_extruder*/) { const preheat_t &pre = material_preset[m]; - TERN_(HAS_HOTEND, if (TEST(pmask, PT_HOTEND)) thermalManager.setTargetHotend(pre.hotend_temp, e)); - TERN_(HAS_HEATED_BED, if (TEST(pmask, PT_BED)) thermalManager.setTargetBed(pre.bed_temp)); - //TERN_(HAS_HEATED_CHAMBER, if (TEST(pmask, PT_CHAMBER)) thermalManager.setTargetChamber(pre.chamber_temp)); - TERN_(HAS_FAN, if (TEST(pmask, PT_FAN)) thermalManager.set_fan_speed(0, pre.fan_speed)); + TERN_(HAS_HOTEND, if (TEST(pmask, PT_HOTEND)) thermalManager.setTargetHotend(pre.hotend_temp, e)); + TERN_(HAS_HEATED_BED, if (TEST(pmask, PT_BED)) thermalManager.setTargetBed(pre.bed_temp)); + TERN_(HAS_HEATED_CHAMBER, if (TEST(pmask, PT_CHAMBER)) thermalManager.setTargetChamber(pre.chamber_temp)); + TERN_(HAS_FAN, if (TEST(pmask, PT_FAN)) thermalManager.set_fan_speed(0, pre.fan_speed)); } #endif diff --git a/Marlin/src/lcd/marlinui.h b/Marlin/src/lcd/marlinui.h index a47096a3bf..26b559e6bc 100644 --- a/Marlin/src/lcd/marlinui.h +++ b/Marlin/src/lcd/marlinui.h @@ -118,6 +118,9 @@ typedef bool (*statusResetFunc_t)(); #if HAS_HEATED_BED celsius_t bed_temp; #endif + #if HAS_HEATED_CHAMBER + celsius_t chamber_temp; + #endif #if HAS_FAN uint16_t fan_speed; #endif diff --git a/Marlin/src/lcd/menu/menu_configuration.cpp b/Marlin/src/lcd/menu/menu_configuration.cpp index 65a2f222ce..c581bab4e3 100644 --- a/Marlin/src/lcd/menu/menu_configuration.cpp +++ b/Marlin/src/lcd/menu/menu_configuration.cpp @@ -451,6 +451,9 @@ void menu_advanced_settings(); #if HAS_HEATED_BED EDIT_ITEM(int3, MSG_BED, &ui.material_preset[m].bed_temp, BED_MINTEMP, BED_MAX_TARGET); #endif + #if HAS_HEATED_CHAMBER + EDIT_ITEM(int3, MSG_CHAMBER, &ui.material_preset[m].chamber_temp, CHAMBER_MINTEMP, CHAMBER_MAX_TARGET); + #endif #if ENABLED(EEPROM_SETTINGS) ACTION_ITEM(MSG_STORE_EEPROM, ui.store_settings); #endif diff --git a/Marlin/src/lcd/menu/menu_temperature.cpp b/Marlin/src/lcd/menu/menu_temperature.cpp index e8a7b25dcb..1a43b121ce 100644 --- a/Marlin/src/lcd/menu/menu_temperature.cpp +++ b/Marlin/src/lcd/menu/menu_temperature.cpp @@ -45,15 +45,17 @@ #if HAS_PREHEAT - void Temperature::lcd_preheat(const uint8_t e, const int8_t indh, const int8_t indb) { - UNUSED(e); UNUSED(indh); UNUSED(indb); + void Temperature::lcd_preheat(const uint8_t e, const int8_t indh/*=-1*/, const int8_t indb/*=-1*/, const int8_t indc/*=-1*/) { + UNUSED(e); UNUSED(indh); UNUSED(indb); UNUSED(indc); #if HAS_HOTEND - if (indh >= 0 && ui.material_preset[indh].hotend_temp > 0) - setTargetHotend(_MIN(thermalManager.hotend_max_target(e), ui.material_preset[indh].hotend_temp), e); + if (indh >= 0 && ui.material_preset[indh].hotend_temp > 0) setTargetHotend(ui.material_preset[indh].hotend_temp, e); #endif #if HAS_HEATED_BED if (indb >= 0 && ui.material_preset[indb].bed_temp > 0) setTargetBed(ui.material_preset[indb].bed_temp); #endif + #if HAS_HEATED_CHAMBER + if (indc >= 0 && ui.material_preset[indc].chamber_temp > 0) setTargetChamber(ui.material_preset[indc].chamber_temp); + #endif #if HAS_FAN if (indh >= 0) { const uint8_t fan_index = active_extruder < (FAN_COUNT) ? active_extruder : 0; @@ -68,30 +70,33 @@ } #if HAS_TEMP_HOTEND - inline void _preheat_end(const uint8_t m, const uint8_t e) { thermalManager.lcd_preheat(e, m, -1); } - void do_preheat_end_m() { _preheat_end(editable.int8, 0); } + inline void _preheat_end(const uint8_t e, const uint8_t m) { thermalManager.lcd_preheat(e, m); } + void do_preheat_end_m() { _preheat_end(0, editable.int8); } #endif #if HAS_HEATED_BED inline void _preheat_bed(const uint8_t m) { thermalManager.lcd_preheat(0, -1, m); } #endif + #if HAS_HEATED_CHAMBER + inline void _preheat_chamber(const uint8_t m) { thermalManager.lcd_preheat(0, -1, -1, m); } + #endif #if HAS_COOLER - inline void _precool_laser(const uint8_t m, const uint8_t e) { thermalManager.lcd_preheat(e, m, -1); } - void do_precool_laser_m() { _precool_laser(editable.int8, thermalManager.temp_cooler.target); } + inline void _precool_laser(const uint8_t e, const uint8_t m) { thermalManager.lcd_preheat(e, m); } + void do_precool_laser_m() { _precool_laser(thermalManager.temp_cooler.target, editable.int8); } #endif - #if HAS_TEMP_HOTEND && HAS_HEATED_BED - inline void _preheat_both(const uint8_t m, const uint8_t e) { thermalManager.lcd_preheat(e, m, m); } + #if HAS_TEMP_HOTEND && (HAS_HEATED_BED || HAS_HEATED_CHAMBER) + inline void _preheat_all(const uint8_t e, const uint8_t m) { thermalManager.lcd_preheat(e, m, m, m); } // Indexed "Preheat ABC" and "Heat Bed" items #define PREHEAT_ITEMS(M,E) do{ \ - ACTION_ITEM_N_f(E, ui.get_preheat_label(M), MSG_PREHEAT_M_H, []{ _preheat_both(M, MenuItemBase::itemIndex); }); \ - ACTION_ITEM_N_f(E, ui.get_preheat_label(M), MSG_PREHEAT_M_END_E, []{ _preheat_end(M, MenuItemBase::itemIndex); }); \ + ACTION_ITEM_N_f(E, ui.get_preheat_label(M), MSG_PREHEAT_M_H, []{ _preheat_all(MenuItemBase::itemIndex, M); }); \ + ACTION_ITEM_N_f(E, ui.get_preheat_label(M), MSG_PREHEAT_M_END_E, []{ _preheat_end(MenuItemBase::itemIndex, M); }); \ }while(0) #elif HAS_MULTI_HOTEND // No heated bed, so just indexed "Preheat ABC" items - #define PREHEAT_ITEMS(M,E) ACTION_ITEM_N_f(E, ui.get_preheat_label(M), MSG_PREHEAT_M_H, []{ _preheat_end(M, MenuItemBase::itemIndex); }) + #define PREHEAT_ITEMS(M,E) ACTION_ITEM_N_f(E, ui.get_preheat_label(M), MSG_PREHEAT_M_H, []{ _preheat_end(MenuItemBase::itemIndex, M); }) #endif @@ -107,8 +112,8 @@ #if HOTENDS == 1 - #if HAS_HEATED_BED - ACTION_ITEM_f(ui.get_preheat_label(m), MSG_PREHEAT_M, []{ _preheat_both(editable.int8, 0); }); + #if HAS_HEATED_BED || HAS_HEATED_CHAMBER + ACTION_ITEM_f(ui.get_preheat_label(m), MSG_PREHEAT_M, []{ _preheat_all(0, editable.int8); }); ACTION_ITEM_f(ui.get_preheat_label(m), MSG_PREHEAT_M_END, do_preheat_end_m); #else ACTION_ITEM_f(ui.get_preheat_label(m), MSG_PREHEAT_M, do_preheat_end_m); @@ -129,6 +134,10 @@ ACTION_ITEM_f(ui.get_preheat_label(m), MSG_PREHEAT_M_BEDONLY, []{ _preheat_bed(editable.int8); }); #endif + #if HAS_HEATED_CHAMBER + ACTION_ITEM_f(ui.get_preheat_label(m), MSG_PREHEAT_M_CHAMBER, []{ _preheat_chamber(editable.int8); }); + #endif + END_MENU(); } diff --git a/Marlin/src/module/settings.cpp b/Marlin/src/module/settings.cpp index 485d01066a..8c33e73f00 100644 --- a/Marlin/src/module/settings.cpp +++ b/Marlin/src/module/settings.cpp @@ -3564,13 +3564,17 @@ void MarlinSettings::reset() { #if HAS_HEATED_BED constexpr uint16_t bpre[] = { REPEAT2_S(1, INCREMENT(PREHEAT_COUNT), _PITEM, TEMP_BED) }; #endif + #if HAS_HEATED_CHAMBER + constexpr uint16_t cpre[] = { REPEAT2_S(1, INCREMENT(PREHEAT_COUNT), _PITEM, TEMP_CHAMBER) }; + #endif #if HAS_FAN constexpr uint8_t fpre[] = { REPEAT2_S(1, INCREMENT(PREHEAT_COUNT), _PITEM, FAN_SPEED) }; #endif for (uint8_t i = 0; i < PREHEAT_COUNT; ++i) { - TERN_(HAS_HOTEND, ui.material_preset[i].hotend_temp = hpre[i]); - TERN_(HAS_HEATED_BED, ui.material_preset[i].bed_temp = bpre[i]); - TERN_(HAS_FAN, ui.material_preset[i].fan_speed = fpre[i]); + TERN_(HAS_HOTEND, ui.material_preset[i].hotend_temp = hpre[i]); + TERN_(HAS_HEATED_BED, ui.material_preset[i].bed_temp = bpre[i]); + TERN_(HAS_HEATED_CHAMBER, ui.material_preset[i].chamber_temp = cpre[i]); + TERN_(HAS_FAN, ui.material_preset[i].fan_speed = fpre[i]); } #endif diff --git a/Marlin/src/module/temperature.h b/Marlin/src/module/temperature.h index 27e28f07a8..cc25cfad14 100644 --- a/Marlin/src/module/temperature.h +++ b/Marlin/src/module/temperature.h @@ -1335,7 +1335,7 @@ class Temperature { #endif #if HAS_MARLINUI_MENU && HAS_TEMPERATURE && HAS_PREHEAT - static void lcd_preheat(const uint8_t e, const int8_t indh, const int8_t indb); + static void lcd_preheat(const uint8_t e, const int8_t indh=-1, const int8_t indb=-1, const int8_t indc=-1); #endif private: From 4ad6fa59df95d175c0acb49c33c2cf83fee5d449 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 18 Mar 2025 18:22:22 -0500 Subject: [PATCH 125/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Mor?= =?UTF-8?q?e=20extensible=20Temperature::lcd=5Fpreheat?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/lcd/menu/menu_temperature.cpp | 32 +++++++++++++++--------- Marlin/src/module/temperature.h | 12 ++++++++- 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/Marlin/src/lcd/menu/menu_temperature.cpp b/Marlin/src/lcd/menu/menu_temperature.cpp index 1a43b121ce..0a376494e5 100644 --- a/Marlin/src/lcd/menu/menu_temperature.cpp +++ b/Marlin/src/lcd/menu/menu_temperature.cpp @@ -45,47 +45,55 @@ #if HAS_PREHEAT - void Temperature::lcd_preheat(const uint8_t e, const int8_t indh/*=-1*/, const int8_t indb/*=-1*/, const int8_t indc/*=-1*/) { - UNUSED(e); UNUSED(indh); UNUSED(indb); UNUSED(indc); + /** + * @fn Temperature::lcd_preheat + * @brief Apply the "preheat" parameters for a material preset to the + * hotend (or laser), bed, chamber, or all of the above. + * @param m Material index + * @param targets Bit mask of targets to "preheat" (or turn off) + * @param e Extruder index (if needed) + */ + void Temperature::lcd_preheat(const uint8_t m, const uint8_t targets, const uint8_t e/*=0*/) { + UNUSED(e); #if HAS_HOTEND - if (indh >= 0 && ui.material_preset[indh].hotend_temp > 0) setTargetHotend(ui.material_preset[indh].hotend_temp, e); + if (targets & PreheatTarget::HOTEND) setTargetHotend(ui.material_preset[m].hotend_temp, e); #endif #if HAS_HEATED_BED - if (indb >= 0 && ui.material_preset[indb].bed_temp > 0) setTargetBed(ui.material_preset[indb].bed_temp); + if (targets & PreheatTarget::BED) setTargetBed(ui.material_preset[m].bed_temp); #endif #if HAS_HEATED_CHAMBER - if (indc >= 0 && ui.material_preset[indc].chamber_temp > 0) setTargetChamber(ui.material_preset[indc].chamber_temp); + if (targets & PreheatTarget::CHAMBER) setTargetChamber(ui.material_preset[m].chamber_temp); #endif #if HAS_FAN - if (indh >= 0) { + if (targets & PreheatTarget::HOTEND) { const uint8_t fan_index = active_extruder < (FAN_COUNT) ? active_extruder : 0; if (true #if REDUNDANT_PART_COOLING_FAN && fan_index != REDUNDANT_PART_COOLING_FAN #endif - ) set_fan_speed(fan_index, ui.material_preset[indh].fan_speed); + ) set_fan_speed(fan_index, ui.material_preset[m].fan_speed); } #endif ui.return_to_status(); } #if HAS_TEMP_HOTEND - inline void _preheat_end(const uint8_t e, const uint8_t m) { thermalManager.lcd_preheat(e, m); } + inline void _preheat_end(const uint8_t e, const uint8_t m) { thermalManager.lcd_preheat(m, PreheatTarget::HOTEND, e); } void do_preheat_end_m() { _preheat_end(0, editable.int8); } #endif #if HAS_HEATED_BED - inline void _preheat_bed(const uint8_t m) { thermalManager.lcd_preheat(0, -1, m); } + inline void _preheat_bed(const uint8_t m) { thermalManager.lcd_preheat(m, PreheatTarget::BED); } #endif #if HAS_HEATED_CHAMBER - inline void _preheat_chamber(const uint8_t m) { thermalManager.lcd_preheat(0, -1, -1, m); } + inline void _preheat_chamber(const uint8_t m) { thermalManager.lcd_preheat(m, PreheatTarget::CHAMBER); } #endif #if HAS_COOLER - inline void _precool_laser(const uint8_t e, const uint8_t m) { thermalManager.lcd_preheat(e, m); } + inline void _precool_laser(const uint8_t e, const uint8_t m) { thermalManager.lcd_preheat(m, PreheatTarget::HOTEND, e); } void do_precool_laser_m() { _precool_laser(thermalManager.temp_cooler.target, editable.int8); } #endif #if HAS_TEMP_HOTEND && (HAS_HEATED_BED || HAS_HEATED_CHAMBER) - inline void _preheat_all(const uint8_t e, const uint8_t m) { thermalManager.lcd_preheat(e, m, m, m); } + inline void _preheat_all(const uint8_t e, const uint8_t m) { thermalManager.lcd_preheat(m, PreheatTarget::ALL, e); } // Indexed "Preheat ABC" and "Heat Bed" items #define PREHEAT_ITEMS(M,E) do{ \ diff --git a/Marlin/src/module/temperature.h b/Marlin/src/module/temperature.h index cc25cfad14..5f7ea8daf4 100644 --- a/Marlin/src/module/temperature.h +++ b/Marlin/src/module/temperature.h @@ -599,6 +599,15 @@ typedef struct { raw_adc_t raw_min, raw_max; celsius_t mintemp, maxtemp; } temp_ #define HAS_FAN_LOGIC 1 #endif +#if HAS_MARLINUI_MENU && HAS_TEMPERATURE && HAS_PREHEAT + enum PreheatTarget : uint8_t { + HOTEND = (1 << 0), + BED = (1 << 1), + CHAMBER = (1 << 2), + ALL = 0xFF + }; +#endif + class Temperature { public: @@ -1335,7 +1344,8 @@ class Temperature { #endif #if HAS_MARLINUI_MENU && HAS_TEMPERATURE && HAS_PREHEAT - static void lcd_preheat(const uint8_t e, const int8_t indh=-1, const int8_t indb=-1, const int8_t indc=-1); + // Apply the "preheat" parameters for a material preset to the hotend (or laser), bed, chamber, or all of the above + static void lcd_preheat(const uint8_t m, const uint8_t targets, const uint8_t e=0); #endif private: From 23fa94178e1b1d00869058575eee0e7f06602839 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Wed, 19 Mar 2025 00:31:12 +0000 Subject: [PATCH 126/787] [cron] Bump distribution date (2025-03-19) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 6f5abc50e1..d2f7ac3ffd 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-03-18" +//#define STRING_DISTRIBUTION_DATE "2025-03-19" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index a36c00865f..fbdc9cdd04 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-03-18" + #define STRING_DISTRIBUTION_DATE "2025-03-19" #endif /** From 15ee0d0e081fd42cf00a5b26b289a2ea14ddd9f5 Mon Sep 17 00:00:00 2001 From: ellensp <530024+ellensp@users.noreply.github.com> Date: Wed, 19 Mar 2025 14:39:24 +1300 Subject: [PATCH 127/787] =?UTF-8?q?=E2=9C=A8=20MAG=5FMOUNTED=5FPROBE=5FSER?= =?UTF-8?q?VO=5FNR=20(#27551)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: gjdodd --- Marlin/Configuration.h | 14 ++++++++++++++ Marlin/src/inc/Conditionals-3-etc.h | 5 ++++- Marlin/src/inc/Conditionals-4-adv.h | 4 ++++ Marlin/src/inc/SanityCheck.h | 2 +- Marlin/src/module/probe.cpp | 24 ++++++++++++++++++++++-- Marlin/src/module/servo.h | 7 +++++++ buildroot/tests/LPC1769 | 2 +- 7 files changed, 53 insertions(+), 5 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 6e16dc5caf..1202bc1e53 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -1540,6 +1540,20 @@ #define PROBE_DEPLOY_FEEDRATE (133*60) // (mm/min) Probe deploy speed #define PROBE_STOW_FEEDRATE (133*60) // (mm/min) Probe stow speed + /** + * Magnetically Mounted Probe with a Servo mechanism + * Probe Deploy and Stow both follow the same basic sequence: + * - Rotate the SERVO to its Deployed angle + * - Perform XYZ moves to deploy or stow the PROBE + * - Rotate the SERVO to its Stowed angle + */ + //#define MAG_MOUNTED_PROBE_SERVO_NR 0 // Servo Number for this probe + #ifdef MAG_MOUNTED_PROBE_SERVO_NR + #define MAG_MOUNTED_PROBE_SERVO_ANGLES { 90, 0 } // Servo Angles for Deployed, Stowed + #define MAG_MOUNTED_PRE_DEPLOY { PROBE_DEPLOY_FEEDRATE, { 15, 160, 30 } } // Safe position for servo activation + #define MAG_MOUNTED_PRE_STOW { PROBE_DEPLOY_FEEDRATE, { 15, 160, 30 } } // Safe position for servo deactivation + #endif + #define MAG_MOUNTED_DEPLOY_1 { PROBE_DEPLOY_FEEDRATE, { 245, 114, 30 } } // Move to side Dock & Attach probe #define MAG_MOUNTED_DEPLOY_2 { PROBE_DEPLOY_FEEDRATE, { 210, 114, 30 } } // Move probe off dock #define MAG_MOUNTED_DEPLOY_3 { PROBE_DEPLOY_FEEDRATE, { 0, 0, 0 } } // Extra move if needed diff --git a/Marlin/src/inc/Conditionals-3-etc.h b/Marlin/src/inc/Conditionals-3-etc.h index 7f005c3539..e4dcdda58f 100644 --- a/Marlin/src/inc/Conditionals-3-etc.h +++ b/Marlin/src/inc/Conditionals-3-etc.h @@ -135,7 +135,10 @@ #ifdef Z_PROBE_SERVO_NR #define HAS_Z_SERVO_PROBE 1 #endif -#if ANY(HAS_Z_SERVO_PROBE, SWITCHING_EXTRUDER, SWITCHING_NOZZLE) +#ifdef MAG_MOUNTED_PROBE_SERVO_NR + #define HAS_MAG_MOUNTED_SERVO_PROBE 1 +#endif +#if ANY(HAS_Z_SERVO_PROBE, HAS_MAG_MOUNTED_SERVO_PROBE, SWITCHING_EXTRUDER, SWITCHING_NOZZLE) #define HAS_SERVO_ANGLES 1 #endif #if !HAS_SERVO_ANGLES diff --git a/Marlin/src/inc/Conditionals-4-adv.h b/Marlin/src/inc/Conditionals-4-adv.h index 103de78865..b697f22a20 100644 --- a/Marlin/src/inc/Conditionals-4-adv.h +++ b/Marlin/src/inc/Conditionals-4-adv.h @@ -53,6 +53,10 @@ #undef NUM_SERVOS #define NUM_SERVOS INCREMENT(Z_PROBE_SERVO_NR) #endif + #if HAS_MAG_MOUNTED_SERVO_PROBE && NUM_SERVOS <= MAG_MOUNTED_PROBE_SERVO_NR + #undef NUM_SERVOS + #define NUM_SERVOS INCREMENT(MAG_MOUNTED_PROBE_SERVO_NR) + #endif #if ENABLED(CHAMBER_VENT) && NUM_SERVOS <= CHAMBER_VENT_SERVO_NR #undef NUM_SERVOS #define NUM_SERVOS INCREMENT(CHAMBER_VENT_SERVO_NR) diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index e07fa78173..0029980ada 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -982,7 +982,7 @@ static_assert(NUM_SERVOS <= NUM_SERVO_PLUGS, "NUM_SERVOS (or some servo index) i /** * Servo deactivation depends on servo endstops, switching nozzle, or switching extruder */ -#if ENABLED(DEACTIVATE_SERVOS_AFTER_MOVE) && NONE(HAS_Z_SERVO_PROBE, POLARGRAPH) && !defined(SWITCHING_NOZZLE_SERVO_NR) && !defined(SWITCHING_EXTRUDER_SERVO_NR) && !defined(SWITCHING_TOOLHEAD_SERVO_NR) +#if ENABLED(DEACTIVATE_SERVOS_AFTER_MOVE) && NONE(HAS_Z_SERVO_PROBE, POLARGRAPH) && !defined(SWITCHING_NOZZLE_SERVO_NR) && !defined(SWITCHING_EXTRUDER_SERVO_NR) && !defined(SWITCHING_TOOLHEAD_SERVO_NR) && !defined(MAG_MOUNTED_PROBE_SERVO_NR) #error "Z_PROBE_SERVO_NR, switching nozzle, switching toolhead, switching extruder, or POLARGRAPH is required for DEACTIVATE_SERVOS_AFTER_MOVE." #endif diff --git a/Marlin/src/module/probe.cpp b/Marlin/src/module/probe.cpp index a66c11a782..e121bca812 100644 --- a/Marlin/src/module/probe.cpp +++ b/Marlin/src/module/probe.cpp @@ -82,7 +82,7 @@ #include "../feature/host_actions.h" // for PROMPT_USER_CONTINUE #endif -#if HAS_Z_SERVO_PROBE +#if HAS_Z_SERVO_PROBE || HAS_MAG_MOUNTED_SERVO_PROBE #include "servo.h" #endif @@ -272,6 +272,13 @@ xyz_pos_t Probe::offset; // Initialized by settings.load typedef struct { float fr_mm_min; xyz_pos_t where; } mag_probe_move_t; inline void run_deploy_moves() { + #ifdef MAG_MOUNTED_PRE_DEPLOY + constexpr mag_probe_move_t pre_deploy = MAG_MOUNTED_PRE_DEPLOY; + do_blocking_move_to(pre_deploy.where, MMM_TO_MMS(pre_deploy.fr_mm_min)); + #endif + #if HAS_MAG_MOUNTED_SERVO_PROBE + servo[MAG_MOUNTED_PROBE_SERVO_NR].move(servo_angles[MAG_MOUNTED_PROBE_SERVO_NR][0]); + #endif #ifdef MAG_MOUNTED_DEPLOY_1 constexpr mag_probe_move_t deploy_1 = MAG_MOUNTED_DEPLOY_1; do_blocking_move_to(deploy_1.where, MMM_TO_MMS(deploy_1.fr_mm_min)); @@ -292,9 +299,19 @@ xyz_pos_t Probe::offset; // Initialized by settings.load constexpr mag_probe_move_t deploy_5 = MAG_MOUNTED_DEPLOY_5; do_blocking_move_to(deploy_5.where, MMM_TO_MMS(deploy_5.fr_mm_min)); #endif + #if HAS_MAG_MOUNTED_SERVO_PROBE + servo[MAG_MOUNTED_PROBE_SERVO_NR].move(servo_angles[MAG_MOUNTED_PROBE_SERVO_NR][1]); + #endif } inline void run_stow_moves() { + #ifdef MAG_MOUNTED_PRE_STOW + constexpr mag_probe_move_t pre_stow = MAG_MOUNTED_PRE_STOW; + do_blocking_move_to(pre_stow.where, MMM_TO_MMS(pre_stow.fr_mm_min)); + #endif + #if HAS_MAG_MOUNTED_SERVO_PROBE + servo[MAG_MOUNTED_PROBE_SERVO_NR].move(servo_angles[MAG_MOUNTED_PROBE_SERVO_NR][0]); + #endif #ifdef MAG_MOUNTED_STOW_1 constexpr mag_probe_move_t stow_1 = MAG_MOUNTED_STOW_1; do_blocking_move_to(stow_1.where, MMM_TO_MMS(stow_1.fr_mm_min)); @@ -315,6 +332,9 @@ xyz_pos_t Probe::offset; // Initialized by settings.load constexpr mag_probe_move_t stow_5 = MAG_MOUNTED_STOW_5; do_blocking_move_to(stow_5.where, MMM_TO_MMS(stow_5.fr_mm_min)); #endif + #if HAS_MAG_MOUNTED_SERVO_PROBE + servo[MAG_MOUNTED_PROBE_SERVO_NR].move(servo_angles[MAG_MOUNTED_PROBE_SERVO_NR][1]); + #endif } #endif // MAG_MOUNTED_PROBE @@ -541,7 +561,7 @@ bool Probe::set_deployed(const bool deploy, const bool no_return/*=false*/) { #if ENABLED(PROBE_TRIGGERED_WHEN_STOWED_TEST) // Only deploy/stow if needed - if (PROBE_TRIGGERED() == deploy) { + if (PROBE_TRIGGERED() == deploy || !deploy) { if (!deploy) endstops.enable_z_probe(false); // Switch off triggered when stowed probes early // otherwise an Allen-Key probe can't be stowed. probe_specific_action(deploy); diff --git a/Marlin/src/module/servo.h b/Marlin/src/module/servo.h index 3b6c33a8f7..f35a8c3930 100644 --- a/Marlin/src/module/servo.h +++ b/Marlin/src/module/servo.h @@ -63,6 +63,9 @@ #endif constexpr uint16_t sazp[] = Z_SERVO_ANGLES; static_assert(COUNT(sazp) == 2, "Z_SERVO_ANGLES needs 2 angles."); + #elif defined(MAG_MOUNTED_PROBE_SERVO_ANGLES) + constexpr uint16_t sazp[] = MAG_MOUNTED_PROBE_SERVO_ANGLES; + static_assert(COUNT(sazp) == 2, "MAG_MOUNTED_PROBE_SERVO_ANGLES needs 2 angles."); #else constexpr uint16_t sazp[2] = { 0 }; #endif @@ -82,6 +85,9 @@ #ifndef Z_PROBE_SERVO_NR #define Z_PROBE_SERVO_NR -1 #endif + #ifndef MAG_MOUNTED_PROBE_SERVO_NR + #define MAG_MOUNTED_PROBE_SERVO_NR -1 + #endif #define SASN(J,I) TERN(SWITCHING_NOZZLE_TWO_SERVOS, sasn[J][I], sasn[I]) @@ -91,6 +97,7 @@ : N == SWITCHING_NOZZLE_SERVO_NR ? SASN(0,I) \ : N == SWITCHING_NOZZLE_E1_SERVO_NR ? SASN(1,I) \ : N == Z_PROBE_SERVO_NR ? sazp[I] \ + : N == MAG_MOUNTED_PROBE_SERVO_NR ? sazp[I] \ : 0 ) #if ENABLED(EDITABLE_SERVO_ANGLES) diff --git a/buildroot/tests/LPC1769 b/buildroot/tests/LPC1769 index ad14e3353d..a97790e988 100755 --- a/buildroot/tests/LPC1769 +++ b/buildroot/tests/LPC1769 @@ -15,7 +15,7 @@ exec_test $1 $2 "Azteeg X5GT Example Configuration" "$3" restore_configs opt_set MOTHERBOARD BOARD_SMOOTHIEBOARD \ EXTRUDERS 2 TEMP_SENSOR_0 -5 TEMP_SENSOR_1 -4 TEMP_SENSOR_BED 5 TEMP_0_CS_PIN P1_29 \ - GRID_MAX_POINTS_X 16 \ + MAG_MOUNTED_PROBE_SERVO_NR 0 GRID_MAX_POINTS_X 16 \ NOZZLE_CLEAN_START_POINT "{ { 10, 10, 3 }, { 10, 10, 3 } }" \ NOZZLE_CLEAN_END_POINT "{ { 10, 20, 3 }, { 10, 20, 3 } }" opt_enable TFTGLCD_PANEL_SPI SDSUPPORT ADAPTIVE_FAN_SLOWING REPORT_ADAPTIVE_FAN_SLOWING TEMP_TUNING_MAINTAIN_FAN \ From 719bb9c03bb0bc53d324f14bb6eef982e8cea4b1 Mon Sep 17 00:00:00 2001 From: ellensp <530024+ellensp@users.noreply.github.com> Date: Wed, 19 Mar 2025 15:14:58 +1300 Subject: [PATCH 128/787] =?UTF-8?q?=F0=9F=94=A7=20LCD=5FPINS=5FENABLE=20?= =?UTF-8?q?=3D>=20LCD=5FPINS=5FEN=20(#27700)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/pins/rp2040/pins_RP2040.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Marlin/src/pins/rp2040/pins_RP2040.h b/Marlin/src/pins/rp2040/pins_RP2040.h index 1b88ce347b..48e37e4e1f 100644 --- a/Marlin/src/pins/rp2040/pins_RP2040.h +++ b/Marlin/src/pins/rp2040/pins_RP2040.h @@ -320,13 +320,13 @@ #if ENABLED(REPRAPWORLD_GRAPHICAL_LCD) #define LCD_PINS_RS 49 // CS chip select /SS chip slave select - #define LCD_PINS_ENABLE 51 // SID (MOSI) + #define LCD_PINS_EN 51 // SID (MOSI) #define LCD_PINS_D4 52 // SCK (CLK) clock #elif ALL(IS_NEWPANEL, PANEL_ONE) #define LCD_PINS_RS 40 - #define LCD_PINS_ENABLE 42 + #define LCD_PINS_EN 42 #define LCD_PINS_D4 65 #define LCD_PINS_D5 66 #define LCD_PINS_D6 44 @@ -337,7 +337,7 @@ #if ENABLED(CR10_STOCKDISPLAY) #define LCD_PINS_RS 27 - #define LCD_PINS_ENABLE 29 + #define LCD_PINS_EN 29 #define LCD_PINS_D4 25 #if !IS_NEWPANEL @@ -347,7 +347,7 @@ #elif ENABLED(ZONESTAR_LCD) #define LCD_PINS_RS 64 - #define LCD_PINS_ENABLE 44 + #define LCD_PINS_EN 44 #define LCD_PINS_D4 63 #define LCD_PINS_D5 40 #define LCD_PINS_D6 42 @@ -365,7 +365,7 @@ #define DOGLCD_A0 LCD_PINS_DC #else #define LCD_PINS_RS 16 - #define LCD_PINS_ENABLE 17 + #define LCD_PINS_EN 17 #define LCD_PINS_D4 23 #define LCD_PINS_D5 25 #define LCD_PINS_D6 27 From 4f3279fa315b4664349eeae96af62b505e8227ea Mon Sep 17 00:00:00 2001 From: Sophist <3001893+Sophist-UK@users.noreply.github.com> Date: Wed, 19 Mar 2025 03:21:30 +0000 Subject: [PATCH 129/787] =?UTF-8?q?=F0=9F=9A=B8=20Move=20About=20/=20Games?= =?UTF-8?q?=20to=20menu=20bottom=20(#26820)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/lcd/menu/menu_main.cpp | 56 ++++++++++++++----------------- 1 file changed, 25 insertions(+), 31 deletions(-) diff --git a/Marlin/src/lcd/menu/menu_main.cpp b/Marlin/src/lcd/menu/menu_main.cpp index 6142e0e153..60f5c271c6 100644 --- a/Marlin/src/lcd/menu/menu_main.cpp +++ b/Marlin/src/lcd/menu/menu_main.cpp @@ -234,16 +234,6 @@ void menu_configuration(); #endif // CUSTOM_MENU_MAIN -#if ENABLED(ADVANCED_PAUSE_FEATURE) - // This menu item is last with an encoder. Otherwise, somewhere in the middle. - #if E_STEPPERS == 1 && DISABLED(FILAMENT_LOAD_UNLOAD_GCODES) - #define FILAMENT_CHANGE_ITEM() YESNO_ITEM(MSG_FILAMENTCHANGE, menu_change_filament, nullptr, \ - GET_TEXT_F(MSG_FILAMENTCHANGE), (const char *)nullptr, F("?")) - #else - #define FILAMENT_CHANGE_ITEM() SUBMENU(MSG_FILAMENTCHANGE, menu_change_filament) - #endif -#endif - void menu_main() { const bool busy = printingIsActive(); #if HAS_MEDIA @@ -348,7 +338,11 @@ void menu_main() { #endif #if ENABLED(ADVANCED_PAUSE_FEATURE) - FILAMENT_CHANGE_ITEM(); + #if E_STEPPERS == 1 && DISABLED(FILAMENT_LOAD_UNLOAD_GCODES) + YESNO_ITEM(MSG_FILAMENTCHANGE, menu_change_filament, nullptr, GET_TEXT_F(MSG_FILAMENTCHANGE), (const char *)nullptr, F("?")); + #else + SUBMENU(MSG_FILAMENTCHANGE, menu_change_filament); + #endif #endif #if HAS_TEMPERATURE @@ -381,10 +375,6 @@ void menu_main() { } #endif - #if ENABLED(LCD_INFO_MENU) - SUBMENU(MSG_INFO_MENU, menu_info); - #endif - #if ENABLED(LED_CONTROL_MENU) SUBMENU(MSG_LIGHTS, menu_led); #elif ALL(CASE_LIGHT_MENU, CASELIGHT_USES_BRIGHTNESS) @@ -412,7 +402,6 @@ void menu_main() { #endif #if HAS_MEDIA && DISABLED(MEDIA_MENU_AT_TOP) - // BEGIN MEDIA MENU if (card_detected) { if (!card_open) { #if ENABLED(MENU_ADDAUTOSTART) @@ -449,7 +438,6 @@ void menu_main() { #endif #endif } - // END MEDIA MENU #endif #if HAS_SERVICE_INTERVALS @@ -482,7 +470,26 @@ void menu_main() { #endif #endif - #if HAS_GAMES && DISABLED(LCD_INFO_MENU) + #if HAS_MULTI_LANGUAGE + SUBMENU(LANGUAGE, menu_language); + #endif + + #if ENABLED(HOST_SHUTDOWN_MENU_ITEM) && defined(SHUTDOWN_ACTION) + SUBMENU(MSG_HOST_SHUTDOWN, []{ + MenuItem_confirm::select_screen( + GET_TEXT_F(MSG_BUTTON_PROCEED), GET_TEXT_F(MSG_BUTTON_CANCEL), + []{ ui.return_to_status(); hostui.shutdown(); }, nullptr, + GET_TEXT_F(MSG_HOST_SHUTDOWN), (const char *)nullptr, F("?") + ); + }); + #endif + + #if ENABLED(LCD_INFO_MENU) + + SUBMENU(MSG_INFO_MENU, menu_info); + + #elif HAS_GAMES + #if ENABLED(GAMES_EASTER_EGG) SKIP_ITEM(); SKIP_ITEM(); @@ -504,20 +511,7 @@ void menu_main() { #endif ); } - #endif - #if HAS_MULTI_LANGUAGE - SUBMENU(LANGUAGE, menu_language); - #endif - - #if ENABLED(HOST_SHUTDOWN_MENU_ITEM) && defined(SHUTDOWN_ACTION) - SUBMENU(MSG_HOST_SHUTDOWN, []{ - MenuItem_confirm::select_screen( - GET_TEXT_F(MSG_BUTTON_PROCEED), GET_TEXT_F(MSG_BUTTON_CANCEL), - []{ ui.return_to_status(); hostui.shutdown(); }, nullptr, - GET_TEXT_F(MSG_HOST_SHUTDOWN), (const char *)nullptr, F("?") - ); - }); #endif END_MENU(); From fc49efcaef97ab657b28ce1077c7bc07d538bacc Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Wed, 19 Mar 2025 14:34:24 -0500 Subject: [PATCH 130/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Lam?= =?UTF-8?q?bda=20for=20MarlinUI=20media=20items?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/lcd/menu/menu_main.cpp | 102 +++++++++++------------------- 1 file changed, 36 insertions(+), 66 deletions(-) diff --git a/Marlin/src/lcd/menu/menu_main.cpp b/Marlin/src/lcd/menu/menu_main.cpp index 60f5c271c6..9509c72cc5 100644 --- a/Marlin/src/lcd/menu/menu_main.cpp +++ b/Marlin/src/lcd/menu/menu_main.cpp @@ -248,34 +248,8 @@ void menu_main() { #define MEDIA_MENU_AT_TOP #endif - if (busy) { - #if MACHINE_CAN_PAUSE - ACTION_ITEM(MSG_PAUSE_PRINT, ui.pause_print); - #endif - #if MACHINE_CAN_STOP - SUBMENU(MSG_STOP_PRINT, []{ - MenuItem_confirm::select_screen( - GET_TEXT_F(MSG_BUTTON_STOP), GET_TEXT_F(MSG_BACK), - ui.abort_print, nullptr, - GET_TEXT_F(MSG_STOP_PRINT), (const char *)nullptr, F("?") - ); - }); - #endif - - #if ENABLED(GCODE_REPEAT_MARKERS) - if (repeat.is_active()) - ACTION_ITEM(MSG_END_LOOPS, repeat.cancel); - #endif - - SUBMENU(MSG_TUNE, menu_tune); - - #if ENABLED(CANCEL_OBJECTS) && DISABLED(SLIM_LCD_MENUS) - SUBMENU(MSG_CANCEL_OBJECT, []{ editable.int8 = -1; ui.goto_screen(menu_cancelobject); }); - #endif - } - else { - #if ALL(HAS_MEDIA, MEDIA_MENU_AT_TOP) - // BEGIN MEDIA MENU + auto media_menus = [&]{ + #if HAS_MEDIA if (card_detected) { if (!card_open) { #if ENABLED(MENU_ADDAUTOSTART) @@ -312,8 +286,38 @@ void menu_main() { #endif #endif } - // END MEDIA MENU #endif + }; + + if (busy) { + #if MACHINE_CAN_PAUSE + ACTION_ITEM(MSG_PAUSE_PRINT, ui.pause_print); + #endif + #if MACHINE_CAN_STOP + SUBMENU(MSG_STOP_PRINT, []{ + MenuItem_confirm::select_screen( + GET_TEXT_F(MSG_BUTTON_STOP), GET_TEXT_F(MSG_BACK), + ui.abort_print, nullptr, + GET_TEXT_F(MSG_STOP_PRINT), (const char *)nullptr, F("?") + ); + }); + #endif + + #if ENABLED(GCODE_REPEAT_MARKERS) + if (repeat.is_active()) + ACTION_ITEM(MSG_END_LOOPS, repeat.cancel); + #endif + + SUBMENU(MSG_TUNE, menu_tune); + + #if ENABLED(CANCEL_OBJECTS) && DISABLED(SLIM_LCD_MENUS) + SUBMENU(MSG_CANCEL_OBJECT, []{ editable.int8 = -1; ui.goto_screen(menu_cancelobject); }); + #endif + } + else { + + // SD Card / Flash Drive + TERN_(MEDIA_MENU_AT_TOP, media_menus()); if (TERN0(MACHINE_CAN_PAUSE, printingIsPaused())) ACTION_ITEM(MSG_RESUME_PRINT, ui.resume_print); @@ -401,43 +405,9 @@ void menu_main() { GCODES_ITEM(MSG_SWITCH_PS_ON, F("M80")); #endif - #if HAS_MEDIA && DISABLED(MEDIA_MENU_AT_TOP) - if (card_detected) { - if (!card_open) { - #if ENABLED(MENU_ADDAUTOSTART) - ACTION_ITEM(MSG_RUN_AUTO_FILES, card.autofile_begin); // Run Auto Files - #endif - - #if HAS_SD_DETECT - GCODES_ITEM(MSG_CHANGE_MEDIA, F("M21" TERN_(HAS_MULTI_VOLUME, "S"))); // M21 Change Media - #if HAS_MULTI_VOLUME - GCODES_ITEM(MSG_ATTACH_USB_MEDIA, F("M21U")); // M21 Attach USB Media - #endif - #else // - or - - ACTION_ITEM(MSG_RELEASE_MEDIA, []{ // M22 Release Media - queue.inject(F("M22")); - #if ENABLED(TFT_COLOR_UI) - // Menu display issue on item removal with multi language selection menu - if (encoderTopLine > 0) encoderTopLine--; - ui.refresh(); - #endif - }); - #endif - SUBMENU(MSG_MEDIA_MENU, MEDIA_MENU_GATEWAY); // Media Menu (or Password First) - } - } - else { - #if HAS_SD_DETECT - ACTION_ITEM(MSG_NO_MEDIA, nullptr); // "No Media" - #else - #if HAS_MULTI_VOLUME - GCODES_ITEM(MSG_ATTACH_SD_MEDIA, F("M21S")); // M21S Attach SD Card - GCODES_ITEM(MSG_ATTACH_USB_MEDIA, F("M21U")); // M21U Attach USB Media - #else - GCODES_ITEM(MSG_ATTACH_MEDIA, F("M21")); // M21 Attach Media - #endif - #endif - } + // SD Card / Flash Drive + #if DISABLED(MEDIA_MENU_AT_TOP) + if (!busy) media_menus(); #endif #if HAS_SERVICE_INTERVALS From a7684ecd6710ede96b8f18f9debe2b69fc7e9f12 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Wed, 19 Mar 2025 15:13:45 -0500 Subject: [PATCH 131/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Reu?= =?UTF-8?q?se=20MarlinUI::apply=5Fpreheat?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/lcd/marlinui.cpp | 14 +++++- Marlin/src/lcd/marlinui.h | 3 +- Marlin/src/lcd/menu/menu_temperature.cpp | 54 +++++------------------- Marlin/src/module/temperature.h | 14 ------ 4 files changed, 25 insertions(+), 60 deletions(-) diff --git a/Marlin/src/lcd/marlinui.cpp b/Marlin/src/lcd/marlinui.cpp index bd974d8d0a..679c43b402 100644 --- a/Marlin/src/lcd/marlinui.cpp +++ b/Marlin/src/lcd/marlinui.cpp @@ -153,7 +153,17 @@ constexpr uint8_t epps = ENCODER_PULSES_PER_STEP; TERN_(HAS_HOTEND, if (TEST(pmask, PT_HOTEND)) thermalManager.setTargetHotend(pre.hotend_temp, e)); TERN_(HAS_HEATED_BED, if (TEST(pmask, PT_BED)) thermalManager.setTargetBed(pre.bed_temp)); TERN_(HAS_HEATED_CHAMBER, if (TEST(pmask, PT_CHAMBER)) thermalManager.setTargetChamber(pre.chamber_temp)); - TERN_(HAS_FAN, if (TEST(pmask, PT_FAN)) thermalManager.set_fan_speed(0, pre.fan_speed)); + TERN_(HAS_FAN, if (TEST(pmask, PT_FAN)) thermalManager.set_fan_speed(e, pre.fan_speed)); + #if HAS_FAN + if (TEST(pmask, PT_FAN)) { + const uint8_t fan_index = e < (FAN_COUNT) ? e : 0; + if (true + #if REDUNDANT_PART_COOLING_FAN + && fan_index != REDUNDANT_PART_COOLING_FAN + #endif + ) thermalManager.set_fan_speed(fan_index, pre.fan_speed); + } + #endif } #endif @@ -1935,7 +1945,7 @@ uint8_t expand_u8str_P(char * const outstr, PGM_P const ptpl, const int8_t ind, settings.reset(); completion_feedback(); #if ENABLED(TOUCH_SCREEN_CALIBRATION) - if (touch_calibration.need_calibration()) ui.goto_screen(touch_screen_calibration); + if (touch_calibration.need_calibration()) goto_screen(touch_screen_calibration); #endif } diff --git a/Marlin/src/lcd/marlinui.h b/Marlin/src/lcd/marlinui.h index 26b559e6bc..9f2ac5a69a 100644 --- a/Marlin/src/lcd/marlinui.h +++ b/Marlin/src/lcd/marlinui.h @@ -652,7 +652,8 @@ public: static void preheat_hotend(const uint8_t m, const uint8_t e=active_extruder) { TERN_(HAS_HOTEND, apply_preheat(m, _BV(PT_HOTEND))); } static void preheat_hotend_and_fan(const uint8_t m, const uint8_t e=active_extruder) { preheat_hotend(m, e); preheat_set_fan(m); } static void preheat_bed(const uint8_t m) { TERN_(HAS_HEATED_BED, apply_preheat(m, _BV(PT_BED))); } - static void preheat_all(const uint8_t m) { apply_preheat(m, PT_ALL); } + static void preheat_chamber(const uint8_t m) { TERN_(HAS_HEATED_CHAMBER, apply_preheat(m, _BV(PT_CHAMBER))); } + static void preheat_all(const uint8_t m, const uint8_t e=active_extruder) { apply_preheat(m, PT_ALL, e); } #endif static void reset_status_timeout(const millis_t ms) { diff --git a/Marlin/src/lcd/menu/menu_temperature.cpp b/Marlin/src/lcd/menu/menu_temperature.cpp index 0a376494e5..b43f906cc7 100644 --- a/Marlin/src/lcd/menu/menu_temperature.cpp +++ b/Marlin/src/lcd/menu/menu_temperature.cpp @@ -45,66 +45,34 @@ #if HAS_PREHEAT - /** - * @fn Temperature::lcd_preheat - * @brief Apply the "preheat" parameters for a material preset to the - * hotend (or laser), bed, chamber, or all of the above. - * @param m Material index - * @param targets Bit mask of targets to "preheat" (or turn off) - * @param e Extruder index (if needed) - */ - void Temperature::lcd_preheat(const uint8_t m, const uint8_t targets, const uint8_t e/*=0*/) { - UNUSED(e); - #if HAS_HOTEND - if (targets & PreheatTarget::HOTEND) setTargetHotend(ui.material_preset[m].hotend_temp, e); - #endif - #if HAS_HEATED_BED - if (targets & PreheatTarget::BED) setTargetBed(ui.material_preset[m].bed_temp); - #endif - #if HAS_HEATED_CHAMBER - if (targets & PreheatTarget::CHAMBER) setTargetChamber(ui.material_preset[m].chamber_temp); - #endif - #if HAS_FAN - if (targets & PreheatTarget::HOTEND) { - const uint8_t fan_index = active_extruder < (FAN_COUNT) ? active_extruder : 0; - if (true - #if REDUNDANT_PART_COOLING_FAN - && fan_index != REDUNDANT_PART_COOLING_FAN - #endif - ) set_fan_speed(fan_index, ui.material_preset[m].fan_speed); - } - #endif - ui.return_to_status(); - } - #if HAS_TEMP_HOTEND - inline void _preheat_end(const uint8_t e, const uint8_t m) { thermalManager.lcd_preheat(m, PreheatTarget::HOTEND, e); } - void do_preheat_end_m() { _preheat_end(0, editable.int8); } + inline void _preheat_end(const uint8_t m, const uint8_t e) { ui.preheat_hotend(m, e); ui.return_to_status(); } + void do_preheat_end_m() { _preheat_end(editable.int8, 0); } #endif #if HAS_HEATED_BED - inline void _preheat_bed(const uint8_t m) { thermalManager.lcd_preheat(m, PreheatTarget::BED); } + inline void _preheat_bed(const uint8_t m) { ui.preheat_bed(m); ui.return_to_status(); } #endif #if HAS_HEATED_CHAMBER - inline void _preheat_chamber(const uint8_t m) { thermalManager.lcd_preheat(m, PreheatTarget::CHAMBER); } + inline void _preheat_chamber(const uint8_t m) { ui.preheat_chamber(m); ui.return_to_status(); } #endif #if HAS_COOLER - inline void _precool_laser(const uint8_t e, const uint8_t m) { thermalManager.lcd_preheat(m, PreheatTarget::HOTEND, e); } - void do_precool_laser_m() { _precool_laser(thermalManager.temp_cooler.target, editable.int8); } + inline void _precool_laser(const uint8_t m, const uint8_t e) { ui.preheat_hotend(m, e); ui.return_to_status(); } + void do_precool_laser_m() { _precool_laser(editable.int8, thermalManager.temp_cooler.target); } #endif #if HAS_TEMP_HOTEND && (HAS_HEATED_BED || HAS_HEATED_CHAMBER) - inline void _preheat_all(const uint8_t e, const uint8_t m) { thermalManager.lcd_preheat(m, PreheatTarget::ALL, e); } + inline void _preheat_all(const uint8_t m, const uint8_t e) { ui.preheat_all(m, e); ui.return_to_status(); } // Indexed "Preheat ABC" and "Heat Bed" items #define PREHEAT_ITEMS(M,E) do{ \ - ACTION_ITEM_N_f(E, ui.get_preheat_label(M), MSG_PREHEAT_M_H, []{ _preheat_all(MenuItemBase::itemIndex, M); }); \ - ACTION_ITEM_N_f(E, ui.get_preheat_label(M), MSG_PREHEAT_M_END_E, []{ _preheat_end(MenuItemBase::itemIndex, M); }); \ + ACTION_ITEM_N_f(E, ui.get_preheat_label(M), MSG_PREHEAT_M_H, []{ _preheat_all(M, MenuItemBase::itemIndex); }); \ + ACTION_ITEM_N_f(E, ui.get_preheat_label(M), MSG_PREHEAT_M_END_E, []{ _preheat_end(M, MenuItemBase::itemIndex); }); \ }while(0) #elif HAS_MULTI_HOTEND // No heated bed, so just indexed "Preheat ABC" items - #define PREHEAT_ITEMS(M,E) ACTION_ITEM_N_f(E, ui.get_preheat_label(M), MSG_PREHEAT_M_H, []{ _preheat_end(MenuItemBase::itemIndex, M); }) + #define PREHEAT_ITEMS(M,E) ACTION_ITEM_N_f(E, ui.get_preheat_label(M), MSG_PREHEAT_M_H, []{ _preheat_end(M, MenuItemBase::itemIndex); }) #endif @@ -121,7 +89,7 @@ #if HOTENDS == 1 #if HAS_HEATED_BED || HAS_HEATED_CHAMBER - ACTION_ITEM_f(ui.get_preheat_label(m), MSG_PREHEAT_M, []{ _preheat_all(0, editable.int8); }); + ACTION_ITEM_f(ui.get_preheat_label(m), MSG_PREHEAT_M, []{ _preheat_all(editable.int8, 0); }); ACTION_ITEM_f(ui.get_preheat_label(m), MSG_PREHEAT_M_END, do_preheat_end_m); #else ACTION_ITEM_f(ui.get_preheat_label(m), MSG_PREHEAT_M, do_preheat_end_m); diff --git a/Marlin/src/module/temperature.h b/Marlin/src/module/temperature.h index 5f7ea8daf4..934b1b1246 100644 --- a/Marlin/src/module/temperature.h +++ b/Marlin/src/module/temperature.h @@ -599,15 +599,6 @@ typedef struct { raw_adc_t raw_min, raw_max; celsius_t mintemp, maxtemp; } temp_ #define HAS_FAN_LOGIC 1 #endif -#if HAS_MARLINUI_MENU && HAS_TEMPERATURE && HAS_PREHEAT - enum PreheatTarget : uint8_t { - HOTEND = (1 << 0), - BED = (1 << 1), - CHAMBER = (1 << 2), - ALL = 0xFF - }; -#endif - class Temperature { public: @@ -1343,11 +1334,6 @@ class Temperature { static void set_heating_message(const uint8_t, const bool=false) {} #endif - #if HAS_MARLINUI_MENU && HAS_TEMPERATURE && HAS_PREHEAT - // Apply the "preheat" parameters for a material preset to the hotend (or laser), bed, chamber, or all of the above - static void lcd_preheat(const uint8_t m, const uint8_t targets, const uint8_t e=0); - #endif - private: // Reading raw temperatures and converting to Celsius when ready From 26aac7aaab2d2cd4a09f2f17b5b6a852e7cdeb99 Mon Sep 17 00:00:00 2001 From: ellensp <530024+ellensp@users.noreply.github.com> Date: Thu, 20 Mar 2025 09:45:30 +1300 Subject: [PATCH 132/787] =?UTF-8?q?=F0=9F=90=9B=20Fix=20RAMPS=20AUX1=20RX/?= =?UTF-8?q?TX=20pins=20(#27745)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/pins/ramps/pins_RAMPS.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Marlin/src/pins/ramps/pins_RAMPS.h b/Marlin/src/pins/ramps/pins_RAMPS.h index e033cfd060..8237c7e227 100644 --- a/Marlin/src/pins/ramps/pins_RAMPS.h +++ b/Marlin/src/pins/ramps/pins_RAMPS.h @@ -486,15 +486,15 @@ #endif // -// AUX1 5V GND D2 D1 +// AUX1 5V GND D1 D0 // 2 4 6 8 // 1 3 5 7 // 5V GND A3 A4 // #define AUX1_05 57 // (A3) -#define AUX1_06 2 +#define AUX1_06 1 // TX0 #define AUX1_07 58 // (A4) -#define AUX1_08 1 +#define AUX1_08 0 // RX0 // // AUX2 GND A9 D40 D42 A11 From 58749a9a0ed93f10295695d7acbe607a6e871d30 Mon Sep 17 00:00:00 2001 From: ellensp <530024+ellensp@users.noreply.github.com> Date: Thu, 20 Mar 2025 10:02:01 +1300 Subject: [PATCH 133/787] =?UTF-8?q?=F0=9F=A9=B9=20BTT=20Manta=20M8P=20V2.0?= =?UTF-8?q?=20fixes=20(#27748)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The notorious curse of incorrect BTT pins rears its head once again! --- Marlin/src/pins/stm32h7/pins_BTT_MANTA_M8P_V2_0.h | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Marlin/src/pins/stm32h7/pins_BTT_MANTA_M8P_V2_0.h b/Marlin/src/pins/stm32h7/pins_BTT_MANTA_M8P_V2_0.h index d274c99e19..941d6ab068 100644 --- a/Marlin/src/pins/stm32h7/pins_BTT_MANTA_M8P_V2_0.h +++ b/Marlin/src/pins/stm32h7/pins_BTT_MANTA_M8P_V2_0.h @@ -307,7 +307,6 @@ //#define Y_HARDWARE_SERIAL Serial1 //#define Y2_HARDWARE_SERIAL Serial1 //#define Z_HARDWARE_SERIAL Serial1 - //#define Z2_HARDWARE_SERIAL Serial1 //#define E0_HARDWARE_SERIAL Serial1 //#define E1_HARDWARE_SERIAL Serial1 //#define E2_HARDWARE_SERIAL Serial1 @@ -317,11 +316,11 @@ #define X_SERIAL_TX_PIN PC13 #define Y_SERIAL_TX_PIN PE3 #define Z_SERIAL_TX_PIN PB9 - #define Z2_SERIAL_TX_PIN PB5 - #define E0_SERIAL_TX_PIN PG14 - #define E1_SERIAL_TX_PIN PG10 - #define E2_SERIAL_TX_PIN PD5 - #define E3_SERIAL_TX_PIN PC6 + #define E0_SERIAL_TX_PIN PB5 + #define E1_SERIAL_TX_PIN PG14 + #define E2_SERIAL_TX_PIN PG10 + #define E3_SERIAL_TX_PIN PD5 + #define E4_SERIAL_TX_PIN PC6 // Reduce baud rate to improve software serial reliability #ifndef TMC_BAUD_RATE From c7e64371c989925c74a5c2a13683f71bbbd6bdc7 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Wed, 19 Mar 2025 17:35:23 -0500 Subject: [PATCH 134/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Pro?= =?UTF-8?q?UI:=20pre-calculate=20menu=20sizes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/lcd/e3v2/proui/dwin.cpp | 176 ++++++++++++++++++++++++----- 1 file changed, 149 insertions(+), 27 deletions(-) diff --git a/Marlin/src/lcd/e3v2/proui/dwin.cpp b/Marlin/src/lcd/e3v2/proui/dwin.cpp index cbf806a7c9..03f25b5010 100644 --- a/Marlin/src/lcd/e3v2/proui/dwin.cpp +++ b/Marlin/src/lcd/e3v2/proui/dwin.cpp @@ -3101,8 +3101,18 @@ frame_rect_t selrect(frame_rect_t) { } void drawPrepareMenu() { + constexpr uint8_t items = (3 + + COUNT_ENABLED(LCD_BED_TRAMMING) + + 2 + + TERN(MESH_BED_LEVELING, 1, ENABLED(HAS_BED_PROBE)) + + TERN(HAS_ZOFFSET_ITEM, ENABLED(HAS_BED_PROBE), ENABLED(BABYSTEPPING)) + + PREHEAT_COUNT + + 1 + + 2 * ALL(PROUI_TUNING_GRAPH, PROUI_ITEM_PLOT) + + 1 + ); checkkey = ID_Menu; - if (SET_MENU_R(prepareMenu, selrect({133, 1, 28, 13}), MSG_PREPARE, 12 + PREHEAT_COUNT)) { + if (SET_MENU_R(prepareMenu, selrect({133, 1, 28, 13}), MSG_PREPARE, items)) { BACK_ITEM(gotoMainMenu); MENU_ITEM(ICON_FilMan, MSG_FILAMENT_MAN, onDrawSubMenu, drawFilamentManMenu); MENU_ITEM(ICON_Axis, MSG_MOVE_AXIS, onDrawMoveSubMenu, drawMoveMenu); @@ -3145,8 +3155,14 @@ void drawPrepareMenu() { #if ENABLED(LCD_BED_TRAMMING) void drawTrammingMenu() { + constexpr uint8_t items = (1 + + 2 * ALL(HAS_BED_PROBE, HAS_MESH) + + (DISABLED(HAS_BED_PROBE) && ENABLED(HAS_ZOFFSET_ITEM)) + + 4 + + ENABLED(BED_TRAMMING_INCLUDE_CENTER) + ); checkkey = ID_Menu; - if (SET_MENU(trammingMenu, MSG_BED_TRAMMING, 8)) { + if (SET_MENU(trammingMenu, MSG_BED_TRAMMING, items)) { BACK_ITEM(drawPrepareMenu); #if HAS_BED_PROBE && HAS_MESH MENU_ITEM(ICON_Tram, MSG_TRAMMING_WIZARD, onDrawMenuItem, trammingwizard); @@ -3168,8 +3184,13 @@ void drawPrepareMenu() { #endif // LCD_BED_TRAMMING void drawControlMenu() { + constexpr uint8_t items = (3 + + COUNT_ENABLED(CASE_LIGHT_MENU, LED_CONTROL_MENU) + + TERN0(EEPROM_SETTINGS, 3) + + 2 + ); checkkey = ID_Menu; - if (SET_MENU_R(controlMenu, selrect({103, 1, 28, 14}), MSG_CONTROL, 11)) { + if (SET_MENU_R(controlMenu, selrect({103, 1, 28, 14}), MSG_CONTROL, items)) { BACK_ITEM(gotoMainMenu); MENU_ITEM(ICON_Temperature, MSG_TEMPERATURE, onDrawTempSubMenu, drawTemperatureMenu); MENU_ITEM(ICON_Motion, MSG_MOTION, onDrawMotionSubMenu, drawMotionMenu); @@ -3198,8 +3219,20 @@ void drawControlMenu() { } void drawAdvancedSettingsMenu() { + constexpr uint8_t items = (1 + + COUNT_ENABLED(EEPROM_SETTINGS, HAS_MESH, HAS_BED_PROBE, HAS_HOME_OFFSET, HAS_TRINAMIC_CONFIG, HAS_ESDIAG, \ + HAS_LOCKSCREEN, EDITABLE_DISPLAY_TIMEOUT, SOUND_MENU_ITEM, POWER_LOSS_RECOVERY, HAS_GCODE_PREVIEW, \ + PROUI_MEDIASORT, BAUD_RATE_GCODE, HAS_CUSTOM_COLORS) + + 1 + + (ENABLED(PIDTEMP) && ANY(PID_AUTOTUNE_MENU, PID_EDIT_MENU)) + + ANY(MPC_EDIT_MENU, MPC_AUTOTUNE_MENU) + + (ENABLED(PIDTEMPBED) && ANY(PID_AUTOTUNE_MENU, PID_EDIT_MENU)) + + TERN0(PRINTCOUNTER, 2) + + 1 + + TERN0(HAS_LCD_BRIGHTNESS, 2) + ); checkkey = ID_Menu; - if (SET_MENU(advancedSettingsMenu, MSG_ADVANCED_SETTINGS, 24)) { + if (SET_MENU(advancedSettingsMenu, MSG_ADVANCED_SETTINGS, items)) { BACK_ITEM(gotoMainMenu); #if ENABLED(EEPROM_SETTINGS) MENU_ITEM(ICON_WriteEEPROM, MSG_STORE_EEPROM, onDrawMenuItem, writeEEPROM); @@ -3268,8 +3301,9 @@ void drawAdvancedSettingsMenu() { } void drawMoveMenu() { + constexpr uint8_t items = 2 + COUNT_ENABLED(HAS_X_AXIS, HAS_Y_AXIS, HAS_Z_AXIS, HAS_HOTEND); checkkey = ID_Menu; - if (SET_MENU_R(moveMenu, selrect({192, 1, 42, 14}), MSG_MOVE_AXIS, 6)) { + if (SET_MENU_R(moveMenu, selrect({192, 1, 42, 14}), MSG_MOVE_AXIS, items)) { BACK_ITEM(drawPrepareMenu); EDIT_ITEM(ICON_Axis, MSG_LIVE_MOVE, onDrawChkbMenu, setLiveMove, &enableLiveMove); #if HAS_X_AXIS @@ -3293,8 +3327,9 @@ void drawMoveMenu() { #if HAS_HOME_OFFSET void drawHomeOffsetMenu() { + constexpr uint8_t items = 1 + COUNT_ENABLED(HAS_X_AXIS, HAS_Y_AXIS, HAS_Z_AXIS); checkkey = ID_Menu; - if (SET_MENU(homeOffsetMenu, MSG_SET_HOME_OFFSETS, 4)) { + if (SET_MENU(homeOffsetMenu, MSG_SET_HOME_OFFSETS, items)) { BACK_ITEM(drawAdvancedSettingsMenu); #if HAS_X_AXIS EDIT_ITEM(ICON_HomeOffsetX, MSG_HOME_OFFSET_X, onDrawPFloatMenu, setHomeOffsetX, &home_offset.x); @@ -3314,8 +3349,12 @@ void drawMoveMenu() { #if HAS_BED_PROBE void drawProbeSetMenu() { + constexpr uint8_t items = (1 + + COUNT_ENABLED(HAS_X_AXIS, HAS_Y_AXIS, HAS_Z_AXIS, Z_MIN_PROBE_REPEATABILITY_TEST) + + TERN0(BLTOUCH, 3 + ENABLED(HAS_BLTOUCH_HS_MODE)) + ); checkkey = ID_Menu; - if (SET_MENU(probeSettingsMenu, MSG_ZPROBE_SETTINGS, 9)) { + if (SET_MENU(probeSettingsMenu, MSG_ZPROBE_SETTINGS, items)) { BACK_ITEM(drawAdvancedSettingsMenu); #if HAS_X_AXIS EDIT_ITEM(ICON_ProbeOffsetX, MSG_ZPROBE_XOFFSET, onDrawPFloatMenu, setProbeOffsetX, &probe.offset.x); @@ -3344,8 +3383,12 @@ void drawMoveMenu() { #endif // HAS_BED_PROBE void drawFilSetMenu() { + constexpr uint8_t items = (1 + + COUNT_ENABLED(HAS_FILAMENT_SENSOR, HAS_FILAMENT_RUNOUT_DISTANCE, PREVENT_COLD_EXTRUSION, FWRETRACT) + + TERN0(CONFIGURE_FILAMENT_CHANGE, 2) + ); checkkey = ID_Menu; - if (SET_MENU(filSetMenu, MSG_FILAMENT_SET, 9)) { + if (SET_MENU(filSetMenu, MSG_FILAMENT_SET, items)) { BACK_ITEM(drawAdvancedSettingsMenu); #if HAS_FILAMENT_SENSOR EDIT_ITEM(ICON_Runout, MSG_RUNOUT_SENSOR, onDrawChkbMenu, setRunoutEnable, &runout.enabled); @@ -3384,8 +3427,12 @@ void drawFilSetMenu() { #if ENABLED(LED_CONTROL_MENU) void drawLedControlMenu() { + constexpr uint8_t items = (1 + + !ALL(CASE_LIGHT_MENU, CASE_LIGHT_USE_NEOPIXEL) + + ENABLED(HAS_COLOR_LEDS) * TERN(LED_COLOR_PRESETS, 8, 3 + ENABLED(HAS_WHITE_LED)), + ); checkkey = ID_Menu; - if (SET_MENU(ledControlMenu, MSG_LED_CONTROL, 10)) { + if (SET_MENU(ledControlMenu, MSG_LED_CONTROL, items)) { BACK_ITEM((currentMenu == tuneMenu) ? drawTuneMenu : drawControlMenu); #if !ALL(CASE_LIGHT_MENU, CASE_LIGHT_USE_NEOPIXEL) EDIT_ITEM(ICON_LedControl, MSG_LIGHTS, onDrawChkbMenu, setLedStatus, &leds.lights_on); @@ -3416,8 +3463,21 @@ void drawFilSetMenu() { #endif // LED_CONTROL_MENU void drawTuneMenu() { + constexpr uint8_t items = (2 + + COUNT_ENABLED(HAS_HOTEND, HAS_HEATED_BED, HAS_FAN) + + ALL(HAS_ZOFFSET_ITEM, BABYSTEPPING) + + 1 + + COUNT_ENABLED(ADVANCED_PAUSE_FEATURE, HAS_FILAMENT_SENSOR, PROUI_ITEM_PLR, FWRETRACT, PROUI_ITEM_JD, PROUI_ITEM_ADVK, HAS_LOCKSCREEN) + + TERN0(HAS_LCD_BRIGHTNESS, 2) + + ENABLED(EDITABLE_DISPLAY_TIMEOUT) + + 2 * ALL(PROUI_TUNING_GRAPH, PROUI_ITEM_PLOT) + + TERN(CASE_LIGHT_MENU, + 1 + COUNT_ENABLED(CASELIGHT_USES_BRIGHTNESS, LED_CONTROL_MENU), + ENABLED(LED_CONTROL_MENU) && DISABLED(CASE_LIGHT_USE_NEOPIXEL) + ) + ); checkkey = ID_Menu; - if (SET_MENU_R(tuneMenu, selrect({73, 2, 28, 12}), MSG_TUNE, 20)) { + if (SET_MENU_R(tuneMenu, selrect({73, 2, 28, 12}), MSG_TUNE, items)) { BACK_ITEM(gotoPrintProcess); EDIT_ITEM(ICON_Speed, MSG_SPEED, onDrawSpeedItem, setSpeed, &feedrate_percentage); #if HAS_HOTEND @@ -3518,8 +3578,9 @@ void drawTuneMenu() { #endif void drawInputShaping_menu() { + constexpr uint8_t items = 1 + 2 * COUNT_ENABLED(INPUT_SHAPING_X, INPUT_SHAPING_Y, INPUT_SHAPING_Z); checkkey = ID_Menu; - if (SET_MENU(inputShapingMenu, MSG_INPUT_SHAPING, 1 PLUS_TERN0(INPUT_SHAPING_X, 2) PLUS_TERN0(INPUT_SHAPING_Y, 2) PLUS_TERN0(INPUT_SHAPING_Z, 2))) { + if (SET_MENU(inputShapingMenu, MSG_INPUT_SHAPING, items)) { BACK_ITEM(drawMotionMenu); #if ENABLED(INPUT_SHAPING_X) MENU_ITEM(ICON_ShapingX, MSG_SHAPING_A_FREQ, onDrawShapingXFreq, setShapingXFreq); @@ -3553,8 +3614,22 @@ void drawTuneMenu() { #endif void drawTrinamicConfigMenu() { + constexpr uint8_t items = (1 + #if AXIS_IS_TMC(X) + + 1 + #endif + #if AXIS_IS_TMC(Y) + + 1 + #endif + #if AXIS_IS_TMC(Z) + + 1 + #endif + #if AXIS_IS_TMC(E0) + + 1 + #endif + ); checkkey = ID_Menu; - if (SET_MENU(trinamicConfigMenu, MSG_TMC_DRIVERS, 5)) { + if (SET_MENU(trinamicConfigMenu, MSG_TMC_DRIVERS, items)) { BACK_ITEM(drawAdvancedSettingsMenu); #if AXIS_IS_TMC(X) EDIT_ITEM(ICON_TMCXSet, MSG_TMC_ACURRENT, onDrawPIntMenu, setXTMCCurrent, &stepperX.val_mA); @@ -3574,8 +3649,12 @@ void drawTuneMenu() { #endif void drawMotionMenu() { + constexpr uint8_t items = (4 + + COUNT_ENABLED(EDITABLE_STEPS_PER_UNIT, EDITABLE_HOMING_FEEDRATE, LIN_ADVANCE, SHAPING_MENU, ADAPTIVE_STEP_SMOOTHING_TOGGLE) + + 2 + ); checkkey = ID_Menu; - if (SET_MENU_R(motionMenu, selrect({1, 16, 28, 13}), MSG_MOTION, 11)) { + if (SET_MENU_R(motionMenu, selrect({1, 16, 28, 13}), MSG_MOTION, items)) { BACK_ITEM(drawControlMenu); MENU_ITEM(ICON_MaxSpeed, MSG_SPEED, onDrawSpeed, drawMaxSpeedMenu); MENU_ITEM(ICON_MaxAccelerated, MSG_ACCELERATION, onDrawAcc, drawMaxAccelMenu); @@ -3620,8 +3699,13 @@ void drawMotionMenu() { #endif void drawFilamentManMenu() { + constexpr uint8_t items = (1 + + ENABLED(NOZZLE_PARK_FEATURE) + + TERN0(ADVANCED_PAUSE_FEATURE, 1 + ENABLED(HAS_PREHEAT)) + + TERN0(FILAMENT_LOAD_UNLOAD_GCODES, 2) + ); checkkey = ID_Menu; - if (SET_MENU(filamentMenu, MSG_FILAMENT_MAN, 6)) { + if (SET_MENU(filamentMenu, MSG_FILAMENT_MAN, items)) { BACK_ITEM(drawPrepareMenu); #if ENABLED(NOZZLE_PARK_FEATURE) MENU_ITEM(ICON_Park, MSG_FILAMENT_PARK_ENABLED, onDrawMenuItem, parkHead); @@ -3681,16 +3765,21 @@ void drawFilamentManMenu() { #define _preheatMenu(N) \ void drawPreheat## N ##Menu() { \ + constexpr uint8_t items = 1 + COUNT_ENABLED(HAS_HOTEND, HAS_HEATED_BED, HAS_FAN, EEPROM_SETTINGS); \ hmiValue.select = (N) - 1; \ - drawPreheatMenu(SET_MENU(preheatMenu, MSG_PREHEAT_## N ##_SETTINGS, 5)); \ + drawPreheatMenu(SET_MENU(preheatMenu, MSG_PREHEAT_## N ##_SETTINGS, items)); \ } REPEAT_1(PREHEAT_COUNT, _preheatMenu) #endif // HAS_PREHEAT void drawTemperatureMenu() { + constexpr uint8_t items = (1 + + COUNT_ENABLED(HAS_HOTEND, HAS_HEATED_BED, HAS_FAN) + + PREHEAT_COUNT + ); checkkey = ID_Menu; - if (SET_MENU_R(temperatureMenu, selrect({236, 2, 28, 12}), MSG_TEMPERATURE, 4 + PREHEAT_COUNT)) { + if (SET_MENU_R(temperatureMenu, selrect({236, 2, 28, 12}), MSG_TEMPERATURE, items)) { BACK_ITEM(drawControlMenu); #if HAS_HOTEND hotendTargetItem = EDIT_ITEM(ICON_HotendTemp, MSG_UBL_SET_TEMP_HOTEND, onDrawHotendTemp, setHotendTemp, &thermalManager.temp_hotend[0].target); @@ -3710,8 +3799,9 @@ void drawTemperatureMenu() { } void drawMaxSpeedMenu() { + constexpr uint8_t items = 1 + COUNT_ENABLED(HAS_X_AXIS, HAS_Y_AXIS, HAS_Z_AXIS, HAS_HOTEND); checkkey = ID_Menu; - if (SET_MENU_R(maxSpeedMenu, selrect({1, 16, 28, 13}), MSG_MAX_SPEED, 5)) { + if (SET_MENU_R(maxSpeedMenu, selrect({1, 16, 28, 13}), MSG_MAX_SPEED, items)) { BACK_ITEM(drawMotionMenu); #if HAS_X_AXIS EDIT_ITEM(ICON_MaxSpeedX, MSG_VMAX_A, onDrawMaxSpeedX, setMaxSpeedX, &planner.settings.max_feedrate_mm_s[X_AXIS]); @@ -3730,8 +3820,9 @@ void drawMaxSpeedMenu() { } void drawMaxAccelMenu() { + constexpr uint8_t items = 1 + COUNT_ENABLED(HAS_X_AXIS, HAS_Y_AXIS, HAS_Z_AXIS, HAS_HOTEND); checkkey = ID_Menu; - if (SET_MENU_R(maxAccelMenu, selrect({1, 16, 28, 13}), MSG_AMAX_EN, 5)) { + if (SET_MENU_R(maxAccelMenu, selrect({1, 16, 28, 13}), MSG_AMAX_EN, items)) { BACK_ITEM(drawMotionMenu); #if HAS_X_AXIS EDIT_ITEM(ICON_MaxAccX, MSG_AMAX_A, onDrawMaxAccelX, setMaxAccelX, &planner.settings.max_acceleration_mm_per_s2[X_AXIS]); @@ -3752,8 +3843,9 @@ void drawMaxAccelMenu() { #if ENABLED(CLASSIC_JERK) void drawMaxJerkMenu() { + constexpr uint8_t items = 1 + COUNT_ENABLED(HAS_X_AXIS, HAS_Y_AXIS, HAS_Z_AXIS, HAS_HOTEND); checkkey = ID_Menu; - if (SET_MENU_R(maxJerkMenu, selrect({1, 16, 28, 13}), MSG_JERK, 5)) { + if (SET_MENU_R(maxJerkMenu, selrect({1, 16, 28, 13}), MSG_JERK, items)) { BACK_ITEM(drawMotionMenu); #if HAS_X_AXIS EDIT_ITEM(ICON_MaxSpeedJerkX, MSG_VA_JERK, onDrawMaxJerkX, setMaxJerkX, &planner.max_jerk.x); @@ -3776,8 +3868,9 @@ void drawMaxAccelMenu() { #if ENABLED(EDITABLE_STEPS_PER_UNIT) void drawStepsMenu() { + constexpr uint8_t items = 1 + COUNT_ENABLED(HAS_X_AXIS, HAS_Y_AXIS, HAS_Z_AXIS, HAS_HOTEND); checkkey = ID_Menu; - if (SET_MENU_R(stepsMenu, selrect({1, 16, 28, 13}), MSG_STEPS_PER_MM, 5)) { + if (SET_MENU_R(stepsMenu, selrect({1, 16, 28, 13}), MSG_STEPS_PER_MM, items)) { BACK_ITEM(drawMotionMenu); #if HAS_X_AXIS EDIT_ITEM(ICON_StepX, MSG_A_STEPS, onDrawStepsX, setStepsX, &planner.settings.axis_steps_per_mm[X_AXIS]); @@ -3800,8 +3893,9 @@ void drawMaxAccelMenu() { #if ENABLED(EDITABLE_HOMING_FEEDRATE) void drawHomingFRMenu() { + constexpr uint8_t items = 1 + COUNT_ENABLED(HAS_X_AXIS, HAS_Y_AXIS, HAS_Z_AXIS); checkkey = ID_Menu; - if (SET_MENU(homingFRMenu, MSG_HOMING_FEEDRATE, 4)) { + if (SET_MENU(homingFRMenu, MSG_HOMING_FEEDRATE, items)) { BACK_ITEM(drawMotionMenu); #if HAS_X_AXIS uint16_t xhome = static_cast(homing_feedrate_mm_m.x); @@ -3921,8 +4015,12 @@ void drawMaxAccelMenu() { #endif void drawHotendMPCMenu() { + constexpr uint8_t items = (1 + + ENABLED(MPC_AUTOTUNE_MENU) + + TERN0(MPC_EDIT_MENU, 4 + ENABLED(MPC_INCLUDE_FAN)) + ); checkkey = ID_Menu; - if (SET_MENU_F(hotendMPCMenu, "MPC Settings", 7)) { + if (SET_MENU_F(hotendMPCMenu, "MPC Settings", items)) { MPC_t &mpc = thermalManager.temp_hotend[0].mpc; BACK_ITEM(drawAdvancedSettingsMenu); #if ENABLED(MPC_AUTOTUNE_MENU) @@ -3991,8 +4089,13 @@ void drawMaxAccelMenu() { #endif void drawHotendPIDMenu() { + constexpr uint8_t items = (1 + + TERN0(PID_AUTOTUNE_MENU, 3) + + TERN0(PID_EDIT_MENU, 3) + + ENABLED(EEPROM_SETTINGS) + ); checkkey = ID_Menu; - if (SET_MENU_F(hotendPIDMenu, STR_HOTEND_PID " Settings", 8)) { + if (SET_MENU_F(hotendPIDMenu, STR_HOTEND_PID " Settings", items)) { BACK_ITEM(drawAdvancedSettingsMenu); #if ENABLED(PID_AUTOTUNE_MENU) MENU_ITEM_F(ICON_PIDNozzle, STR_HOTEND_PID, onDrawMenuItem, hotendPID); @@ -4021,8 +4124,13 @@ void drawMaxAccelMenu() { #endif void drawBedPIDMenu() { + constexpr uint8_t items = (1 + + TERN0(PID_AUTOTUNE_MENU, 3) + + TERN0(PID_EDIT_MENU, 3) + + ENABLED(EEPROM_SETTINGS) + ); checkkey = ID_Menu; - if (SET_MENU_F(bedPIDMenu, STR_BED_PID " Settings", 8)) { + if (SET_MENU_F(bedPIDMenu, STR_BED_PID " Settings", items)) { BACK_ITEM(drawAdvancedSettingsMenu); #if ENABLED(PID_AUTOTUNE_MENU) MENU_ITEM_F(ICON_PIDBed, STR_BED_PID, onDrawMenuItem,bedPID); @@ -4051,8 +4159,13 @@ void drawMaxAccelMenu() { #endif void drawChamberPIDMenu() { + constexpr uint8_t items = (1 + + TERN0(PID_AUTOTUNE_MENU, 3) + + TERN0(PID_EDIT_MENU, 3) + + ENABLED(EEPROM_SETTINGS) + ); checkkey = ID_Menu; - if (SET_MENU_F(chamberPIDMenu, STR_CHAMBER_PID " Settings", 8)) { + if (SET_MENU_F(chamberPIDMenu, STR_CHAMBER_PID " Settings", items)) { BACK_ITEM(drawAdvancedSettingsMenu); #if ENABLED(PID_AUTOTUNE_MENU) MENU_ITEM_F(ICON_PIDChamber, STR_CHAMBER_PID, onDrawMenuItem,chamberPID); @@ -4096,8 +4209,9 @@ void drawMaxAccelMenu() { #if ENABLED(INDIVIDUAL_AXIS_HOMING_SUBMENU) void drawHomingMenu() { + constexpr uint8_t items = 2 + COUNT_ENABLED(HAS_X_AXIS, HAS_Y_AXIS, HAS_Z_AXIS, Z_STEPPER_AUTO_ALIGN, MESH_BED_LEVELING); checkkey = ID_Menu; - if (SET_MENU(homingMenu, MSG_HOMING, 6)) { + if (SET_MENU(homingMenu, MSG_HOMING, items)) { BACK_ITEM(drawPrepareMenu); MENU_ITEM(ICON_Homing, MSG_AUTO_HOME, onDrawMenuItem, autoHome); #if HAS_X_AXIS @@ -4212,8 +4326,16 @@ void drawMaxAccelMenu() { #if HAS_MESH void drawMeshSetMenu() { + constexpr uint8_t items = (1 + + ENABLED(PREHEAT_BEFORE_LEVELING) + + 2 + + ENABLED(HAS_BED_PROBE) + + TERN0(AUTO_BED_LEVELING_UBL, 6) + + TERN0(PROUI_MESH_EDIT, 2) + + 1 + ); checkkey = ID_Menu; - if (SET_MENU(meshMenu, MSG_MESH_LEVELING, 14)) { + if (SET_MENU(meshMenu, MSG_MESH_LEVELING, items)) { BACK_ITEM(drawAdvancedSettingsMenu); #if ENABLED(PREHEAT_BEFORE_LEVELING) EDIT_ITEM(ICON_Temperature, MSG_UBL_SET_TEMP_BED, onDrawPIntMenu, setBedLevT, &hmiData.bedLevT); From 4895388909096c1df822af3ea01d1bc39568642d Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Thu, 20 Mar 2025 00:28:49 +0000 Subject: [PATCH 135/787] [cron] Bump distribution date (2025-03-20) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index d2f7ac3ffd..1d434d8ba3 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-03-19" +//#define STRING_DISTRIBUTION_DATE "2025-03-20" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index fbdc9cdd04..6bf03f900f 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-03-19" + #define STRING_DISTRIBUTION_DATE "2025-03-20" #endif /** From d9f2c6444fb04bc78a146a1cd795d66a64d65a84 Mon Sep 17 00:00:00 2001 From: Andrew <18502096+classicrocker883@users.noreply.github.com> Date: Wed, 19 Mar 2025 21:01:47 -0400 Subject: [PATCH 136/787] =?UTF-8?q?=F0=9F=9A=B8=20ProUI=20"View=20Mesh=20(?= =?UTF-8?q?grid)"=20item=20(#26181)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Scott Lahteine --- Marlin/src/lcd/e3v2/proui/bedlevel_tools.cpp | 1 + Marlin/src/lcd/e3v2/proui/bedlevel_tools.h | 6 ++-- Marlin/src/lcd/e3v2/proui/dwin.cpp | 19 ++++++++++-- Marlin/src/lcd/e3v2/proui/dwin_defines.h | 4 +++ Marlin/src/lcd/e3v2/proui/meshviewer.cpp | 31 ++++++++++++-------- Marlin/src/lcd/language/language_en.h | 1 + 6 files changed, 44 insertions(+), 18 deletions(-) diff --git a/Marlin/src/lcd/e3v2/proui/bedlevel_tools.cpp b/Marlin/src/lcd/e3v2/proui/bedlevel_tools.cpp index e4b6fb72a0..b85caaf6cc 100644 --- a/Marlin/src/lcd/e3v2/proui/bedlevel_tools.cpp +++ b/Marlin/src/lcd/e3v2/proui/bedlevel_tools.cpp @@ -63,6 +63,7 @@ BedLevelTools bedLevelTools; #if ENABLED(USE_GRID_MESHVIEWER) + bool BedLevelTools::grid_meshview = false; bool BedLevelTools::viewer_print_value = false; #endif bool BedLevelTools::goto_mesh_value = false; diff --git a/Marlin/src/lcd/e3v2/proui/bedlevel_tools.h b/Marlin/src/lcd/e3v2/proui/bedlevel_tools.h index a0da0ceeb3..5716316ee4 100644 --- a/Marlin/src/lcd/e3v2/proui/bedlevel_tools.h +++ b/Marlin/src/lcd/e3v2/proui/bedlevel_tools.h @@ -46,8 +46,8 @@ class BedLevelTools { public: - #if ENABLED(USE_GRID_MESHVIEWER) - static bool viewer_asymmetric_range; + #if USE_GRID_MESHVIEWER + static bool grid_meshview; static bool viewer_print_value; #endif static bool goto_mesh_value; @@ -69,7 +69,7 @@ public: static float getMaxValue(); static float getMinValue(); static bool meshValidate(); - #if ENABLED(USE_GRID_MESHVIEWER) + #if USE_GRID_MESHVIEWER static void drawBedMesh(int16_t selected=-1, uint8_t gridline_width=1, uint16_t padding_x=8, uint16_t padding_y_top=(40 + 53 - 7)); static void setMeshViewerStatus(); #endif diff --git a/Marlin/src/lcd/e3v2/proui/dwin.cpp b/Marlin/src/lcd/e3v2/proui/dwin.cpp index 03f25b5010..a775d2ae27 100644 --- a/Marlin/src/lcd/e3v2/proui/dwin.cpp +++ b/Marlin/src/lcd/e3v2/proui/dwin.cpp @@ -2000,7 +2000,7 @@ void dwinRedrawScreen() { #endif // ADVANCED_PAUSE_FEATURE #if HAS_MESH - void dwinMeshViewer() { + void _dwinMeshViewer() { if (!leveling_is_valid()) dwinPopupContinue(ICON_Leveling_1, GET_TEXT_F(MSG_MESH_VIEWER), GET_TEXT_F(MSG_NO_VALID_MESH)); else { @@ -2008,6 +2008,13 @@ void dwinRedrawScreen() { meshViewer.draw(); } } + void dwinMeshViewer() { + TERN_(USE_GRID_MESHVIEWER, bedLevelTools.grid_meshview = false); + _dwinMeshViewer(); + } + #if ENABLED(USE_GRID_MESHVIEWER) + void dwinMeshViewerGrid() { bedLevelTools.grid_meshview = true; _dwinMeshViewer(); } + #endif #endif #if HAS_LOCKSCREEN @@ -3727,13 +3734,17 @@ void drawFilamentManMenu() { #if ENABLED(MESH_BED_LEVELING) void drawManualMeshMenu() { + constexpr uint8_t items = 6 + ENABLED(USE_GRID_MESHVIEWER); checkkey = ID_Menu; - if (SET_MENU(manualMeshMenu, MSG_UBL_MANUAL_MESH, 6)) { + if (SET_MENU(manualMeshMenu, MSG_UBL_MANUAL_MESH, items)) { BACK_ITEM(drawPrepareMenu); MENU_ITEM(ICON_ManualMesh, MSG_LEVEL_BED, onDrawMenuItem, manualMeshStart); mMeshMoveZItem = EDIT_ITEM(ICON_Zoffset, MSG_MOVE_Z, onDrawMMeshMoveZ, setMMeshMoveZ, ¤t_position.z); MENU_ITEM(ICON_Axis, MSG_UBL_CONTINUE_MESH, onDrawMenuItem, manualMeshContinue); MENU_ITEM(ICON_MeshViewer, MSG_MESH_VIEW, onDrawSubMenu, dwinMeshViewer); + #if USE_GRID_MESHVIEWER + MENU_ITEM(ICON_MeshViewer, MSG_MESH_VIEW_GRID, onDrawSubMenu, dwinMeshViewerGrid); + #endif MENU_ITEM(ICON_MeshSave, MSG_UBL_SAVE_MESH, onDrawMenuItem, manualMeshSave); } updateMenu(manualMeshMenu); @@ -4333,6 +4344,7 @@ void drawMaxAccelMenu() { + TERN0(AUTO_BED_LEVELING_UBL, 6) + TERN0(PROUI_MESH_EDIT, 2) + 1 + + ENABLED(USE_GRID_MESHVIEWER) ); checkkey = ID_Menu; if (SET_MENU(meshMenu, MSG_MESH_LEVELING, items)) { @@ -4358,6 +4370,9 @@ void drawMaxAccelMenu() { MENU_ITEM(ICON_MeshEdit, MSG_EDIT_MESH, onDrawSubMenu, drawEditMeshMenu); #endif MENU_ITEM(ICON_MeshViewer, MSG_MESH_VIEW, onDrawSubMenu, dwinMeshViewer); + #if USE_GRID_MESHVIEWER + MENU_ITEM(ICON_MeshViewer, MSG_MESH_VIEW_GRID, onDrawSubMenu, dwinMeshViewerGrid); + #endif } updateMenu(meshMenu); } diff --git a/Marlin/src/lcd/e3v2/proui/dwin_defines.h b/Marlin/src/lcd/e3v2/proui/dwin_defines.h index b72bdf1d23..832702db8f 100644 --- a/Marlin/src/lcd/e3v2/proui/dwin_defines.h +++ b/Marlin/src/lcd/e3v2/proui/dwin_defines.h @@ -35,6 +35,10 @@ //#define DACAI_DISPLAY // Enable for DACAI display //#define TITLE_CENTERED // Center Menu Title Text +#if HAS_MESH + #define USE_GRID_MESHVIEWER 1 +#endif + #if HAS_MESH #define PROUI_MESH_EDIT // Add a menu to edit mesh points #if ENABLED(PROUI_MESH_EDIT) diff --git a/Marlin/src/lcd/e3v2/proui/meshviewer.cpp b/Marlin/src/lcd/e3v2/proui/meshviewer.cpp index 38d0af4f82..e167af5665 100644 --- a/Marlin/src/lcd/e3v2/proui/meshviewer.cpp +++ b/Marlin/src/lcd/e3v2/proui/meshviewer.cpp @@ -39,7 +39,7 @@ #include "../../../feature/bedlevel/bedlevel.h" #include "meshviewer.h" -#if ENABLED(USE_GRID_MESHVIEWER) +#if USE_GRID_MESHVIEWER #include "bedlevel_tools.h" #endif @@ -112,14 +112,20 @@ void MeshViewer::drawMesh(const bed_mesh_t zval, const uint8_t csizex, const uin void MeshViewer::draw(const bool withsave/*=false*/, const bool redraw/*=true*/) { title.showCaption(GET_TEXT_F(MSG_MESH_VIEWER)); - #if ENABLED(USE_GRID_MESHVIEWER) - DWINUI::clearMainArea(); - bedLevelTools.viewer_print_value = true; - bedLevelTools.drawBedMesh(-1, 1, 8, 10 + TITLE_HEIGHT); - #else + + const bool see_mesh = TERN0(USE_GRID_MESHVIEWER, bedLevelTools.grid_meshview); + if (see_mesh) { + #if USE_GRID_MESHVIEWER + DWINUI::clearMainArea(); + bedLevelTools.viewer_print_value = true; + bedLevelTools.drawBedMesh(-1, 1, 8, 10 + TITLE_HEIGHT); + #endif + } + else { if (redraw) drawMesh(bedlevel.z_values, GRID_MAX_POINTS_X, GRID_MAX_POINTS_Y); else DWINUI::drawBox(1, hmiData.colorBackground, { 89, 305, 99, 38 }); - #endif + } + if (withsave) { DWINUI::drawButton(BTN_Save, 26, 305); DWINUI::drawButton(BTN_Continue, 146, 305); @@ -128,12 +134,11 @@ void MeshViewer::draw(const bool withsave/*=false*/, const bool redraw/*=true*/) else DWINUI::drawButton(BTN_Continue, 86, 305); - #if ENABLED(USE_GRID_MESHVIEWER) - bedLevelTools.setMeshViewerStatus(); - #else - char str_1[6], str_2[6] = ""; - ui.status_printf(0, F("Mesh minZ: %s, maxZ: %s"), dtostrf(min, 1, 2, str_1), dtostrf(max, 1, 2, str_2)); - #endif + if (see_mesh) { + TERN_(USE_GRID_MESHVIEWER, bedLevelTools.setMeshViewerStatus()); + } + else // TODO: in marlinui.h set_status_and_level was defined to (..., const int8_t level=0); remove ", 0" when pulling other PR + ui.set_status_and_level(MString<30>(F("Mesh Z min: "), p_float_t(min, 2), F(", max: "), p_float_t(max, 2)), 0); } void drawMeshViewer() { meshViewer.draw(true, meshredraw); } diff --git a/Marlin/src/lcd/language/language_en.h b/Marlin/src/lcd/language/language_en.h index 6076c6fb30..5762fa150e 100644 --- a/Marlin/src/lcd/language/language_en.h +++ b/Marlin/src/lcd/language/language_en.h @@ -198,6 +198,7 @@ namespace LanguageNarrow_en { LSTR MSG_MESH_VIEWER = _UxGT("Mesh Viewer"); LSTR MSG_EDIT_MESH = _UxGT("Edit Mesh"); LSTR MSG_MESH_VIEW = _UxGT("View Mesh"); + LSTR MSG_MESH_VIEW_GRID = _UxGT("View Mesh (grid)"); LSTR MSG_EDITING_STOPPED = _UxGT("Mesh Editing Stopped"); LSTR MSG_NO_VALID_MESH = _UxGT("No valid mesh"); LSTR MSG_ACTIVATE_MESH = _UxGT("Activate Leveling"); From 5d755676a9deee640593c85d735719cc332a124d Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Wed, 19 Mar 2025 20:40:54 -0500 Subject: [PATCH 137/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Sil?= =?UTF-8?q?ence=20findMissingTranslations=20grep=20output?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- buildroot/share/scripts/findMissingTranslations.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/buildroot/share/scripts/findMissingTranslations.sh b/buildroot/share/scripts/findMissingTranslations.sh index 366075d5b9..115c2b67df 100755 --- a/buildroot/share/scripts/findMissingTranslations.sh +++ b/buildroot/share/scripts/findMissingTranslations.sh @@ -71,11 +71,11 @@ for WORD in $(awk '/LSTR/{print $2}' language_en.h); do # Find all selected languages that lack the string LANG_MISSING=" " for LANG in $TEST_LANGS; do - if [[ $(grep -c -E "^ *LSTR +$WORD\b" language_${LANG}.h) -eq 0 ]]; then + if [[ $(grep -c -E "^ *LSTR +$WORD\b" language_${LANG}.h 2>/dev/null) -eq 0 ]]; then INHERIT=$(awk '/using namespace/{print $3}' language_${LANG}.h | sed -E 's/Language_([a-zA-Z_]+)\s*;/\1/') if [[ -z $INHERIT || $INHERIT == "en" ]]; then LANG_MISSING+="$LANG " - elif [[ $(grep -c -E "^ *LSTR +$WORD\b" language_${INHERIT}.h) -eq 0 ]]; then + elif [[ $(grep -c -E "^ *LSTR +$WORD\b" language_${INHERIT}.h 2>/dev/null) -eq 0 ]]; then LANG_MISSING+="$LANG " fi fi From 57fe45a2a6f4f27019d771359896712cc04c44e2 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Fri, 21 Mar 2025 00:29:17 +0000 Subject: [PATCH 138/787] [cron] Bump distribution date (2025-03-21) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 1d434d8ba3..a1aa9e6164 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-03-20" +//#define STRING_DISTRIBUTION_DATE "2025-03-21" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 6bf03f900f..ce3bc61e5c 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-03-20" + #define STRING_DISTRIBUTION_DATE "2025-03-21" #endif /** From 9a8b1eab93a67c536821844de4a0b70f31479d0b Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Thu, 20 Mar 2025 20:28:30 -0500 Subject: [PATCH 139/787] =?UTF-8?q?=F0=9F=A9=B9=20Cleanup=20(for=20STM32?= =?UTF-8?q?=20I2C=20LCD)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In advance of #26433 --- .../AVR/{ => u8g}/u8g_com_HAL_AVR_sw_spi.cpp | 6 +- .../u8g_com_stm32duino_swspi.cpp | 0 Marlin/src/inc/Conditionals-2-LCD.h | 2 +- Marlin/src/lcd/dogm/lcdprint_u8g.cpp | 22 +++ Marlin/src/lcd/dogm/marlinui_DOGM.h | 8 +- .../u8g/u8g_dev_ssd1306_sh1106_128x64_I2C.cpp | 163 +++++++++--------- .../u8g_dev_ssd1306_sh1106_128x64_SWSPI.cpp | 2 +- .../lcd/dogm/u8g/u8g_dev_ssd1309_12864.cpp | 2 +- .../dogm/u8g/u8g_dev_st7565_64128n_HAL.cpp | 94 +++++----- .../dogm/u8g/u8g_dev_st7920_128x64_HAL.cpp | 56 +++--- .../dogm/u8g/u8g_dev_uc1701_mini12864_HAL.cpp | 98 +++++------ .../u8g/ultralcd_st7920_u8glib_rrd_AVR.cpp | 4 +- Marlin/src/lcd/dogm/u8g_fontutf8.cpp | 22 +++ Marlin/src/lcd/dogm/u8g_fontutf8.h | 22 +++ .../pins/esp32/pins_GODI_CONTROLLER_V1_0.h | 1 - Marlin/src/pins/ramps/pins_DAGOMA_D6.h | 12 +- Marlin/src/pins/ramps/pins_ZRIB_V53.h | 4 - Marlin/src/pins/sanguino/pins_ZMIB_V2.h | 2 - Marlin/src/pins/stm32f1/pins_BTT_SKR_E3_DIP.h | 8 +- Marlin/src/pins/stm32f1/pins_FYSETC_CHEETAH.h | 2 +- Marlin/src/pins/stm32f1/pins_MD_D301.h | 22 +-- Marlin/src/pins/stm32f1/pins_ZM3E2_V1_0.h | 2 - Marlin/src/pins/stm32f1/pins_ZM3E4_V1_0.h | 5 - Marlin/src/pins/stm32f1/pins_ZM3E4_V2_0.h | 3 - .../pins/stm32f4/pins_FYSETC_CHEETAH_V30.h | 2 +- Marlin/src/pins/stm32f4/pins_I3DBEEZ9.h | 12 +- .../src/pins/stm32f4/pins_MELLOW_FLY_E3_V2.h | 12 +- .../src/pins/stm32f4/pins_XTLW_CLIMBER_8TH.h | 14 +- .../pins/stm32g0/pins_BTT_MANTA_M4P_V2_1.h | 12 +- .../pins/stm32g0/pins_BTT_MANTA_M5P_V1_0.h | 12 +- Marlin/src/pins/stm32g0/pins_BTT_SKRAT_V1_0.h | 12 +- 31 files changed, 326 insertions(+), 312 deletions(-) rename Marlin/src/HAL/AVR/{ => u8g}/u8g_com_HAL_AVR_sw_spi.cpp (98%) rename Marlin/src/HAL/STM32F1/{dogm => u8g}/u8g_com_stm32duino_swspi.cpp (100%) diff --git a/Marlin/src/HAL/AVR/u8g_com_HAL_AVR_sw_spi.cpp b/Marlin/src/HAL/AVR/u8g/u8g_com_HAL_AVR_sw_spi.cpp similarity index 98% rename from Marlin/src/HAL/AVR/u8g_com_HAL_AVR_sw_spi.cpp rename to Marlin/src/HAL/AVR/u8g/u8g_com_HAL_AVR_sw_spi.cpp index 9617c9544d..f4fa1eb428 100644 --- a/Marlin/src/HAL/AVR/u8g_com_HAL_AVR_sw_spi.cpp +++ b/Marlin/src/HAL/AVR/u8g/u8g_com_HAL_AVR_sw_spi.cpp @@ -55,12 +55,12 @@ #if defined(ARDUINO) && !defined(ARDUINO_ARCH_STM32) && !defined(ARDUINO_ARCH_SAM) -#include "../../inc/MarlinConfigPre.h" +#include "../../../inc/MarlinConfigPre.h" #if HAS_MARLINUI_U8GLIB -#include "../shared/Marduino.h" -#include "../shared/Delay.h" +#include "../../shared/Marduino.h" +#include "../../shared/Delay.h" #include diff --git a/Marlin/src/HAL/STM32F1/dogm/u8g_com_stm32duino_swspi.cpp b/Marlin/src/HAL/STM32F1/u8g/u8g_com_stm32duino_swspi.cpp similarity index 100% rename from Marlin/src/HAL/STM32F1/dogm/u8g_com_stm32duino_swspi.cpp rename to Marlin/src/HAL/STM32F1/u8g/u8g_com_stm32duino_swspi.cpp diff --git a/Marlin/src/inc/Conditionals-2-LCD.h b/Marlin/src/inc/Conditionals-2-LCD.h index 8c818864a0..2462231593 100644 --- a/Marlin/src/inc/Conditionals-2-LCD.h +++ b/Marlin/src/inc/Conditionals-2-LCD.h @@ -201,7 +201,7 @@ #define DOGLCD #define IS_U8GLIB_ST7920 1 #define IS_ULTIPANEL 1 - #define ENCODER_PULSES_PER_STEP 2 + #define STD_ENCODER_PULSES_PER_STEP 2 #elif ENABLED(MKS_12864OLED) diff --git a/Marlin/src/lcd/dogm/lcdprint_u8g.cpp b/Marlin/src/lcd/dogm/lcdprint_u8g.cpp index 30d687ddef..e9132c94b9 100644 --- a/Marlin/src/lcd/dogm/lcdprint_u8g.cpp +++ b/Marlin/src/lcd/dogm/lcdprint_u8g.cpp @@ -1,3 +1,25 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2018 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + /** * @file lcdprint_u8g.cpp * @brief LCD print api for u8glib diff --git a/Marlin/src/lcd/dogm/marlinui_DOGM.h b/Marlin/src/lcd/dogm/marlinui_DOGM.h index ac65eab7de..c0cc7c4438 100644 --- a/Marlin/src/lcd/dogm/marlinui_DOGM.h +++ b/Marlin/src/lcd/dogm/marlinui_DOGM.h @@ -38,19 +38,19 @@ #if HAS_MEDIA #ifdef __SAMD21__ - #define U8G_CLASS U8GLIB_ST7920_128X64_4X_HAL + #define U8G_CLASS U8GLIB_ST7920_128X64_4X_HAL // 2 stripes, HW SPI (Shared with SD card. Non-standard LCD adapter on AVR.) #else // Hardware SPI on DUE - #define U8G_CLASS U8GLIB_ST7920_128X64_4X + #define U8G_CLASS U8GLIB_ST7920_128X64_4X // 2 stripes, SW SPI (Original u8glib device) #endif #define U8G_PARAM LCD_PINS_RS #elif (LCD_PINS_D4 == SD_SCK_PIN) && (LCD_PINS_EN == SD_MOSI_PIN) // Hardware SPI shared with SD Card - #define U8G_CLASS U8GLIB_ST7920_128X64_4X_HAL + #define U8G_CLASS U8GLIB_ST7920_128X64_4X_HAL // 2 stripes, HW SPI (Shared with SD card. Non-standard LCD adapter on AVR.) #define U8G_PARAM LCD_PINS_RS #else // Software SPI - #define U8G_CLASS U8GLIB_ST7920_128X64_4X + #define U8G_CLASS U8GLIB_ST7920_128X64_4X // 2 stripes, SW SPI (Original u8glib device) #define U8G_PARAM LCD_PINS_D4, LCD_PINS_EN, LCD_PINS_RS #endif diff --git a/Marlin/src/lcd/dogm/u8g/u8g_dev_ssd1306_sh1106_128x64_I2C.cpp b/Marlin/src/lcd/dogm/u8g/u8g_dev_ssd1306_sh1106_128x64_I2C.cpp index 4d4756c298..f44b4f8ac5 100644 --- a/Marlin/src/lcd/dogm/u8g/u8g_dev_ssd1306_sh1106_128x64_I2C.cpp +++ b/Marlin/src/lcd/dogm/u8g/u8g_dev_ssd1306_sh1106_128x64_I2C.cpp @@ -75,58 +75,58 @@ #define HEIGHT 64 #define PAGE_HEIGHT 8 +#define CMD_COL_ADR(N) (0x10 | ((N) >> 4)), ((N) & 0xF) +#define CMD_PAGE_ADR(N) (0x20), (N) +#define CMD_COLUMN_RANGE(N,O) (0x21), (N), (O) +#define CMD_PAGE_RANGE(N,O) (0x22), (N), (O) +#define CMD_SCROLL(N) ((N) ? 0x2F : 0x2E) +#define CMD_START_LINE(N) (0x40 | (N)) +#define CMD_CONTRAST(N) (0x81), (N) +#define CMD_CHARGE_PUMP(N) (0x8D), ((N) ? 0x14 : 0x10) +#define CMD_ADC_REVERSE(N) ((N) ? 0xA1 : 0xA0) +#define CMD_ALL_PIX(N) ((N) ? 0xA5 : 0xA4) +#define CMD_INVERTED(N) ((N) ? 0xA7 : 0xA6) +#define CMD_MUX_RATIO(N) (0xA8), (N) +#define CMD_ON(N) ((N) ? 0xAF : 0xAE) +#define CMD_OUT_MODE(N) ((N) ? 0xC8 : 0xC0) +#define CMD_DISP_OFFS(N) (0xD3), (N) +#define CMD_OSC_FREQ(R,F) (0xD5), ((F) << 4 | (R)) +#define CMD_CHARGE_PER(P,D) (0xD9), ((D) << 4 | (P)) +#define CMD_COM_CONFIG(N) (0xDA), ((N) ? 0x12 : 0x02) +#define CMD_VCOM_DESEL(N) (0xDB), (N) +#define CMD_NOOP() (0xE3) + uint8_t u8g_WriteEscSeqP_2_wire(u8g_t *u8g, u8g_dev_t *dev, const uint8_t *esc_seq); -// SH1106 (132x64) is compatible with SSD1306 (128x64) by adding a small margin to the larger display - -#define SH1106_PAGE_ADR(N) (0x20), (N) -#define SH1106_COL_ADR(N) (0x10 | ((N) >> 4)), ((N) & 0xFF) -#define SH1106_COLUMN_RANGE(N,O) (0x21), (N), (O) -#define SH1106_PAGE_RANGE(N,O) (0x22), (N), (O) -#define SH1106_SCROLL(N) ((N) ? 0x2F : 0x2E) -#define SH1106_START_LINE(N) (0x40 | (N)) -#define SH1106_CONTRAST(N) (0x81), (N) -#define SH1106_CHARGE_PUMP(N) (0x8D), ((N) ? 0x14 : 0x10) -#define SH1106_ADC_REVERSE(N) ((N) ? 0xA1 : 0xA0) -#define SH1106_ALL_PIX(N) ((N) ? 0xA5 : 0xA4) -#define SH1106_INVERTED(N) ((N) ? 0xA7 : 0xA6) -#define SH1106_MUX_RATIO(N) (0xA8), (N) -#define SH1106_ON(N) ((N) ? 0xAF : 0xAE) -#define SH1106_OUT_MODE(N) ((N) ? 0xC8 : 0xC0) -#define SH1106_DISP_OFFS(N) (0xD3), (N) -#define SH1106_OSC_FREQ(R,F) (0xD5), ((F) << 4 | (R)) -#define SH1106_CHARGE_PER(P,D) (0xD9), ((D) << 4 | (P)) -#define SH1106_COM_CONFIG(N) (0xDA), ((N) ? 0x12 : 0x02) -#define SH1106_VCOM_DESEL(N) (0xDB), (N) -#define SH1106_NOOP() (0xE3) +// SH1106 is compatible with SSD1306, but is 132x64. Display 128x64 centered within the 132x64. static const uint8_t u8g_dev_sh1106_128x64_data_start_2_wire[] PROGMEM = { - SH1106_COL_ADR(2), // Column 2 to center 128 pixels in 132 pixels - U8G_ESC_END // End of sequence + CMD_COL_ADR(2), // Column 2 to center 128 pixels in 132 pixels + U8G_ESC_END // End of sequence }; static const uint8_t u8g_dev_sh1106_128x64_init_seq_2_wire[] PROGMEM = { - U8G_ESC_ADR(0), // Initiate command mode - SH1106_ON(0), // Display off, sleep mode - SH1106_MUX_RATIO(0x3F), // Mux ratio - SH1106_DISP_OFFS(0), // Display offset - SH1106_START_LINE(0), // Start line - SH1106_ADC_REVERSE(1), // Segment remap A0/A1 - SH1106_OUT_MODE(1), // 0: scan dir normal, 1: reverse - SH1106_COM_CONFIG(1), // COM pin HW config, sequential com pin config (bit 4), disable left/right remap (bit 5) - SH1106_CONTRAST(0xCF), // Set contrast control - SH1106_PAGE_ADR(0x02), // page addressing mode - SH1106_COLUMN_RANGE(2, 129), // Set column range 2 .. 129 - SH1106_PAGE_RANGE(0, 7), // Set page range 0 .. 7 - SH1106_CHARGE_PER(0x1, 0xF), // Pre-charge period - SH1106_VCOM_DESEL(0x40), // Vcomh deselect level - SH1106_ALL_PIX(0), // Output RAM to display - SH1106_INVERTED(0), // Normal display mode - SH1106_OSC_FREQ(0, 8), // Clock divide ratio (0:1) and oscillator frequency (8) - SH1106_CHARGE_PUMP(1), // Charge pump setting - SH1106_SCROLL(0), // Deactivate scroll - SH1106_ON(1), // Display on - U8G_ESC_END // End of sequence + U8G_ESC_ADR(0), // Initiate command mode + CMD_ON(0), // Display off, sleep mode + CMD_MUX_RATIO(0x3F), // Mux ratio + CMD_DISP_OFFS(0), // Display offset + CMD_START_LINE(0), // Start line + CMD_ADC_REVERSE(1), // Segment remap A0/A1 + CMD_OUT_MODE(1), // 0: scan dir normal, 1: reverse + CMD_COM_CONFIG(1), // COM pin HW config, sequential com pin config (bit 4), disable left/right remap (bit 5) + CMD_CONTRAST(0xCF), // Set contrast control + CMD_PAGE_ADR(0x02), // page addressing mode + CMD_COLUMN_RANGE(2, 129), // Set column range 2 .. 129 + CMD_PAGE_RANGE(0, 7), // Set page range 0 .. 7 + CMD_CHARGE_PER(0x1, 0xF), // Pre-charge period + CMD_VCOM_DESEL(0x40), // Vcomh deselect level + CMD_ALL_PIX(0), // Output RAM to display + CMD_INVERTED(0), // Normal display mode + CMD_OSC_FREQ(0, 8), // Clock divide ratio (0:1) and oscillator frequency (8) + CMD_CHARGE_PUMP(1), // Charge pump setting + CMD_SCROLL(0), // Deactivate scroll + CMD_ON(1), // Display ON + U8G_ESC_END // End of sequence }; uint8_t u8g_dev_sh1106_128x64_2x_2_wire_fn(u8g_t *u8g, u8g_dev_t *dev, uint8_t msg, void *arg) { @@ -142,7 +142,7 @@ uint8_t u8g_dev_sh1106_128x64_2x_2_wire_fn(u8g_t *u8g, u8g_dev_t *dev, uint8_t m u8g_WriteEscSeqP_2_wire(u8g, dev, u8g_dev_sh1106_128x64_data_start_2_wire); u8g_WriteByte(u8g, dev, 0xB0 | (pb->p.page*2)); // Select current page u8g_SetAddress(u8g, dev, 1); // Data mode - u8g_WriteSequence(u8g, dev, pb->width, (uint8_t *) pb->buf); + u8g_WriteSequence(u8g, dev, pb->width, (uint8_t *)pb->buf); u8g_SetChipSelect(u8g, dev, 0); u8g_SetAddress(u8g, dev, 0); // Instruction mode u8g_WriteEscSeqP_2_wire(u8g, dev, u8g_dev_sh1106_128x64_data_start_2_wire); @@ -157,39 +157,39 @@ uint8_t u8g_dev_sh1106_128x64_2x_2_wire_fn(u8g_t *u8g, u8g_dev_t *dev, uint8_t m return u8g_dev_pb16v1_base_fn(u8g, dev, msg, arg); } -uint8_t u8g_dev_sh1106_128x64_2x_i2c_2_wire_buf[WIDTH*2] U8G_NOCOMMON ; -u8g_pb_t u8g_dev_sh1106_128x64_2x_i2c_2_wire_pb = { {16, HEIGHT, 0, 0, 0}, WIDTH, u8g_dev_sh1106_128x64_2x_i2c_2_wire_buf}; +uint8_t u8g_dev_sh1106_128x64_2x_i2c_2_wire_buf[WIDTH * 2] U8G_NOCOMMON; +u8g_pb_t u8g_dev_sh1106_128x64_2x_i2c_2_wire_pb = { { 16, HEIGHT, 0, 0, 0 }, WIDTH, u8g_dev_sh1106_128x64_2x_i2c_2_wire_buf }; u8g_dev_t u8g_dev_sh1106_128x64_2x_i2c_2_wire = { u8g_dev_sh1106_128x64_2x_2_wire_fn, &u8g_dev_sh1106_128x64_2x_i2c_2_wire_pb, U8G_COM_SSD_I2C_HAL }; ///////////////////////////////////////////////////////////////////////////////////////////// static const uint8_t u8g_dev_ssd1306_128x64_data_start_2_wire[] PROGMEM = { - SH1106_COL_ADR(0), // Column 0 - U8G_ESC_END // End of sequence + CMD_COL_ADR(0), // Column 0 + U8G_ESC_END // End of sequence }; static const uint8_t u8g_dev_ssd1306_128x64_init_seq_2_wire[] PROGMEM = { - U8G_ESC_CS(0), // Disable chip - SH1106_ON(0), // Display off, sleep mode - SH1106_MUX_RATIO(0x3F), // Mux ratio - SH1106_DISP_OFFS(0), // Display offset - SH1106_START_LINE(0), // Start line - SH1106_ADC_REVERSE(1), // Segment remap A0/A1 - SH1106_OUT_MODE(1), // 0: scan dir normal, 1: reverse - SH1106_COM_CONFIG(1), // COM pin HW config, sequential com pin config (bit 4), disable left/right remap (bit 5) - SH1106_CONTRAST(0xCF), // Set contrast control - SH1106_PAGE_ADR(0x02), // page addressing mode - SH1106_COLUMN_RANGE(0, 127), // Set column range 0 .. 127 - SH1106_PAGE_RANGE(0, 7), // Set page range from 0 .. 7 - SH1106_CHARGE_PER(0x1, 0xF), // Pre-charge period - SH1106_VCOM_DESEL(0x40), // Vcomh deselect level - SH1106_ALL_PIX(0), // Send RAM to display - SH1106_INVERTED(0), // Normal display mode - SH1106_OSC_FREQ(0, 8), // Clock divide ratio (0:1) and oscillator frequency (8) - SH1106_CHARGE_PUMP(1), // Charge pump setting - SH1106_SCROLL(0), // Deactivate scroll - SH1106_ON(1), // Display on - U8G_ESC_END // End of sequence + U8G_ESC_CS(0), // Disable chip + CMD_ON(0), // Display OFF, sleep mode + CMD_MUX_RATIO(0x3F), // Mux ratio + CMD_DISP_OFFS(0), // Display offset + CMD_START_LINE(0), // Start line + CMD_ADC_REVERSE(1), // Segment remap A0/A1 + CMD_OUT_MODE(1), // 0: scan dir normal, 1: reverse + CMD_COM_CONFIG(1), // COM pin HW config, sequential COM pin config (bit 4), disable left/right remap (bit 5) + CMD_CONTRAST(0xCF), // Set contrast control + CMD_PAGE_ADR(2), // Page addressing mode + CMD_COLUMN_RANGE(0, 127), // Set column range 0 .. 127 + CMD_PAGE_RANGE(0, 7), // Set page range from 0 .. 7 + CMD_CHARGE_PER(0x1, 0xF), // Pre-charge period + CMD_VCOM_DESEL(0x40), // Vcomh deselect level + CMD_ALL_PIX(0), // Send RAM to display + CMD_INVERTED(0), // Normal display mode + CMD_OSC_FREQ(0, 8), // Clock divide ratio (0:1) and oscillator frequency (8) + CMD_CHARGE_PUMP(1), // Charge pump setting + CMD_SCROLL(0), // Deactivate scroll + CMD_ON(1), // Display ON + U8G_ESC_END // End of sequence }; uint8_t u8g_dev_ssd1306_128x64_2x_2_wire_fn(u8g_t *u8g, u8g_dev_t *dev, uint8_t msg, void *arg) { @@ -205,7 +205,7 @@ uint8_t u8g_dev_ssd1306_128x64_2x_2_wire_fn(u8g_t *u8g, u8g_dev_t *dev, uint8_t u8g_WriteEscSeqP_2_wire(u8g, dev, u8g_dev_ssd1306_128x64_data_start_2_wire); u8g_WriteByte(u8g, dev, 0xB0 | (pb->p.page*2)); // Select current page u8g_SetAddress(u8g, dev, 1); // Data mode - u8g_WriteSequence(u8g, dev, pb->width, (uint8_t *) pb->buf); + u8g_WriteSequence(u8g, dev, pb->width, (uint8_t *)pb->buf); u8g_SetChipSelect(u8g, dev, 0); u8g_SetAddress(u8g, dev, 0); // Instruction mode u8g_WriteEscSeqP_2_wire(u8g, dev, u8g_dev_ssd1306_128x64_data_start_2_wire); @@ -220,8 +220,8 @@ uint8_t u8g_dev_ssd1306_128x64_2x_2_wire_fn(u8g_t *u8g, u8g_dev_t *dev, uint8_t return u8g_dev_pb16v1_base_fn(u8g, dev, msg, arg); } -uint8_t u8g_dev_ssd1306_128x64_2x_i2c_2_wire_buf[WIDTH*2] U8G_NOCOMMON ; -u8g_pb_t u8g_dev_ssd1306_128x64_2x_i2c_2_wire_pb = { {16, HEIGHT, 0, 0, 0}, WIDTH, u8g_dev_ssd1306_128x64_2x_i2c_2_wire_buf}; +uint8_t u8g_dev_ssd1306_128x64_2x_i2c_2_wire_buf[WIDTH * 2] U8G_NOCOMMON; +u8g_pb_t u8g_dev_ssd1306_128x64_2x_i2c_2_wire_pb = { {16, HEIGHT, 0, 0, 0}, WIDTH, u8g_dev_ssd1306_128x64_2x_i2c_2_wire_buf }; u8g_dev_t u8g_dev_ssd1306_128x64_2x_i2c_2_wire = { u8g_dev_ssd1306_128x64_2x_2_wire_fn, &u8g_dev_ssd1306_128x64_2x_i2c_2_wire_pb, U8G_COM_SSD_I2C_HAL }; ///////////////////////////////////////////////////////////////////////////////////////////// @@ -236,7 +236,7 @@ uint8_t u8g_WriteEscSeqP_2_wire(u8g_t *u8g, u8g_dev_t *dev, const uint8_t *esc_s for (;;) { uint8_t value = u8g_pgm_read(esc_seq); if (is_escape == 0) { - if (value != 255) { + if (value != 0xFF) { if (u8g_WriteByte(u8g, dev, value) == 0) return 0; if (u8g_WriteByte(u8g, dev, I2C_CMD_MODE) == 0) return 0; } @@ -245,17 +245,17 @@ uint8_t u8g_WriteEscSeqP_2_wire(u8g_t *u8g, u8g_dev_t *dev, const uint8_t *esc_s } } else { - if (value == 255) { + if (value == 0xFF) { if (u8g_WriteByte(u8g, dev, value) == 0) return 0; if (u8g_WriteByte(u8g, dev, I2C_CMD_MODE) == 0) return 0; } - else if (value == 254) { + else if (value == 0xFE) { break; } else if (value >= 0xF0) { - // not yet used, do nothing + // Not yet used, do nothing } - else if (value >= 0xE0 ) { + else if (value >= 0xE0) { u8g_SetAddress(u8g, dev, value & 0x0F); } else if (value >= 0xD0) { @@ -270,11 +270,10 @@ uint8_t u8g_WriteEscSeqP_2_wire(u8g_t *u8g, u8g_dev_t *dev, const uint8_t *esc_s u8g_SetResetHigh(u8g, dev); u8g_Delay(value); } - else if (value >= 0xBE) { - // not yet implemented + else if (value >= 0xBE) { // Not yet implemented //u8g_SetVCC(u8g, dev, value & 0x01); } - else if (value <= 127) { + else if (value <= 0x7F) { u8g_Delay(value); } is_escape = 0; diff --git a/Marlin/src/lcd/dogm/u8g/u8g_dev_ssd1306_sh1106_128x64_SWSPI.cpp b/Marlin/src/lcd/dogm/u8g/u8g_dev_ssd1306_sh1106_128x64_SWSPI.cpp index afb3c28a8c..fae4b78aec 100644 --- a/Marlin/src/lcd/dogm/u8g/u8g_dev_ssd1306_sh1106_128x64_SWSPI.cpp +++ b/Marlin/src/lcd/dogm/u8g/u8g_dev_ssd1306_sh1106_128x64_SWSPI.cpp @@ -64,7 +64,7 @@ #define PAGE_HEIGHT 8 #define SH1106_PAGE_ADR(N) (0x20), (N) -#define SH1106_COL_ADR(N) (0x10 | ((N) >> 4)), ((N) & 0xFF) +#define SH1106_COL_ADR(N) (0x10 | ((N) >> 4)), ((N) & 0xF) #define SH1106_COLUMN_RANGE(N,O) (0x21), (N), (O) #define SH1106_PAGE_RANGE(N,O) (0x22), (N), (O) #define SH1106_SCROLL(N) ((N) ? 0x2F : 0x2E) diff --git a/Marlin/src/lcd/dogm/u8g/u8g_dev_ssd1309_12864.cpp b/Marlin/src/lcd/dogm/u8g/u8g_dev_ssd1309_12864.cpp index 010231d056..db9437d034 100644 --- a/Marlin/src/lcd/dogm/u8g/u8g_dev_ssd1309_12864.cpp +++ b/Marlin/src/lcd/dogm/u8g/u8g_dev_ssd1309_12864.cpp @@ -32,7 +32,7 @@ #define PAGE_HEIGHT 8 #define SSD1309_PAGE_ADR(N) (0x20), (N) -#define SSD1309_COL_ADR(N) (0x10 | ((N) >> 4)), ((N) & 0xFF) +#define SSD1309_COL_ADR(N) (0x10 | ((N) >> 4)), ((N) & 0xF) #define SSD1309_COLUMN_RANGE(N,O) (0x21), (N), (O) #define SSD1309_PAGE_RANGE(N,O) (0x22), (N), (O) #define SSD1309_SCROLL(N) ((N) ? 0x2F : 0x2E) diff --git a/Marlin/src/lcd/dogm/u8g/u8g_dev_st7565_64128n_HAL.cpp b/Marlin/src/lcd/dogm/u8g/u8g_dev_st7565_64128n_HAL.cpp index 61a1e214bd..5f69680d01 100644 --- a/Marlin/src/lcd/dogm/u8g/u8g_dev_st7565_64128n_HAL.cpp +++ b/Marlin/src/lcd/dogm/u8g/u8g_dev_st7565_64128n_HAL.cpp @@ -85,72 +85,72 @@ /* init sequence from https://github.com/adafruit/ST7565-LCD/blob/master/ST7565/ST7565.cpp */ static const uint8_t u8g_dev_st7565_64128n_HAL_init_seq[] PROGMEM = { - U8G_ESC_CS(0), // disable chip - U8G_ESC_ADR(0), // instruction mode - U8G_ESC_CS(1), // enable chip - U8G_ESC_RST(15), // do reset low pulse with (15*16)+2 milliseconds (=maximum delay)*/ + U8G_ESC_CS(0), // Disable chip + U8G_ESC_ADR(0), // Instruction mode + U8G_ESC_CS(1), // Enable chip + U8G_ESC_RST(15), // Do reset low pulse with (15*16)+2 milliseconds (=maximum delay)*/ ST7565_BIAS_MODE(0), // 0xA2: LCD bias 1/9 (according to Displaytech 64128N datasheet) ST7565_ADC_REVERSE(0), // Normal ADC Select (according to Displaytech 64128N datasheet) - ST7565_OUT_MODE(1), // common output mode: set scan direction + ST7565_OUT_MODE(1), // Common output mode: set scan direction ST7565_START_LINE(0), // Display start line for Displaytech 64128N - ST7565_POWER_CONTROL(0x4), // power control: turn on voltage converter - U8G_ESC_DLY(50), // delay 50 ms + ST7565_POWER_CONTROL(0x4), // Power control: turn on voltage converter + U8G_ESC_DLY(50), // Delay 50 ms - ST7565_POWER_CONTROL(0x6), // power control: turn on voltage regulator - U8G_ESC_DLY(50), // delay 50 ms + ST7565_POWER_CONTROL(0x6), // Power control: turn on voltage regulator + U8G_ESC_DLY(50), // Delay 50 ms - ST7565_POWER_CONTROL(0x7), // power control: turn on voltage follower - U8G_ESC_DLY(50), // delay 50 ms + ST7565_POWER_CONTROL(0x7), // Power control: turn on voltage follower + U8G_ESC_DLY(50), // Delay 50 ms #ifdef ST7565_VOLTAGE_DIVIDER_VALUE // Set V5 voltage resistor ratio. Affects brightness of Displaytech 64128N ST7565_V5_RATIO(ST7565_VOLTAGE_DIVIDER_VALUE), #endif - ST7565_INVERTED(0), // display normal, bit val 0: LCD pixel off. + ST7565_INVERTED(0), // Display normal, bit val 0: LCD pixel off. ST7565_CONTRAST(0x1E), // Contrast value for Displaytech 64128N - ST7565_ON(1), // display on + ST7565_ON(1), // Display on - U8G_ESC_DLY(100), // delay 100 ms - ST7565_ALL_PIX(1), // display all points, ST7565 - U8G_ESC_DLY(100), // delay 100 ms - U8G_ESC_DLY(100), // delay 100 ms - ST7565_ALL_PIX(0), // normal display - U8G_ESC_CS(0), // disable chip - U8G_ESC_END // end of sequence + U8G_ESC_DLY(100), // Delay 100 ms + ST7565_ALL_PIX(1), // Display all points, ST7565 + U8G_ESC_DLY(100), // Delay 100 ms + U8G_ESC_DLY(100), // Delay 100 ms + ST7565_ALL_PIX(0), // Normal display + U8G_ESC_CS(0), // Disable chip + U8G_ESC_END // End of sequence }; static const uint8_t u8g_dev_st7565_64128n_HAL_data_start[] PROGMEM = { - U8G_ESC_ADR(0), // instruction mode - U8G_ESC_CS(1), // enable chip - ST7565_COLUMN_ADR(ST7565_XOFFSET), // high 4 bits to 0, low 4 bits to 0. Changed for DisplayTech 64128N - U8G_ESC_END // end of sequence + U8G_ESC_ADR(0), // Instruction mode + U8G_ESC_CS(1), // Enable chip + ST7565_COLUMN_ADR(ST7565_XOFFSET), // High 4 bits to 0, low 4 bits to 0. Changed for DisplayTech 64128N + U8G_ESC_END // End of sequence }; static const uint8_t u8g_dev_st7565_64128n_HAL_sleep_on[] PROGMEM = { - U8G_ESC_ADR(0), // instruction mode - U8G_ESC_CS(1), // enable chip - ST7565_SLEEP_MODE(), // static indicator off - //0x00, // indicator register set (not sure if this is required) - ST7565_ON(0), // display off - ST7565_ALL_PIX(1), // all points on - U8G_ESC_CS(0), // disable chip, bugfix 12 nov 2014 - U8G_ESC_END // end of sequence + U8G_ESC_ADR(0), // Instruction mode + U8G_ESC_CS(1), // Enable chip + ST7565_SLEEP_MODE(), // Static indicator off + //0x00, // Indicator register set (not sure if this is required) + ST7565_ON(0), // Display off + ST7565_ALL_PIX(1), // All points on + U8G_ESC_CS(0), // Disable chip, bugfix 12 nov 2014 + U8G_ESC_END // End of sequence }; static const uint8_t u8g_dev_st7565_64128n_HAL_sleep_off[] PROGMEM = { - U8G_ESC_ADR(0), // instruction mode - U8G_ESC_CS(1), // enable chip - ST7565_ALL_PIX(0), // all points off - ST7565_ON(1), // display on - U8G_ESC_DLY(50), // delay 50 ms - U8G_ESC_CS(0), // disable chip, bugfix 12 nov 2014 - U8G_ESC_END // end of sequence + U8G_ESC_ADR(0), // Instruction mode + U8G_ESC_CS(1), // Enable chip + ST7565_ALL_PIX(0), // All points off + ST7565_ON(1), // Display on + U8G_ESC_DLY(50), // Delay 50 ms + U8G_ESC_CS(0), // Disable chip, bugfix 12 nov 2014 + U8G_ESC_END // End of sequence }; uint8_t u8g_dev_st7565_64128n_HAL_fn(u8g_t *u8g, u8g_dev_t *dev, const uint8_t msg, void *arg) { @@ -164,15 +164,15 @@ uint8_t u8g_dev_st7565_64128n_HAL_fn(u8g_t *u8g, u8g_dev_t *dev, const uint8_t m case U8G_DEV_MSG_PAGE_NEXT: { u8g_pb_t *pb = (u8g_pb_t *)(dev->dev_mem); u8g_WriteEscSeqP(u8g, dev, u8g_dev_st7565_64128n_HAL_data_start); - u8g_WriteByte(u8g, dev, ST7565_PAGE_ADR(pb->p.page)); /* select current page (ST7565R) */ - u8g_SetAddress(u8g, dev, 1); /* data mode */ + u8g_WriteByte(u8g, dev, ST7565_PAGE_ADR(pb->p.page)); // select current page (ST7565R) + u8g_SetAddress(u8g, dev, 1); // data mode if (!u8g_pb_WriteBuffer(pb, u8g, dev)) return 0; u8g_SetChipSelect(u8g, dev, 0); } break; case U8G_DEV_MSG_CONTRAST: u8g_SetChipSelect(u8g, dev, 1); - u8g_SetAddress(u8g, dev, 0); /* instruction mode */ + u8g_SetAddress(u8g, dev, 0); // instruction mode u8g_WriteByte(u8g, dev, 0x81); u8g_WriteByte(u8g, dev, (*(uint8_t *)arg) >> 2); u8g_SetChipSelect(u8g, dev, 0); @@ -199,21 +199,21 @@ uint8_t u8g_dev_st7565_64128n_HAL_2x_fn(u8g_t *u8g, u8g_dev_t *dev, const uint8_ u8g_pb_t *pb = (u8g_pb_t *)(dev->dev_mem); u8g_WriteEscSeqP(u8g, dev, u8g_dev_st7565_64128n_HAL_data_start); - u8g_WriteByte(u8g, dev, ST7565_PAGE_ADR(2 * pb->p.page)); /* select current page (ST7565R) */ - u8g_SetAddress(u8g, dev, 1); /* data mode */ + u8g_WriteByte(u8g, dev, ST7565_PAGE_ADR(2 * pb->p.page)); // select current page (ST7565R) + u8g_SetAddress(u8g, dev, 1); // data mode u8g_WriteSequence(u8g, dev, pb->width, (uint8_t *)pb->buf); u8g_SetChipSelect(u8g, dev, 0); u8g_WriteEscSeqP(u8g, dev, u8g_dev_st7565_64128n_HAL_data_start); - u8g_WriteByte(u8g, dev, ST7565_PAGE_ADR(2 * pb->p.page + 1)); /* select current page (ST7565R) */ - u8g_SetAddress(u8g, dev, 1); /* data mode */ + u8g_WriteByte(u8g, dev, ST7565_PAGE_ADR(2 * pb->p.page + 1)); // select current page (ST7565R) + u8g_SetAddress(u8g, dev, 1); // data mode u8g_WriteSequence(u8g, dev, pb->width, (uint8_t *)(pb->buf)+pb->width); u8g_SetChipSelect(u8g, dev, 0); } break; case U8G_DEV_MSG_CONTRAST: u8g_SetChipSelect(u8g, dev, 1); - u8g_SetAddress(u8g, dev, 0); /* instruction mode */ + u8g_SetAddress(u8g, dev, 0); // instruction mode u8g_WriteByte(u8g, dev, 0x81); u8g_WriteByte(u8g, dev, (*(uint8_t *)arg) >> 2); u8g_SetChipSelect(u8g, dev, 0); diff --git a/Marlin/src/lcd/dogm/u8g/u8g_dev_st7920_128x64_HAL.cpp b/Marlin/src/lcd/dogm/u8g/u8g_dev_st7920_128x64_HAL.cpp index fb9d4b7ad6..6c330db204 100644 --- a/Marlin/src/lcd/dogm/u8g/u8g_dev_st7920_128x64_HAL.cpp +++ b/Marlin/src/lcd/dogm/u8g/u8g_dev_st7920_128x64_HAL.cpp @@ -63,22 +63,22 @@ /* init sequence from https://github.com/adafruit/ST7565-LCD/blob/master/ST7565/ST7565.cpp */ static const uint8_t u8g_dev_st7920_128x64_HAL_init_seq[] PROGMEM = { - U8G_ESC_CS(0), // disable chip - U8G_ESC_ADR(0), // instruction mode - U8G_ESC_RST(15), // do reset low pulse with (15*16)+2 milliseconds (=maximum delay) + U8G_ESC_CS(0), // Disable chip + U8G_ESC_ADR(0), // Instruction mode + U8G_ESC_RST(15), // Do reset low pulse with (15*16)+2 milliseconds (=maximum delay) U8G_ESC_DLY(100), // 8 Dez 2012: additional delay 100 ms because of reset - U8G_ESC_CS(1), // enable chip - U8G_ESC_DLY(50), // delay 50 ms + U8G_ESC_CS(1), // Enable chip + U8G_ESC_DLY(50), // Delay 50 ms 0x038, // 8 Bit interface (DL=1), basic instruction set (RE=0) - 0x00C, // display on, cursor & blink off; 0x08: all off + 0x00C, // Display on, cursor & blink off; 0x08: all off 0x006, // Entry mode: Cursor move to right, DDRAM address counter (AC) plus 1, no shift - 0x002, // disable scroll, enable CGRAM address - 0x001, // clear RAM, needs 1.6 ms - U8G_ESC_DLY(100), // delay 100 ms + 0x002, // Disable scroll, enable CGRAM address + 0x001, // Clear RAM, needs 1.6 ms + U8G_ESC_DLY(100), // Delay 100 ms - U8G_ESC_CS(0), // disable chip - U8G_ESC_END // end of sequence + U8G_ESC_CS(0), // Disable chip + U8G_ESC_END // End of sequence }; void clear_graphics_DRAM(u8g_t *u8g, u8g_dev_t *dev) { @@ -115,24 +115,24 @@ uint8_t u8g_dev_st7920_128x64_HAL_fn(u8g_t *u8g, u8g_dev_t *dev, uint8_t msg, vo uint8_t *ptr; u8g_pb_t *pb = (u8g_pb_t *)(dev->dev_mem); - u8g_SetAddress(u8g, dev, 0); /* cmd mode */ + u8g_SetAddress(u8g, dev, 0); // Cmd mode u8g_SetChipSelect(u8g, dev, 1); y = pb->p.page_y0; ptr = (uint8_t *)pb->buf; for (i = 0; i < 8; i ++) { - u8g_SetAddress(u8g, dev, 0); /* cmd mode */ - u8g_WriteByte(u8g, dev, 0x03E ); /* enable extended mode */ + u8g_SetAddress(u8g, dev, 0); // Cmd mode + u8g_WriteByte(u8g, dev, 0x03E ); // Enable extended mode if (y < 32) { - u8g_WriteByte(u8g, dev, 0x080 | y ); /* y pos */ - u8g_WriteByte(u8g, dev, 0x080 ); /* set x pos to 0*/ + u8g_WriteByte(u8g, dev, 0x080 | y ); // Y pos + u8g_WriteByte(u8g, dev, 0x080 ); // Set x pos to 0 } else { - u8g_WriteByte(u8g, dev, 0x080 | (y-32) ); /* y pos */ - u8g_WriteByte(u8g, dev, 0x080 | 8); /* set x pos to 64*/ + u8g_WriteByte(u8g, dev, 0x080 | (y-32) ); // Y pos + u8g_WriteByte(u8g, dev, 0x080 | 8); // Set x pos to 64 } - u8g_SetAddress(u8g, dev, 1); /* data mode */ + u8g_SetAddress(u8g, dev, 1); // Data mode u8g_WriteSequence(u8g, dev, (LCD_PIXEL_WIDTH) / 8, ptr); ptr += (LCD_PIXEL_WIDTH) / 8; y++; @@ -160,24 +160,24 @@ uint8_t u8g_dev_st7920_128x64_HAL_4x_fn(u8g_t *u8g, u8g_dev_t *dev, uint8_t msg, uint8_t *ptr; u8g_pb_t *pb = (u8g_pb_t *)(dev->dev_mem); - u8g_SetAddress(u8g, dev, 0); /* cmd mode */ + u8g_SetAddress(u8g, dev, 0); // Cmd mode u8g_SetChipSelect(u8g, dev, 1); y = pb->p.page_y0; ptr = (uint8_t *)pb->buf; for (i = 0; i < 32; i ++) { - u8g_SetAddress(u8g, dev, 0); /* cmd mode */ - u8g_WriteByte(u8g, dev, 0x03E ); /* enable extended mode */ + u8g_SetAddress(u8g, dev, 0); // Cmd mode + u8g_WriteByte(u8g, dev, 0x03E ); // Enable extended mode if (y < 32) { - u8g_WriteByte(u8g, dev, 0x080 | y ); /* y pos */ - u8g_WriteByte(u8g, dev, 0x080 ); /* set x pos to 0*/ + u8g_WriteByte(u8g, dev, 0x080 | y ); // Y pos + u8g_WriteByte(u8g, dev, 0x080 ); // Set x pos to 0 } else { - u8g_WriteByte(u8g, dev, 0x080 | (y-32) ); /* y pos */ - u8g_WriteByte(u8g, dev, 0x080 | 8); /* set x pos to 64*/ + u8g_WriteByte(u8g, dev, 0x080 | (y-32) ); // Y pos + u8g_WriteByte(u8g, dev, 0x080 | 8); // Set x pos to 64 } - u8g_SetAddress(u8g, dev, 1); /* data mode */ + u8g_SetAddress(u8g, dev, 1); // Data mode u8g_WriteSequence(u8g, dev, (LCD_PIXEL_WIDTH) / 8, ptr); ptr += (LCD_PIXEL_WIDTH) / 8; y++; @@ -200,7 +200,7 @@ U8G_PB_DEV(u8g_dev_st7920_128x64_HAL_hw_spi, LCD_PIXEL_WIDTH, LCD_PIXEL_HEIGHT, u8g_dev_t u8g_dev_st7920_128x64_HAL_4x_hw_spi = { u8g_dev_st7920_128x64_HAL_4x_fn, &u8g_dev_st7920_128x64_HAL_4x_pb, U8G_COM_ST7920_HAL_HW_SPI }; #if NONE(__AVR__, ARDUINO_ARCH_STM32, ARDUINO_ARCH_ESP32) || defined(U8G_HAL_LINKS) - // Also use this device for HAL version of rrd class. This results in the same device being used + // Also use this device for HAL version of RRD class. This results in the same device being used // for the ST7920 for HAL systems no matter what is selected in marlinui_DOGM.h. u8g_dev_t u8g_dev_st7920_128x64_rrd_sw_spi = { u8g_dev_st7920_128x64_HAL_4x_fn, &u8g_dev_st7920_128x64_HAL_4x_pb, U8G_COM_ST7920_HAL_SW_SPI }; #endif diff --git a/Marlin/src/lcd/dogm/u8g/u8g_dev_uc1701_mini12864_HAL.cpp b/Marlin/src/lcd/dogm/u8g/u8g_dev_uc1701_mini12864_HAL.cpp index f9c68c15fc..1d1291ff9a 100644 --- a/Marlin/src/lcd/dogm/u8g/u8g_dev_uc1701_mini12864_HAL.cpp +++ b/Marlin/src/lcd/dogm/u8g/u8g_dev_uc1701_mini12864_HAL.cpp @@ -83,59 +83,59 @@ #define UC1701_BOOST_RATIO(N) (0xF8), (N) static const uint8_t u8g_dev_uc1701_mini12864_HAL_init_seq[] PROGMEM = { - U8G_ESC_CS(0), // disable chip - U8G_ESC_ADR(0), // instruction mode - U8G_ESC_RST(1), // do reset low pulse with (1*16)+2 milliseconds - U8G_ESC_CS(1), // enable chip + U8G_ESC_CS(0), // Disable chip + U8G_ESC_ADR(0), // Instruction mode + U8G_ESC_RST(1), // Do reset low pulse with (1*16)+2 milliseconds + U8G_ESC_CS(1), // Enable chip - UC1701_RESET(), // soft reset - UC1701_START_LINE(0), // set display start line to 0 + UC1701_RESET(), // Soft reset + UC1701_START_LINE(0), // Set display start line to 0 UC1701_ADC_REVERSE(0), // ADC set to reverse - UC1701_OUT_MODE(1), // common output mode - UC1701_INVERTED(0), // display normal, bit val 0: LCD pixel off + UC1701_OUT_MODE(1), // Common output mode + UC1701_INVERTED(0), // Display normal, bit val 0: LCD pixel off UC1701_BIAS_MODE(0), // LCD bias 1/9 - UC1701_POWER_CONTROL(0x7), // all power control circuits on - UC1701_BOOST_RATIO(0x0), // set booster ratio to 4x - UC1701_V5_RATIO(3), // set V0 voltage resistor ratio to large - UC1701_CONTRAST(0x27), // set contrast - UC1701_INDICATOR(0), // indicator disable - UC1701_ON(1), // display on + UC1701_POWER_CONTROL(0x7), // All power control circuits on + UC1701_BOOST_RATIO(0x0), // Set booster ratio to 4x + UC1701_V5_RATIO(3), // Set V0 voltage resistor ratio to large + UC1701_CONTRAST(0x27), // Set contrast + UC1701_INDICATOR(0), // Indicator disable + UC1701_ON(1), // Display on - U8G_ESC_CS(0), // disable chip - U8G_ESC_DLY(100), // delay 100 ms - U8G_ESC_CS(1), // enable chip + U8G_ESC_CS(0), // Disable chip + U8G_ESC_DLY(100), // Delay 100 ms + U8G_ESC_CS(1), // Enable chip - UC1701_ALL_PIX(1), // display all points, ST7565 - U8G_ESC_CS(0), // disable chip - U8G_ESC_DLY(100), // delay 100 ms - U8G_ESC_DLY(100), // delay 100 ms - U8G_ESC_CS(1), // enable chip - UC1701_ALL_PIX(0), // normal display - U8G_ESC_CS(0), // disable chip - U8G_ESC_DLY(150), // delay 150 ms before sending any data - U8G_ESC_END // end of sequence + UC1701_ALL_PIX(1), // Display all points, ST7565 + U8G_ESC_CS(0), // Disable chip + U8G_ESC_DLY(100), // Delay 100 ms + U8G_ESC_DLY(100), // Delay 100 ms + U8G_ESC_CS(1), // Enable chip + UC1701_ALL_PIX(0), // Normal display + U8G_ESC_CS(0), // Disable chip + U8G_ESC_DLY(150), // Delay 150 ms before sending any data + U8G_ESC_END // End of sequence }; static const uint8_t u8g_dev_uc1701_mini12864_HAL_data_start[] PROGMEM = { - U8G_ESC_ADR(0), // instruction mode - U8G_ESC_CS(1), // enable chip + U8G_ESC_ADR(0), // Instruction mode + U8G_ESC_CS(1), // Enable chip #if ANY(MKS_MINI_12864, ENDER2_STOCKDISPLAY, FYSETC_MINI_12864) - UC1701_START_LINE(0), // set display start line to 0 + UC1701_START_LINE(0), // Set display start line to 0 UC1701_ADC_REVERSE(0), // ADC set to reverse - UC1701_OUT_MODE(1), // common output mode - UC1701_INVERTED(0), // display normal, bit val 0: LCD pixel off + UC1701_OUT_MODE(1), // Common output mode + UC1701_INVERTED(0), // Display normal, bit val 0: LCD pixel off UC1701_BIAS_MODE(0), // LCD bias 1/9 - UC1701_POWER_CONTROL(0x7),// all power control circuits on - UC1701_BOOST_RATIO(0x0), // set booster ratio to 4x - UC1701_V5_RATIO(3), // set V0 voltage resistor ratio to large - UC1701_INDICATOR(0), // indicator disable - UC1701_ON(1), // display on - UC1701_COLUMN_HI(0), // set upper 4 bits of the col adr to 0 - U8G_ESC_END, // end of sequence - U8G_ESC_DLY(5) // delay 5 ms + UC1701_POWER_CONTROL(0x7),// All power control circuits on + UC1701_BOOST_RATIO(0x0), // Set booster ratio to 4x + UC1701_V5_RATIO(3), // Set V0 voltage resistor ratio to large + UC1701_INDICATOR(0), // Indicator disable + UC1701_ON(1), // Display on + UC1701_COLUMN_HI(0), // Set upper 4 bits of the col adr to 0 + U8G_ESC_END, // End of sequence + U8G_ESC_DLY(5) // Delay 5 ms #else - UC1701_COLUMN_ADR(0), // address 0 - U8G_ESC_END // end of sequence + UC1701_COLUMN_ADR(0), // Address 0 + U8G_ESC_END // End of sequence #endif }; @@ -151,15 +151,15 @@ uint8_t u8g_dev_uc1701_mini12864_HAL_fn(u8g_t *u8g, u8g_dev_t *dev, uint8_t msg, case U8G_DEV_MSG_PAGE_NEXT: { u8g_pb_t *pb = (u8g_pb_t *)(dev->dev_mem); u8g_WriteEscSeqP(u8g, dev, u8g_dev_uc1701_mini12864_HAL_data_start); - u8g_WriteByte(u8g, dev, 0x0B0 | pb->p.page); /* select current page */ - u8g_SetAddress(u8g, dev, 1); /* data mode */ + u8g_WriteByte(u8g, dev, 0x0B0 | pb->p.page); // Select current page + u8g_SetAddress(u8g, dev, 1); // Data mode if (!u8g_pb_WriteBuffer(pb, u8g, dev)) return 0; u8g_SetChipSelect(u8g, dev, 0); } break; case U8G_DEV_MSG_CONTRAST: u8g_SetChipSelect(u8g, dev, 1); - u8g_SetAddress(u8g, dev, 0); /* instruction mode */ + u8g_SetAddress(u8g, dev, 0); // Instruction mode u8g_WriteByte(u8g, dev, 0x081); u8g_WriteByte(u8g, dev, (*(uint8_t *)arg) >> 2); u8g_SetChipSelect(u8g, dev, 0); @@ -180,20 +180,20 @@ uint8_t u8g_dev_uc1701_mini12864_HAL_2x_fn(u8g_t *u8g, u8g_dev_t *dev, uint8_t m case U8G_DEV_MSG_PAGE_NEXT: { u8g_pb_t *pb = (u8g_pb_t *)(dev->dev_mem); u8g_WriteEscSeqP(u8g, dev, u8g_dev_uc1701_mini12864_HAL_data_start); - u8g_WriteByte(u8g, dev, 0x0B0 | (2 * pb->p.page)); /* select current page */ - u8g_SetAddress(u8g, dev, 1); /* data mode */ + u8g_WriteByte(u8g, dev, 0x0B0 | (2 * pb->p.page)); // Select current page + u8g_SetAddress(u8g, dev, 1); // Data mode u8g_WriteSequence(u8g, dev, pb->width, (uint8_t *)pb->buf); u8g_SetChipSelect(u8g, dev, 0); u8g_WriteEscSeqP(u8g, dev, u8g_dev_uc1701_mini12864_HAL_data_start); - u8g_WriteByte(u8g, dev, 0x0B0 | (2 * pb->p.page + 1)); /* select current page */ - u8g_SetAddress(u8g, dev, 1); /* data mode */ + u8g_WriteByte(u8g, dev, 0x0B0 | (2 * pb->p.page + 1)); // Select current page + u8g_SetAddress(u8g, dev, 1); // Data mode u8g_WriteSequence(u8g, dev, pb->width, (uint8_t *)(pb->buf)+pb->width); u8g_SetChipSelect(u8g, dev, 0); } break; case U8G_DEV_MSG_CONTRAST: u8g_SetChipSelect(u8g, dev, 1); - u8g_SetAddress(u8g, dev, 0); /* instruction mode */ + u8g_SetAddress(u8g, dev, 0); // Instruction mode u8g_WriteByte(u8g, dev, 0x081); u8g_WriteByte(u8g, dev, (*(uint8_t *)arg) >> 2); u8g_SetChipSelect(u8g, dev, 0); diff --git a/Marlin/src/lcd/dogm/u8g/ultralcd_st7920_u8glib_rrd_AVR.cpp b/Marlin/src/lcd/dogm/u8g/ultralcd_st7920_u8glib_rrd_AVR.cpp index cd7445e019..6f8990bf20 100644 --- a/Marlin/src/lcd/dogm/u8g/ultralcd_st7920_u8glib_rrd_AVR.cpp +++ b/Marlin/src/lcd/dogm/u8g/ultralcd_st7920_u8glib_rrd_AVR.cpp @@ -20,8 +20,8 @@ * */ -// NOTE - the HAL version of the rrd device uses a generic ST7920 device. -// See u8g_dev_st7920_128x64_HAL.cpp for the HAL version. +// NOTE - The HAL version of the RRD device uses a generic ST7920 device. +// See u8g_dev_st7920_128x64_HAL.cpp #include "../../../inc/MarlinConfigPre.h" diff --git a/Marlin/src/lcd/dogm/u8g_fontutf8.cpp b/Marlin/src/lcd/dogm/u8g_fontutf8.cpp index 5d9ef627c9..1ee71f7c59 100644 --- a/Marlin/src/lcd/dogm/u8g_fontutf8.cpp +++ b/Marlin/src/lcd/dogm/u8g_fontutf8.cpp @@ -1,3 +1,25 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2018 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + /** * @file u8g_fontutf8.cpp * @brief font api for u8g lib diff --git a/Marlin/src/lcd/dogm/u8g_fontutf8.h b/Marlin/src/lcd/dogm/u8g_fontutf8.h index 281894509d..00df000d9c 100644 --- a/Marlin/src/lcd/dogm/u8g_fontutf8.h +++ b/Marlin/src/lcd/dogm/u8g_fontutf8.h @@ -1,3 +1,25 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2018 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + /** * @file fontutf8.h * @brief font api for u8g lib diff --git a/Marlin/src/pins/esp32/pins_GODI_CONTROLLER_V1_0.h b/Marlin/src/pins/esp32/pins_GODI_CONTROLLER_V1_0.h index 7cbaa96088..cffb7f3cb4 100644 --- a/Marlin/src/pins/esp32/pins_GODI_CONTROLLER_V1_0.h +++ b/Marlin/src/pins/esp32/pins_GODI_CONTROLLER_V1_0.h @@ -130,7 +130,6 @@ // #if ANY(EDUTRONICS_12864OLED_SH1106, EDUTRONICS_12864OLED_SSD1306) - #define LCDSCREEN_NAME "EDUTRONICS 12864 OLED" #define BTN_EN2 1 #define BTN_EN1 3 #define BTN_ENC 0 diff --git a/Marlin/src/pins/ramps/pins_DAGOMA_D6.h b/Marlin/src/pins/ramps/pins_DAGOMA_D6.h index f44657d2b5..99b04070d8 100644 --- a/Marlin/src/pins/ramps/pins_DAGOMA_D6.h +++ b/Marlin/src/pins/ramps/pins_DAGOMA_D6.h @@ -55,15 +55,9 @@ // Alter timing for graphical display #if IS_U8GLIB_ST7920 - #ifndef BOARD_ST7920_DELAY_1 - #define BOARD_ST7920_DELAY_1 0 - #endif - #ifndef BOARD_ST7920_DELAY_2 - #define BOARD_ST7920_DELAY_2 250 - #endif - #ifndef BOARD_ST7920_DELAY_3 - #define BOARD_ST7920_DELAY_3 250 - #endif + #define BOARD_ST7920_DELAY_1 0 + #define BOARD_ST7920_DELAY_2 250 + #define BOARD_ST7920_DELAY_3 250 #endif #define KILL_PIN -1 // NC diff --git a/Marlin/src/pins/ramps/pins_ZRIB_V53.h b/Marlin/src/pins/ramps/pins_ZRIB_V53.h index 22b806a2b6..2b99921909 100644 --- a/Marlin/src/pins/ramps/pins_ZRIB_V53.h +++ b/Marlin/src/pins/ramps/pins_ZRIB_V53.h @@ -334,7 +334,6 @@ // #if ENABLED(ZONESTAR_12864LCD) - #define LCDSCREEN_NAME "ZONESTAR LCD12864" #define LCD_SDSS_PIN 16 #define LCD_PINS_RS 16 // ST7920 CS (LCD-4) #define LCD_PINS_EN 23 // ST7920 DAT LCD-R/W (LCD-5) @@ -345,7 +344,6 @@ #define BEEPER_PIN 37 #define KILL_PIN 35 #elif ENABLED(REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER) - #define LCDSCREEN_NAME "Reprap LCD12864" // Use EXP1 & EXP2 connector #define LCD_PINS_RS 16 // ST7920 CS #define LCD_PINS_EN 17 // ST7920 DAT @@ -362,7 +360,6 @@ //================================================================================ #if ANY(ZONESTAR_12864OLED, ZONESTAR_12864OLED_SSD1306) - #define LCDSCREEN_NAME "ZONESTAR 12864OLED" #define LCD_SDSS_PIN 16 #define LCD_PINS_RS 23 // RESET Pull low for 1s to init #define LCD_PINS_DC 17 @@ -386,7 +383,6 @@ //================================================================================ #if ENABLED(ZONESTAR_LCD) - #define LCDSCREEN_NAME "LCD2004 ADCKEY" #define LCD_PINS_RS EXP1_04_PIN #define LCD_PINS_EN EXP1_03_PIN #define LCD_PINS_D4 EXP1_05_PIN diff --git a/Marlin/src/pins/sanguino/pins_ZMIB_V2.h b/Marlin/src/pins/sanguino/pins_ZMIB_V2.h index b583c17b31..0446f99dd3 100644 --- a/Marlin/src/pins/sanguino/pins_ZMIB_V2.h +++ b/Marlin/src/pins/sanguino/pins_ZMIB_V2.h @@ -189,7 +189,6 @@ // // LCD 128x64 // - #define LCDSCREEN_NAME "ZONESTAR_12864LCD" #define FORCE_SOFT_SPI //#define LCD_SDSS_PIN EXP1_03_PIN #define LCD_PINS_RS EXP1_03_PIN // ST7920 CS (LCD-4) @@ -204,7 +203,6 @@ // // OLED 128x64 // - #define LCDSCREEN_NAME "ZONESTAR 12864OLED" #define FORCE_SOFT_SPI #define LCD_PINS_RS EXP1_06_PIN #define LCD_PINS_DC EXP1_04_PIN diff --git a/Marlin/src/pins/stm32f1/pins_BTT_SKR_E3_DIP.h b/Marlin/src/pins/stm32f1/pins_BTT_SKR_E3_DIP.h index 54a8ae104b..06c7cacc5b 100644 --- a/Marlin/src/pins/stm32f1/pins_BTT_SKR_E3_DIP.h +++ b/Marlin/src/pins/stm32f1/pins_BTT_SKR_E3_DIP.h @@ -300,8 +300,14 @@ #define LCD_BACKLIGHT_PIN -1 #define FORCE_SOFT_SPI + #elif ENABLED(ULTI_CONTROLLER) + + #define LCD_PINS_D6 EXP1_03_PIN + #define DOGLCD_SCL_PIN EXP1_07_PIN // I2C1 + #define DOGLCD_SDA_PIN EXP1_08_PIN // I2C1 + #else - #error "Only CR10_STOCKDISPLAY, ZONESTAR_LCD, ENDER2_STOCKDISPLAY, MKS_MINI_12864, FYSETC_MINI_12864_2_1 and MKS_LCD12864A/B are currently supported on the SKR E3 DIP." + #error "Only CR10_STOCKDISPLAY, ZONESTAR_LCD, ENDER2_STOCKDISPLAY, ULTI_CONTROLLER, MKS_MINI_12864, FYSETC_MINI_12864_2_1 and MKS_LCD12864A/B are currently supported on the SKR E3 DIP." #endif #endif // HAS_WIRED_LCD diff --git a/Marlin/src/pins/stm32f1/pins_FYSETC_CHEETAH.h b/Marlin/src/pins/stm32f1/pins_FYSETC_CHEETAH.h index 0364517e24..a2b0f2a99d 100644 --- a/Marlin/src/pins/stm32f1/pins_FYSETC_CHEETAH.h +++ b/Marlin/src/pins/stm32f1/pins_FYSETC_CHEETAH.h @@ -166,7 +166,7 @@ #define DOGLCD_SCK EXP1_06_PIN #define DOGLCD_MOSI EXP1_08_PIN - #if ANY(FYSETC_MINI_12864, U8GLIB_ST7920) + #if ANY(FYSETC_MINI_12864, IS_U8GLIB_ST7920) #define FORCE_SOFT_SPI #endif //#define LCD_SCREEN_ROTATE 180 // 0, 90, 180, 270 diff --git a/Marlin/src/pins/stm32f1/pins_MD_D301.h b/Marlin/src/pins/stm32f1/pins_MD_D301.h index 3cd7dffed3..629d22c83f 100644 --- a/Marlin/src/pins/stm32f1/pins_MD_D301.h +++ b/Marlin/src/pins/stm32f1/pins_MD_D301.h @@ -49,11 +49,6 @@ // #define SERVO0_PIN PB0 -// -// Z Probe must be this pin -// -#define Z_MIN_PROBE_PIN PB1 - // // Limit Switches // @@ -61,13 +56,20 @@ #define X_MAX_PIN PF11 #define Y_MIN_PIN PF14 #define Y_MAX_PIN PF13 -#ifdef Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN - #define Z_MIN_PIN PB1 -#else - #define Z_MIN_PIN PG0 -#endif +#define Z_MIN_PIN PG0 #define Z_MAX_PIN PF15 +// +// Z Probe must be this pin +// +#ifndef Z_MIN_PROBE_PIN + #define Z_MIN_PROBE_PIN PB1 +#endif + +#if ENABLED(Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN) + #error "It's physically impossible to connect the Z Probe to the Z Min Endstop pin on this board." +#endif + // // Filament Sensor // diff --git a/Marlin/src/pins/stm32f1/pins_ZM3E2_V1_0.h b/Marlin/src/pins/stm32f1/pins_ZM3E2_V1_0.h index ecea985494..86cbf5c677 100644 --- a/Marlin/src/pins/stm32f1/pins_ZM3E2_V1_0.h +++ b/Marlin/src/pins/stm32f1/pins_ZM3E2_V1_0.h @@ -192,7 +192,6 @@ // 2 +5V // 1 GND - #define LCDSCREEN_NAME "ZONESTAR LCD12864" #define LCD_PINS_RS EXP1_03_PIN #define LCD_PINS_EN EXP1_06_PIN #define LCD_PINS_D4 EXP1_04_PIN @@ -220,7 +219,6 @@ // 3 RX3 PB11 KNOB_ENB #define FORCE_SOFT_SPI - #define LCDSCREEN_NAME "ZONESTAR 12864OLED" #define LCD_PINS_RS EXP1_06_PIN // = LCD_RESET_PIN #define LCD_PINS_DC EXP1_04_PIN // DC #define DOGLCD_CS EXP1_03_PIN // CS diff --git a/Marlin/src/pins/stm32f1/pins_ZM3E4_V1_0.h b/Marlin/src/pins/stm32f1/pins_ZM3E4_V1_0.h index 069086a43b..009d1f897c 100644 --- a/Marlin/src/pins/stm32f1/pins_ZM3E4_V1_0.h +++ b/Marlin/src/pins/stm32f1/pins_ZM3E4_V1_0.h @@ -280,7 +280,6 @@ // #if ENABLED(ZONESTAR_12864LCD) - #define LCDSCREEN_NAME "ZONESTAR LCD12864" #define LCD_PINS_RS EXP1_03_PIN // 7 CS make sure for zonestar zm3e4! #define LCD_PINS_EN EXP1_06_PIN // 6 DATA make sure for zonestar zm3e4! #define LCD_PINS_D4 EXP1_04_PIN // 8 SCK make sure for zonestar zm3e4! @@ -290,7 +289,6 @@ #define BTN_EN2 EXP1_08_PIN #define BTN_ENC EXP1_07_PIN #elif ENABLED(REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER) - #define LCDSCREEN_NAME "REPRAPDISCOUNT LCD12864" #define LCD_PINS_RS EXP1_03_PIN // 7 CS make sure for zonestar zm3e4! #define LCD_PINS_EN EXP1_04_PIN // 6 DATA make sure for zonestar zm3e4! #define LCD_PINS_D4 EXP1_06_PIN // 8 SCK make sure for zonestar zm3e4! @@ -301,7 +299,6 @@ #define BTN_ENC EXP1_01_PIN #elif ENABLED(ZONESTAR_DWIN_LCD) // Connect to EXP2 connector - #define LCDSCREEN_NAME "ZONESTAR DWIN LCD" #define BEEPER_PIN EXP2_05_PIN #define KILL_PIN PC0 #define BTN_EN1 EXP2_08_PIN @@ -310,7 +307,6 @@ #endif #if ENABLED(ZONESTAR_LCD2004_KNOB) - #define LCDSCREEN_NAME "LCD2004 KNOB" #define LCD_PINS_RS EXP1_03_PIN #define LCD_PINS_EN EXP1_04_PIN #define LCD_PINS_D4 EXP1_06_PIN @@ -323,7 +319,6 @@ #define BEEPER_PIN EXP1_02_PIN #define KILL_PIN EXP2_07_PIN #elif ENABLED(ZONESTAR_LCD2004_ADCKEY) - #define LCDSCREEN_NAME "LCD2004 5KEY" #define LCD_PINS_RS EXP1_03_PIN #define LCD_PINS_EN EXP1_04_PIN #define LCD_PINS_D4 EXP1_06_PIN diff --git a/Marlin/src/pins/stm32f1/pins_ZM3E4_V2_0.h b/Marlin/src/pins/stm32f1/pins_ZM3E4_V2_0.h index 66e538cb48..833c3427c1 100644 --- a/Marlin/src/pins/stm32f1/pins_ZM3E4_V2_0.h +++ b/Marlin/src/pins/stm32f1/pins_ZM3E4_V2_0.h @@ -276,7 +276,6 @@ #define WIFI_EN PC14 #if ENABLED(ZONESTAR_12864LCD) - #define LCDSCREEN_NAME "ZONESTAR LCD12864" #define LCD_PINS_RS EXP1_03_PIN // 7 CS make sure for zonestar zm3e4! #define LCD_PINS_EN EXP1_06_PIN // 6 DATA make sure for zonestar zm3e4! #define LCD_PINS_D4 EXP1_04_PIN // 8 SCK make sure for zonestar zm3e4! @@ -286,7 +285,6 @@ #define BTN_EN2 EXP1_08_PIN #define BTN_ENC EXP1_07_PIN #elif ENABLED(REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER) - #define LCDSCREEN_NAME "REPRAPDISCOUNT LCD12864" #define LCD_PINS_RS EXP2_03_PIN // 7 CS make sure for zonestar zm3e4! #define LCD_PINS_EN EXP2_06_PIN // 6 DATA make sure for zonestar zm3e4! #define LCD_PINS_D4 EXP2_04_PIN // 8 SCK make sure for zonestar zm3e4! @@ -297,7 +295,6 @@ #define BTN_ENC EXP2_07_PIN #elif ENABLED(ZONESTAR_DWIN_LCD) // Connect to EXP2 connector - #define LCDSCREEN_NAME "ZONESTAR DWIN LCD" #define BEEPER_PIN EXP2_05_PIN // PE11 #define KILL_PIN -1 // EXP1_01_PIN #define BTN_EN2 EXP2_07_PIN // PE8 diff --git a/Marlin/src/pins/stm32f4/pins_FYSETC_CHEETAH_V30.h b/Marlin/src/pins/stm32f4/pins_FYSETC_CHEETAH_V30.h index 54e1acc936..d0427b2c31 100644 --- a/Marlin/src/pins/stm32f4/pins_FYSETC_CHEETAH_V30.h +++ b/Marlin/src/pins/stm32f4/pins_FYSETC_CHEETAH_V30.h @@ -280,7 +280,7 @@ #endif // HAS_WIRED_LCD // Alter timing for graphical display -#if ENABLED(U8GLIB_ST7920) +#if IS_U8GLIB_ST7920 #define BOARD_ST7920_DELAY_1 96 #define BOARD_ST7920_DELAY_2 48 #define BOARD_ST7920_DELAY_3 600 diff --git a/Marlin/src/pins/stm32f4/pins_I3DBEEZ9.h b/Marlin/src/pins/stm32f4/pins_I3DBEEZ9.h index e36bdae3a8..1620c86bed 100644 --- a/Marlin/src/pins/stm32f4/pins_I3DBEEZ9.h +++ b/Marlin/src/pins/stm32f4/pins_I3DBEEZ9.h @@ -571,15 +571,9 @@ // Alter timing for graphical display #if IS_U8GLIB_ST7920 - #ifndef BOARD_ST7920_DELAY_1 - #define BOARD_ST7920_DELAY_1 125 - #endif - #ifndef BOARD_ST7920_DELAY_2 - #define BOARD_ST7920_DELAY_2 90 - #endif - #ifndef BOARD_ST7920_DELAY_3 - #define BOARD_ST7920_DELAY_3 600 - #endif + #define BOARD_ST7920_DELAY_1 125 + #define BOARD_ST7920_DELAY_2 90 + #define BOARD_ST7920_DELAY_3 600 #endif #if ENABLED(WIFISUPPORT) diff --git a/Marlin/src/pins/stm32f4/pins_MELLOW_FLY_E3_V2.h b/Marlin/src/pins/stm32f4/pins_MELLOW_FLY_E3_V2.h index 3fff8515b9..3ae1432a14 100644 --- a/Marlin/src/pins/stm32f4/pins_MELLOW_FLY_E3_V2.h +++ b/Marlin/src/pins/stm32f4/pins_MELLOW_FLY_E3_V2.h @@ -480,15 +480,9 @@ // Alter timing for graphical display #if IS_U8GLIB_ST7920 - #ifndef BOARD_ST7920_DELAY_1 - #define BOARD_ST7920_DELAY_1 120 - #endif - #ifndef BOARD_ST7920_DELAY_2 - #define BOARD_ST7920_DELAY_2 80 - #endif - #ifndef BOARD_ST7920_DELAY_3 - #define BOARD_ST7920_DELAY_3 580 - #endif + #define BOARD_ST7920_DELAY_1 120 + #define BOARD_ST7920_DELAY_2 80 + #define BOARD_ST7920_DELAY_3 580 #endif //#define POWER_MONITOR_VOLTAGE_PIN PC3 diff --git a/Marlin/src/pins/stm32f4/pins_XTLW_CLIMBER_8TH.h b/Marlin/src/pins/stm32f4/pins_XTLW_CLIMBER_8TH.h index 3ed778c16f..053fb19525 100644 --- a/Marlin/src/pins/stm32f4/pins_XTLW_CLIMBER_8TH.h +++ b/Marlin/src/pins/stm32f4/pins_XTLW_CLIMBER_8TH.h @@ -275,14 +275,8 @@ #endif // HAS_WIRED_LCD // Alter timing for graphical display -#if ENABLED(U8GLIB_ST7920) - #ifndef BOARD_ST7920_DELAY_1 - #define BOARD_ST7920_DELAY_1 120 - #endif - #ifndef BOARD_ST7920_DELAY_2 - #define BOARD_ST7920_DELAY_2 80 - #endif - #ifndef BOARD_ST7920_DELAY_3 - #define BOARD_ST7920_DELAY_3 580 - #endif +#if IS_U8GLIB_ST7920 + #define BOARD_ST7920_DELAY_1 120 + #define BOARD_ST7920_DELAY_2 80 + #define BOARD_ST7920_DELAY_3 580 #endif diff --git a/Marlin/src/pins/stm32g0/pins_BTT_MANTA_M4P_V2_1.h b/Marlin/src/pins/stm32g0/pins_BTT_MANTA_M4P_V2_1.h index 9c50f4b7d8..ec6784b3b5 100644 --- a/Marlin/src/pins/stm32g0/pins_BTT_MANTA_M4P_V2_1.h +++ b/Marlin/src/pins/stm32g0/pins_BTT_MANTA_M4P_V2_1.h @@ -282,15 +282,9 @@ // Alter timing for graphical display #if IS_U8GLIB_ST7920 - #ifndef BOARD_ST7920_DELAY_1 - #define BOARD_ST7920_DELAY_1 120 - #endif - #ifndef BOARD_ST7920_DELAY_2 - #define BOARD_ST7920_DELAY_2 80 - #endif - #ifndef BOARD_ST7920_DELAY_3 - #define BOARD_ST7920_DELAY_3 580 - #endif + #define BOARD_ST7920_DELAY_1 120 + #define BOARD_ST7920_DELAY_2 80 + #define BOARD_ST7920_DELAY_3 580 #endif // diff --git a/Marlin/src/pins/stm32g0/pins_BTT_MANTA_M5P_V1_0.h b/Marlin/src/pins/stm32g0/pins_BTT_MANTA_M5P_V1_0.h index dce4f87cdf..4ff278acc5 100644 --- a/Marlin/src/pins/stm32g0/pins_BTT_MANTA_M5P_V1_0.h +++ b/Marlin/src/pins/stm32g0/pins_BTT_MANTA_M5P_V1_0.h @@ -308,15 +308,9 @@ // Alter timing for graphical display #if IS_U8GLIB_ST7920 - #ifndef BOARD_ST7920_DELAY_1 - #define BOARD_ST7920_DELAY_1 120 - #endif - #ifndef BOARD_ST7920_DELAY_2 - #define BOARD_ST7920_DELAY_2 80 - #endif - #ifndef BOARD_ST7920_DELAY_3 - #define BOARD_ST7920_DELAY_3 580 - #endif + #define BOARD_ST7920_DELAY_1 120 + #define BOARD_ST7920_DELAY_2 80 + #define BOARD_ST7920_DELAY_3 580 #endif // diff --git a/Marlin/src/pins/stm32g0/pins_BTT_SKRAT_V1_0.h b/Marlin/src/pins/stm32g0/pins_BTT_SKRAT_V1_0.h index 5b3ff90f9e..2a112f34b1 100644 --- a/Marlin/src/pins/stm32g0/pins_BTT_SKRAT_V1_0.h +++ b/Marlin/src/pins/stm32g0/pins_BTT_SKRAT_V1_0.h @@ -518,15 +518,9 @@ // Alter timing for graphical display #if IS_U8GLIB_ST7920 - #ifndef BOARD_ST7920_DELAY_1 - #define BOARD_ST7920_DELAY_1 120 - #endif - #ifndef BOARD_ST7920_DELAY_2 - #define BOARD_ST7920_DELAY_2 80 - #endif - #ifndef BOARD_ST7920_DELAY_3 - #define BOARD_ST7920_DELAY_3 580 - #endif + #define BOARD_ST7920_DELAY_1 120 + #define BOARD_ST7920_DELAY_2 80 + #define BOARD_ST7920_DELAY_3 580 #endif #if HAS_SPI_TFT From 2cf4d02a32e717ef6b1d348fe0504aba15cafb23 Mon Sep 17 00:00:00 2001 From: ellensp <530024+ellensp@users.noreply.github.com> Date: Fri, 21 Mar 2025 15:03:14 +1300 Subject: [PATCH 140/787] =?UTF-8?q?=F0=9F=A9=B9=20Fix=20TOUCH=5FUI=5FFTDI?= =?UTF-8?q?=5FEVE=20build=20(#27667)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Followup to #27275 --- .../lcd/extui/ftdi_eve_touch_ui/generic/leveling_menu.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/leveling_menu.cpp b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/leveling_menu.cpp index ce281c685b..44e5341f64 100644 --- a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/leveling_menu.cpp +++ b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/leveling_menu.cpp @@ -70,6 +70,10 @@ using namespace Theme; #define BACK_POS BTN_POS(1,6), BTN_SIZE(3,1) #endif +#ifndef Z_ALIGN_COMMANDS + #define Z_ALIGN_COMMANDS "G34" +#endif + void LevelingMenu::onRedraw(draw_mode_t what) { if (what & BACKGROUND) { CommandProcessor cmd; @@ -116,7 +120,7 @@ bool LevelingMenu::onTouchEnd(uint8_t tag) { switch (tag) { case 1: GOTO_PREVIOUS(); break; #if ANY(Z_STEPPER_AUTO_ALIGN, MECHANICAL_GANTRY_CALIBRATION, X_LEVEL_SEQUENCE) - case 2: SpinnerDialogBox::enqueueAndWait(F(LEVELING_COMMANDS)); break; + case 2: SpinnerDialogBox::enqueueAndWait(F(Z_ALIGN_COMMANDS)); break; #endif #if HAS_BED_PROBE case 3: From c29b44fcca8562b20342ad81ba117c78ef39cf40 Mon Sep 17 00:00:00 2001 From: ellensp <530024+ellensp@users.noreply.github.com> Date: Fri, 21 Mar 2025 15:44:43 +1300 Subject: [PATCH 141/787] =?UTF-8?q?=F0=9F=A9=B9=20Fix=20Simulator=20KILL?= =?UTF-8?q?=20pin=20overlap=20(#27668)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/pins/native/pins_RAMPS_NATIVE.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/src/pins/native/pins_RAMPS_NATIVE.h b/Marlin/src/pins/native/pins_RAMPS_NATIVE.h index ffc716a502..b27b9c7b49 100644 --- a/Marlin/src/pins/native/pins_RAMPS_NATIVE.h +++ b/Marlin/src/pins/native/pins_RAMPS_NATIVE.h @@ -730,5 +730,5 @@ #endif // HAS_WIRED_LCD #ifndef KILL_PIN - #define KILL_PIN EXP2_08_PIN + #define KILL_PIN 11 #endif From a68b70de15282b2f15cb2e96e44ea31fd4b4eedd Mon Sep 17 00:00:00 2001 From: ellensp <530024+ellensp@users.noreply.github.com> Date: Fri, 21 Mar 2025 15:48:18 +1300 Subject: [PATCH 142/787] =?UTF-8?q?=F0=9F=93=8C=20Clean=20up=20ESP32=20bui?= =?UTF-8?q?ld=20(#27672)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/libs/numtostr.cpp | 4 +++- ini/esp32.ini | 2 +- ini/features.ini | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Marlin/src/libs/numtostr.cpp b/Marlin/src/libs/numtostr.cpp index b9503cb242..aa00b5d6e2 100644 --- a/Marlin/src/libs/numtostr.cpp +++ b/Marlin/src/libs/numtostr.cpp @@ -25,7 +25,9 @@ #include "../inc/MarlinConfigPre.h" #include "../core/utility.h" -#pragma GCC diagnostic ignored "-Wimplicit-fallthrough" +#if !ARDUINO_ARCH_ESP32 + #pragma GCC diagnostic ignored "-Wimplicit-fallthrough" +#endif constexpr char DIGIT(const uint8_t n) { return '0' + n; } diff --git a/ini/esp32.ini b/ini/esp32.ini index 4afaeaa030..f40b37ef14 100644 --- a/ini/esp32.ini +++ b/ini/esp32.ini @@ -45,7 +45,7 @@ extends = env:esp32 board = marlin_MKS_TinyBee platform = espressif32@~3.5.0 board_build.partitions = default_8MB.csv -build_src_flags = -O3 -Wno-volatile +build_src_flags = -O3 monitor_filters = esp32_exception_decoder [env:godi_esp32] diff --git a/ini/features.ini b/ini/features.ini index 49e0c5054e..f56175a3d6 100644 --- a/ini/features.ini +++ b/ini/features.ini @@ -375,7 +375,7 @@ IS_SCARA = build_src_filter=+ + MORGAN_SCARA = build_src_filter=+ HAS_MICROSTEPS = build_src_filter=+ -(ESP3D_)?WIFISUPPORT = AsyncTCP, ESP Async WebServer +(ESP3D_)?WIFISUPPORT = esp32async/AsyncTCP@3.3.3, mathieucarbou/ESP Async WebServer@3.0.6 ESP3DLib=https://github.com/luc-github/ESP3DLib/archive/dc0f3d96c6.zip arduinoWebSockets=links2004/WebSockets@2.3.4 luc-github/ESP32SSDP@1.1.1 From 363f324179b608d3be5eabcb0e964ee8a9d0b2ab Mon Sep 17 00:00:00 2001 From: Teemo Vaas Date: Fri, 22 Dec 2023 06:47:36 +0200 Subject: [PATCH 143/787] =?UTF-8?q?=F0=9F=9A=B8=20Fix=20G4=20Dwell=20overf?= =?UTF-8?q?low?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/core/millis_t.h | 5 ++++- Marlin/src/gcode/gcode.cpp | 8 ++++---- Marlin/src/gcode/gcode.h | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Marlin/src/core/millis_t.h b/Marlin/src/core/millis_t.h index e7032a2e55..7c00b91a5b 100644 --- a/Marlin/src/core/millis_t.h +++ b/Marlin/src/core/millis_t.h @@ -30,5 +30,8 @@ typedef uint32_t millis_t; #define MS_TO_SEC(N) millis_t((N)/1000UL) #define MS_TO_SEC_PRECISE(N) (float(N)/1000.0f) -#define PENDING(NOW,SOON) ((int32_t)(NOW-(SOON))<0) +#define FUTURE(START,DURA) (millis_t(millis()-(START))<(DURA)) +#define PAST(START,DURA) (!FUTURE(START,DURA)) + +#define PENDING(NOW,SOON) (int32_t((NOW)-(SOON))<0) #define ELAPSED(NOW,SOON) (!PENDING(NOW,SOON)) diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp index 881149fb52..69d77e875e 100644 --- a/Marlin/src/gcode/gcode.cpp +++ b/Marlin/src/gcode/gcode.cpp @@ -242,11 +242,11 @@ void GcodeSuite::get_destination_from_command() { } /** - * Dwell waits immediately. It does not synchronize. Use M400 instead of G4 + * Dwell waits immediately. It does not synchronize. */ -void GcodeSuite::dwell(millis_t time) { - time += millis(); - while (PENDING(millis(), time)) idle(); +void GcodeSuite::dwell(const millis_t time) { + const millis_t startMillis = millis(); + while (FUTURE(startMillis, time)) idle(); } /** diff --git a/Marlin/src/gcode/gcode.h b/Marlin/src/gcode/gcode.h index e86a58d85d..1f3ccba37c 100644 --- a/Marlin/src/gcode/gcode.h +++ b/Marlin/src/gcode/gcode.h @@ -503,7 +503,7 @@ public: #define KEEPALIVE_STATE(N) NOOP #endif - static void dwell(millis_t time); + static void dwell(const millis_t time); private: From 91a87f45d9d491a259446f439fe9a3ceadecbf87 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Fri, 21 Mar 2025 13:51:08 -0500 Subject: [PATCH 144/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Som?= =?UTF-8?q?e=20millis()=20'unsigned=20long'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/HAL/LINUX/arduino.cpp | 4 ++-- Marlin/src/HAL/LINUX/include/Arduino.h | 4 ++-- Marlin/src/HAL/LPC1768/u8g/LCD_I2C_routines.cpp | 2 +- Marlin/src/HAL/STM32F1/sdio.cpp | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Marlin/src/HAL/LINUX/arduino.cpp b/Marlin/src/HAL/LINUX/arduino.cpp index 0a48697a9c..a387a9623e 100644 --- a/Marlin/src/HAL/LINUX/arduino.cpp +++ b/Marlin/src/HAL/LINUX/arduino.cpp @@ -33,8 +33,8 @@ void sei() { } // Enable // Time functions void _delay_ms(const int ms) { delay(ms); } -uint32_t millis() { - return (uint32_t)Clock::millis(); +unsigned long millis() { + return (unsigned long)Clock::millis(); } // This is required for some Arduino libraries we are using diff --git a/Marlin/src/HAL/LINUX/include/Arduino.h b/Marlin/src/HAL/LINUX/include/Arduino.h index f05aaed880..b11e75ccbc 100644 --- a/Marlin/src/HAL/LINUX/include/Arduino.h +++ b/Marlin/src/HAL/LINUX/include/Arduino.h @@ -76,9 +76,9 @@ extern "C" { extern "C" void delay(const int ms); void _delay_ms(const int ms); void delayMicroseconds(unsigned long); -uint32_t millis(); +unsigned long millis(); -//IO functions +// IO functions void pinMode(const pin_t, const uint8_t); void digitalWrite(pin_t, uint8_t); bool digitalRead(pin_t); diff --git a/Marlin/src/HAL/LPC1768/u8g/LCD_I2C_routines.cpp b/Marlin/src/HAL/LPC1768/u8g/LCD_I2C_routines.cpp index e714c3c16d..09603de972 100644 --- a/Marlin/src/HAL/LPC1768/u8g/LCD_I2C_routines.cpp +++ b/Marlin/src/HAL/LPC1768/u8g/LCD_I2C_routines.cpp @@ -28,7 +28,7 @@ #include "../include/i2c_util.h" #include "../../../core/millis_t.h" -extern int millis(); +uint32_t millis(); #ifdef __cplusplus extern "C" { diff --git a/Marlin/src/HAL/STM32F1/sdio.cpp b/Marlin/src/HAL/STM32F1/sdio.cpp index 23f984eff3..5bb1ddb6c5 100644 --- a/Marlin/src/HAL/STM32F1/sdio.cpp +++ b/Marlin/src/HAL/STM32F1/sdio.cpp @@ -145,7 +145,7 @@ bool SDIO_ReadBlock(uint32_t blockAddress, uint8_t *data) { return false; } -uint32_t millis(); +unsigned long millis(); bool SDIO_WriteBlock(uint32_t blockAddress, const uint8_t *data) { if (SDIO_GetCardState() != SDIO_CARD_TRANSFER) return false; From 14fa7057718acbed8d0e4238f2eba9b9f645db64 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Sat, 22 Mar 2025 00:28:38 +0000 Subject: [PATCH 145/787] [cron] Bump distribution date (2025-03-22) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index a1aa9e6164..f31c7298a1 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-03-21" +//#define STRING_DISTRIBUTION_DATE "2025-03-22" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index ce3bc61e5c..a24628c209 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-03-21" + #define STRING_DISTRIBUTION_DATE "2025-03-22" #endif /** From 1701fd8f641757fa752acf40a6a1a7bdc4d572d4 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 25 Mar 2025 16:39:09 -0500 Subject: [PATCH 146/787] =?UTF-8?q?=F0=9F=94=A5=20DELTA=5FMAX=5FRADIUS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/Configuration.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 1202bc1e53..9a96169646 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -1025,9 +1025,6 @@ // Print surface diameter/2 minus unreachable space (avoid collisions with vertical towers). #define PRINTABLE_RADIUS 140.0 // (mm) - // Maximum reachable area - #define DELTA_MAX_RADIUS 140.0 // (mm) - // Center-to-center distance of the holes in the diagonal push rods. #define DELTA_DIAGONAL_ROD 250.0 // (mm) From a8fea3d67451ef9b0593b2d790ad92cad0a5f9a8 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 25 Mar 2025 16:41:40 -0500 Subject: [PATCH 147/787] =?UTF-8?q?=F0=9F=A9=B9=20Cleanup=20(for=20STM32?= =?UTF-8?q?=20I2C=20LCD)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Followup to 9a8b1eab --- Marlin/src/pins/stm32f1/pins_BTT_SKR_E3_DIP.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Marlin/src/pins/stm32f1/pins_BTT_SKR_E3_DIP.h b/Marlin/src/pins/stm32f1/pins_BTT_SKR_E3_DIP.h index 06c7cacc5b..9c7c8148cb 100644 --- a/Marlin/src/pins/stm32f1/pins_BTT_SKR_E3_DIP.h +++ b/Marlin/src/pins/stm32f1/pins_BTT_SKR_E3_DIP.h @@ -302,9 +302,9 @@ #elif ENABLED(ULTI_CONTROLLER) - #define LCD_PINS_D6 EXP1_03_PIN - #define DOGLCD_SCL_PIN EXP1_07_PIN // I2C1 - #define DOGLCD_SDA_PIN EXP1_08_PIN // I2C1 + #define LCD_PINS_D6 EXP1_03_PIN + #define DOGLCD_SCL_PIN EXP1_07_PIN // I2C1 + #define DOGLCD_SDA_PIN EXP1_08_PIN // I2C1 #else #error "Only CR10_STOCKDISPLAY, ZONESTAR_LCD, ENDER2_STOCKDISPLAY, ULTI_CONTROLLER, MKS_MINI_12864, FYSETC_MINI_12864_2_1 and MKS_LCD12864A/B are currently supported on the SKR E3 DIP." From dda42fb599d17fd049ee38a95b4e80dc95c9cbd2 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Wed, 26 Mar 2025 00:29:30 +0000 Subject: [PATCH 148/787] [cron] Bump distribution date (2025-03-26) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index f31c7298a1..18f9ce19e8 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-03-22" +//#define STRING_DISTRIBUTION_DATE "2025-03-26" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index a24628c209..0d24f4c508 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-03-22" + #define STRING_DISTRIBUTION_DATE "2025-03-26" #endif /** From ac5fa61de5775b54e1a9f4dc9ad8a7583ef93996 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Thu, 27 Mar 2025 02:25:43 -0500 Subject: [PATCH 149/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Mor?= =?UTF-8?q?e=20robust=20TERN=5F=20macro?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/core/macros.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Marlin/src/core/macros.h b/Marlin/src/core/macros.h index 21d9929bc5..344ab04e74 100644 --- a/Marlin/src/core/macros.h +++ b/Marlin/src/core/macros.h @@ -206,19 +206,23 @@ #define TERN(O,A,B) _TERN(_ENA_1(O),B,A) // OPTION ? 'A' : 'B' #define TERN0(O,A) _TERN(_ENA_1(O),0,A) // OPTION ? 'A' : '0' #define TERN1(O,A) _TERN(_ENA_1(O),1,A) // OPTION ? 'A' : '1' -#define TERN_(O,A) _TERN(_ENA_1(O),,A) // OPTION ? 'A' : '' #define _TERN(E,V...) __TERN(_CAT(T_,E),V) // Prepend 'T_' to get 'T_0' or 'T_1' #define __TERN(T,V...) ___TERN(_CAT(_NO,T),V) // Prepend '_NO' to get '_NOT_0' or '_NOT_1' #define ___TERN(P,V...) THIRD(P,V) // If first argument has a comma, A. Else B. #define IF_DISABLED(O,A) TERN(O,,A) +// "Ternary" that emits or omits the given content +#define EMIT(V...) V +#define OMIT(...) +#define TERN_(O,A) _TERN(_ENA_1(O),OMIT,EMIT)(A) // OPTION ? 'A' : '' + // Macros to conditionally emit array items and function arguments #define _OPTITEM(A...) A, -#define OPTITEM(O,A...) TERN_(O,DEFER4(_OPTITEM)(A)) +#define OPTITEM(O,A...) TERN_(O,DEFER(_OPTITEM)(A)) #define _OPTARG(A...) , A -#define OPTARG(O,A...) TERN_(O,DEFER4(_OPTARG)(A)) +#define OPTARG(O,A...) TERN_(O,DEFER(_OPTARG)(A)) #define _OPTCODE(A) A; -#define OPTCODE(O,A) TERN_(O,DEFER4(_OPTCODE)(A)) +#define OPTCODE(O,A) TERN_(O,DEFER(_OPTCODE)(A)) // Macros to avoid operations that aren't always optimized away (e.g., 'f + 0.0' and 'f * 1.0'). // Compiler flags -fno-signed-zeros -ffinite-math-only also cover 'f * 1.0', 'f - f', etc. From add72fd0452addb13ac7c1fea7d7476dd991cd93 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Thu, 27 Mar 2025 02:29:11 -0500 Subject: [PATCH 150/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Ind?= =?UTF-8?q?ividual=20TMC=20flags?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/feature/digipot/digipot_mcp4451.cpp | 8 +- Marlin/src/feature/tmc_util.cpp | 481 +++++------------- Marlin/src/gcode/calibrate/G28.cpp | 12 +- Marlin/src/gcode/calibrate/G34.cpp | 49 +- Marlin/src/gcode/feature/trinamic/M906.cpp | 251 +++------ .../src/gcode/feature/trinamic/M911-M914.cpp | 176 +++---- Marlin/src/gcode/feature/trinamic/M919.cpp | 157 ++---- Marlin/src/gcode/gcode.cpp | 1 + Marlin/src/gcode/gcode.h | 15 +- Marlin/src/inc/Conditionals-4-adv.h | 69 ++- Marlin/src/inc/Conditionals-5-post.h | 88 ++-- Marlin/src/inc/Conditionals-6-type.h | 47 +- Marlin/src/inc/SanityCheck.h | 22 +- Marlin/src/inc/Warnings.cpp | 32 +- Marlin/src/lcd/e3v2/jyersui/dwin.cpp | 8 +- Marlin/src/lcd/e3v2/proui/dwin.cpp | 39 +- .../src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp | 16 +- .../lcd/extui/dgus/mks/DGUSScreenHandler.cpp | 16 +- .../generic/stepper_current_screen.cpp | 68 +-- .../src/lcd/extui/mks_ui/draw_number_key.cpp | 52 +- .../mks_ui/draw_tmc_current_settings.cpp | 71 +-- Marlin/src/lcd/extui/ui_api.cpp | 232 +++------ Marlin/src/lcd/menu/menu_tmc.cpp | 80 +-- Marlin/src/lcd/sovol_rts/sovol_rts.cpp | 57 +-- Marlin/src/module/motion.cpp | 344 +++---------- Marlin/src/module/motion.h | 3 + Marlin/src/module/settings.cpp | 176 ++----- Marlin/src/module/stepper.cpp | 124 ++--- Marlin/src/module/stepper/indirection.h | 204 ++------ Marlin/src/module/stepper/trinamic.cpp | 194 ++----- Marlin/src/module/stepper/trinamic.h | 44 +- 31 files changed, 958 insertions(+), 2178 deletions(-) diff --git a/Marlin/src/feature/digipot/digipot_mcp4451.cpp b/Marlin/src/feature/digipot/digipot_mcp4451.cpp index e35b42a28b..156755856c 100644 --- a/Marlin/src/feature/digipot/digipot_mcp4451.cpp +++ b/Marlin/src/feature/digipot/digipot_mcp4451.cpp @@ -87,13 +87,7 @@ void DigipotI2C::init() { Wire.begin(); #endif // Set up initial currents as defined in Configuration_adv.h - static const float digipot_motor_current[] PROGMEM = - #if ENABLED(DIGIPOT_USE_RAW_VALUES) - DIGIPOT_MOTOR_CURRENT - #else - DIGIPOT_I2C_MOTOR_CURRENTS - #endif - ; + static const float digipot_motor_current[] PROGMEM = TERN(DIGIPOT_USE_RAW_VALUES, DIGIPOT_MOTOR_CURRENT, DIGIPOT_I2C_MOTOR_CURRENTS); for (uint8_t i = 0; i < COUNT(digipot_motor_current); ++i) set_current(i, pgm_read_float(&digipot_motor_current[i])); } diff --git a/Marlin/src/feature/tmc_util.cpp b/Marlin/src/feature/tmc_util.cpp index 6afbf4a0ce..62972eb7f5 100644 --- a/Marlin/src/feature/tmc_util.cpp +++ b/Marlin/src/feature/tmc_util.cpp @@ -344,127 +344,70 @@ if (need_update_error_counters || need_debug_reporting) { - #if AXIS_IS_TMC(X) || AXIS_IS_TMC(X2) - { - bool result = false; - #if AXIS_IS_TMC(X) - if (monitor_tmc_driver(stepperX, need_update_error_counters, need_debug_reporting)) result = true; - #endif - #if AXIS_IS_TMC(X2) - if (monitor_tmc_driver(stepperX2, need_update_error_counters, need_debug_reporting)) result = true; - #endif - if (result) { - #if AXIS_IS_TMC(X) - step_current_down(stepperX); - #endif - #if AXIS_IS_TMC(X2) - step_current_down(stepperX2); - #endif + #if X_IS_TRINAMIC || X2_IS_TRINAMIC + if ( TERN0(X_IS_TRINAMIC, monitor_tmc_driver(stepperX, need_update_error_counters, need_debug_reporting)) + || TERN0(X2_IS_TRINAMIC, monitor_tmc_driver(stepperX2, need_update_error_counters, need_debug_reporting)) + ) { + TERN_(X_IS_TRINAMIC, step_current_down(stepperX)); + TERN_(X2_IS_TRINAMIC, step_current_down(stepperX2)); } - } #endif - #if AXIS_IS_TMC(Y) || AXIS_IS_TMC(Y2) - { - bool result = false; - #if AXIS_IS_TMC(Y) - if (monitor_tmc_driver(stepperY, need_update_error_counters, need_debug_reporting)) result = true; - #endif - #if AXIS_IS_TMC(Y2) - if (monitor_tmc_driver(stepperY2, need_update_error_counters, need_debug_reporting)) result = true; - #endif - if (result) { - #if AXIS_IS_TMC(Y) - step_current_down(stepperY); - #endif - #if AXIS_IS_TMC(Y2) - step_current_down(stepperY2); - #endif + #if Y_IS_TRINAMIC || Y2_IS_TRINAMIC + if ( TERN0(Y_IS_TRINAMIC, monitor_tmc_driver(stepperY, need_update_error_counters, need_debug_reporting)) + || TERN0(Y2_IS_TRINAMIC, monitor_tmc_driver(stepperY2, need_update_error_counters, need_debug_reporting)) + ) { + TERN_(Y_IS_TRINAMIC, step_current_down(stepperY)); + TERN_(Y2_IS_TRINAMIC, step_current_down(stepperY2)); } - } #endif - #if AXIS_IS_TMC(Z) || AXIS_IS_TMC(Z2) || AXIS_IS_TMC(Z3) || AXIS_IS_TMC(Z4) - { - bool result = false; - #if AXIS_IS_TMC(Z) - if (monitor_tmc_driver(stepperZ, need_update_error_counters, need_debug_reporting)) result = true; - #endif - #if AXIS_IS_TMC(Z2) - if (monitor_tmc_driver(stepperZ2, need_update_error_counters, need_debug_reporting)) result = true; - #endif - #if AXIS_IS_TMC(Z3) - if (monitor_tmc_driver(stepperZ3, need_update_error_counters, need_debug_reporting)) result = true; - #endif - #if AXIS_IS_TMC(Z4) - if (monitor_tmc_driver(stepperZ4, need_update_error_counters, need_debug_reporting)) result = true; - #endif - if (result) { - #if AXIS_IS_TMC(Z) - step_current_down(stepperZ); - #endif - #if AXIS_IS_TMC(Z2) - step_current_down(stepperZ2); - #endif - #if AXIS_IS_TMC(Z3) - step_current_down(stepperZ3); - #endif - #if AXIS_IS_TMC(Z4) - step_current_down(stepperZ4); - #endif + #if ANY(Z_IS_TRINAMIC, Z2_IS_TRINAMIC, Z3_IS_TRINAMIC, Z4_IS_TRINAMIC) + if ( TERN0(Z_IS_TRINAMIC, monitor_tmc_driver(stepperZ, need_update_error_counters, need_debug_reporting)) + || TERN0(Z2_IS_TRINAMIC, monitor_tmc_driver(stepperZ2, need_update_error_counters, need_debug_reporting)) + || TERN0(Z3_IS_TRINAMIC, monitor_tmc_driver(stepperZ3, need_update_error_counters, need_debug_reporting)) + || TERN0(Z4_IS_TRINAMIC, monitor_tmc_driver(stepperZ4, need_update_error_counters, need_debug_reporting)) + ) { + TERN_(Z_IS_TRINAMIC, step_current_down(stepperZ)); + TERN_(Z2_IS_TRINAMIC, step_current_down(stepperZ2)); + TERN_(Z3_IS_TRINAMIC, step_current_down(stepperZ3)); + TERN_(Z4_IS_TRINAMIC, step_current_down(stepperZ4)); } - } #endif - #if AXIS_IS_TMC(I) + #if I_IS_TRINAMIC if (monitor_tmc_driver(stepperI, need_update_error_counters, need_debug_reporting)) step_current_down(stepperI); #endif - #if AXIS_IS_TMC(J) + #if J_IS_TRINAMIC if (monitor_tmc_driver(stepperJ, need_update_error_counters, need_debug_reporting)) step_current_down(stepperJ); #endif - #if AXIS_IS_TMC(K) + #if K_IS_TRINAMIC if (monitor_tmc_driver(stepperK, need_update_error_counters, need_debug_reporting)) step_current_down(stepperK); #endif - #if AXIS_IS_TMC(U) + #if U_IS_TRINAMIC if (monitor_tmc_driver(stepperU, need_update_error_counters, need_debug_reporting)) step_current_down(stepperU); #endif - #if AXIS_IS_TMC(V) + #if V_IS_TRINAMIC if (monitor_tmc_driver(stepperV, need_update_error_counters, need_debug_reporting)) step_current_down(stepperV); #endif - #if AXIS_IS_TMC(W) + #if W_IS_TRINAMIC if (monitor_tmc_driver(stepperW, need_update_error_counters, need_debug_reporting)) step_current_down(stepperW); #endif - #if AXIS_IS_TMC(E0) - (void)monitor_tmc_driver(stepperE0, need_update_error_counters, need_debug_reporting); - #endif - #if AXIS_IS_TMC(E1) - (void)monitor_tmc_driver(stepperE1, need_update_error_counters, need_debug_reporting); - #endif - #if AXIS_IS_TMC(E2) - (void)monitor_tmc_driver(stepperE2, need_update_error_counters, need_debug_reporting); - #endif - #if AXIS_IS_TMC(E3) - (void)monitor_tmc_driver(stepperE3, need_update_error_counters, need_debug_reporting); - #endif - #if AXIS_IS_TMC(E4) - (void)monitor_tmc_driver(stepperE4, need_update_error_counters, need_debug_reporting); - #endif - #if AXIS_IS_TMC(E5) - (void)monitor_tmc_driver(stepperE5, need_update_error_counters, need_debug_reporting); - #endif - #if AXIS_IS_TMC(E6) - (void)monitor_tmc_driver(stepperE6, need_update_error_counters, need_debug_reporting); - #endif - #if AXIS_IS_TMC(E7) - (void)monitor_tmc_driver(stepperE7, need_update_error_counters, need_debug_reporting); - #endif + TERN_(E0_IS_TRINAMIC, (void)monitor_tmc_driver(stepperE0, need_update_error_counters, need_debug_reporting)); + TERN_(E1_IS_TRINAMIC, (void)monitor_tmc_driver(stepperE1, need_update_error_counters, need_debug_reporting)); + TERN_(E2_IS_TRINAMIC, (void)monitor_tmc_driver(stepperE2, need_update_error_counters, need_debug_reporting)); + TERN_(E3_IS_TRINAMIC, (void)monitor_tmc_driver(stepperE3, need_update_error_counters, need_debug_reporting)); + TERN_(E4_IS_TRINAMIC, (void)monitor_tmc_driver(stepperE4, need_update_error_counters, need_debug_reporting)); + TERN_(E5_IS_TRINAMIC, (void)monitor_tmc_driver(stepperE5, need_update_error_counters, need_debug_reporting)); + TERN_(E6_IS_TRINAMIC, (void)monitor_tmc_driver(stepperE6, need_update_error_counters, need_debug_reporting)); + TERN_(E7_IS_TRINAMIC, (void)monitor_tmc_driver(stepperE7, need_update_error_counters, need_debug_reporting)); if (TERN0(TMC_DEBUG, need_debug_reporting)) SERIAL_EOL(); } @@ -781,82 +724,38 @@ static void tmc_debug_loop(const TMC_debug_enum n OPTARGS_LOGICAL(const bool)) { if (TERN0(HAS_X_AXIS, x)) { - #if AXIS_IS_TMC(X) - tmc_status(stepperX, n); - #endif - #if AXIS_IS_TMC(X2) - tmc_status(stepperX2, n); - #endif + TERN_(X_IS_TRINAMIC, tmc_status(stepperX, n)); + TERN_(X2_IS_TRINAMIC, tmc_status(stepperX2, n)); } if (TERN0(HAS_Y_AXIS, y)) { - #if AXIS_IS_TMC(Y) - tmc_status(stepperY, n); - #endif - #if AXIS_IS_TMC(Y2) - tmc_status(stepperY2, n); - #endif + TERN_(Y_IS_TRINAMIC, tmc_status(stepperY, n)); + TERN_(Y2_IS_TRINAMIC, tmc_status(stepperY2, n)); } if (TERN0(HAS_Z_AXIS, z)) { - #if AXIS_IS_TMC(Z) - tmc_status(stepperZ, n); - #endif - #if AXIS_IS_TMC(Z2) - tmc_status(stepperZ2, n); - #endif - #if AXIS_IS_TMC(Z3) - tmc_status(stepperZ3, n); - #endif - #if AXIS_IS_TMC(Z4) - tmc_status(stepperZ4, n); - #endif + TERN_(Z_IS_TRINAMIC, tmc_status(stepperZ, n)); + TERN_(Z2_IS_TRINAMIC, tmc_status(stepperZ2, n)); + TERN_(Z3_IS_TRINAMIC, tmc_status(stepperZ3, n)); + TERN_(Z4_IS_TRINAMIC, tmc_status(stepperZ4, n)); } - #if AXIS_IS_TMC(I) - if (i) tmc_status(stepperI, n); - #endif - #if AXIS_IS_TMC(J) - if (j) tmc_status(stepperJ, n); - #endif - #if AXIS_IS_TMC(K) - if (k) tmc_status(stepperK, n); - #endif - #if AXIS_IS_TMC(U) - if (u) tmc_status(stepperU, n); - #endif - #if AXIS_IS_TMC(V) - if (v) tmc_status(stepperV, n); - #endif - #if AXIS_IS_TMC(W) - if (w) tmc_status(stepperW, n); - #endif + TERN_(I_IS_TRINAMIC, if (i) tmc_status(stepperI, n)); + TERN_(J_IS_TRINAMIC, if (j) tmc_status(stepperJ, n)); + TERN_(K_IS_TRINAMIC, if (k) tmc_status(stepperK, n)); + TERN_(U_IS_TRINAMIC, if (u) tmc_status(stepperU, n)); + TERN_(V_IS_TRINAMIC, if (v) tmc_status(stepperV, n)); + TERN_(W_IS_TRINAMIC, if (w) tmc_status(stepperW, n)); if (TERN0(HAS_EXTRUDERS, e)) { - #if AXIS_IS_TMC(E0) - tmc_status(stepperE0, n); - #endif - #if AXIS_IS_TMC(E1) - tmc_status(stepperE1, n); - #endif - #if AXIS_IS_TMC(E2) - tmc_status(stepperE2, n); - #endif - #if AXIS_IS_TMC(E3) - tmc_status(stepperE3, n); - #endif - #if AXIS_IS_TMC(E4) - tmc_status(stepperE4, n); - #endif - #if AXIS_IS_TMC(E5) - tmc_status(stepperE5, n); - #endif - #if AXIS_IS_TMC(E6) - tmc_status(stepperE6, n); - #endif - #if AXIS_IS_TMC(E7) - tmc_status(stepperE7, n); - #endif + TERN_(E0_IS_TRINAMIC, tmc_status(stepperE0, n)); + TERN_(E1_IS_TRINAMIC, tmc_status(stepperE1, n)); + TERN_(E2_IS_TRINAMIC, tmc_status(stepperE2, n)); + TERN_(E3_IS_TRINAMIC, tmc_status(stepperE3, n)); + TERN_(E4_IS_TRINAMIC, tmc_status(stepperE4, n)); + TERN_(E5_IS_TRINAMIC, tmc_status(stepperE5, n)); + TERN_(E6_IS_TRINAMIC, tmc_status(stepperE6, n)); + TERN_(E7_IS_TRINAMIC, tmc_status(stepperE7, n)); } SERIAL_EOL(); @@ -864,82 +763,38 @@ static void drv_status_loop(const TMC_drv_status_enum n OPTARGS_LOGICAL(const bool)) { if (TERN0(HAS_X_AXIS, x)) { - #if AXIS_IS_TMC(X) - tmc_parse_drv_status(stepperX, n); - #endif - #if AXIS_IS_TMC(X2) - tmc_parse_drv_status(stepperX2, n); - #endif + TERN_(X_IS_TRINAMIC, tmc_parse_drv_status(stepperX, n)); + TERN_(X2_IS_TRINAMIC, tmc_parse_drv_status(stepperX2, n)); } if (TERN0(HAS_Y_AXIS, y)) { - #if AXIS_IS_TMC(Y) - tmc_parse_drv_status(stepperY, n); - #endif - #if AXIS_IS_TMC(Y2) - tmc_parse_drv_status(stepperY2, n); - #endif + TERN_(Y_IS_TRINAMIC, tmc_parse_drv_status(stepperY, n)); + TERN_(Y2_IS_TRINAMIC, tmc_parse_drv_status(stepperY2, n)); } if (TERN0(HAS_Z_AXIS, z)) { - #if AXIS_IS_TMC(Z) - tmc_parse_drv_status(stepperZ, n); - #endif - #if AXIS_IS_TMC(Z2) - tmc_parse_drv_status(stepperZ2, n); - #endif - #if AXIS_IS_TMC(Z3) - tmc_parse_drv_status(stepperZ3, n); - #endif - #if AXIS_IS_TMC(Z4) - tmc_parse_drv_status(stepperZ4, n); - #endif + TERN_(Z_IS_TRINAMIC, tmc_parse_drv_status(stepperZ, n)); + TERN_(Z2_IS_TRINAMIC, tmc_parse_drv_status(stepperZ2, n)); + TERN_(Z3_IS_TRINAMIC, tmc_parse_drv_status(stepperZ3, n)); + TERN_(Z4_IS_TRINAMIC, tmc_parse_drv_status(stepperZ4, n)); } - #if AXIS_IS_TMC(I) - if (i) tmc_parse_drv_status(stepperI, n); - #endif - #if AXIS_IS_TMC(J) - if (j) tmc_parse_drv_status(stepperJ, n); - #endif - #if AXIS_IS_TMC(K) - if (k) tmc_parse_drv_status(stepperK, n); - #endif - #if AXIS_IS_TMC(U) - if (u) tmc_parse_drv_status(stepperU, n); - #endif - #if AXIS_IS_TMC(V) - if (v) tmc_parse_drv_status(stepperV, n); - #endif - #if AXIS_IS_TMC(W) - if (w) tmc_parse_drv_status(stepperW, n); - #endif + TERN_(I_IS_TRINAMIC, if (i) tmc_parse_drv_status(stepperI, n)); + TERN_(J_IS_TRINAMIC, if (j) tmc_parse_drv_status(stepperJ, n)); + TERN_(K_IS_TRINAMIC, if (k) tmc_parse_drv_status(stepperK, n)); + TERN_(U_IS_TRINAMIC, if (u) tmc_parse_drv_status(stepperU, n)); + TERN_(V_IS_TRINAMIC, if (v) tmc_parse_drv_status(stepperV, n)); + TERN_(W_IS_TRINAMIC, if (w) tmc_parse_drv_status(stepperW, n)); if (TERN0(HAS_EXTRUDERS, e)) { - #if AXIS_IS_TMC(E0) - tmc_parse_drv_status(stepperE0, n); - #endif - #if AXIS_IS_TMC(E1) - tmc_parse_drv_status(stepperE1, n); - #endif - #if AXIS_IS_TMC(E2) - tmc_parse_drv_status(stepperE2, n); - #endif - #if AXIS_IS_TMC(E3) - tmc_parse_drv_status(stepperE3, n); - #endif - #if AXIS_IS_TMC(E4) - tmc_parse_drv_status(stepperE4, n); - #endif - #if AXIS_IS_TMC(E5) - tmc_parse_drv_status(stepperE5, n); - #endif - #if AXIS_IS_TMC(E6) - tmc_parse_drv_status(stepperE6, n); - #endif - #if AXIS_IS_TMC(E7) - tmc_parse_drv_status(stepperE7, n); - #endif + TERN_(E0_IS_TRINAMIC, tmc_parse_drv_status(stepperE0, n)); + TERN_(E1_IS_TRINAMIC, tmc_parse_drv_status(stepperE1, n)); + TERN_(E2_IS_TRINAMIC, tmc_parse_drv_status(stepperE2, n)); + TERN_(E3_IS_TRINAMIC, tmc_parse_drv_status(stepperE3, n)); + TERN_(E4_IS_TRINAMIC, tmc_parse_drv_status(stepperE4, n)); + TERN_(E5_IS_TRINAMIC, tmc_parse_drv_status(stepperE5, n)); + TERN_(E6_IS_TRINAMIC, tmc_parse_drv_status(stepperE6, n)); + TERN_(E7_IS_TRINAMIC, tmc_parse_drv_status(stepperE7, n)); } SERIAL_EOL(); @@ -1078,82 +933,38 @@ static void tmc_get_registers(TMC_get_registers_enum n OPTARGS_LOGICAL(const bool)) { if (TERN0(HAS_X_AXIS, x)) { - #if AXIS_IS_TMC(X) - tmc_get_registers(stepperX, n); - #endif - #if AXIS_IS_TMC(X2) - tmc_get_registers(stepperX2, n); - #endif + TERN_(X_IS_TRINAMIC, tmc_get_registers(stepperX, n)); + TERN_(X2_IS_TRINAMIC, tmc_get_registers(stepperX2, n)); } if (TERN0(HAS_Y_AXIS, y)) { - #if AXIS_IS_TMC(Y) - tmc_get_registers(stepperY, n); - #endif - #if AXIS_IS_TMC(Y2) - tmc_get_registers(stepperY2, n); - #endif + TERN_(Y_IS_TRINAMIC, tmc_get_registers(stepperY, n)); + TERN_(Y2_IS_TRINAMIC, tmc_get_registers(stepperY2, n)); } if (TERN0(HAS_Z_AXIS, z)) { - #if AXIS_IS_TMC(Z) - tmc_get_registers(stepperZ, n); - #endif - #if AXIS_IS_TMC(Z2) - tmc_get_registers(stepperZ2, n); - #endif - #if AXIS_IS_TMC(Z3) - tmc_get_registers(stepperZ3, n); - #endif - #if AXIS_IS_TMC(Z4) - tmc_get_registers(stepperZ4, n); - #endif + TERN_(Z_IS_TRINAMIC, tmc_get_registers(stepperZ, n)); + TERN_(Z2_IS_TRINAMIC, tmc_get_registers(stepperZ2, n)); + TERN_(Z3_IS_TRINAMIC, tmc_get_registers(stepperZ3, n)); + TERN_(Z4_IS_TRINAMIC, tmc_get_registers(stepperZ4, n)); } - #if AXIS_IS_TMC(I) - if (i) tmc_get_registers(stepperI, n); - #endif - #if AXIS_IS_TMC(J) - if (j) tmc_get_registers(stepperJ, n); - #endif - #if AXIS_IS_TMC(K) - if (k) tmc_get_registers(stepperK, n); - #endif - #if AXIS_IS_TMC(U) - if (u) tmc_get_registers(stepperU, n); - #endif - #if AXIS_IS_TMC(V) - if (v) tmc_get_registers(stepperV, n); - #endif - #if AXIS_IS_TMC(W) - if (w) tmc_get_registers(stepperW, n); - #endif + TERN_(I_IS_TRINAMIC, if (i) tmc_get_registers(stepperI, n)); + TERN_(J_IS_TRINAMIC, if (j) tmc_get_registers(stepperJ, n)); + TERN_(K_IS_TRINAMIC, if (k) tmc_get_registers(stepperK, n)); + TERN_(U_IS_TRINAMIC, if (u) tmc_get_registers(stepperU, n)); + TERN_(V_IS_TRINAMIC, if (v) tmc_get_registers(stepperV, n)); + TERN_(W_IS_TRINAMIC, if (w) tmc_get_registers(stepperW, n)); if (TERN0(HAS_EXTRUDERS, e)) { - #if AXIS_IS_TMC(E0) - tmc_get_registers(stepperE0, n); - #endif - #if AXIS_IS_TMC(E1) - tmc_get_registers(stepperE1, n); - #endif - #if AXIS_IS_TMC(E2) - tmc_get_registers(stepperE2, n); - #endif - #if AXIS_IS_TMC(E3) - tmc_get_registers(stepperE3, n); - #endif - #if AXIS_IS_TMC(E4) - tmc_get_registers(stepperE4, n); - #endif - #if AXIS_IS_TMC(E5) - tmc_get_registers(stepperE5, n); - #endif - #if AXIS_IS_TMC(E6) - tmc_get_registers(stepperE6, n); - #endif - #if AXIS_IS_TMC(E7) - tmc_get_registers(stepperE7, n); - #endif + TERN_(E0_IS_TRINAMIC, tmc_get_registers(stepperE0, n)); + TERN_(E1_IS_TRINAMIC, tmc_get_registers(stepperE1, n)); + TERN_(E2_IS_TRINAMIC, tmc_get_registers(stepperE2, n)); + TERN_(E3_IS_TRINAMIC, tmc_get_registers(stepperE3, n)); + TERN_(E4_IS_TRINAMIC, tmc_get_registers(stepperE4, n)); + TERN_(E5_IS_TRINAMIC, tmc_get_registers(stepperE5, n)); + TERN_(E6_IS_TRINAMIC, tmc_get_registers(stepperE6, n)); + TERN_(E7_IS_TRINAMIC, tmc_get_registers(stepperE7, n)); } SERIAL_EOL(); @@ -1243,82 +1054,38 @@ void test_tmc_connection(LOGICAL_AXIS_ARGS_LC(const bool)) { uint8_t axis_connection = 0; if (TERN0(HAS_X_AXIS, x)) { - #if AXIS_IS_TMC(X) - axis_connection += test_connection(stepperX); - #endif - #if AXIS_IS_TMC(X2) - axis_connection += test_connection(stepperX2); - #endif + TERN_(X_IS_TRINAMIC, axis_connection += test_connection(stepperX)); + TERN_(X2_IS_TRINAMIC, axis_connection += test_connection(stepperX2)); } if (TERN0(HAS_Y_AXIS, y)) { - #if AXIS_IS_TMC(Y) - axis_connection += test_connection(stepperY); - #endif - #if AXIS_IS_TMC(Y2) - axis_connection += test_connection(stepperY2); - #endif + TERN_(Y_IS_TRINAMIC, axis_connection += test_connection(stepperY)); + TERN_(Y2_IS_TRINAMIC, axis_connection += test_connection(stepperY2)); } if (TERN0(HAS_Z_AXIS, z)) { - #if AXIS_IS_TMC(Z) - axis_connection += test_connection(stepperZ); - #endif - #if AXIS_IS_TMC(Z2) - axis_connection += test_connection(stepperZ2); - #endif - #if AXIS_IS_TMC(Z3) - axis_connection += test_connection(stepperZ3); - #endif - #if AXIS_IS_TMC(Z4) - axis_connection += test_connection(stepperZ4); - #endif + TERN_(Z_IS_TRINAMIC, axis_connection += test_connection(stepperZ)); + TERN_(Z2_IS_TRINAMIC, axis_connection += test_connection(stepperZ2)); + TERN_(Z3_IS_TRINAMIC, axis_connection += test_connection(stepperZ3)); + TERN_(Z4_IS_TRINAMIC, axis_connection += test_connection(stepperZ4)); } - #if AXIS_IS_TMC(I) - if (i) axis_connection += test_connection(stepperI); - #endif - #if AXIS_IS_TMC(J) - if (j) axis_connection += test_connection(stepperJ); - #endif - #if AXIS_IS_TMC(K) - if (k) axis_connection += test_connection(stepperK); - #endif - #if AXIS_IS_TMC(U) - if (u) axis_connection += test_connection(stepperU); - #endif - #if AXIS_IS_TMC(V) - if (v) axis_connection += test_connection(stepperV); - #endif - #if AXIS_IS_TMC(W) - if (w) axis_connection += test_connection(stepperW); - #endif + TERN_(I_IS_TRINAMIC, if (i) axis_connection += test_connection(stepperI)); + TERN_(J_IS_TRINAMIC, if (j) axis_connection += test_connection(stepperJ)); + TERN_(K_IS_TRINAMIC, if (k) axis_connection += test_connection(stepperK)); + TERN_(U_IS_TRINAMIC, if (u) axis_connection += test_connection(stepperU)); + TERN_(V_IS_TRINAMIC, if (v) axis_connection += test_connection(stepperV)); + TERN_(W_IS_TRINAMIC, if (w) axis_connection += test_connection(stepperW)); if (TERN0(HAS_EXTRUDERS, e)) { - #if AXIS_IS_TMC(E0) - axis_connection += test_connection(stepperE0); - #endif - #if AXIS_IS_TMC(E1) - axis_connection += test_connection(stepperE1); - #endif - #if AXIS_IS_TMC(E2) - axis_connection += test_connection(stepperE2); - #endif - #if AXIS_IS_TMC(E3) - axis_connection += test_connection(stepperE3); - #endif - #if AXIS_IS_TMC(E4) - axis_connection += test_connection(stepperE4); - #endif - #if AXIS_IS_TMC(E5) - axis_connection += test_connection(stepperE5); - #endif - #if AXIS_IS_TMC(E6) - axis_connection += test_connection(stepperE6); - #endif - #if AXIS_IS_TMC(E7) - axis_connection += test_connection(stepperE7); - #endif + TERN_(E0_IS_TRINAMIC, axis_connection += test_connection(stepperE0)); + TERN_(E1_IS_TRINAMIC, axis_connection += test_connection(stepperE1)); + TERN_(E2_IS_TRINAMIC, axis_connection += test_connection(stepperE2)); + TERN_(E3_IS_TRINAMIC, axis_connection += test_connection(stepperE3)); + TERN_(E4_IS_TRINAMIC, axis_connection += test_connection(stepperE4)); + TERN_(E5_IS_TRINAMIC, axis_connection += test_connection(stepperE5)); + TERN_(E6_IS_TRINAMIC, axis_connection += test_connection(stepperE6)); + TERN_(E7_IS_TRINAMIC, axis_connection += test_connection(stepperE7)); } if (axis_connection) LCD_MESSAGE(MSG_ERROR_TMC); diff --git a/Marlin/src/gcode/calibrate/G28.cpp b/Marlin/src/gcode/calibrate/G28.cpp index 85d27e14e8..6c8af9ddb0 100644 --- a/Marlin/src/gcode/calibrate/G28.cpp +++ b/Marlin/src/gcode/calibrate/G28.cpp @@ -88,10 +88,8 @@ fr_mm_s = HYPOT(minfr, minfr); // Set homing current to X and Y axis if defined - #if HAS_CURRENT_HOME(X) - set_homing_current(X_AXIS); - #endif - #if HAS_CURRENT_HOME(Y) && NONE(CORE_IS_XY, MARKFORGED_XY, MARKFORGED_YX) + TERN_(X_HAS_HOME_CURRENT, set_homing_current(X_AXIS)); + #if Y_HAS_HOME_CURRENT && NONE(CORE_IS_XY, MARKFORGED_XY, MARKFORGED_YX) set_homing_current(Y_AXIS); #endif @@ -113,10 +111,8 @@ current_position.set(0.0, 0.0); - #if HAS_CURRENT_HOME(X) - restore_homing_current(X_AXIS); - #endif - #if HAS_CURRENT_HOME(Y) && NONE(CORE_IS_XY, MARKFORGED_XY, MARKFORGED_YX) + TERN_(X_HAS_HOME_CURRENT, restore_homing_current(X_AXIS)); + #if Y_HAS_HOME_CURRENT && NONE(CORE_IS_XY, MARKFORGED_XY, MARKFORGED_YX) restore_homing_current(Y_AXIS); #endif diff --git a/Marlin/src/gcode/calibrate/G34.cpp b/Marlin/src/gcode/calibrate/G34.cpp index 9a0cb0054b..0654eb0ec9 100644 --- a/Marlin/src/gcode/calibrate/G34.cpp +++ b/Marlin/src/gcode/calibrate/G34.cpp @@ -95,37 +95,36 @@ void GcodeSuite::G34() { #if HAS_MOTOR_CURRENT_SPI const uint16_t target_current = parser.intval('S', GANTRY_CALIBRATION_CURRENT); - const uint32_t previous_current = stepper.motor_current_setting[Z_AXIS]; + const uint32_t previous_current_Z = stepper.motor_current_setting[Z_AXIS]; stepper.set_digipot_current(Z_AXIS, target_current); #elif HAS_MOTOR_CURRENT_PWM const uint16_t target_current = parser.intval('S', GANTRY_CALIBRATION_CURRENT); - const uint32_t previous_current = stepper.motor_current_setting[1]; // Z + const uint32_t previous_current_Z = stepper.motor_current_setting[1]; // Z stepper.set_digipot_current(1, target_current); #elif HAS_MOTOR_CURRENT_DAC const float target_current = parser.floatval('S', GANTRY_CALIBRATION_CURRENT); - const float previous_current = dac_amps(Z_AXIS, target_current); + const float previous_current_Z = dac_amps(Z_AXIS, target_current); stepper_dac.set_current_value(Z_AXIS, target_current); #elif HAS_MOTOR_CURRENT_I2C const uint16_t target_current = parser.intval('S', GANTRY_CALIBRATION_CURRENT); - previous_current = dac_amps(Z_AXIS); + const float previous_current_Z = dac_amps(Z_AXIS); digipot_i2c.set_current(Z_AXIS, target_current) #elif HAS_TRINAMIC_CONFIG const uint16_t target_current = parser.intval('S', GANTRY_CALIBRATION_CURRENT); - static uint16_t previous_current_arr[NUM_Z_STEPPERS]; - #if AXIS_IS_TMC(Z) - previous_current_arr[0] = stepperZ.getMilliamps(); + #if Z_IS_TRINAMIC + static uint16_t previous_current_Z = stepperZ.getMilliamps(); stepperZ.rms_current(target_current); #endif - #if AXIS_IS_TMC(Z2) - previous_current_arr[1] = stepperZ2.getMilliamps(); + #if Z2_IS_TRINAMIC + static uint16_t previous_current_Z2 = stepperZ2.getMilliamps(); stepperZ2.rms_current(target_current); #endif - #if AXIS_IS_TMC(Z3) - previous_current_arr[2] = stepperZ3.getMilliamps(); + #if Z3_IS_TRINAMIC + static uint16_t previous_current_Z3 = stepperZ3.getMilliamps(); stepperZ3.rms_current(target_current); #endif - #if AXIS_IS_TMC(Z4) - previous_current_arr[3] = stepperZ4.getMilliamps(); + #if Z4_IS_TRINAMIC + static uint16_t previous_current_Z4 = stepperZ4.getMilliamps(); stepperZ4.rms_current(target_current); #endif #endif @@ -140,26 +139,18 @@ void GcodeSuite::G34() { #endif #if HAS_MOTOR_CURRENT_SPI - stepper.set_digipot_current(Z_AXIS, previous_current); + stepper.set_digipot_current(Z_AXIS, previous_current_Z); #elif HAS_MOTOR_CURRENT_PWM - stepper.set_digipot_current(1, previous_current); + stepper.set_digipot_current(1, previous_current_Z); #elif HAS_MOTOR_CURRENT_DAC - stepper_dac.set_current_value(Z_AXIS, previous_current); + stepper_dac.set_current_value(Z_AXIS, previous_current_Z); #elif HAS_MOTOR_CURRENT_I2C - digipot_i2c.set_current(Z_AXIS, previous_current) + digipot_i2c.set_current(Z_AXIS, previous_current_Z) #elif HAS_TRINAMIC_CONFIG - #if AXIS_IS_TMC(Z) - stepperZ.rms_current(previous_current_arr[0]); - #endif - #if AXIS_IS_TMC(Z2) - stepperZ2.rms_current(previous_current_arr[1]); - #endif - #if AXIS_IS_TMC(Z3) - stepperZ3.rms_current(previous_current_arr[2]); - #endif - #if AXIS_IS_TMC(Z4) - stepperZ4.rms_current(previous_current_arr[3]); - #endif + TERN_(Z_IS_TRINAMIC, stepperZ.rms_current(previous_current_Z)); + TERN_(Z2_IS_TRINAMIC, stepperZ2.rms_current(previous_current_Z2)); + TERN_(Z3_IS_TRINAMIC, stepperZ3.rms_current(previous_current_Z3)); + TERN_(Z4_IS_TRINAMIC, stepperZ4.rms_current(previous_current_Z4)); #endif // Back off end plate, back to normal motion range diff --git a/Marlin/src/gcode/feature/trinamic/M906.cpp b/Marlin/src/gcode/feature/trinamic/M906.cpp index c0dc456a8a..43d980098e 100644 --- a/Marlin/src/gcode/feature/trinamic/M906.cpp +++ b/Marlin/src/gcode/feature/trinamic/M906.cpp @@ -60,173 +60,96 @@ void GcodeSuite::M906() { bool report = true; - #if AXIS_IS_TMC(X2) || AXIS_IS_TMC(Y2) || AXIS_IS_TMC(Z2) || AXIS_IS_TMC(Z3) || AXIS_IS_TMC(Z4) + #if ANY(X2_IS_TRINAMIC, Y2_IS_TRINAMIC, Z2_IS_TRINAMIC, Z3_IS_TRINAMIC, Z4_IS_TRINAMIC) const int8_t index = parser.byteval('I', -1); - #elif AXIS_IS_TMC(X) || AXIS_IS_TMC(Y) || AXIS_IS_TMC(Z) + #elif ANY(X_IS_TRINAMIC, Y_IS_TRINAMIC, Z_IS_TRINAMIC) constexpr int8_t index = -1; #endif LOOP_LOGICAL_AXES(i) if (uint16_t value = parser.intval(AXIS_CHAR(i))) { report = false; switch (i) { - #if AXIS_IS_TMC(X) || AXIS_IS_TMC(X2) + #if X_IS_TRINAMIC || X2_IS_TRINAMIC case X_AXIS: - #if AXIS_IS_TMC(X) - if (index < 0 || index == 0) TMC_SET_CURRENT(X); - #endif - #if AXIS_IS_TMC(X2) - if (index < 0 || index == 1) TMC_SET_CURRENT(X2); - #endif + TERN_(X_IS_TRINAMIC, if (index < 0 || index == 0) TMC_SET_CURRENT(X)); + TERN_(X2_IS_TRINAMIC, if (index < 0 || index == 1) TMC_SET_CURRENT(X2)); break; #endif - #if AXIS_IS_TMC(Y) || AXIS_IS_TMC(Y2) + #if Y_IS_TRINAMIC || Y2_IS_TRINAMIC case Y_AXIS: - #if AXIS_IS_TMC(Y) - if (index < 0 || index == 0) TMC_SET_CURRENT(Y); - #endif - #if AXIS_IS_TMC(Y2) - if (index < 0 || index == 1) TMC_SET_CURRENT(Y2); - #endif + TERN_(Y_IS_TRINAMIC, if (index < 0 || index == 0) TMC_SET_CURRENT(Y)); + TERN_(Y2_IS_TRINAMIC, if (index < 0 || index == 1) TMC_SET_CURRENT(Y2)); break; #endif - #if AXIS_IS_TMC(Z) || AXIS_IS_TMC(Z2) || AXIS_IS_TMC(Z3) || AXIS_IS_TMC(Z4) + #if ANY(Z_IS_TRINAMIC, Z2_IS_TRINAMIC, Z3_IS_TRINAMIC, Z4_IS_TRINAMIC) case Z_AXIS: - #if AXIS_IS_TMC(Z) - if (index < 0 || index == 0) TMC_SET_CURRENT(Z); - #endif - #if AXIS_IS_TMC(Z2) - if (index < 0 || index == 1) TMC_SET_CURRENT(Z2); - #endif - #if AXIS_IS_TMC(Z3) - if (index < 0 || index == 2) TMC_SET_CURRENT(Z3); - #endif - #if AXIS_IS_TMC(Z4) - if (index < 0 || index == 3) TMC_SET_CURRENT(Z4); - #endif + TERN_(Z_IS_TRINAMIC, if (index < 0 || index == 0) TMC_SET_CURRENT(Z)); + TERN_(Z2_IS_TRINAMIC, if (index < 0 || index == 1) TMC_SET_CURRENT(Z2)); + TERN_(Z3_IS_TRINAMIC, if (index < 0 || index == 2) TMC_SET_CURRENT(Z3)); + TERN_(Z4_IS_TRINAMIC, if (index < 0 || index == 3) TMC_SET_CURRENT(Z4)); break; #endif - #if AXIS_IS_TMC(I) + #if I_IS_TRINAMIC case I_AXIS: TMC_SET_CURRENT(I); break; #endif - #if AXIS_IS_TMC(J) + #if J_IS_TRINAMIC case J_AXIS: TMC_SET_CURRENT(J); break; #endif - #if AXIS_IS_TMC(K) + #if K_IS_TRINAMIC case K_AXIS: TMC_SET_CURRENT(K); break; #endif - #if AXIS_IS_TMC(U) + #if U_IS_TRINAMIC case U_AXIS: TMC_SET_CURRENT(U); break; #endif - #if AXIS_IS_TMC(V) + #if V_IS_TRINAMIC case V_AXIS: TMC_SET_CURRENT(V); break; #endif - #if AXIS_IS_TMC(W) + #if W_IS_TRINAMIC case W_AXIS: TMC_SET_CURRENT(W); break; #endif - #if AXIS_IS_TMC(E0) || AXIS_IS_TMC(E1) || AXIS_IS_TMC(E2) || AXIS_IS_TMC(E3) || AXIS_IS_TMC(E4) || AXIS_IS_TMC(E5) || AXIS_IS_TMC(E6) || AXIS_IS_TMC(E7) + #if ANY(E0_IS_TRINAMIC, E1_IS_TRINAMIC, E2_IS_TRINAMIC, E3_IS_TRINAMIC, E4_IS_TRINAMIC, E5_IS_TRINAMIC, E6_IS_TRINAMIC, E7_IS_TRINAMIC) case E_AXIS: { const int8_t eindex = get_target_e_stepper_from_command(-2); - #if AXIS_IS_TMC(E0) - if (eindex < 0 || eindex == 0) TMC_SET_CURRENT(E0); - #endif - #if AXIS_IS_TMC(E1) - if (eindex < 0 || eindex == 1) TMC_SET_CURRENT(E1); - #endif - #if AXIS_IS_TMC(E2) - if (eindex < 0 || eindex == 2) TMC_SET_CURRENT(E2); - #endif - #if AXIS_IS_TMC(E3) - if (eindex < 0 || eindex == 3) TMC_SET_CURRENT(E3); - #endif - #if AXIS_IS_TMC(E4) - if (eindex < 0 || eindex == 4) TMC_SET_CURRENT(E4); - #endif - #if AXIS_IS_TMC(E5) - if (eindex < 0 || eindex == 5) TMC_SET_CURRENT(E5); - #endif - #if AXIS_IS_TMC(E6) - if (eindex < 0 || eindex == 6) TMC_SET_CURRENT(E6); - #endif - #if AXIS_IS_TMC(E7) - if (eindex < 0 || eindex == 7) TMC_SET_CURRENT(E7); - #endif + TERN_(E0_IS_TRINAMIC, if (eindex < 0 || eindex == 0) TMC_SET_CURRENT(E0)); + TERN_(E1_IS_TRINAMIC, if (eindex < 0 || eindex == 1) TMC_SET_CURRENT(E1)); + TERN_(E2_IS_TRINAMIC, if (eindex < 0 || eindex == 2) TMC_SET_CURRENT(E2)); + TERN_(E3_IS_TRINAMIC, if (eindex < 0 || eindex == 3) TMC_SET_CURRENT(E3)); + TERN_(E4_IS_TRINAMIC, if (eindex < 0 || eindex == 4) TMC_SET_CURRENT(E4)); + TERN_(E5_IS_TRINAMIC, if (eindex < 0 || eindex == 5) TMC_SET_CURRENT(E5)); + TERN_(E6_IS_TRINAMIC, if (eindex < 0 || eindex == 6) TMC_SET_CURRENT(E6)); + TERN_(E7_IS_TRINAMIC, if (eindex < 0 || eindex == 7) TMC_SET_CURRENT(E7)); } break; #endif } } if (report) { - #if AXIS_IS_TMC(X) - TMC_SAY_CURRENT(X); - #endif - #if AXIS_IS_TMC(X2) - TMC_SAY_CURRENT(X2); - #endif - #if AXIS_IS_TMC(Y) - TMC_SAY_CURRENT(Y); - #endif - #if AXIS_IS_TMC(Y2) - TMC_SAY_CURRENT(Y2); - #endif - #if AXIS_IS_TMC(Z) - TMC_SAY_CURRENT(Z); - #endif - #if AXIS_IS_TMC(Z2) - TMC_SAY_CURRENT(Z2); - #endif - #if AXIS_IS_TMC(Z3) - TMC_SAY_CURRENT(Z3); - #endif - #if AXIS_IS_TMC(Z4) - TMC_SAY_CURRENT(Z4); - #endif - #if AXIS_IS_TMC(I) - TMC_SAY_CURRENT(I); - #endif - #if AXIS_IS_TMC(J) - TMC_SAY_CURRENT(J); - #endif - #if AXIS_IS_TMC(K) - TMC_SAY_CURRENT(K); - #endif - #if AXIS_IS_TMC(U) - TMC_SAY_CURRENT(U); - #endif - #if AXIS_IS_TMC(V) - TMC_SAY_CURRENT(V); - #endif - #if AXIS_IS_TMC(W) - TMC_SAY_CURRENT(W); - #endif - - #if AXIS_IS_TMC(E0) - TMC_SAY_CURRENT(E0); - #endif - #if AXIS_IS_TMC(E1) - TMC_SAY_CURRENT(E1); - #endif - #if AXIS_IS_TMC(E2) - TMC_SAY_CURRENT(E2); - #endif - #if AXIS_IS_TMC(E3) - TMC_SAY_CURRENT(E3); - #endif - #if AXIS_IS_TMC(E4) - TMC_SAY_CURRENT(E4); - #endif - #if AXIS_IS_TMC(E5) - TMC_SAY_CURRENT(E5); - #endif - #if AXIS_IS_TMC(E6) - TMC_SAY_CURRENT(E6); - #endif - #if AXIS_IS_TMC(E7) - TMC_SAY_CURRENT(E7); - #endif + TERN_(X_IS_TRINAMIC, TMC_SAY_CURRENT(X)); + TERN_(X2_IS_TRINAMIC, TMC_SAY_CURRENT(X2)); + TERN_(Y_IS_TRINAMIC, TMC_SAY_CURRENT(Y)); + TERN_(Y2_IS_TRINAMIC, TMC_SAY_CURRENT(Y2)); + TERN_(Z_IS_TRINAMIC, TMC_SAY_CURRENT(Z)); + TERN_(Z2_IS_TRINAMIC, TMC_SAY_CURRENT(Z2)); + TERN_(Z3_IS_TRINAMIC, TMC_SAY_CURRENT(Z3)); + TERN_(Z4_IS_TRINAMIC, TMC_SAY_CURRENT(Z4)); + TERN_(I_IS_TRINAMIC, TMC_SAY_CURRENT(I)); + TERN_(J_IS_TRINAMIC, TMC_SAY_CURRENT(J)); + TERN_(K_IS_TRINAMIC, TMC_SAY_CURRENT(K)); + TERN_(U_IS_TRINAMIC, TMC_SAY_CURRENT(U)); + TERN_(V_IS_TRINAMIC, TMC_SAY_CURRENT(V)); + TERN_(W_IS_TRINAMIC, TMC_SAY_CURRENT(W)); + TERN_(E0_IS_TRINAMIC, TMC_SAY_CURRENT(E0)); + TERN_(E1_IS_TRINAMIC, TMC_SAY_CURRENT(E1)); + TERN_(E2_IS_TRINAMIC, TMC_SAY_CURRENT(E2)); + TERN_(E3_IS_TRINAMIC, TMC_SAY_CURRENT(E3)); + TERN_(E4_IS_TRINAMIC, TMC_SAY_CURRENT(E4)); + TERN_(E5_IS_TRINAMIC, TMC_SAY_CURRENT(E5)); + TERN_(E6_IS_TRINAMIC, TMC_SAY_CURRENT(E6)); + TERN_(E7_IS_TRINAMIC, TMC_SAY_CURRENT(E7)); } } @@ -240,93 +163,67 @@ void GcodeSuite::M906_report(const bool forReplay/*=true*/) { SERIAL_ECHOPGM(" M906"); }; - #if AXIS_IS_TMC(X) || AXIS_IS_TMC(Y) || AXIS_IS_TMC(Z) \ - || AXIS_IS_TMC(I) || AXIS_IS_TMC(J) || AXIS_IS_TMC(K) \ - || AXIS_IS_TMC(U) || AXIS_IS_TMC(V) || AXIS_IS_TMC(W) + #if ANY(X_IS_TRINAMIC, Y_IS_TRINAMIC, Z_IS_TRINAMIC, I_IS_TRINAMIC, J_IS_TRINAMIC, K_IS_TRINAMIC, U_IS_TRINAMIC, V_IS_TRINAMIC, W_IS_TRINAMIC) say_M906(forReplay); - #if AXIS_IS_TMC(X) - SERIAL_ECHOPGM_P(SP_X_STR, stepperX.getMilliamps()); - #endif - #if AXIS_IS_TMC(Y) - SERIAL_ECHOPGM_P(SP_Y_STR, stepperY.getMilliamps()); - #endif - #if AXIS_IS_TMC(Z) - SERIAL_ECHOPGM_P(SP_Z_STR, stepperZ.getMilliamps()); - #endif - #if AXIS_IS_TMC(I) - SERIAL_ECHOPGM_P(SP_I_STR, stepperI.getMilliamps()); - #endif - #if AXIS_IS_TMC(J) - SERIAL_ECHOPGM_P(SP_J_STR, stepperJ.getMilliamps()); - #endif - #if AXIS_IS_TMC(K) - SERIAL_ECHOPGM_P(SP_K_STR, stepperK.getMilliamps()); - #endif - #if AXIS_IS_TMC(U) - SERIAL_ECHOPGM_P(SP_U_STR, stepperU.getMilliamps()); - #endif - #if AXIS_IS_TMC(V) - SERIAL_ECHOPGM_P(SP_V_STR, stepperV.getMilliamps()); - #endif - #if AXIS_IS_TMC(W) - SERIAL_ECHOPGM_P(SP_W_STR, stepperW.getMilliamps()); - #endif + TERN_(X_IS_TRINAMIC, SERIAL_ECHOPGM_P(SP_X_STR, stepperX.getMilliamps())); + TERN_(Y_IS_TRINAMIC, SERIAL_ECHOPGM_P(SP_Y_STR, stepperY.getMilliamps())); + TERN_(Z_IS_TRINAMIC, SERIAL_ECHOPGM_P(SP_Z_STR, stepperZ.getMilliamps())); + TERN_(I_IS_TRINAMIC, SERIAL_ECHOPGM_P(SP_I_STR, stepperI.getMilliamps())); + TERN_(J_IS_TRINAMIC, SERIAL_ECHOPGM_P(SP_J_STR, stepperJ.getMilliamps())); + TERN_(K_IS_TRINAMIC, SERIAL_ECHOPGM_P(SP_K_STR, stepperK.getMilliamps())); + TERN_(U_IS_TRINAMIC, SERIAL_ECHOPGM_P(SP_U_STR, stepperU.getMilliamps())); + TERN_(V_IS_TRINAMIC, SERIAL_ECHOPGM_P(SP_V_STR, stepperV.getMilliamps())); + TERN_(W_IS_TRINAMIC, SERIAL_ECHOPGM_P(SP_W_STR, stepperW.getMilliamps())); SERIAL_EOL(); #endif - #if AXIS_IS_TMC(X2) || AXIS_IS_TMC(Y2) || AXIS_IS_TMC(Z2) + #if X2_IS_TRINAMIC || Y2_IS_TRINAMIC || Z2_IS_TRINAMIC say_M906(forReplay); SERIAL_ECHOPGM(" I1"); - #if AXIS_IS_TMC(X2) - SERIAL_ECHOPGM_P(SP_X_STR, stepperX2.getMilliamps()); - #endif - #if AXIS_IS_TMC(Y2) - SERIAL_ECHOPGM_P(SP_Y_STR, stepperY2.getMilliamps()); - #endif - #if AXIS_IS_TMC(Z2) - SERIAL_ECHOPGM_P(SP_Z_STR, stepperZ2.getMilliamps()); - #endif + TERN_(X2_IS_TRINAMIC, SERIAL_ECHOPGM_P(SP_X_STR, stepperX2.getMilliamps())); + TERN_(Y2_IS_TRINAMIC, SERIAL_ECHOPGM_P(SP_Y_STR, stepperY2.getMilliamps())); + TERN_(Z2_IS_TRINAMIC, SERIAL_ECHOPGM_P(SP_Z_STR, stepperZ2.getMilliamps())); SERIAL_EOL(); #endif - #if AXIS_IS_TMC(Z3) + #if Z3_IS_TRINAMIC say_M906(forReplay); SERIAL_ECHOLNPGM(" I2 Z", stepperZ3.getMilliamps()); #endif - #if AXIS_IS_TMC(Z4) + #if Z4_IS_TRINAMIC say_M906(forReplay); SERIAL_ECHOLNPGM(" I3 Z", stepperZ4.getMilliamps()); #endif - #if AXIS_IS_TMC(E0) + #if E0_IS_TRINAMIC say_M906(forReplay); SERIAL_ECHOLNPGM(" T0 E", stepperE0.getMilliamps()); #endif - #if AXIS_IS_TMC(E1) + #if E1_IS_TRINAMIC say_M906(forReplay); SERIAL_ECHOLNPGM(" T1 E", stepperE1.getMilliamps()); #endif - #if AXIS_IS_TMC(E2) + #if E2_IS_TRINAMIC say_M906(forReplay); SERIAL_ECHOLNPGM(" T2 E", stepperE2.getMilliamps()); #endif - #if AXIS_IS_TMC(E3) + #if E3_IS_TRINAMIC say_M906(forReplay); SERIAL_ECHOLNPGM(" T3 E", stepperE3.getMilliamps()); #endif - #if AXIS_IS_TMC(E4) + #if E4_IS_TRINAMIC say_M906(forReplay); SERIAL_ECHOLNPGM(" T4 E", stepperE4.getMilliamps()); #endif - #if AXIS_IS_TMC(E5) + #if E5_IS_TRINAMIC say_M906(forReplay); SERIAL_ECHOLNPGM(" T5 E", stepperE5.getMilliamps()); #endif - #if AXIS_IS_TMC(E6) + #if E6_IS_TRINAMIC say_M906(forReplay); SERIAL_ECHOLNPGM(" T6 E", stepperE6.getMilliamps()); #endif - #if AXIS_IS_TMC(E7) + #if E7_IS_TRINAMIC say_M906(forReplay); SERIAL_ECHOLNPGM(" T7 E", stepperE7.getMilliamps()); #endif diff --git a/Marlin/src/gcode/feature/trinamic/M911-M914.cpp b/Marlin/src/gcode/feature/trinamic/M911-M914.cpp index ba6d9538a4..f4b0ac3670 100644 --- a/Marlin/src/gcode/feature/trinamic/M911-M914.cpp +++ b/Marlin/src/gcode/feature/trinamic/M911-M914.cpp @@ -274,7 +274,23 @@ } /** - * M913: Set HYBRID_THRESHOLD speed. + * M913: Set HYBRID_THRESHOLD speed, aka PWM Threshold. + * + * Parameters: + * I - For multi-stepper axes, the one-based index of the stepper to modify in each set + * + * E - Set threshold for one or more Extruders + * T - The zero-based index of the Extruder to modify + * + * X - Set threshold for one or more X axis steppers + * Y - Set threshold for one or more Y axis steppers + * Z - Set threshold for one or more Z axis steppers + * A - Set threshold for one or more A axis steppers + * B - Set threshold for one or more B axis steppers + * C - Set threshold for one or more C axis steppers + * U - Set threshold for one or more U axis steppers + * V - Set threshold for one or more V axis steppers + * W - Set threshold for one or more W axis steppers */ void GcodeSuite::M913() { #define TMC_SAY_PWMTHRS(A,Q) tmc_print_pwmthrs(stepper##Q) @@ -283,9 +299,9 @@ #define TMC_SET_PWMTHRS_E(E) stepperE##E.set_pwm_thrs(value) bool report = true; - #if AXIS_IS_TMC(X2) || AXIS_IS_TMC(Y2) || AXIS_IS_TMC(Z2) || AXIS_IS_TMC(Z3) || AXIS_IS_TMC(Z4) + #if ANY(X2_IS_TRINAMIC, Y2_IS_TRINAMIC, Z2_IS_TRINAMIC, Z3_IS_TRINAMIC, Z4_IS_TRINAMIC) const uint8_t index = parser.byteval('I'); - #elif AXIS_IS_TMC(X) || AXIS_IS_TMC(Y) || AXIS_IS_TMC(Z) + #elif ANY(X_IS_TRINAMIC, Y_IS_TRINAMIC, Z_IS_TRINAMIC) constexpr uint8_t index = 0; #endif LOOP_LOGICAL_AXES(i) if (int32_t value = parser.longval(AXIS_CHAR(i))) { @@ -387,70 +403,37 @@ SERIAL_ECHOPGM(" M913"); }; - #if X_HAS_STEALTHCHOP || Y_HAS_STEALTHCHOP || Z_HAS_STEALTHCHOP + #if ANY(X_HAS_STEALTHCHOP, Y_HAS_STEALTHCHOP, Z_HAS_STEALTHCHOP, I_HAS_STEALTHCHOP, J_HAS_STEALTHCHOP, K_HAS_STEALTHCHOP, U_HAS_STEALTHCHOP, V_HAS_STEALTHCHOP, W_HAS_STEALTHCHOP) say_M913(forReplay); - #if X_HAS_STEALTHCHOP - SERIAL_ECHOPGM_P(SP_X_STR, stepperX.get_pwm_thrs()); - #endif - #if Y_HAS_STEALTHCHOP - SERIAL_ECHOPGM_P(SP_Y_STR, stepperY.get_pwm_thrs()); - #endif - #if Z_HAS_STEALTHCHOP - SERIAL_ECHOPGM_P(SP_Z_STR, stepperZ.get_pwm_thrs()); - #endif + TERN_(X_HAS_STEALTHCHOP, SERIAL_ECHOPGM_P(SP_X_STR, stepperX.get_pwm_thrs())); + TERN_(Y_HAS_STEALTHCHOP, SERIAL_ECHOPGM_P(SP_Y_STR, stepperY.get_pwm_thrs())); + TERN_(Z_HAS_STEALTHCHOP, SERIAL_ECHOPGM_P(SP_Z_STR, stepperZ.get_pwm_thrs())); + TERN_(I_HAS_STEALTHCHOP, SERIAL_ECHOPGM_P(SP_I_STR, stepperI.get_pwm_thrs())); + TERN_(J_HAS_STEALTHCHOP, SERIAL_ECHOPGM_P(SP_J_STR, stepperJ.get_pwm_thrs())); + TERN_(K_HAS_STEALTHCHOP, SERIAL_ECHOPGM_P(SP_K_STR, stepperK.get_pwm_thrs())); + TERN_(U_HAS_STEALTHCHOP, SERIAL_ECHOPGM_P(SP_U_STR, stepperU.get_pwm_thrs())); + TERN_(V_HAS_STEALTHCHOP, SERIAL_ECHOPGM_P(SP_V_STR, stepperV.get_pwm_thrs())); + TERN_(W_HAS_STEALTHCHOP, SERIAL_ECHOPGM_P(SP_W_STR, stepperW.get_pwm_thrs())); SERIAL_EOL(); #endif #if X2_HAS_STEALTHCHOP || Y2_HAS_STEALTHCHOP || Z2_HAS_STEALTHCHOP say_M913(forReplay); SERIAL_ECHOPGM(" I2"); - #if X2_HAS_STEALTHCHOP - SERIAL_ECHOPGM_P(SP_X_STR, stepperX2.get_pwm_thrs()); - #endif - #if Y2_HAS_STEALTHCHOP - SERIAL_ECHOPGM_P(SP_Y_STR, stepperY2.get_pwm_thrs()); - #endif - #if Z2_HAS_STEALTHCHOP - SERIAL_ECHOPGM_P(SP_Z_STR, stepperZ2.get_pwm_thrs()); - #endif + TERN_(X2_HAS_STEALTHCHOP, SERIAL_ECHOPGM_P(SP_X_STR, stepperX2.get_pwm_thrs())); + TERN_(Y2_HAS_STEALTHCHOP, SERIAL_ECHOPGM_P(SP_Y_STR, stepperY2.get_pwm_thrs())); + TERN_(Z2_HAS_STEALTHCHOP, SERIAL_ECHOPGM_P(SP_Z_STR, stepperZ2.get_pwm_thrs())); SERIAL_EOL(); #endif - #if Z3_HAS_STEALTHCHOP say_M913(forReplay); SERIAL_ECHOLNPGM(" I3 Z", stepperZ3.get_pwm_thrs()); #endif - #if Z4_HAS_STEALTHCHOP say_M913(forReplay); SERIAL_ECHOLNPGM(" I4 Z", stepperZ4.get_pwm_thrs()); #endif - #if I_HAS_STEALTHCHOP - say_M913(forReplay); - SERIAL_ECHOLNPGM_P(SP_I_STR, stepperI.get_pwm_thrs()); - #endif - #if J_HAS_STEALTHCHOP - say_M913(forReplay); - SERIAL_ECHOLNPGM_P(SP_J_STR, stepperJ.get_pwm_thrs()); - #endif - #if K_HAS_STEALTHCHOP - say_M913(forReplay); - SERIAL_ECHOLNPGM_P(SP_K_STR, stepperK.get_pwm_thrs()); - #endif - #if U_HAS_STEALTHCHOP - say_M913(forReplay); - SERIAL_ECHOLNPGM_P(SP_U_STR, stepperU.get_pwm_thrs()); - #endif - #if V_HAS_STEALTHCHOP - say_M913(forReplay); - SERIAL_ECHOLNPGM_P(SP_V_STR, stepperV.get_pwm_thrs()); - #endif - #if W_HAS_STEALTHCHOP - say_M913(forReplay); - SERIAL_ECHOLNPGM_P(SP_W_STR, stepperW.get_pwm_thrs()); - #endif - #if E0_HAS_STEALTHCHOP say_M913(forReplay); SERIAL_ECHOLNPGM(" T0 E", stepperE0.get_pwm_thrs()); @@ -498,7 +481,19 @@ } /** - * M914: Set StallGuard sensitivity. + * M914: Set StallGuard sensitivity in terms of "homing threshold" (not for stall detection during printing). + * + * Parameters: + * I - For multi-stepper axes, the one-based index of the stepper to modify in each set + * X - Set threshold for one or more X axis steppers + * Y - Set threshold for one or more Y axis steppers + * Z - Set threshold for one or more Z axis steppers + * A - Set threshold for one or more A axis steppers + * B - Set threshold for one or more B axis steppers + * C - Set threshold for one or more C axis steppers + * U - Set threshold for one or more U axis steppers + * V - Set threshold for one or more V axis steppers + * W - Set threshold for one or more W axis steppers */ void GcodeSuite::M914() { bool report = true; @@ -536,33 +531,33 @@ #if K_SENSORLESS case K_AXIS: stepperK.homing_threshold(value); break; #endif - #if U_SENSORLESS && AXIS_HAS_STALLGUARD(U) + #if U_SENSORLESS case U_AXIS: stepperU.homing_threshold(value); break; #endif - #if V_SENSORLESS && AXIS_HAS_STALLGUARD(V) + #if V_SENSORLESS case V_AXIS: stepperV.homing_threshold(value); break; #endif - #if W_SENSORLESS && AXIS_HAS_STALLGUARD(W) + #if W_SENSORLESS case W_AXIS: stepperW.homing_threshold(value); break; #endif } } if (report) { - TERN_(X_SENSORLESS, tmc_print_sgt(stepperX)); + TERN_( X_SENSORLESS, tmc_print_sgt(stepperX)); TERN_(X2_SENSORLESS, tmc_print_sgt(stepperX2)); - TERN_(Y_SENSORLESS, tmc_print_sgt(stepperY)); + TERN_( Y_SENSORLESS, tmc_print_sgt(stepperY)); TERN_(Y2_SENSORLESS, tmc_print_sgt(stepperY2)); - TERN_(Z_SENSORLESS, tmc_print_sgt(stepperZ)); + TERN_( Z_SENSORLESS, tmc_print_sgt(stepperZ)); TERN_(Z2_SENSORLESS, tmc_print_sgt(stepperZ2)); TERN_(Z3_SENSORLESS, tmc_print_sgt(stepperZ3)); TERN_(Z4_SENSORLESS, tmc_print_sgt(stepperZ4)); - TERN_(I_SENSORLESS, tmc_print_sgt(stepperI)); - TERN_(J_SENSORLESS, tmc_print_sgt(stepperJ)); - TERN_(K_SENSORLESS, tmc_print_sgt(stepperK)); - TERN_(U_SENSORLESS, tmc_print_sgt(stepperU)); - TERN_(V_SENSORLESS, tmc_print_sgt(stepperV)); - TERN_(W_SENSORLESS, tmc_print_sgt(stepperW)); + TERN_( I_SENSORLESS, tmc_print_sgt(stepperI)); + TERN_( J_SENSORLESS, tmc_print_sgt(stepperJ)); + TERN_( K_SENSORLESS, tmc_print_sgt(stepperK)); + TERN_( U_SENSORLESS, tmc_print_sgt(stepperU)); + TERN_( V_SENSORLESS, tmc_print_sgt(stepperV)); + TERN_( W_SENSORLESS, tmc_print_sgt(stepperW)); } } @@ -578,67 +573,34 @@ #if X_SENSORLESS || Y_SENSORLESS || Z_SENSORLESS say_M914(forReplay); - #if X_SENSORLESS - SERIAL_ECHOPGM_P(SP_X_STR, stepperX.homing_threshold()); - #endif - #if Y_SENSORLESS - SERIAL_ECHOPGM_P(SP_Y_STR, stepperY.homing_threshold()); - #endif - #if Z_SENSORLESS - SERIAL_ECHOPGM_P(SP_Z_STR, stepperZ.homing_threshold()); - #endif + TERN_(X_SENSORLESS, SERIAL_ECHOPGM_P(SP_X_STR, stepperX.homing_threshold())); + TERN_(Y_SENSORLESS, SERIAL_ECHOPGM_P(SP_Y_STR, stepperY.homing_threshold())); + TERN_(Z_SENSORLESS, SERIAL_ECHOPGM_P(SP_Z_STR, stepperZ.homing_threshold())); + TERN_(I_SENSORLESS, SERIAL_ECHOPGM_P(SP_I_STR, stepperI.homing_threshold())); + TERN_(J_SENSORLESS, SERIAL_ECHOPGM_P(SP_J_STR, stepperJ.homing_threshold())); + TERN_(K_SENSORLESS, SERIAL_ECHOPGM_P(SP_K_STR, stepperK.homing_threshold())); + TERN_(U_SENSORLESS, SERIAL_ECHOPGM_P(SP_U_STR, stepperU.homing_threshold())); + TERN_(V_SENSORLESS, SERIAL_ECHOPGM_P(SP_V_STR, stepperV.homing_threshold())); + TERN_(W_SENSORLESS, SERIAL_ECHOPGM_P(SP_W_STR, stepperW.homing_threshold())); SERIAL_EOL(); #endif #if X2_SENSORLESS || Y2_SENSORLESS || Z2_SENSORLESS say_M914(forReplay); SERIAL_ECHOPGM(" I2"); - #if X2_SENSORLESS - SERIAL_ECHOPGM_P(SP_X_STR, stepperX2.homing_threshold()); - #endif - #if Y2_SENSORLESS - SERIAL_ECHOPGM_P(SP_Y_STR, stepperY2.homing_threshold()); - #endif - #if Z2_SENSORLESS - SERIAL_ECHOPGM_P(SP_Z_STR, stepperZ2.homing_threshold()); - #endif + TERN_(X2_SENSORLESS, SERIAL_ECHOPGM_P(SP_X_STR, stepperX2.homing_threshold())); + TERN_(Y2_SENSORLESS, SERIAL_ECHOPGM_P(SP_Y_STR, stepperY2.homing_threshold())); + TERN_(Z2_SENSORLESS, SERIAL_ECHOPGM_P(SP_Z_STR, stepperZ2.homing_threshold())); SERIAL_EOL(); #endif - #if Z3_SENSORLESS say_M914(forReplay); SERIAL_ECHOLNPGM(" I3 Z", stepperZ3.homing_threshold()); #endif - #if Z4_SENSORLESS say_M914(forReplay); SERIAL_ECHOLNPGM(" I4 Z", stepperZ4.homing_threshold()); #endif - - #if I_SENSORLESS - say_M914(forReplay); - SERIAL_ECHOLNPGM_P(SP_I_STR, stepperI.homing_threshold()); - #endif - #if J_SENSORLESS - say_M914(forReplay); - SERIAL_ECHOLNPGM_P(SP_J_STR, stepperJ.homing_threshold()); - #endif - #if K_SENSORLESS - say_M914(forReplay); - SERIAL_ECHOLNPGM_P(SP_K_STR, stepperK.homing_threshold()); - #endif - #if U_SENSORLESS - say_M914(forReplay); - SERIAL_ECHOLNPGM_P(SP_U_STR, stepperU.homing_threshold()); - #endif - #if V_SENSORLESS - say_M914(forReplay); - SERIAL_ECHOLNPGM_P(SP_V_STR, stepperV.homing_threshold()); - #endif - #if W_SENSORLESS - say_M914(forReplay); - SERIAL_ECHOLNPGM_P(SP_W_STR, stepperW.homing_threshold()); - #endif } #endif // USE_SENSORLESS diff --git a/Marlin/src/gcode/feature/trinamic/M919.cpp b/Marlin/src/gcode/feature/trinamic/M919.cpp index 98227c7125..cabb30d7ff 100644 --- a/Marlin/src/gcode/feature/trinamic/M919.cpp +++ b/Marlin/src/gcode/feature/trinamic/M919.cpp @@ -91,9 +91,9 @@ void GcodeSuite::M919() { if (err) return; - #if AXIS_IS_TMC(X2) || AXIS_IS_TMC(Y2) || AXIS_IS_TMC(Z2) || AXIS_IS_TMC(Z3) || AXIS_IS_TMC(Z4) + #if ANY(X2_IS_TRINAMIC, Y2_IS_TRINAMIC, Z2_IS_TRINAMIC, Z3_IS_TRINAMIC, Z4_IS_TRINAMIC) const int8_t index = parser.byteval('I'); - #elif AXIS_IS_TMC(X) || AXIS_IS_TMC(Y) || AXIS_IS_TMC(Z) + #elif ANY(X_IS_TRINAMIC, Y_IS_TRINAMIC, Z_IS_TRINAMIC) constexpr int8_t index = -1; #endif @@ -107,7 +107,7 @@ void GcodeSuite::M919() { #define TMC_SET_CHOPPER_TIME(Q) stepper##Q.set_chopper_times(make_chopper_timing(CHOPPER_TIMING_##Q, toff, hend, hstrt)) - #if AXIS_IS_TMC(E0) || AXIS_IS_TMC(E1) || AXIS_IS_TMC(E2) || AXIS_IS_TMC(E3) || AXIS_IS_TMC(E4) || AXIS_IS_TMC(E5) || AXIS_IS_TMC(E6) || AXIS_IS_TMC(E7) + #if ANY(E0_IS_TRINAMIC, E1_IS_TRINAMIC, E2_IS_TRINAMIC, E3_IS_TRINAMIC, E4_IS_TRINAMIC, E5_IS_TRINAMIC, E6_IS_TRINAMIC, E7_IS_TRINAMIC) #define HAS_E_CHOPPER 1 int8_t eindex = -1; #endif @@ -121,163 +121,66 @@ void GcodeSuite::M919() { SERIAL_ECHOLNPGM(GCODE_ERR_MSG("Axis ", C(AXIS_CHAR(i)), " has no TMC drivers.")); break; - #if AXIS_IS_TMC(X) || AXIS_IS_TMC(X2) + #if X_IS_TRINAMIC || X2_IS_TRINAMIC case X_AXIS: - #if AXIS_IS_TMC(X) - if (index <= 0) TMC_SET_CHOPPER_TIME(X); - #endif - #if AXIS_IS_TMC(X2) - if (index < 0 || index == 1) TMC_SET_CHOPPER_TIME(X2); - #endif + TERN_(X_IS_TRINAMIC, if (index <= 0) TMC_SET_CHOPPER_TIME(X)); + TERN_(X2_IS_TRINAMIC, if (index < 0 || index == 1) TMC_SET_CHOPPER_TIME(X2)); break; #endif - #if AXIS_IS_TMC(Y) || AXIS_IS_TMC(Y2) + #if Y_IS_TRINAMIC || Y2_IS_TRINAMIC case Y_AXIS: - #if AXIS_IS_TMC(Y) - if (index <= 0) TMC_SET_CHOPPER_TIME(Y); - #endif - #if AXIS_IS_TMC(Y2) - if (index < 0 || index == 1) TMC_SET_CHOPPER_TIME(Y2); - #endif + TERN_(Y_IS_TRINAMIC, if (index <= 0) TMC_SET_CHOPPER_TIME(Y)); + TERN_(Y2_IS_TRINAMIC, if (index < 0 || index == 1) TMC_SET_CHOPPER_TIME(Y2)); break; #endif - #if AXIS_IS_TMC(Z) || AXIS_IS_TMC(Z2) || AXIS_IS_TMC(Z3) || AXIS_IS_TMC(Z4) + #if ANY(Z_IS_TRINAMIC, Z2_IS_TRINAMIC, Z3_IS_TRINAMIC, Z4_IS_TRINAMIC) case Z_AXIS: - #if AXIS_IS_TMC(Z) - if (index <= 0) TMC_SET_CHOPPER_TIME(Z); - #endif - #if AXIS_IS_TMC(Z2) - if (index < 0 || index == 1) TMC_SET_CHOPPER_TIME(Z2); - #endif - #if AXIS_IS_TMC(Z3) - if (index < 0 || index == 2) TMC_SET_CHOPPER_TIME(Z3); - #endif - #if AXIS_IS_TMC(Z4) - if (index < 0 || index == 3) TMC_SET_CHOPPER_TIME(Z4); - #endif + TERN_(Z_IS_TRINAMIC, if (index <= 0) TMC_SET_CHOPPER_TIME(Z)); + TERN_(Z2_IS_TRINAMIC, if (index < 0 || index == 1) TMC_SET_CHOPPER_TIME(Z2)); + TERN_(Z3_IS_TRINAMIC, if (index < 0 || index == 2) TMC_SET_CHOPPER_TIME(Z3)); + TERN_(Z4_IS_TRINAMIC, if (index < 0 || index == 3) TMC_SET_CHOPPER_TIME(Z4)); break; #endif - #if AXIS_IS_TMC(I) + #if I_IS_TRINAMIC case I_AXIS: TMC_SET_CHOPPER_TIME(I); break; #endif - #if AXIS_IS_TMC(J) + #if J_IS_TRINAMIC case J_AXIS: TMC_SET_CHOPPER_TIME(J); break; #endif - #if AXIS_IS_TMC(K) + #if K_IS_TRINAMIC case K_AXIS: TMC_SET_CHOPPER_TIME(K); break; #endif - #if AXIS_IS_TMC(U) + #if U_IS_TRINAMIC case U_AXIS: TMC_SET_CHOPPER_TIME(U); break; #endif - #if AXIS_IS_TMC(V) + #if V_IS_TRINAMIC case V_AXIS: TMC_SET_CHOPPER_TIME(V); break; #endif - #if AXIS_IS_TMC(W) + #if W_IS_TRINAMIC case W_AXIS: TMC_SET_CHOPPER_TIME(W); break; #endif #if HAS_E_CHOPPER case E_AXIS: { - #if AXIS_IS_TMC(E0) - if (eindex <= 0) TMC_SET_CHOPPER_TIME(E0); - #endif - #if AXIS_IS_TMC(E1) - if (eindex < 0 || eindex == 1) TMC_SET_CHOPPER_TIME(E1); - #endif - #if AXIS_IS_TMC(E2) - if (eindex < 0 || eindex == 2) TMC_SET_CHOPPER_TIME(E2); - #endif - #if AXIS_IS_TMC(E3) - if (eindex < 0 || eindex == 3) TMC_SET_CHOPPER_TIME(E3); - #endif - #if AXIS_IS_TMC(E4) - if (eindex < 0 || eindex == 4) TMC_SET_CHOPPER_TIME(E4); - #endif - #if AXIS_IS_TMC(E5) - if (eindex < 0 || eindex == 5) TMC_SET_CHOPPER_TIME(E5); - #endif - #if AXIS_IS_TMC(E6) - if (eindex < 0 || eindex == 6) TMC_SET_CHOPPER_TIME(E6); - #endif - #if AXIS_IS_TMC(E7) - if (eindex < 0 || eindex == 7) TMC_SET_CHOPPER_TIME(E7); - #endif + TERN_(E0_IS_TRINAMIC, if (eindex <= 0) TMC_SET_CHOPPER_TIME(E0)); + TERN_(E1_IS_TRINAMIC, if (eindex < 0 || eindex == 1) TMC_SET_CHOPPER_TIME(E1)); + TERN_(E2_IS_TRINAMIC, if (eindex < 0 || eindex == 2) TMC_SET_CHOPPER_TIME(E2)); + TERN_(E3_IS_TRINAMIC, if (eindex < 0 || eindex == 3) TMC_SET_CHOPPER_TIME(E3)); + TERN_(E4_IS_TRINAMIC, if (eindex < 0 || eindex == 4) TMC_SET_CHOPPER_TIME(E4)); + TERN_(E5_IS_TRINAMIC, if (eindex < 0 || eindex == 5) TMC_SET_CHOPPER_TIME(E5)); + TERN_(E6_IS_TRINAMIC, if (eindex < 0 || eindex == 6) TMC_SET_CHOPPER_TIME(E6)); + TERN_(E7_IS_TRINAMIC, if (eindex < 0 || eindex == 7) TMC_SET_CHOPPER_TIME(E7)); } break; #endif } } if (report) { - #define TMC_SAY_CHOPPER_TIME(Q) tmc_print_chopper_time(stepper##Q) - #if AXIS_IS_TMC(X) - TMC_SAY_CHOPPER_TIME(X); - #endif - #if AXIS_IS_TMC(X2) - TMC_SAY_CHOPPER_TIME(X2); - #endif - #if AXIS_IS_TMC(Y) - TMC_SAY_CHOPPER_TIME(Y); - #endif - #if AXIS_IS_TMC(Y2) - TMC_SAY_CHOPPER_TIME(Y2); - #endif - #if AXIS_IS_TMC(Z) - TMC_SAY_CHOPPER_TIME(Z); - #endif - #if AXIS_IS_TMC(Z2) - TMC_SAY_CHOPPER_TIME(Z2); - #endif - #if AXIS_IS_TMC(Z3) - TMC_SAY_CHOPPER_TIME(Z3); - #endif - #if AXIS_IS_TMC(Z4) - TMC_SAY_CHOPPER_TIME(Z4); - #endif - #if AXIS_IS_TMC(I) - TMC_SAY_CHOPPER_TIME(I); - #endif - #if AXIS_IS_TMC(J) - TMC_SAY_CHOPPER_TIME(J); - #endif - #if AXIS_IS_TMC(K) - TMC_SAY_CHOPPER_TIME(K); - #endif - #if AXIS_IS_TMC(U) - TMC_SAY_CHOPPER_TIME(U); - #endif - #if AXIS_IS_TMC(V) - TMC_SAY_CHOPPER_TIME(V); - #endif - #if AXIS_IS_TMC(W) - TMC_SAY_CHOPPER_TIME(W); - #endif - #if AXIS_IS_TMC(E0) - TMC_SAY_CHOPPER_TIME(E0); - #endif - #if AXIS_IS_TMC(E1) - TMC_SAY_CHOPPER_TIME(E1); - #endif - #if AXIS_IS_TMC(E2) - TMC_SAY_CHOPPER_TIME(E2); - #endif - #if AXIS_IS_TMC(E3) - TMC_SAY_CHOPPER_TIME(E3); - #endif - #if AXIS_IS_TMC(E4) - TMC_SAY_CHOPPER_TIME(E4); - #endif - #if AXIS_IS_TMC(E5) - TMC_SAY_CHOPPER_TIME(E5); - #endif - #if AXIS_IS_TMC(E6) - TMC_SAY_CHOPPER_TIME(E6); - #endif - #if AXIS_IS_TMC(E7) - TMC_SAY_CHOPPER_TIME(E7); - #endif + #define TMC_SAY_CHOPPER_TIME(Q) OPTCODE(Q##_IS_TRINAMIC, tmc_print_chopper_time(stepper##Q)) + MAP(TMC_SAY_CHOPPER_TIME, ALL_AXIS_NAMES) } } diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp index 69d77e875e..64326b32af 100644 --- a/Marlin/src/gcode/gcode.cpp +++ b/Marlin/src/gcode/gcode.cpp @@ -139,6 +139,7 @@ int8_t GcodeSuite::get_target_extruder_from_command() { * Get the target E stepper from the 'T' parameter. * If there is no 'T' parameter then dval will be substituted. * Returns -1 if the resulting E stepper index is out of range. + * Use a default of -2 for silent failure. */ int8_t GcodeSuite::get_target_e_stepper_from_command(const int8_t dval/*=-1*/) { const int8_t e = parser.intval('T', dval); diff --git a/Marlin/src/gcode/gcode.h b/Marlin/src/gcode/gcode.h index 1f3ccba37c..7ba1c58d2a 100644 --- a/Marlin/src/gcode/gcode.h +++ b/Marlin/src/gcode/gcode.h @@ -159,7 +159,7 @@ * M120 - Enable endstops detection. * M121 - Disable endstops detection. * - * M122 - Debug stepper (Requires at least one _DRIVER_TYPE defined as TMC2130/2160/5130/5160/2208/2209/2660) + * M122 - Debug stepper (Requires *_DRIVER_TYPE TMC(2130|2160|5130|5160|2208|2209|2660)) * M123 - Report fan tachometers. (Requires En_FAN_TACHO_PIN) Optionally set auto-report interval. (Requires AUTO_REPORT_FANS) * M125 - Save current position and move to filament change position. (Requires PARK_HEAD_ON_PAUSE) * @@ -265,7 +265,7 @@ * M552 - Get or set IP address. Enable/disable network interface. (Requires enabled Ethernet port) * M553 - Get or set IP netmask. (Requires enabled Ethernet port) * M554 - Get or set IP gateway. (Requires enabled Ethernet port) - * M569 - Enable stealthChop on an axis. (Requires at least one _DRIVER_TYPE to be TMC2130/2160/2208/2209/5130/5160) + * M569 - Enable stealthChop on an axis. (Requires *_DRIVER_TYPE TMC(2130|2160|2208|2209|5130|5160)) * M575 - Change the serial baud rate. (Requires BAUD_RATE_GCODE) * M592 - Get or set Nonlinear Extrusion parameters. (Requires NONLINEAR_EXTRUSION) * M593 - Get or set input shaping parameters. (Requires INPUT_SHAPING_[XY]) @@ -308,17 +308,18 @@ * * M871 - Print/reset/clear first layer temperature offset values. (Requires PTC_PROBE, PTC_BED, or PTC_HOTEND) * M876 - Handle Prompt Response. (Requires HOST_PROMPT_SUPPORT and not EMERGENCY_PARSER) - * M900 - Get or Set Linear Advance K-factor. (Requires LIN_ADVANCE) - * M906 - Set or get motor current in milliamps using axis codes XYZE, etc. Report values if no axis codes given. (Requires at least one _DRIVER_TYPE defined as TMC2130/2160/5130/5160/2208/2209/2660) + * M900 - Set or Report Linear Advance K-factor. (Requires LIN_ADVANCE) + * M906 - Set or Report motor current in milliamps using axis codes XYZE, etc. Report values if no axis codes given. (Requires *_DRIVER_TYPE TMC(2130|2160|5130|5160|2208|2209|2660)) * M907 - Set digital trimpot motor current using axis codes. (Requires a board with digital trimpots) * M908 - Control digital trimpot directly. (Requires HAS_MOTOR_CURRENT_DAC or DIGIPOTSS_PIN) * M909 - Print digipot/DAC current value. (Requires HAS_MOTOR_CURRENT_DAC) * M910 - Commit digipot/DAC value to external EEPROM via I2C. (Requires HAS_MOTOR_CURRENT_DAC) - * M911 - Report stepper driver overtemperature pre-warn condition. (Requires at least one _DRIVER_TYPE defined as TMC2130/2160/5130/5160/2208/2209/2660) - * M912 - Clear stepper driver overtemperature pre-warn condition flag. (Requires at least one _DRIVER_TYPE defined as TMC2130/2160/5130/5160/2208/2209/2660) + * M911 - Report stepper driver overtemperature pre-warn condition. (Requires *_DRIVER_TYPE TMC(2130|2160|5130|5160|2208|2209|2660)) + * M912 - Clear stepper driver overtemperature pre-warn condition flag. (Requires *_DRIVER_TYPE TMC(2130|2160|5130|5160|2208|2209|2660)) * M913 - Set HYBRID_THRESHOLD speed. (Requires HYBRID_THRESHOLD) * M914 - Set StallGuard sensitivity. (Requires SENSORLESS_HOMING or SENSORLESS_PROBING) - * M919 - Get or Set motor Chopper Times (time_off, hysteresis_end, hysteresis_start) using axis codes XYZE, etc. If no parameters are given, report. (Requires at least one _DRIVER_TYPE defined as TMC2130/2160/5130/5160/2208/2209/2660) + * M919 - Set or Report motor Chopper Times (time_off, hysteresis_end, hysteresis_start) using axis codes XYZE, etc. + * If no parameters are given, report. (Requires *_DRIVER_TYPE TMC(2130|2160|5130|5160|2208|2209|2660)) * M936 - OTA update firmware. (Requires OTA_FIRMWARE_UPDATE) * M951 - Set Magnetic Parking Extruder parameters. (Requires MAGNETIC_PARKING_EXTRUDER) * M3426 - Read MCP3426 ADC over I2C. (Requires HAS_MCP3426_ADC) diff --git a/Marlin/src/inc/Conditionals-4-adv.h b/Marlin/src/inc/Conditionals-4-adv.h index b697f22a20..eaa8aca5b0 100644 --- a/Marlin/src/inc/Conditionals-4-adv.h +++ b/Marlin/src/inc/Conditionals-4-adv.h @@ -1307,8 +1307,75 @@ #endif #endif +#if AXIS_IS_TMC(X) + #define X_IS_TRINAMIC 1 +#endif +#if AXIS_IS_TMC(Y) + #define Y_IS_TRINAMIC 1 +#endif +#if AXIS_IS_TMC(Z) + #define Z_IS_TRINAMIC 1 +#endif +#if AXIS_IS_TMC(I) + #define I_IS_TRINAMIC 1 +#endif +#if AXIS_IS_TMC(J) + #define J_IS_TRINAMIC 1 +#endif +#if AXIS_IS_TMC(K) + #define K_IS_TRINAMIC 1 +#endif +#if AXIS_IS_TMC(U) + #define U_IS_TRINAMIC 1 +#endif +#if AXIS_IS_TMC(V) + #define V_IS_TRINAMIC 1 +#endif +#if AXIS_IS_TMC(W) + #define W_IS_TRINAMIC 1 +#endif +#if AXIS_IS_TMC(X2) + #define X2_IS_TRINAMIC 1 +#endif +#if AXIS_IS_TMC(Y2) + #define Y2_IS_TRINAMIC 1 +#endif +#if AXIS_IS_TMC(Z2) + #define Z2_IS_TRINAMIC 1 +#endif +#if AXIS_IS_TMC(Z3) + #define Z3_IS_TRINAMIC 1 +#endif +#if AXIS_IS_TMC(Z4) + #define Z4_IS_TRINAMIC 1 +#endif +#if AXIS_IS_TMC(E0) + #define E0_IS_TRINAMIC 1 +#endif +#if AXIS_IS_TMC(E1) + #define E1_IS_TRINAMIC 1 +#endif +#if AXIS_IS_TMC(E2) + #define E2_IS_TRINAMIC 1 +#endif +#if AXIS_IS_TMC(E3) + #define E3_IS_TRINAMIC 1 +#endif +#if AXIS_IS_TMC(E4) + #define E4_IS_TRINAMIC 1 +#endif +#if AXIS_IS_TMC(E5) + #define E5_IS_TRINAMIC 1 +#endif +#if AXIS_IS_TMC(E6) + #define E6_IS_TRINAMIC 1 +#endif +#if AXIS_IS_TMC(E7) + #define E7_IS_TRINAMIC 1 +#endif + // Test for edge stepping on any axis -#define AXIS_HAS_DEDGE(A) (ENABLED(EDGE_STEPPING) && AXIS_IS_TMC(A)) +#define AXIS_HAS_DEDGE(A) ALL(EDGE_STEPPING, A##_IS_TRINAMIC) #if ENABLED(DIRECT_STEPPING) #ifndef STEPPER_PAGES diff --git a/Marlin/src/inc/Conditionals-5-post.h b/Marlin/src/inc/Conditionals-5-post.h index d07a5914cd..93be95c95d 100644 --- a/Marlin/src/inc/Conditionals-5-post.h +++ b/Marlin/src/inc/Conditionals-5-post.h @@ -1052,7 +1052,7 @@ // Steppers #if HAS_X_AXIS - #if PIN_EXISTS(X_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(X)) + #if PIN_EXISTS(X_ENABLE) || ALL(SOFTWARE_DRIVER_ENABLE, X_IS_TRINAMIC) #define HAS_X_ENABLE 1 #endif #if PIN_EXISTS(X_DIR) @@ -1065,7 +1065,7 @@ #define HAS_X_MS_PINS 1 #endif - #if PIN_EXISTS(X2_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(X2)) + #if PIN_EXISTS(X2_ENABLE) || ALL(SOFTWARE_DRIVER_ENABLE, X2_IS_TRINAMIC) #define HAS_X2_ENABLE 1 #endif #if PIN_EXISTS(X2_DIR) @@ -1084,7 +1084,7 @@ */ #if HAS_Y_AXIS - #if PIN_EXISTS(Y_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(Y)) + #if PIN_EXISTS(Y_ENABLE) || ALL(SOFTWARE_DRIVER_ENABLE, Y_IS_TRINAMIC) #define HAS_Y_ENABLE 1 #endif #if PIN_EXISTS(Y_DIR) @@ -1098,7 +1098,7 @@ #endif #if HAS_Y2_STEPPER - #if PIN_EXISTS(Y2_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(Y2)) + #if PIN_EXISTS(Y2_ENABLE) || ALL(SOFTWARE_DRIVER_ENABLE, Y2_IS_TRINAMIC) #define HAS_Y2_ENABLE 1 #endif #if PIN_EXISTS(Y2_DIR) @@ -1114,7 +1114,7 @@ #endif #if HAS_Z_AXIS - #if PIN_EXISTS(Z_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(Z)) + #if PIN_EXISTS(Z_ENABLE) || ALL(SOFTWARE_DRIVER_ENABLE, Z_IS_TRINAMIC) #define HAS_Z_ENABLE 1 #endif #if PIN_EXISTS(Z_DIR) @@ -1129,7 +1129,7 @@ #endif #if NUM_Z_STEPPERS >= 2 - #if PIN_EXISTS(Z2_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(Z2)) + #if PIN_EXISTS(Z2_ENABLE) || ALL(SOFTWARE_DRIVER_ENABLE, Z2_IS_TRINAMIC) #define HAS_Z2_ENABLE 1 #endif #if PIN_EXISTS(Z2_DIR) @@ -1144,7 +1144,7 @@ #endif #if NUM_Z_STEPPERS >= 3 - #if PIN_EXISTS(Z3_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(Z3)) + #if PIN_EXISTS(Z3_ENABLE) || ALL(SOFTWARE_DRIVER_ENABLE, Z3_IS_TRINAMIC) #define HAS_Z3_ENABLE 1 #endif #if PIN_EXISTS(Z3_DIR) @@ -1159,7 +1159,7 @@ #endif #if NUM_Z_STEPPERS >= 4 - #if PIN_EXISTS(Z4_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(Z4)) + #if PIN_EXISTS(Z4_ENABLE) || ALL(SOFTWARE_DRIVER_ENABLE, Z4_IS_TRINAMIC) #define HAS_Z4_ENABLE 1 #endif #if PIN_EXISTS(Z4_DIR) @@ -1174,7 +1174,7 @@ #endif #if HAS_I_AXIS - #if PIN_EXISTS(I_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(I)) + #if PIN_EXISTS(I_ENABLE) || ALL(SOFTWARE_DRIVER_ENABLE, I_IS_TRINAMIC) #define HAS_I_ENABLE 1 #endif #if PIN_EXISTS(I_DIR) @@ -1189,7 +1189,7 @@ #endif #if HAS_J_AXIS - #if PIN_EXISTS(J_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(J)) + #if PIN_EXISTS(J_ENABLE) || ALL(SOFTWARE_DRIVER_ENABLE, J_IS_TRINAMIC) #define HAS_J_ENABLE 1 #endif #if PIN_EXISTS(J_DIR) @@ -1204,7 +1204,7 @@ #endif #if HAS_K_AXIS - #if PIN_EXISTS(K_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(K)) + #if PIN_EXISTS(K_ENABLE) || ALL(SOFTWARE_DRIVER_ENABLE, K_IS_TRINAMIC) #define HAS_K_ENABLE 1 #endif #if PIN_EXISTS(K_DIR) @@ -1219,7 +1219,7 @@ #endif #if HAS_U_AXIS - #if PIN_EXISTS(U_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(U)) + #if PIN_EXISTS(U_ENABLE) || ALL(SOFTWARE_DRIVER_ENABLE, U_IS_TRINAMIC) #define HAS_U_ENABLE 1 #endif #if PIN_EXISTS(U_DIR) @@ -1234,7 +1234,7 @@ #endif #if HAS_V_AXIS - #if PIN_EXISTS(V_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(V)) + #if PIN_EXISTS(V_ENABLE) || ALL(SOFTWARE_DRIVER_ENABLE, V_IS_TRINAMIC) #define HAS_V_ENABLE 1 #endif #if PIN_EXISTS(V_DIR) @@ -1249,7 +1249,7 @@ #endif #if HAS_W_AXIS - #if PIN_EXISTS(W_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(W)) + #if PIN_EXISTS(W_ENABLE) || ALL(SOFTWARE_DRIVER_ENABLE, W_IS_TRINAMIC) #define HAS_W_ENABLE 1 #endif #if PIN_EXISTS(W_DIR) @@ -1266,7 +1266,7 @@ // Extruder steppers and solenoids #if HAS_EXTRUDERS - #if PIN_EXISTS(E0_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E0)) + #if PIN_EXISTS(E0_ENABLE) || ALL(SOFTWARE_DRIVER_ENABLE, E0_IS_TRINAMIC) #define HAS_E0_ENABLE 1 #endif #if PIN_EXISTS(E0_DIR) @@ -1280,7 +1280,7 @@ #endif #if E_STEPPERS > 1 || ENABLED(E_DUAL_STEPPER_DRIVERS) - #if PIN_EXISTS(E1_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E1)) + #if PIN_EXISTS(E1_ENABLE) || ALL(SOFTWARE_DRIVER_ENABLE, E1_IS_TRINAMIC) #define HAS_E1_ENABLE 1 #endif #if PIN_EXISTS(E1_DIR) @@ -1295,7 +1295,7 @@ #endif #if E_STEPPERS > 2 - #if PIN_EXISTS(E2_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E2)) + #if PIN_EXISTS(E2_ENABLE) || ALL(SOFTWARE_DRIVER_ENABLE, E2_IS_TRINAMIC) #define HAS_E2_ENABLE 1 #endif #if PIN_EXISTS(E2_DIR) @@ -1310,7 +1310,7 @@ #endif #if E_STEPPERS > 3 - #if PIN_EXISTS(E3_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E3)) + #if PIN_EXISTS(E3_ENABLE) || ALL(SOFTWARE_DRIVER_ENABLE, E3_IS_TRINAMIC) #define HAS_E3_ENABLE 1 #endif #if PIN_EXISTS(E3_DIR) @@ -1325,7 +1325,7 @@ #endif #if E_STEPPERS > 4 - #if PIN_EXISTS(E4_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E4)) + #if PIN_EXISTS(E4_ENABLE) || ALL(SOFTWARE_DRIVER_ENABLE, E4_IS_TRINAMIC) #define HAS_E4_ENABLE 1 #endif #if PIN_EXISTS(E4_DIR) @@ -1340,7 +1340,7 @@ #endif #if E_STEPPERS > 5 - #if PIN_EXISTS(E5_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E5)) + #if PIN_EXISTS(E5_ENABLE) || ALL(SOFTWARE_DRIVER_ENABLE, E5_IS_TRINAMIC) #define HAS_E5_ENABLE 1 #endif #if PIN_EXISTS(E5_DIR) @@ -1355,7 +1355,7 @@ #endif #if E_STEPPERS > 6 - #if PIN_EXISTS(E6_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E6)) + #if PIN_EXISTS(E6_ENABLE) || ALL(SOFTWARE_DRIVER_ENABLE, E6_IS_TRINAMIC) #define HAS_E6_ENABLE 1 #endif #if PIN_EXISTS(E6_DIR) @@ -1370,7 +1370,7 @@ #endif #if E_STEPPERS > 7 - #if PIN_EXISTS(E7_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E7)) + #if PIN_EXISTS(E7_ENABLE) || ALL(SOFTWARE_DRIVER_ENABLE, E7_IS_TRINAMIC) #define HAS_E7_ENABLE 1 #endif #if PIN_EXISTS(E7_DIR) @@ -1441,7 +1441,7 @@ #undef Z4_STALL_SENSITIVITY #endif - #if AXIS_IS_TMC(X) + #if X_IS_TRINAMIC #if defined(X_STALL_SENSITIVITY) && AXIS_HAS_STALLGUARD(X) #define X_SENSORLESS 1 #if ENABLED(SPI_ENDSTOPS) && AXIS_HAS_SPI(X) @@ -1461,7 +1461,7 @@ #define X_SLAVE_ADDRESS 0 #endif #endif - #if AXIS_IS_TMC(X2) + #if X2_IS_TRINAMIC #if defined(X2_STALL_SENSITIVITY) && AXIS_HAS_STALLGUARD(X2) #define X2_SENSORLESS 1 #endif @@ -1479,7 +1479,7 @@ #endif #endif - #if AXIS_IS_TMC(Y) + #if Y_IS_TRINAMIC #if defined(Y_STALL_SENSITIVITY) && AXIS_HAS_STALLGUARD(Y) #define Y_SENSORLESS 1 #if ENABLED(SPI_ENDSTOPS) && AXIS_HAS_SPI(Y) @@ -1499,7 +1499,7 @@ #define Y_SLAVE_ADDRESS 0 #endif #endif - #if AXIS_IS_TMC(Y2) + #if Y2_IS_TRINAMIC #if defined(Y2_STALL_SENSITIVITY) && AXIS_HAS_STALLGUARD(Y2) #define Y2_SENSORLESS 1 #endif @@ -1517,7 +1517,7 @@ #endif #endif - #if AXIS_IS_TMC(Z) + #if Z_IS_TRINAMIC #if defined(Z_STALL_SENSITIVITY) && AXIS_HAS_STALLGUARD(Z) #define Z_SENSORLESS 1 #if ENABLED(SPI_ENDSTOPS) && AXIS_HAS_SPI(Z) @@ -1537,7 +1537,7 @@ #define Z_SLAVE_ADDRESS 0 #endif #endif - #if NUM_Z_STEPPERS >= 2 && AXIS_IS_TMC(Z2) + #if NUM_Z_STEPPERS >= 2 && Z2_IS_TRINAMIC #if defined(Z2_STALL_SENSITIVITY) && AXIS_HAS_STALLGUARD(Z2) #define Z2_SENSORLESS 1 #endif @@ -1554,7 +1554,7 @@ #define Z2_SLAVE_ADDRESS 0 #endif #endif - #if NUM_Z_STEPPERS >= 3 && AXIS_IS_TMC(Z3) + #if NUM_Z_STEPPERS >= 3 && Z3_IS_TRINAMIC #if defined(Z3_STALL_SENSITIVITY) && AXIS_HAS_STALLGUARD(Z3) #define Z3_SENSORLESS 1 #endif @@ -1571,7 +1571,7 @@ #define Z3_SLAVE_ADDRESS 0 #endif #endif - #if NUM_Z_STEPPERS >= 4 && AXIS_IS_TMC(Z4) + #if NUM_Z_STEPPERS >= 4 && Z4_IS_TRINAMIC #if defined(Z4_STALL_SENSITIVITY) && AXIS_HAS_STALLGUARD(Z4) #define Z4_SENSORLESS 1 #endif @@ -1589,7 +1589,7 @@ #endif #endif - #if AXIS_IS_TMC(I) + #if I_IS_TRINAMIC #if defined(I_STALL_SENSITIVITY) && AXIS_HAS_STALLGUARD(I) #define I_SENSORLESS 1 #if ENABLED(SPI_ENDSTOPS) && AXIS_HAS_SPI(I) @@ -1610,7 +1610,7 @@ #endif #endif - #if AXIS_IS_TMC(J) + #if J_IS_TRINAMIC #if defined(J_STALL_SENSITIVITY) && AXIS_HAS_STALLGUARD(J) #define J_SENSORLESS 1 #if ENABLED(SPI_ENDSTOPS) && AXIS_HAS_SPI(J) @@ -1631,7 +1631,7 @@ #endif #endif - #if AXIS_IS_TMC(K) + #if K_IS_TRINAMIC #if defined(K_STALL_SENSITIVITY) && AXIS_HAS_STALLGUARD(K) #define K_SENSORLESS 1 #if ENABLED(SPI_ENDSTOPS) && AXIS_HAS_SPI(K) @@ -1652,7 +1652,7 @@ #endif #endif - #if AXIS_IS_TMC(U) + #if U_IS_TRINAMIC #if defined(U_STALL_SENSITIVITY) && AXIS_HAS_STALLGUARD(U) #define U_SENSORLESS 1 #if ENABLED(SPI_ENDSTOPS) && AXIS_HAS_SPI(U) @@ -1673,7 +1673,7 @@ #endif #endif - #if AXIS_IS_TMC(V) + #if V_IS_TRINAMIC #if defined(V_STALL_SENSITIVITY) && AXIS_HAS_STALLGUARD(V) #define V_SENSORLESS 1 #if ENABLED(SPI_ENDSTOPS) && AXIS_HAS_SPI(V) @@ -1694,7 +1694,7 @@ #endif #endif - #if AXIS_IS_TMC(W) + #if W_IS_TRINAMIC #if defined(W_STALL_SENSITIVITY) && AXIS_HAS_STALLGUARD(W) #define W_SENSORLESS 1 #if ENABLED(SPI_ENDSTOPS) && AXIS_HAS_SPI(W) @@ -1715,7 +1715,7 @@ #endif #endif - #if AXIS_IS_TMC(E0) + #if E0_IS_TRINAMIC #if AXIS_HAS_STEALTHCHOP(E0) #define E0_HAS_STEALTHCHOP 1 #endif @@ -1729,7 +1729,7 @@ #define E0_SLAVE_ADDRESS 0 #endif #endif - #if AXIS_IS_TMC(E1) + #if E1_IS_TRINAMIC #if AXIS_HAS_STEALTHCHOP(E1) #define E1_HAS_STEALTHCHOP 1 #endif @@ -1743,7 +1743,7 @@ #define E1_SLAVE_ADDRESS 0 #endif #endif - #if AXIS_IS_TMC(E2) + #if E2_IS_TRINAMIC #if AXIS_HAS_STEALTHCHOP(E2) #define E2_HAS_STEALTHCHOP 1 #endif @@ -1757,7 +1757,7 @@ #define E2_SLAVE_ADDRESS 0 #endif #endif - #if AXIS_IS_TMC(E3) + #if E3_IS_TRINAMIC #if AXIS_HAS_STEALTHCHOP(E3) #define E3_HAS_STEALTHCHOP 1 #endif @@ -1771,7 +1771,7 @@ #define E3_SLAVE_ADDRESS 0 #endif #endif - #if AXIS_IS_TMC(E4) + #if E4_IS_TRINAMIC #if AXIS_HAS_STEALTHCHOP(E4) #define E4_HAS_STEALTHCHOP 1 #endif @@ -1785,7 +1785,7 @@ #define E4_SLAVE_ADDRESS 0 #endif #endif - #if AXIS_IS_TMC(E5) + #if E5_IS_TRINAMIC #if AXIS_HAS_STEALTHCHOP(E5) #define E5_HAS_STEALTHCHOP 1 #endif @@ -1799,7 +1799,7 @@ #define E5_SLAVE_ADDRESS 0 #endif #endif - #if AXIS_IS_TMC(E6) + #if E6_IS_TRINAMIC #if AXIS_HAS_STEALTHCHOP(E6) #define E6_HAS_STEALTHCHOP 1 #endif @@ -1813,7 +1813,7 @@ #define E6_SLAVE_ADDRESS 0 #endif #endif - #if AXIS_IS_TMC(E7) + #if E7_IS_TRINAMIC #if AXIS_HAS_STEALTHCHOP(E7) #define E7_HAS_STEALTHCHOP 1 #endif diff --git a/Marlin/src/inc/Conditionals-6-type.h b/Marlin/src/inc/Conditionals-6-type.h index e14c6d7ce5..bd8e3b78b4 100644 --- a/Marlin/src/inc/Conditionals-6-type.h +++ b/Marlin/src/inc/Conditionals-6-type.h @@ -38,10 +38,53 @@ #endif // If an axis's Homing Current differs from standard current... -#define HAS_CURRENT_HOME(N) (N##_CURRENT_HOME > 0 && N##_CURRENT_HOME != N##_CURRENT) +#define HAS_HOME_CURRENT(N) (N##_CURRENT_HOME > 0 && N##_CURRENT_HOME != N##_CURRENT) +#if HAS_HOME_CURRENT(X) + #define X_HAS_HOME_CURRENT 1 +#endif +#if HAS_HOME_CURRENT(Y) + #define Y_HAS_HOME_CURRENT 1 +#endif +#if HAS_HOME_CURRENT(Z) + #define Z_HAS_HOME_CURRENT 1 +#endif +#if HAS_HOME_CURRENT(I) + #define I_HAS_HOME_CURRENT 1 +#endif +#if HAS_HOME_CURRENT(J) + #define J_HAS_HOME_CURRENT 1 +#endif +#if HAS_HOME_CURRENT(K) + #define K_HAS_HOME_CURRENT 1 +#endif +#if HAS_HOME_CURRENT(U) + #define U_HAS_HOME_CURRENT 1 +#endif +#if HAS_HOME_CURRENT(V) + #define V_HAS_HOME_CURRENT 1 +#endif +#if HAS_HOME_CURRENT(W) + #define W_HAS_HOME_CURRENT 1 +#endif +#if HAS_HOME_CURRENT(X2) + #define X2_HAS_HOME_CURRENT 1 +#endif +#if HAS_HOME_CURRENT(Y2) + #define Y2_HAS_HOME_CURRENT 1 +#endif +#if HAS_HOME_CURRENT(Z2) + #define Z2_HAS_HOME_CURRENT 1 +#endif +#if HAS_HOME_CURRENT(Z3) + #define Z3_HAS_HOME_CURRENT 1 +#endif +#if HAS_HOME_CURRENT(Z4) + #define Z4_HAS_HOME_CURRENT 1 +#endif +#undef HAS_HOME_CURRENT // Does any axis have homing current? -#define _OR_HAS_CURR_HOME(N) HAS_CURRENT_HOME(N) || +#define _OR_HAS_CURR_HOME(N) N##_HAS_HOME_CURRENT || #if MAIN_AXIS_MAP(_OR_HAS_CURR_HOME) MAP(_OR_HAS_CURR_HOME, X2, Y2, Z2, Z3, Z4) 0 #define HAS_HOMING_CURRENT 1 #endif diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index 0029980ada..3c4cd44561 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -1805,8 +1805,8 @@ static_assert(NUM_SERVOS <= NUM_SERVO_PLUGS, "NUM_SERVOS (or some servo index) i #undef _BAD_HOME_CURRENT #if ENABLED(PROBING_USE_CURRENT_HOME) - #if (defined(Z_CURRENT_HOME) && !HAS_CURRENT_HOME(Z)) || (defined(Z2_CURRENT_HOME) && !HAS_CURRENT_HOME(Z2)) \ - || (defined(Z3_CURRENT_HOME) && !HAS_CURRENT_HOME(Z3)) || (defined(Z4_CURRENT_HOME) && !HAS_CURRENT_HOME(Z4)) + #if (defined(Z_CURRENT_HOME) && !Z_HAS_HOME_CURRENT) || (defined(Z2_CURRENT_HOME) && !Z2_HAS_HOME_CURRENT) \ + || (defined(Z3_CURRENT_HOME) && !Z3_HAS_HOME_CURRENT) || (defined(Z4_CURRENT_HOME) && !Z4_HAS_HOME_CURRENT) #error "PROBING_USE_CURRENT_HOME requires a Z_CURRENT_HOME value that differs from Z_CURRENT." #endif #endif @@ -2452,28 +2452,28 @@ static_assert(NUM_SERVOS <= NUM_SERVO_PLUGS, "NUM_SERVOS (or some servo index) i #endif #endif -#if E_STEPPERS > 0 && !(PINS_EXIST(E0_STEP, E0_DIR) && HAS_E0_ENABLE) +#if E_STEPPERS > 0 && !ALL(HAS_E0_DIR, HAS_E0_STEP, HAS_E0_ENABLE) #error "E0_STEP_PIN, E0_DIR_PIN, or E0_ENABLE_PIN not defined for this board." #endif -#if E_STEPPERS > 1 && !(PINS_EXIST(E1_STEP, E1_DIR) && HAS_E1_ENABLE) +#if E_STEPPERS > 1 && !ALL(HAS_E1_DIR, HAS_E1_STEP, HAS_E1_ENABLE) #error "E1_STEP_PIN, E1_DIR_PIN, or E1_ENABLE_PIN not defined for this board." #endif -#if E_STEPPERS > 2 && !(PINS_EXIST(E2_STEP, E2_DIR) && HAS_E2_ENABLE) +#if E_STEPPERS > 2 && !ALL(HAS_E2_DIR, HAS_E2_STEP, HAS_E2_ENABLE) #error "E2_STEP_PIN, E2_DIR_PIN, or E2_ENABLE_PIN not defined for this board." #endif -#if E_STEPPERS > 3 && !(PINS_EXIST(E3_STEP, E3_DIR) && HAS_E3_ENABLE) +#if E_STEPPERS > 3 && !ALL(HAS_E3_DIR, HAS_E3_STEP, HAS_E3_ENABLE) #error "E3_STEP_PIN, E3_DIR_PIN, or E3_ENABLE_PIN not defined for this board." #endif -#if E_STEPPERS > 4 && !(PINS_EXIST(E4_STEP, E4_DIR) && HAS_E4_ENABLE) +#if E_STEPPERS > 4 && !ALL(HAS_E4_DIR, HAS_E4_STEP, HAS_E4_ENABLE) #error "E4_STEP_PIN, E4_DIR_PIN, or E4_ENABLE_PIN not defined for this board." #endif -#if E_STEPPERS > 5 && !(PINS_EXIST(E5_STEP, E5_DIR) && HAS_E5_ENABLE) +#if E_STEPPERS > 5 && !ALL(HAS_E5_DIR, HAS_E5_STEP, HAS_E5_ENABLE) #error "E5_STEP_PIN, E5_DIR_PIN, or E5_ENABLE_PIN not defined for this board." #endif -#if E_STEPPERS > 6 && !(PINS_EXIST(E6_STEP, E6_DIR) && HAS_E6_ENABLE) +#if E_STEPPERS > 6 && !ALL(HAS_E6_DIR, HAS_E6_STEP, HAS_E6_ENABLE) #error "E6_STEP_PIN, E6_DIR_PIN, or E6_ENABLE_PIN not defined for this board." #endif -#if E_STEPPERS > 7 && !(PINS_EXIST(E7_STEP, E7_DIR) && HAS_E7_ENABLE) +#if E_STEPPERS > 7 && !ALL(HAS_E7_DIR, HAS_E7_STEP, HAS_E7_ENABLE) #error "E7_STEP_PIN, E7_DIR_PIN, or E7_ENABLE_PIN not defined for this board." #endif @@ -3230,7 +3230,7 @@ static_assert(NUM_SERVOS <= NUM_SERVO_PLUGS, "NUM_SERVOS (or some servo index) i #undef INVALID_TMC_ADDRESS #define _TMC_MICROSTEP_IS_VALID(MS) (MS == 0 || MS == 2 || MS == 4 || MS == 8 || MS == 16 || MS == 32 || MS == 64 || MS == 128 || MS == 256) -#define TMC_MICROSTEP_IS_VALID(M) (!AXIS_IS_TMC(M) || _TMC_MICROSTEP_IS_VALID(M##_MICROSTEPS)) +#define TMC_MICROSTEP_IS_VALID(M) (!M##_IS_TRINAMIC || _TMC_MICROSTEP_IS_VALID(M##_MICROSTEPS)) #define INVALID_TMC_MS(ST) static_assert(0, "Invalid " STRINGIFY(ST) "_MICROSTEPS. Valid values are 0, 2, 4, 8, 16, 32, 64, 128, and 256.") #if !TMC_MICROSTEP_IS_VALID(X) diff --git a/Marlin/src/inc/Warnings.cpp b/Marlin/src/inc/Warnings.cpp index df2279a08b..7c107220af 100644 --- a/Marlin/src/inc/Warnings.cpp +++ b/Marlin/src/inc/Warnings.cpp @@ -742,24 +742,24 @@ #endif #if USE_SENSORLESS && DISABLED(NO_HOMING_CURRENT_WARNING) - #if ENABLED(X_SENSORLESS) && defined(X_CURRENT_HOME) && !HAS_CURRENT_HOME(X) - #warning "It's recommended to set X_CURRENT_HOME lower than X_CURRENT with SENSORLESS_HOMING. (Define NO_HOMING_CURRENT_WARNING to suppress this warning.)" - #elif ENABLED(X2_SENSORLESS) && defined(X2_CURRENT_HOME) && !HAS_CURRENT_HOME(X2) - #warning "It's recommended to set X2_CURRENT_HOME lower than X2_CURRENT with SENSORLESS_HOMING. (Define NO_HOMING_CURRENT_WARNING to suppress this warning.)" + #if ENABLED(X_SENSORLESS) && defined(X_CURRENT_HOME) && !X_HAS_HOME_CURRENT + #warning "With SENSORLESS_HOMING it is recommended to set X_CURRENT_HOME less than X_CURRENT. (Define NO_HOMING_CURRENT_WARNING to suppress this warning.)" + #elif ENABLED(X2_SENSORLESS) && defined(X2_CURRENT_HOME) && !X2_HAS_HOME_CURRENT + #warning "With SENSORLESS_HOMING it is recommended to set X2_CURRENT_HOME less than X2_CURRENT. (Define NO_HOMING_CURRENT_WARNING to suppress this warning.)" #endif - #if ENABLED(Y_SENSORLESS) && defined(Y_CURRENT_HOME) && !HAS_CURRENT_HOME(Y) - #warning "It's recommended to set Y_CURRENT_HOME lower than Y_CURRENT with SENSORLESS_HOMING. (Define NO_HOMING_CURRENT_WARNING to suppress this warning.)" - #elif ENABLED(Y2_SENSORLESS) && defined(Y2_CURRENT_HOME) && !HAS_CURRENT_HOME(Y2) - #warning "It's recommended to set Y2_CURRENT_HOME lower than Y2_CURRENT with SENSORLESS_HOMING. (Define NO_HOMING_CURRENT_WARNING to suppress this warning.)" + #if ENABLED(Y_SENSORLESS) && defined(Y_CURRENT_HOME) && !Y_HAS_HOME_CURRENT + #warning "With SENSORLESS_HOMING it is recommended to set Y_CURRENT_HOME less than Y_CURRENT. (Define NO_HOMING_CURRENT_WARNING to suppress this warning.)" + #elif ENABLED(Y2_SENSORLESS) && defined(Y2_CURRENT_HOME) && !Y2_HAS_HOME_CURRENT + #warning "With SENSORLESS_HOMING it is recommended to set Y2_CURRENT_HOME less than Y2_CURRENT. (Define NO_HOMING_CURRENT_WARNING to suppress this warning.)" #endif - #if ENABLED(Z_SENSORLESS) && defined(Z_CURRENT_HOME) && !HAS_CURRENT_HOME(Z) - #warning "It's recommended to set Z_CURRENT_HOME lower than Z_CURRENT with SENSORLESS_HOMING. (Define NO_HOMING_CURRENT_WARNING to suppress this warning.)" - #elif ENABLED(Z2_SENSORLESS) && defined(Z2_CURRENT_HOME) && !HAS_CURRENT_HOME(Z2) - #warning "It's recommended to set Z2_CURRENT_HOME lower than Z2_CURRENT with SENSORLESS_HOMING. (Define NO_HOMING_CURRENT_WARNING to suppress this warning.)" - #elif ENABLED(Z3_SENSORLESS) && defined(Z3_CURRENT_HOME) && !HAS_CURRENT_HOME(Z3) - #warning "It's recommended to set Z3_CURRENT_HOME lower than Z3_CURRENT with SENSORLESS_HOMING. (Define NO_HOMING_CURRENT_WARNING to suppress this warning.)" - #elif ENABLED(Z4_SENSORLESS) && defined(Z4_CURRENT_HOME) && !HAS_CURRENT_HOME(Z4) - #warning "It's recommended to set Z4_CURRENT_HOME lower than Z4_CURRENT with SENSORLESS_HOMING. (Define NO_HOMING_CURRENT_WARNING to suppress this warning.)" + #if ENABLED(Z_SENSORLESS) && defined(Z_CURRENT_HOME) && !Z_HAS_HOME_CURRENT + #warning "With SENSORLESS_HOMING it is recommended to set Z_CURRENT_HOME less than Z_CURRENT. (Define NO_HOMING_CURRENT_WARNING to suppress this warning.)" + #elif ENABLED(Z2_SENSORLESS) && defined(Z2_CURRENT_HOME) && !Z2_HAS_HOME_CURRENT + #warning "With SENSORLESS_HOMING it is recommended to set Z2_CURRENT_HOME less than Z2_CURRENT. (Define NO_HOMING_CURRENT_WARNING to suppress this warning.)" + #elif ENABLED(Z3_SENSORLESS) && defined(Z3_CURRENT_HOME) && !Z3_HAS_HOME_CURRENT + #warning "With SENSORLESS_HOMING it is recommended to set Z3_CURRENT_HOME less than Z3_CURRENT. (Define NO_HOMING_CURRENT_WARNING to suppress this warning.)" + #elif ENABLED(Z4_SENSORLESS) && defined(Z4_CURRENT_HOME) && !Z4_HAS_HOME_CURRENT + #warning "With SENSORLESS_HOMING it is recommended to set Z4_CURRENT_HOME less than Z4_CURRENT. (Define NO_HOMING_CURRENT_WARNING to suppress this warning.)" #endif #endif diff --git a/Marlin/src/lcd/e3v2/jyersui/dwin.cpp b/Marlin/src/lcd/e3v2/jyersui/dwin.cpp index 09100e5029..b9c637d722 100644 --- a/Marlin/src/lcd/e3v2/jyersui/dwin.cpp +++ b/Marlin/src/lcd/e3v2/jyersui/dwin.cpp @@ -3068,7 +3068,7 @@ void JyersDWIN::menuItemHandler(const uint8_t menu, const uint8_t item, bool dra drawMenu(ID_Advanced, ADVANCED_TMC); break; - #if AXIS_IS_TMC(X) + #if X_IS_TRINAMIC case TMC_STEPPER_CURRENT_X: static float stepper_current_x; @@ -3084,7 +3084,7 @@ void JyersDWIN::menuItemHandler(const uint8_t menu, const uint8_t item, bool dra break; #endif - #if AXIS_IS_TMC(Y) + #if Y_IS_TRINAMIC case TMC_STEPPER_CURRENT_Y: static float stepper_current_y; if (draw) { @@ -3098,7 +3098,7 @@ void JyersDWIN::menuItemHandler(const uint8_t menu, const uint8_t item, bool dra break; #endif - #if AXIS_IS_TMC(Z) + #if Z_IS_TRINAMIC case TMC_STEPPER_CURRENT_Z: static float stepper_current_z; if (draw) { @@ -3112,7 +3112,7 @@ void JyersDWIN::menuItemHandler(const uint8_t menu, const uint8_t item, bool dra break; #endif - #if AXIS_IS_TMC(E0) + #if E0_IS_TRINAMIC case TMC_STEPPER_CURRENT_E: static float stepper_current_e; if (draw) { diff --git a/Marlin/src/lcd/e3v2/proui/dwin.cpp b/Marlin/src/lcd/e3v2/proui/dwin.cpp index a775d2ae27..7428a4b254 100644 --- a/Marlin/src/lcd/e3v2/proui/dwin.cpp +++ b/Marlin/src/lcd/e3v2/proui/dwin.cpp @@ -3607,49 +3607,28 @@ void drawTuneMenu() { #endif #if HAS_TRINAMIC_CONFIG - #if AXIS_IS_TMC(X) + #if X_IS_TRINAMIC void setXTMCCurrent() { setPIntOnClick(MIN_TMC_CURRENT, MAX_TMC_CURRENT, []{ stepperX.refresh_stepper_current(); }); } #endif - #if AXIS_IS_TMC(Y) + #if Y_IS_TRINAMIC void setYTMCCurrent() { setPIntOnClick(MIN_TMC_CURRENT, MAX_TMC_CURRENT, []{ stepperY.refresh_stepper_current(); }); } #endif - #if AXIS_IS_TMC(Z) + #if Z_IS_TRINAMIC void setZTMCCurrent() { setPIntOnClick(MIN_TMC_CURRENT, MAX_TMC_CURRENT, []{ stepperZ.refresh_stepper_current(); }); } #endif - #if AXIS_IS_TMC(E0) + #if E0_IS_TRINAMIC void setETMCCurrent() { setPIntOnClick(MIN_TMC_CURRENT, MAX_TMC_CURRENT, []{ stepperE0.refresh_stepper_current(); }); } #endif void drawTrinamicConfigMenu() { - constexpr uint8_t items = (1 - #if AXIS_IS_TMC(X) - + 1 - #endif - #if AXIS_IS_TMC(Y) - + 1 - #endif - #if AXIS_IS_TMC(Z) - + 1 - #endif - #if AXIS_IS_TMC(E0) - + 1 - #endif - ); + constexpr uint8_t items = 1 + COUNT_ENABLED(X_IS_TRINAMIC, Y_IS_TRINAMIC, Z_IS_TRINAMIC, E0_IS_TRINAMIC); checkkey = ID_Menu; if (SET_MENU(trinamicConfigMenu, MSG_TMC_DRIVERS, items)) { BACK_ITEM(drawAdvancedSettingsMenu); - #if AXIS_IS_TMC(X) - EDIT_ITEM(ICON_TMCXSet, MSG_TMC_ACURRENT, onDrawPIntMenu, setXTMCCurrent, &stepperX.val_mA); - #endif - #if AXIS_IS_TMC(Y) - EDIT_ITEM(ICON_TMCYSet, MSG_TMC_BCURRENT, onDrawPIntMenu, setYTMCCurrent, &stepperY.val_mA); - #endif - #if AXIS_IS_TMC(Z) - EDIT_ITEM(ICON_TMCZSet, MSG_TMC_CCURRENT, onDrawPIntMenu, setZTMCCurrent, &stepperZ.val_mA); - #endif - #if AXIS_IS_TMC(E0) - EDIT_ITEM(ICON_TMCESet, MSG_TMC_ECURRENT, onDrawPIntMenu, setETMCCurrent, &stepperE0.val_mA); - #endif + TERN_(X_IS_TRINAMIC, EDIT_ITEM(ICON_TMCXSet, MSG_TMC_ACURRENT, onDrawPIntMenu, setXTMCCurrent, &stepperX.val_mA)); + TERN_(Y_IS_TRINAMIC, EDIT_ITEM(ICON_TMCYSet, MSG_TMC_BCURRENT, onDrawPIntMenu, setYTMCCurrent, &stepperY.val_mA)); + TERN_(Z_IS_TRINAMIC, EDIT_ITEM(ICON_TMCZSet, MSG_TMC_CCURRENT, onDrawPIntMenu, setZTMCCurrent, &stepperZ.val_mA)); + TERN_(E0_IS_TRINAMIC, EDIT_ITEM(ICON_TMCESet, MSG_TMC_ECURRENT, onDrawPIntMenu, setETMCCurrent, &stepperE0.val_mA)); } updateMenu(trinamicConfigMenu); } diff --git a/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp b/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp index 4182c3f2ca..08eff9d41e 100644 --- a/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp +++ b/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp @@ -707,28 +707,28 @@ const struct DGUS_VP_Variable ListOfVP[] PROGMEM = { #endif #if HAS_TRINAMIC_CONFIG // TMC Current Setting - #if AXIS_IS_TMC(X) + #if X_IS_TRINAMIC VPHELPER(VP_TMC_X_Current, &stepperX.val_mA, screen.tmcChangeConfig, screen.sendWordValueToDisplay), #endif - #if AXIS_IS_TMC(Y) + #if Y_IS_TRINAMIC VPHELPER(VP_TMC_Y_Current, &stepperY.val_mA, screen.tmcChangeConfig, screen.sendWordValueToDisplay), #endif - #if AXIS_IS_TMC(Z) + #if Z_IS_TRINAMIC VPHELPER(VP_TMC_Z_Current, &stepperZ.val_mA, screen.tmcChangeConfig, screen.sendWordValueToDisplay), #endif - #if AXIS_IS_TMC(E0) + #if E0_IS_TRINAMIC VPHELPER(VP_TMC_E0_Current, &stepperE0.val_mA, screen.tmcChangeConfig, screen.sendWordValueToDisplay), #endif - #if AXIS_IS_TMC(E1) + #if E1_IS_TRINAMIC VPHELPER(VP_TMC_E1_Current, &stepperE1.val_mA, screen.tmcChangeConfig, screen.sendWordValueToDisplay), #endif - #if AXIS_IS_TMC(X2) + #if X2_IS_TRINAMIC VPHELPER(VP_TMC_X1_Current, &stepperX2.val_mA, screen.tmcChangeConfig, screen.sendWordValueToDisplay), #endif - #if AXIS_IS_TMC(Y2) + #if Y2_IS_TRINAMIC VPHELPER(VP_TMC_Y1_Current, &stepperY2.val_mA, screen.tmcChangeConfig, screen.sendWordValueToDisplay), #endif - #if AXIS_IS_TMC(Z2) + #if Z2_IS_TRINAMIC VPHELPER(VP_TMC_Z1_Current, &stepperZ2.val_mA, screen.tmcChangeConfig, screen.sendWordValueToDisplay), #endif #endif diff --git a/Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.cpp b/Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.cpp index 1999518607..1761451da1 100644 --- a/Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.cpp +++ b/Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.cpp @@ -673,49 +673,49 @@ void DGUSScreenHandlerMKS::tmcChangeConfig(DGUS_VP_Variable &var, void *val_ptr) #endif break; case VP_TMC_X_Current: - #if AXIS_IS_TMC(X) + #if X_IS_TRINAMIC stepperX.rms_current(tmc_val); settings.save(); #endif break; case VP_TMC_X1_Current: - #if AXIS_IS_TMC(X2) + #if X2_IS_TRINAMIC stepperX2.rms_current(tmc_val); settings.save(); #endif break; case VP_TMC_Y_Current: - #if AXIS_IS_TMC(Y) + #if Y_IS_TRINAMIC stepperY.rms_current(tmc_val); settings.save(); #endif break; case VP_TMC_Y1_Current: - #if AXIS_IS_TMC(X2) + #if X2_IS_TRINAMIC stepperY2.rms_current(tmc_val); settings.save(); #endif break; case VP_TMC_Z_Current: - #if AXIS_IS_TMC(Z) + #if Z_IS_TRINAMIC stepperZ.rms_current(tmc_val); settings.save(); #endif break; case VP_TMC_Z1_Current: - #if AXIS_IS_TMC(Z2) + #if Z2_IS_TRINAMIC stepperZ2.rms_current(tmc_val); settings.save(); #endif break; case VP_TMC_E0_Current: - #if AXIS_IS_TMC(E0) + #if E0_IS_TRINAMIC stepperE0.rms_current(tmc_val); settings.save(); #endif break; case VP_TMC_E1_Current: - #if AXIS_IS_TMC(E1) + #if E1_IS_TRINAMIC stepperE1.rms_current(tmc_val); settings.save(); #endif diff --git a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/stepper_current_screen.cpp b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/stepper_current_screen.cpp index ddd273aa47..3511ce3719 100644 --- a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/stepper_current_screen.cpp +++ b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/stepper_current_screen.cpp @@ -33,86 +33,60 @@ void StepperCurrentScreen::onRedraw(draw_mode_t what) { widgets_t w(what); w.precision(0); w.units(GET_TEXT_F(MSG_UNITS_MILLIAMP)); - w.heading( GET_TEXT_F(MSG_TMC_CURRENT)); - #if AXIS_IS_TMC(X) - w.color(x_axis) .adjuster( 2, GET_TEXT_F(MSG_AXIS_X), getAxisCurrent_mA(X) ); - #endif - #if AXIS_IS_TMC(X2) - w.color(x_axis) .adjuster( 4, GET_TEXT_F(MSG_AXIS_X2), getAxisCurrent_mA(X2) ); - #endif - #if AXIS_IS_TMC(Y) - w.color(y_axis) .adjuster( 6, GET_TEXT_F(MSG_AXIS_Y), getAxisCurrent_mA(Y) ); - #endif - #if AXIS_IS_TMC(Y2) - w.color(x_axis) .adjuster( 8, GET_TEXT_F(MSG_AXIS_Y2), getAxisCurrent_mA(Y2) ); - #endif - #if AXIS_IS_TMC(Z) - w.color(z_axis) .adjuster(10, GET_TEXT_F(MSG_AXIS_Z), getAxisCurrent_mA(Z) ); - #endif - #if AXIS_IS_TMC(Z2) - w.color(z_axis) .adjuster(12, GET_TEXT_F(MSG_AXIS_Z2), getAxisCurrent_mA(Z2) ); - #endif - #if AXIS_IS_TMC(E0) - w.color(e_axis) .adjuster(14, GET_TEXT_F( - #if EXTRUDERS == 1 - MSG_AXIS_E - #else - MSG_AXIS_E1 - #endif - ), getAxisCurrent_mA(E0) ); - #endif - #if AXIS_IS_TMC(E1) - w.color(e_axis).adjuster(16, GET_TEXT_F(MSG_AXIS_E2), getAxisCurrent_mA(E1) ); - #endif - #if AXIS_IS_TMC(E2) - w.color(e_axis).adjuster(18, GET_TEXT_F(MSG_AXIS_E3), getAxisCurrent_mA(E2) ); - #endif - #if AXIS_IS_TMC(E3) - w.color(e_axis).adjuster(20, GET_TEXT_F(MSG_AXIS_E4), getAxisCurrent_mA(E3) ); - #endif + w.heading(GET_TEXT_F(MSG_TMC_CURRENT)); + TERN_(X_IS_TRINAMIC, w.color(x_axis) .adjuster( 2, GET_TEXT_F(MSG_AXIS_X), getAxisCurrent_mA(X) ) ); + TERN_(X2_IS_TRINAMIC, w.color(x_axis) .adjuster( 4, GET_TEXT_F(MSG_AXIS_X2), getAxisCurrent_mA(X2)) ); + TERN_(Y_IS_TRINAMIC, w.color(y_axis) .adjuster( 6, GET_TEXT_F(MSG_AXIS_Y), getAxisCurrent_mA(Y) ) ); + TERN_(Y2_IS_TRINAMIC, w.color(x_axis) .adjuster( 8, GET_TEXT_F(MSG_AXIS_Y2), getAxisCurrent_mA(Y2)) ); + TERN_(Z_IS_TRINAMIC, w.color(z_axis) .adjuster(10, GET_TEXT_F(MSG_AXIS_Z), getAxisCurrent_mA(Z) ) ); + TERN_(Z2_IS_TRINAMIC, w.color(z_axis) .adjuster(12, GET_TEXT_F(MSG_AXIS_Z2), getAxisCurrent_mA(Z2)) ); + TERN_(E0_IS_TRINAMIC, w.color(e_axis) .adjuster(14, GET_TEXT_F(TERN(HAS_MULTI_EXTRUDER, MSG_AXIS_E1, MSG_AXIS_E)), getAxisCurrent_mA(E0)) ); + TERN_(E1_IS_TRINAMIC, w.color(e_axis) .adjuster(16, GET_TEXT_F(MSG_AXIS_E2), getAxisCurrent_mA(E1)) ); + TERN_(E2_IS_TRINAMIC, w.color(e_axis) .adjuster(18, GET_TEXT_F(MSG_AXIS_E3), getAxisCurrent_mA(E2)) ); + TERN_(E3_IS_TRINAMIC, w.color(e_axis) .adjuster(20, GET_TEXT_F(MSG_AXIS_E4), getAxisCurrent_mA(E3)) ); w.increments(); } bool StepperCurrentScreen::onTouchHeld(uint8_t tag) { const float increment = getIncrement(); switch (tag) { - #if AXIS_IS_TMC(X) + #if X_IS_TRINAMIC case 2: UI_DECREMENT(AxisCurrent_mA, X ); break; case 3: UI_INCREMENT(AxisCurrent_mA, X ); break; #endif - #if AXIS_IS_TMC(X2) + #if X2_IS_TRINAMIC case 4: UI_DECREMENT(AxisCurrent_mA, X2 ); break; case 5: UI_INCREMENT(AxisCurrent_mA, X2 ); break; #endif - #if AXIS_IS_TMC(Y) + #if Y_IS_TRINAMIC case 6: UI_DECREMENT(AxisCurrent_mA, Y ); break; case 7: UI_INCREMENT(AxisCurrent_mA, Y ); break; #endif - #if AXIS_IS_TMC(Y2) + #if Y2_IS_TRINAMIC case 8: UI_DECREMENT(AxisCurrent_mA, Y2 ); break; case 9: UI_INCREMENT(AxisCurrent_mA, Y2 ); break; #endif - #if AXIS_IS_TMC(Z) + #if Z_IS_TRINAMIC case 10: UI_DECREMENT(AxisCurrent_mA, Z ); break; case 11: UI_INCREMENT(AxisCurrent_mA, Z ); break; #endif - #if AXIS_IS_TMC(Z2) + #if Z2_IS_TRINAMIC case 12: UI_DECREMENT(AxisCurrent_mA, Z2 ); break; case 13: UI_INCREMENT(AxisCurrent_mA, Z2 ); break; #endif - #if AXIS_IS_TMC(E0) + #if E0_IS_TRINAMIC case 14: UI_DECREMENT(AxisCurrent_mA, E0); break; case 15: UI_INCREMENT(AxisCurrent_mA, E0); break; #endif - #if AXIS_IS_TMC(E1) + #if E1_IS_TRINAMIC case 16: UI_DECREMENT(AxisCurrent_mA, E1); break; case 17: UI_INCREMENT(AxisCurrent_mA, E1); break; #endif - #if AXIS_IS_TMC(E2) + #if E2_IS_TRINAMIC case 18: UI_DECREMENT(AxisCurrent_mA, E2); break; case 19: UI_INCREMENT(AxisCurrent_mA, E2); break; #endif - #if AXIS_IS_TMC(E3) + #if E3_IS_TRINAMIC case 20: UI_DECREMENT(AxisCurrent_mA, E3); break; case 21: UI_INCREMENT(AxisCurrent_mA, E3); break; #endif diff --git a/Marlin/src/lcd/extui/mks_ui/draw_number_key.cpp b/Marlin/src/lcd/extui/mks_ui/draw_number_key.cpp index 400b294701..c44cabd10a 100644 --- a/Marlin/src/lcd/extui/mks_ui/draw_number_key.cpp +++ b/Marlin/src/lcd/extui/mks_ui/draw_number_key.cpp @@ -102,13 +102,13 @@ static void disp_key_value() { #endif #if HAS_X_AXIS - case XMaxFeedRate: dtostrf(planner.settings.max_feedrate_mm_s[X_AXIS], 1, 1, public_buf_m); break; + case XMaxFeedRate: dtostrf(planner.settings.max_feedrate_mm_s[X_AXIS], 1, 1, public_buf_m); break; #endif #if HAS_Y_AXIS - case YMaxFeedRate: dtostrf(planner.settings.max_feedrate_mm_s[Y_AXIS], 1, 1, public_buf_m); break; + case YMaxFeedRate: dtostrf(planner.settings.max_feedrate_mm_s[Y_AXIS], 1, 1, public_buf_m); break; #endif #if HAS_Z_AXIS - case ZMaxFeedRate: dtostrf(planner.settings.max_feedrate_mm_s[Z_AXIS], 1, 1, public_buf_m); break; + case ZMaxFeedRate: dtostrf(planner.settings.max_feedrate_mm_s[Z_AXIS], 1, 1, public_buf_m); break; #endif #if HAS_EXTRUDERS case E0MaxFeedRate: dtostrf(planner.settings.max_feedrate_mm_s[E_AXIS], 1, 1, public_buf_m); break; @@ -134,13 +134,13 @@ static void disp_key_value() { #if ENABLED(EDITABLE_STEPS_PER_UNIT) #if HAS_X_AXIS - case Xstep: dtostrf(planner.settings.axis_steps_per_mm[X_AXIS], 1, 1, public_buf_m); break; + case Xstep: dtostrf(planner.settings.axis_steps_per_mm[X_AXIS], 1, 1, public_buf_m); break; #endif #if HAS_Y_AXIS - case Ystep: dtostrf(planner.settings.axis_steps_per_mm[Y_AXIS], 1, 1, public_buf_m); break; + case Ystep: dtostrf(planner.settings.axis_steps_per_mm[Y_AXIS], 1, 1, public_buf_m); break; #endif #if HAS_Z_AXIS - case Zstep: dtostrf(planner.settings.axis_steps_per_mm[Z_AXIS], 1, 1, public_buf_m); break; + case Zstep: dtostrf(planner.settings.axis_steps_per_mm[Z_AXIS], 1, 1, public_buf_m); break; #endif #if HAS_EXTRUDERS case E0step: dtostrf(planner.settings.axis_steps_per_mm[E_AXIS], 1, 1, public_buf_m); break; @@ -150,21 +150,11 @@ static void disp_key_value() { #endif #endif - #if AXIS_IS_TMC(X) - case Xcurrent: dtostrf(stepperX.getMilliamps(), 1, 1, public_buf_m); break; - #endif - #if AXIS_IS_TMC(Y) - case Ycurrent: dtostrf(stepperY.getMilliamps(), 1, 1, public_buf_m); break; - #endif - #if AXIS_IS_TMC(Z) - case Zcurrent: dtostrf(stepperZ.getMilliamps(), 1, 1, public_buf_m); break; - #endif - #if AXIS_IS_TMC(E0) - case E0current: dtostrf(stepperE0.getMilliamps(), 1, 1, public_buf_m); break; - #endif - #if AXIS_IS_TMC(E1) - case E1current: dtostrf(stepperE1.getMilliamps(), 1, 1, public_buf_m); break; - #endif + case Xcurrent: TERN_(X_IS_TRINAMIC, dtostrf(stepperX.getMilliamps(), 1, 1, public_buf_m)); break; + case Ycurrent: TERN_(Y_IS_TRINAMIC, dtostrf(stepperY.getMilliamps(), 1, 1, public_buf_m)); break; + case Zcurrent: TERN_(Z_IS_TRINAMIC, dtostrf(stepperZ.getMilliamps(), 1, 1, public_buf_m)); break; + case E0current: TERN_(E0_IS_TRINAMIC, dtostrf(stepperE0.getMilliamps(), 1, 1, public_buf_m)); break; + case E1current: TERN_(E1_IS_TRINAMIC, dtostrf(stepperE1.getMilliamps(), 1, 1, public_buf_m)); break; case pause_pos_x: dtostrf(gCfgItems.pausePosX, 1, 1, public_buf_m); break; case pause_pos_y: dtostrf(gCfgItems.pausePosY, 1, 1, public_buf_m); break; @@ -275,21 +265,11 @@ static void set_value_confirm() { case E1step: planner.settings.axis_steps_per_mm[E_AXIS_N(1)] = atof(key_value); planner.refresh_positioning(); break; #endif - #if AXIS_IS_TMC(X) - case Xcurrent: stepperX.rms_current(atoi(key_value)); break; - #endif - #if AXIS_IS_TMC(Y) - case Ycurrent: stepperY.rms_current(atoi(key_value)); break; - #endif - #if AXIS_IS_TMC(Z) - case Zcurrent: stepperZ.rms_current(atoi(key_value)); break; - #endif - #if AXIS_IS_TMC(E0) - case E0current: stepperE0.rms_current(atoi(key_value)); break; - #endif - #if AXIS_IS_TMC(E1) - case E1current: stepperE1.rms_current(atoi(key_value)); break; - #endif + case Xcurrent: TERN_(X_IS_TRINAMIC, stepperX.rms_current(atoi(key_value))); break; + case Ycurrent: TERN_(Y_IS_TRINAMIC, stepperY.rms_current(atoi(key_value))); break; + case Zcurrent: TERN_(Z_IS_TRINAMIC, stepperZ.rms_current(atoi(key_value))); break; + case E0current: TERN_(E0_IS_TRINAMIC, stepperE0.rms_current(atoi(key_value))); break; + case E1current: TERN_(E1_IS_TRINAMIC, stepperE1.rms_current(atoi(key_value))); break; case pause_pos_x: gCfgItems.pausePosX = atof(key_value); update_spi_flash(); break; case pause_pos_y: gCfgItems.pausePosY = atof(key_value); update_spi_flash(); break; diff --git a/Marlin/src/lcd/extui/mks_ui/draw_tmc_current_settings.cpp b/Marlin/src/lcd/extui/mks_ui/draw_tmc_current_settings.cpp index b243c88705..cbb2bc059f 100644 --- a/Marlin/src/lcd/extui/mks_ui/draw_tmc_current_settings.cpp +++ b/Marlin/src/lcd/extui/mks_ui/draw_tmc_current_settings.cpp @@ -49,34 +49,16 @@ static void event_handler(lv_obj_t *obj, lv_event_t event) { if (event != LV_EVENT_RELEASED) return; lv_clear_tmc_current_settings(); switch (obj->mks_obj_id) { - case ID_TMC_CURRENT_RETURN: - uiCfg.para_ui_page = false; - draw_return_ui(); - return; - #if AXIS_IS_TMC(X) - case ID_TMC_CURRENT_X: value = Xcurrent; break; - #endif - #if AXIS_IS_TMC(Y) - case ID_TMC_CURRENT_Y: value = Ycurrent; break; - #endif - #if AXIS_IS_TMC(Z) - case ID_TMC_CURRENT_Z: value = Zcurrent; break; - #endif - #if AXIS_IS_TMC(E0) - case ID_TMC_CURRENT_E0: value = E0current; break; - #endif - #if AXIS_IS_TMC(E1) - case ID_TMC_CURRENT_E1: value = E1current; break; - #endif + case ID_TMC_CURRENT_RETURN: uiCfg.para_ui_page = false; draw_return_ui(); return; - case ID_TMC_CURRENT_UP: - uiCfg.para_ui_page = false; - lv_draw_tmc_current_settings(); - return; - case ID_TMC_CURRENT_DOWN: - uiCfg.para_ui_page = true; - lv_draw_tmc_current_settings(); - return; + case ID_TMC_CURRENT_X: TERN_(X_IS_TRINAMIC, value = Xcurrent); break; + case ID_TMC_CURRENT_Y: TERN_(Y_IS_TRINAMIC, value = Ycurrent); break; + case ID_TMC_CURRENT_Z: TERN_(Z_IS_TRINAMIC, value = Zcurrent); break; + case ID_TMC_CURRENT_E0: TERN_(E0_IS_TRINAMIC, value = E0current); break; + case ID_TMC_CURRENT_E1: TERN_(E1_IS_TRINAMIC, value = E1current); break; + + case ID_TMC_CURRENT_UP: uiCfg.para_ui_page = false; lv_draw_tmc_current_settings(); return; + case ID_TMC_CURRENT_DOWN: uiCfg.para_ui_page = true; lv_draw_tmc_current_settings(); return; } lv_draw_number_key(); @@ -87,46 +69,26 @@ void lv_draw_tmc_current_settings() { float milliamps; if (!uiCfg.para_ui_page) { - #if AXIS_IS_TMC(X) - milliamps = stepperX.getMilliamps(); - #else - milliamps = -1; - #endif + milliamps = TERN(X_IS_TRINAMIC, stepperX.getMilliamps(), -1); dtostrf(milliamps, 1, 1, public_buf_l); lv_screen_menu_item_1_edit(scr, machine_menu.X_Current, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_TMC_CURRENT_X, 0, public_buf_l); - #if AXIS_IS_TMC(Y) - milliamps = stepperY.getMilliamps(); - #else - milliamps = -1; - #endif + milliamps = TERN(Y_IS_TRINAMIC, stepperY.getMilliamps(), -1); dtostrf(milliamps, 1, 1, public_buf_l); lv_screen_menu_item_1_edit(scr, machine_menu.Y_Current, PARA_UI_POS_X, PARA_UI_POS_Y * 2, event_handler, ID_TMC_CURRENT_Y, 1, public_buf_l); - #if AXIS_IS_TMC(Z) - milliamps = stepperZ.getMilliamps(); - #else - milliamps = -1; - #endif + milliamps = TERN(Z_IS_TRINAMIC, stepperZ.getMilliamps(), -1); dtostrf(milliamps, 1, 1, public_buf_l); lv_screen_menu_item_1_edit(scr, machine_menu.Z_Current, PARA_UI_POS_X, PARA_UI_POS_Y * 3, event_handler, ID_TMC_CURRENT_Z, 2, public_buf_l); - #if AXIS_IS_TMC(E0) - milliamps = stepperE0.getMilliamps(); - #else - milliamps = -1; - #endif + milliamps = TERN(E0_IS_TRINAMIC, stepperE0.getMilliamps(), -1); dtostrf(milliamps, 1, 1, public_buf_l); lv_screen_menu_item_1_edit(scr, machine_menu.E0_Current, PARA_UI_POS_X, PARA_UI_POS_Y * 4, event_handler, ID_TMC_CURRENT_E0, 3, public_buf_l); lv_big_button_create(scr, "F:/bmp_back70x40.bin", machine_menu.next, PARA_UI_TURN_PAGE_POS_X, PARA_UI_TURN_PAGE_POS_Y, event_handler, ID_TMC_CURRENT_DOWN, true); } else { - #if AXIS_IS_TMC(E1) - milliamps = stepperE1.getMilliamps(); - #else - milliamps = -1; - #endif + milliamps = TERN(E1_IS_TRINAMIC, stepperE1.getMilliamps(), -1); dtostrf(milliamps, 1, 1, public_buf_l); lv_screen_menu_item_1_edit(scr, machine_menu.E1_Current, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_TMC_CURRENT_E1, 0, public_buf_l); @@ -137,9 +99,8 @@ void lv_draw_tmc_current_settings() { } void lv_clear_tmc_current_settings() { - #if HAS_ROTARY_ENCODER - if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g); - #endif + if (TERN0(HAS_ROTARY_ENCODER, gCfgItems.encoder_enable)) + lv_group_remove_all_objs(g); lv_obj_del(scr); } diff --git a/Marlin/src/lcd/extui/ui_api.cpp b/Marlin/src/lcd/extui/ui_api.cpp index 5b6caf378a..b88df6ee9d 100644 --- a/Marlin/src/lcd/extui/ui_api.cpp +++ b/Marlin/src/lcd/extui/ui_api.cpp @@ -438,156 +438,68 @@ namespace ExtUI { #if HAS_TRINAMIC_CONFIG float getAxisCurrent_mA(const axis_t axis) { switch (axis) { - #if AXIS_IS_TMC(X) - case X: return stepperX.getMilliamps(); - #endif - #if AXIS_IS_TMC(Y) - case Y: return stepperY.getMilliamps(); - #endif - #if AXIS_IS_TMC(Z) - case Z: return stepperZ.getMilliamps(); - #endif - #if AXIS_IS_TMC(I) - case I: return stepperI.getMilliamps(); - #endif - #if AXIS_IS_TMC(J) - case J: return stepperJ.getMilliamps(); - #endif - #if AXIS_IS_TMC(K) - case K: return stepperK.getMilliamps(); - #endif - #if AXIS_IS_TMC(U) - case U: return stepperU.getMilliamps(); - #endif - #if AXIS_IS_TMC(V) - case V: return stepperV.getMilliamps(); - #endif - #if AXIS_IS_TMC(W) - case W: return stepperW.getMilliamps(); - #endif - #if AXIS_IS_TMC(X2) - case X2: return stepperX2.getMilliamps(); - #endif - #if AXIS_IS_TMC(Y2) - case Y2: return stepperY2.getMilliamps(); - #endif - #if AXIS_IS_TMC(Z2) - case Z2: return stepperZ2.getMilliamps(); - #endif - #if AXIS_IS_TMC(Z3) - case Z3: return stepperZ3.getMilliamps(); - #endif - #if AXIS_IS_TMC(Z4) - case Z4: return stepperZ4.getMilliamps(); - #endif + OPTCODE(X_IS_TRINAMIC, case X: return stepperX.getMilliamps()) + OPTCODE(Y_IS_TRINAMIC, case Y: return stepperY.getMilliamps()) + OPTCODE(Z_IS_TRINAMIC, case Z: return stepperZ.getMilliamps()) + OPTCODE(I_IS_TRINAMIC, case I: return stepperI.getMilliamps()) + OPTCODE(J_IS_TRINAMIC, case J: return stepperJ.getMilliamps()) + OPTCODE(K_IS_TRINAMIC, case K: return stepperK.getMilliamps()) + OPTCODE(U_IS_TRINAMIC, case U: return stepperU.getMilliamps()) + OPTCODE(V_IS_TRINAMIC, case V: return stepperV.getMilliamps()) + OPTCODE(W_IS_TRINAMIC, case W: return stepperW.getMilliamps()) + OPTCODE(X2_IS_TRINAMIC, case X2: return stepperX2.getMilliamps()) + OPTCODE(Y2_IS_TRINAMIC, case Y2: return stepperY2.getMilliamps()) + OPTCODE(Z2_IS_TRINAMIC, case Z2: return stepperZ2.getMilliamps()) + OPTCODE(Z3_IS_TRINAMIC, case Z3: return stepperZ3.getMilliamps()) + OPTCODE(Z4_IS_TRINAMIC, case Z4: return stepperZ4.getMilliamps()) default: return NAN; }; } float getAxisCurrent_mA(const extruder_t extruder) { switch (extruder) { - #if AXIS_IS_TMC(E0) - case E0: return stepperE0.getMilliamps(); - #endif - #if AXIS_IS_TMC(E1) - case E1: return stepperE1.getMilliamps(); - #endif - #if AXIS_IS_TMC(E2) - case E2: return stepperE2.getMilliamps(); - #endif - #if AXIS_IS_TMC(E3) - case E3: return stepperE3.getMilliamps(); - #endif - #if AXIS_IS_TMC(E4) - case E4: return stepperE4.getMilliamps(); - #endif - #if AXIS_IS_TMC(E5) - case E5: return stepperE5.getMilliamps(); - #endif - #if AXIS_IS_TMC(E6) - case E6: return stepperE6.getMilliamps(); - #endif - #if AXIS_IS_TMC(E7) - case E7: return stepperE7.getMilliamps(); - #endif + OPTCODE(E0_IS_TRINAMIC, case E0: return stepperE0.getMilliamps()) + OPTCODE(E1_IS_TRINAMIC, case E1: return stepperE1.getMilliamps()) + OPTCODE(E2_IS_TRINAMIC, case E2: return stepperE2.getMilliamps()) + OPTCODE(E3_IS_TRINAMIC, case E3: return stepperE3.getMilliamps()) + OPTCODE(E4_IS_TRINAMIC, case E4: return stepperE4.getMilliamps()) + OPTCODE(E5_IS_TRINAMIC, case E5: return stepperE5.getMilliamps()) + OPTCODE(E6_IS_TRINAMIC, case E6: return stepperE6.getMilliamps()) + OPTCODE(E7_IS_TRINAMIC, case E7: return stepperE7.getMilliamps()) default: return NAN; }; } void setAxisCurrent_mA(const_float_t mA, const axis_t axis) { switch (axis) { - #if AXIS_IS_TMC(X) - case X: stepperX.rms_current(constrain(mA, 400, 1500)); break; - #endif - #if AXIS_IS_TMC(Y) - case Y: stepperY.rms_current(constrain(mA, 400, 1500)); break; - #endif - #if AXIS_IS_TMC(Z) - case Z: stepperZ.rms_current(constrain(mA, 400, 1500)); break; - #endif - #if AXIS_IS_TMC(I) - case I: stepperI.rms_current(constrain(mA, 400, 1500)); break; - #endif - #if AXIS_IS_TMC(J) - case J: stepperJ.rms_current(constrain(mA, 400, 1500)); break; - #endif - #if AXIS_IS_TMC(K) - case K: stepperK.rms_current(constrain(mA, 400, 1500)); break; - #endif - #if AXIS_IS_TMC(U) - case U: stepperU.rms_current(constrain(mA, 400, 1500)); break; - #endif - #if AXIS_IS_TMC(V) - case V: stepperV.rms_current(constrain(mA, 400, 1500)); break; - #endif - #if AXIS_IS_TMC(W) - case W: stepperW.rms_current(constrain(mA, 400, 1500)); break; - #endif - #if AXIS_IS_TMC(X2) - case X2: stepperX2.rms_current(constrain(mA, 400, 1500)); break; - #endif - #if AXIS_IS_TMC(Y2) - case Y2: stepperY2.rms_current(constrain(mA, 400, 1500)); break; - #endif - #if AXIS_IS_TMC(Z2) - case Z2: stepperZ2.rms_current(constrain(mA, 400, 1500)); break; - #endif - #if AXIS_IS_TMC(Z3) - case Z3: stepperZ3.rms_current(constrain(mA, 400, 1500)); break; - #endif - #if AXIS_IS_TMC(Z4) - case Z4: stepperZ4.rms_current(constrain(mA, 400, 1500)); break; - #endif + case X: TERN_(X_IS_TRINAMIC, stepperX.rms_current(constrain(mA, 400, 1500))); break; + case Y: TERN_(Y_IS_TRINAMIC, stepperY.rms_current(constrain(mA, 400, 1500))); break; + case Z: TERN_(Z_IS_TRINAMIC, stepperZ.rms_current(constrain(mA, 400, 1500))); break; + case I: TERN_(I_IS_TRINAMIC, stepperI.rms_current(constrain(mA, 400, 1500))); break; + case J: TERN_(J_IS_TRINAMIC, stepperJ.rms_current(constrain(mA, 400, 1500))); break; + case K: TERN_(K_IS_TRINAMIC, stepperK.rms_current(constrain(mA, 400, 1500))); break; + case U: TERN_(U_IS_TRINAMIC, stepperU.rms_current(constrain(mA, 400, 1500))); break; + case V: TERN_(V_IS_TRINAMIC, stepperV.rms_current(constrain(mA, 400, 1500))); break; + case W: TERN_(W_IS_TRINAMIC, stepperW.rms_current(constrain(mA, 400, 1500))); break; + case X2: TERN_(X2_IS_TRINAMIC, stepperX2.rms_current(constrain(mA, 400, 1500))); break; + case Y2: TERN_(Y2_IS_TRINAMIC, stepperY2.rms_current(constrain(mA, 400, 1500))); break; + case Z2: TERN_(Z2_IS_TRINAMIC, stepperZ2.rms_current(constrain(mA, 400, 1500))); break; + case Z3: TERN_(Z3_IS_TRINAMIC, stepperZ3.rms_current(constrain(mA, 400, 1500))); break; + case Z4: TERN_(Z4_IS_TRINAMIC, stepperZ4.rms_current(constrain(mA, 400, 1500))); break; default: break; }; } void setAxisCurrent_mA(const_float_t mA, const extruder_t extruder) { switch (extruder) { - #if AXIS_IS_TMC(E0) - case E0: stepperE0.rms_current(constrain(mA, 400, 1500)); break; - #endif - #if AXIS_IS_TMC(E1) - case E1: stepperE1.rms_current(constrain(mA, 400, 1500)); break; - #endif - #if AXIS_IS_TMC(E2) - case E2: stepperE2.rms_current(constrain(mA, 400, 1500)); break; - #endif - #if AXIS_IS_TMC(E3) - case E3: stepperE3.rms_current(constrain(mA, 400, 1500)); break; - #endif - #if AXIS_IS_TMC(E4) - case E4: stepperE4.rms_current(constrain(mA, 400, 1500)); break; - #endif - #if AXIS_IS_TMC(E5) - case E5: stepperE5.rms_current(constrain(mA, 400, 1500)); break; - #endif - #if AXIS_IS_TMC(E6) - case E6: stepperE6.rms_current(constrain(mA, 400, 1500)); break; - #endif - #if AXIS_IS_TMC(E7) - case E7: stepperE7.rms_current(constrain(mA, 400, 1500)); break; - #endif + case E0: TERN_(E0_IS_TRINAMIC, stepperE0.rms_current(constrain(mA, 400, 1500))); break; + case E1: TERN_(E1_IS_TRINAMIC, stepperE1.rms_current(constrain(mA, 400, 1500))); break; + case E2: TERN_(E2_IS_TRINAMIC, stepperE2.rms_current(constrain(mA, 400, 1500))); break; + case E3: TERN_(E3_IS_TRINAMIC, stepperE3.rms_current(constrain(mA, 400, 1500))); break; + case E4: TERN_(E4_IS_TRINAMIC, stepperE4.rms_current(constrain(mA, 400, 1500))); break; + case E5: TERN_(E5_IS_TRINAMIC, stepperE5.rms_current(constrain(mA, 400, 1500))); break; + case E6: TERN_(E6_IS_TRINAMIC, stepperE6.rms_current(constrain(mA, 400, 1500))); break; + case E7: TERN_(E7_IS_TRINAMIC, stepperE7.rms_current(constrain(mA, 400, 1500))); break; default: break; }; } @@ -614,48 +526,20 @@ namespace ExtUI { void setTMCBumpSensitivity(const_float_t value, const axis_t axis) { switch (axis) { - #if X_SENSORLESS - case X: stepperX.homing_threshold(value); break; - #endif - #if Y_SENSORLESS - case Y: stepperY.homing_threshold(value); break; - #endif - #if Z_SENSORLESS - case Z: stepperZ.homing_threshold(value); break; - #endif - #if I_SENSORLESS - case I: stepperI.homing_threshold(value); break; - #endif - #if J_SENSORLESS - case J: stepperJ.homing_threshold(value); break; - #endif - #if K_SENSORLESS - case K: stepperK.homing_threshold(value); break; - #endif - #if U_SENSORLESS - case U: stepperU.homing_threshold(value); break; - #endif - #if V_SENSORLESS - case V: stepperV.homing_threshold(value); break; - #endif - #if W_SENSORLESS - case W: stepperW.homing_threshold(value); break; - #endif - #if X2_SENSORLESS - case X2: stepperX2.homing_threshold(value); break; - #endif - #if Y2_SENSORLESS - case Y2: stepperY2.homing_threshold(value); break; - #endif - #if Z2_SENSORLESS - case Z2: stepperZ2.homing_threshold(value); break; - #endif - #if Z3_SENSORLESS - case Z3: stepperZ3.homing_threshold(value); break; - #endif - #if Z4_SENSORLESS - case Z4: stepperZ4.homing_threshold(value); break; - #endif + case X: TERN_(X_SENSORLESS, stepperX.homing_threshold(value)); break; + case Y: TERN_(Y_SENSORLESS, stepperY.homing_threshold(value)); break; + case Z: TERN_(Z_SENSORLESS, stepperZ.homing_threshold(value)); break; + case I: TERN_(I_SENSORLESS, stepperI.homing_threshold(value)); break; + case J: TERN_(J_SENSORLESS, stepperJ.homing_threshold(value)); break; + case K: TERN_(K_SENSORLESS, stepperK.homing_threshold(value)); break; + case U: TERN_(U_SENSORLESS, stepperU.homing_threshold(value)); break; + case V: TERN_(V_SENSORLESS, stepperV.homing_threshold(value)); break; + case W: TERN_(W_SENSORLESS, stepperW.homing_threshold(value)); break; + case X2: TERN_(X2_SENSORLESS, stepperX2.homing_threshold(value)); break; + case Y2: TERN_(Y2_SENSORLESS, stepperY2.homing_threshold(value)); break; + case Z2: TERN_(Z2_SENSORLESS, stepperZ2.homing_threshold(value)); break; + case Z3: TERN_(Z3_SENSORLESS, stepperZ3.homing_threshold(value)); break; + case Z4: TERN_(Z4_SENSORLESS, stepperZ4.homing_threshold(value)); break; default: break; } UNUSED(value); diff --git a/Marlin/src/lcd/menu/menu_tmc.cpp b/Marlin/src/lcd/menu/menu_tmc.cpp index c708bb5fa2..f73dd971df 100644 --- a/Marlin/src/lcd/menu/menu_tmc.cpp +++ b/Marlin/src/lcd/menu/menu_tmc.cpp @@ -32,74 +32,42 @@ #include "../../module/stepper/indirection.h" #include "../../feature/tmc_util.h" -#define TMC_EDIT_STORED_I_RMS(ST,STR) EDIT_ITEM_F(uint16_4, F(STR), &stepper##ST.val_mA, 100, 3000, []{ stepper##ST.refresh_stepper_current(); }) +#define TMC_EDIT_STORED_I_RMS(ST,STR) EDIT_ITEM_FAST_F(uint16_4, F(STR), &stepper##ST.val_mA, 100, 3000, []{ stepper##ST.refresh_stepper_current(); }) void menu_tmc_current() { START_MENU(); BACK_ITEM(MSG_TMC_DRIVERS); - #if AXIS_IS_TMC(X) - TMC_EDIT_STORED_I_RMS(X, STR_A); - #endif - #if AXIS_IS_TMC(Y) - TMC_EDIT_STORED_I_RMS(Y, STR_B); - #endif - #if AXIS_IS_TMC(Z) - TMC_EDIT_STORED_I_RMS(Z, STR_C); - #endif - #if AXIS_IS_TMC(X2) - TMC_EDIT_STORED_I_RMS(X2, STR_X2); - #endif - #if AXIS_IS_TMC(Y2) - TMC_EDIT_STORED_I_RMS(Y2, STR_Y2); - #endif - #if AXIS_IS_TMC(Z2) - TMC_EDIT_STORED_I_RMS(Z2, STR_Z2); - #endif - #if AXIS_IS_TMC(Z3) - TMC_EDIT_STORED_I_RMS(Z3, STR_Z3); - #endif - #if AXIS_IS_TMC(Z4) - TMC_EDIT_STORED_I_RMS(Z4, STR_Z4); - #endif - #if AXIS_IS_TMC(E0) - TMC_EDIT_STORED_I_RMS(E0, STR_E0); - #endif - #if AXIS_IS_TMC(E1) - TMC_EDIT_STORED_I_RMS(E1, STR_E1); - #endif - #if AXIS_IS_TMC(E2) - TMC_EDIT_STORED_I_RMS(E2, STR_E2); - #endif - #if AXIS_IS_TMC(E3) - TMC_EDIT_STORED_I_RMS(E3, STR_E3); - #endif - #if AXIS_IS_TMC(E4) - TMC_EDIT_STORED_I_RMS(E4, STR_E4); - #endif - #if AXIS_IS_TMC(E5) - TMC_EDIT_STORED_I_RMS(E5, STR_E5); - #endif - #if AXIS_IS_TMC(E6) - TMC_EDIT_STORED_I_RMS(E6, STR_E6); - #endif - #if AXIS_IS_TMC(E7) - TMC_EDIT_STORED_I_RMS(E7, STR_E7); - #endif + TERN_(X_IS_TRINAMIC, TMC_EDIT_STORED_I_RMS(X, STR_A)); + TERN_(X2_IS_TRINAMIC, TMC_EDIT_STORED_I_RMS(X2, STR_X2)); + TERN_(Y_IS_TRINAMIC, TMC_EDIT_STORED_I_RMS(Y, STR_B)); + TERN_(Y2_IS_TRINAMIC, TMC_EDIT_STORED_I_RMS(Y2, STR_Y2)); + TERN_(Z_IS_TRINAMIC, TMC_EDIT_STORED_I_RMS(Z, STR_C)); + TERN_(Z2_IS_TRINAMIC, TMC_EDIT_STORED_I_RMS(Z2, STR_Z2)); + TERN_(Z3_IS_TRINAMIC, TMC_EDIT_STORED_I_RMS(Z3, STR_Z3)); + TERN_(Z4_IS_TRINAMIC, TMC_EDIT_STORED_I_RMS(Z4, STR_Z4)); + TERN_(E0_IS_TRINAMIC, TMC_EDIT_STORED_I_RMS(E0, STR_E0)); + TERN_(E1_IS_TRINAMIC, TMC_EDIT_STORED_I_RMS(E1, STR_E1)); + TERN_(E2_IS_TRINAMIC, TMC_EDIT_STORED_I_RMS(E2, STR_E2)); + TERN_(E3_IS_TRINAMIC, TMC_EDIT_STORED_I_RMS(E3, STR_E3)); + TERN_(E4_IS_TRINAMIC, TMC_EDIT_STORED_I_RMS(E4, STR_E4)); + TERN_(E5_IS_TRINAMIC, TMC_EDIT_STORED_I_RMS(E5, STR_E5)); + TERN_(E6_IS_TRINAMIC, TMC_EDIT_STORED_I_RMS(E6, STR_E6)); + TERN_(E7_IS_TRINAMIC, TMC_EDIT_STORED_I_RMS(E7, STR_E7)); END_MENU(); } #if ENABLED(HYBRID_THRESHOLD) - #define TMC_EDIT_STORED_HYBRID_THRS(ST, STR) EDIT_ITEM_F(uint16_3, F(STR), &stepper##ST.stored.hybrid_thrs, 0, STEPPER_MAX_THRS(ST), []{ stepper##ST.refresh_hybrid_thrs(); }); + #define TMC_EDIT_STORED_HYBRID_THRS(ST, STR) EDIT_ITEM_FAST_F(uint16_3, F(STR), &stepper##ST.stored.hybrid_thrs, 0, STEPPER_MAX_THRS(ST), []{ stepper##ST.refresh_hybrid_thrs(); }); void menu_tmc_hybrid_thrs() { START_MENU(); BACK_ITEM(MSG_TMC_DRIVERS); - TERN_(X_HAS_STEALTHCHOP, TMC_EDIT_STORED_HYBRID_THRS(X, STR_X)); - TERN_(Y_HAS_STEALTHCHOP, TMC_EDIT_STORED_HYBRID_THRS(Y, STR_Y)); - TERN_(Z_HAS_STEALTHCHOP, TMC_EDIT_STORED_HYBRID_THRS(Z, STR_Z)); + TERN_( X_HAS_STEALTHCHOP, TMC_EDIT_STORED_HYBRID_THRS(X, STR_X)); TERN_(X2_HAS_STEALTHCHOP, TMC_EDIT_STORED_HYBRID_THRS(X2, STR_X2)); + TERN_( Y_HAS_STEALTHCHOP, TMC_EDIT_STORED_HYBRID_THRS(Y, STR_Y)); TERN_(Y2_HAS_STEALTHCHOP, TMC_EDIT_STORED_HYBRID_THRS(Y2, STR_Y2)); + TERN_( Z_HAS_STEALTHCHOP, TMC_EDIT_STORED_HYBRID_THRS(Z, STR_Z)); TERN_(Z2_HAS_STEALTHCHOP, TMC_EDIT_STORED_HYBRID_THRS(Z2, STR_Z2)); TERN_(Z3_HAS_STEALTHCHOP, TMC_EDIT_STORED_HYBRID_THRS(Z3, STR_Z3)); TERN_(Z4_HAS_STEALTHCHOP, TMC_EDIT_STORED_HYBRID_THRS(Z4, STR_Z4)); @@ -114,7 +82,7 @@ void menu_tmc_current() { END_MENU(); } -#endif +#endif // HYBRID_THRESHOLD #if ENABLED(SENSORLESS_HOMING) @@ -140,7 +108,7 @@ void menu_tmc_current() { END_MENU(); } -#endif +#endif // SENSORLESS_HOMING #if HAS_STEALTHCHOP @@ -169,7 +137,7 @@ void menu_tmc_current() { END_MENU(); } -#endif +#endif // HAS_STEALTHCHOP void menu_tmc() { START_MENU(); diff --git a/Marlin/src/lcd/sovol_rts/sovol_rts.cpp b/Marlin/src/lcd/sovol_rts/sovol_rts.cpp index 1f3322ded7..c92850494b 100644 --- a/Marlin/src/lcd/sovol_rts/sovol_rts.cpp +++ b/Marlin/src/lcd/sovol_rts/sovol_rts.cpp @@ -122,7 +122,6 @@ bool card_insert_st; bool sd_printing; int16_t fan_speed; -char cmd[MAX_CMD_SIZE + 16]; inline void RTS_line_to_current(const AxisEnum axis) { if (!planner.is_full()) @@ -1398,18 +1397,10 @@ void RTS::handleData() { case TMCDriver: switch (recdat.data[0]) { case 1: // Current - #if AXIS_IS_TMC(X) - sendData(stepperX.getMilliamps(), Current_X_VP); - #endif - #if AXIS_IS_TMC(Y) - sendData(stepperY.getMilliamps(), Current_Y_VP); - #endif - #if AXIS_IS_TMC(Z) - sendData(stepperZ.getMilliamps(), Current_Z_VP); - #endif - #if AXIS_IS_TMC(E0) - sendData(stepperE0.getMilliamps(), Current_E_VP); - #endif + TERN_(X_IS_TRINAMIC, sendData(stepperX.getMilliamps(), Current_X_VP)); + TERN_(Y_IS_TRINAMIC, sendData(stepperY.getMilliamps(), Current_Y_VP)); + TERN_(Z_IS_TRINAMIC, sendData(stepperZ.getMilliamps(), Current_Z_VP)); + TERN_(E0_IS_TRINAMIC, sendData(stepperE0.getMilliamps(), Current_E_VP)); gotoPage(ID_DriverA_L, ID_DriverA_D); break; @@ -1434,39 +1425,19 @@ void RTS::handleData() { } break; - #if AXIS_IS_TMC(X) - case Current_X: sprintf_P(cmd, PSTR("M906 X%i"), recdat.data[0]); queue.inject(cmd); break; - #endif - #if X_HAS_STEALTHCHOP - case Threshold_X: sprintf_P(cmd, PSTR("M913 X%i"), recdat.data[0]); queue.inject(cmd); break; - #endif - #if X_SENSORLESS - case Sensorless_X: sprintf_P(cmd, PSTR("M914 X%i"), recdat.data[0]); queue.inject(cmd); break; - #endif + case Current_X: TERN_(X_IS_TRINAMIC, queue.inject(TS(F("M906X"), int(recdat.data[0])))); break; + case Threshold_X: TERN_(X_HAS_STEALTHCHOP, queue.inject(TS(F("M913X"), int(recdat.data[0])))); break; + case Sensorless_X: TERN_(X_SENSORLESS, queue.inject(TS(F("M914X"), int(recdat.data[0])))); break; - #if AXIS_IS_TMC(Y) - case Current_Y: sprintf_P(cmd, PSTR("M906 Y%i"), recdat.data[0]); queue.inject(cmd); break; - #endif - #if Y_HAS_STEALTHCHOP - case Threshold_Y: sprintf_P(cmd, PSTR("M913 Y%i"), recdat.data[0]); queue.inject(cmd); break; - #endif - #if Y_SENSORLESS - case Sensorless_Y: sprintf_P(cmd, PSTR("M914 Y%i"), recdat.data[0]); queue.inject(cmd); break; - #endif + case Current_Y: TERN_(X_IS_TRINAMIC, queue.inject(TS(F("M906Y"), int(recdat.data[0])))); break; + case Threshold_Y: TERN_(Y_HAS_STEALTHCHOP, queue.inject(TS(F("M913Y"), int(recdat.data[0])))); break; + case Sensorless_Y: TERN_(Y_SENSORLESS, queue.inject(TS(F("M914Y"), int(recdat.data[0])))); break; - #if AXIS_IS_TMC(Z) - case Current_Z: sprintf_P(cmd, PSTR("M906 Z%i"), recdat.data[0]); queue.inject(cmd); break; - #endif - #if Z_HAS_STEALTHCHOP - case Threshold_Z: sprintf_P(cmd, PSTR("M913 Z%i"), recdat.data[0]); queue.inject(cmd); break; - #endif + case Current_Z: TERN_(Z_IS_TRINAMIC, queue.inject(TS(F("M906Z"), int(recdat.data[0])))); break; + case Threshold_Z: TERN_(Z_HAS_STEALTHCHOP, queue.inject(TS(F("M913Z"), int(recdat.data[0])))); break; - #if AXIS_IS_TMC(E0) - case Current_E: sprintf_P(cmd, PSTR("M906 E%i"), recdat.data[0]); queue.inject(cmd); break; - #endif - #if E0_HAS_STEALTHCHOP - case Threshold_E: sprintf_P(cmd, PSTR("M913 E%i"), recdat.data[0]); queue.inject(cmd); break; - #endif + case Current_E: TERN_(AXIS_IS_TMC_E, queue.inject(TS(F("M906E"), int(recdat.data[0])))); break; + case Threshold_E: TERN_(E_HAS_STEALTHCHOP, queue.inject(TS(F("M913E"), int(recdat.data[0])))); break; #endif // HAS_TRINAMIC_CONFIG diff --git a/Marlin/src/module/motion.cpp b/Marlin/src/module/motion.cpp index 6a039c8ab9..386d46665d 100644 --- a/Marlin/src/module/motion.cpp +++ b/Marlin/src/module/motion.cpp @@ -271,46 +271,46 @@ void report_current_position_projected() { #define debug_current(...) #endif - #if HAS_CURRENT_HOME(X) + #if HAS_CURRENT_HOME_X int16_t saved_current_X; #endif - #if HAS_CURRENT_HOME(Y) + #if HAS_CURRENT_HOME_Y int16_t saved_current_Y; #endif - #if HAS_CURRENT_HOME(Z) + #if HAS_CURRENT_HOME_Z int16_t saved_current_Z; #endif - #if HAS_CURRENT_HOME(X2) + #if HAS_CURRENT_HOME_X2 int16_t saved_current_X2; #endif - #if HAS_CURRENT_HOME(Y2) + #if HAS_CURRENT_HOME_Y2 int16_t saved_current_Y2; #endif - #if HAS_CURRENT_HOME(Z2) + #if HAS_CURRENT_HOME_Z2 int16_t saved_current_Z2; #endif - #if HAS_CURRENT_HOME(Z3) + #if HAS_CURRENT_HOME_Z3 int16_t saved_current_Z3; #endif - #if HAS_CURRENT_HOME(Z4) + #if HAS_CURRENT_HOME_Z4 int16_t saved_current_Z4; #endif - #if HAS_CURRENT_HOME(I) + #if HAS_CURRENT_HOME_I int16_t saved_current_I; #endif - #if HAS_CURRENT_HOME(J) + #if HAS_CURRENT_HOME_J int16_t saved_current_J; #endif - #if HAS_CURRENT_HOME(K) + #if HAS_CURRENT_HOME_K int16_t saved_current_K; #endif - #if HAS_CURRENT_HOME(U) + #if HAS_CURRENT_HOME_U int16_t saved_current_U; #endif - #if HAS_CURRENT_HOME(V) + #if HAS_CURRENT_HOME_V int16_t saved_current_V; #endif - #if HAS_CURRENT_HOME(W) + #if HAS_CURRENT_HOME_W int16_t saved_current_W; #endif @@ -326,6 +326,8 @@ void report_current_position_projected() { stepper##A.rms_current(A##_CURRENT_HOME); \ debug_current(F(STR_##A), saved_current_##A, A##_CURRENT_HOME) + #define _MAP_SAVE_SET(A) OPTCODE(A##_HAS_HOME_CURRENT, _SAVE_SET_CURRENT(A)) + if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Setting homing driver current"); #if ANY(CORE_IS_XY, MARKFORGED_XY, MARKFORGED_YX) @@ -333,34 +335,8 @@ void report_current_position_projected() { // CORE and Markforged kinematics switch (axis) { default: break; - case X_AXIS: case Y_AXIS: - #if HAS_CURRENT_HOME(X) - _SAVE_SET_CURRENT(X); - #endif - #if HAS_CURRENT_HOME(X2) - _SAVE_SET_CURRENT(X2); - #endif - #if HAS_CURRENT_HOME(Y) - _SAVE_SET_CURRENT(Y); - #endif - #if HAS_CURRENT_HOME(Y2) - _SAVE_SET_CURRENT(Y2); - #endif - break; - case Z_AXIS: - #if HAS_CURRENT_HOME(Z) - _SAVE_SET_CURRENT(Z); - #endif - #if HAS_CURRENT_HOME(Z2) - _SAVE_SET_CURRENT(Z2); - #endif - #if HAS_CURRENT_HOME(Z3) - _SAVE_SET_CURRENT(Z3); - #endif - #if HAS_CURRENT_HOME(Z4) - _SAVE_SET_CURRENT(Z4); - #endif - break; + case X_AXIS: case Y_AXIS: MAP(_MAP_SAVE_SET, X, X2, Y, Y2); break; + case Z_AXIS: MAP(_MAP_SAVE_SET, Z, Z2, Z3, Z4); break; } #elif CORE_IS_XZ @@ -368,22 +344,8 @@ void report_current_position_projected() { // CORE XZ / ZX switch (axis) { default: break; - case X_AXIS: case Z_AXIS: - #if HAS_CURRENT_HOME(X) - _SAVE_SET_CURRENT(X); - #endif - #if HAS_CURRENT_HOME(Z) - _SAVE_SET_CURRENT(Z); - #endif - break; - case Y_AXIS: - #if HAS_CURRENT_HOME(Y) - _SAVE_SET_CURRENT(Y); - #endif - #if HAS_CURRENT_HOME(Y2) - _SAVE_SET_CURRENT(Y2); - #endif - break; + case X_AXIS: case Z_AXIS: MAP(_MAP_SAVE_SET, X, Z); break; + case Y_AXIS: MAP(_MAP_SAVE_SET, Y, Y2); break; } #elif CORE_IS_YZ @@ -391,22 +353,8 @@ void report_current_position_projected() { // CORE YZ / ZY switch (axis) { default: break; - case X_AXIS: - #if HAS_CURRENT_HOME(X) - _SAVE_SET_CURRENT(X); - #endif - #if HAS_CURRENT_HOME(X2) - _SAVE_SET_CURRENT(X2); - #endif - break; - case Y_AXIS: case Z_AXIS: - #if HAS_CURRENT_HOME(Y) - _SAVE_SET_CURRENT(Y); - #endif - #if HAS_CURRENT_HOME(Z) - _SAVE_SET_CURRENT(Z); - #endif - break; + case X_AXIS: MAP(_MAP_SAVE_SET, X, X2); break; + case Y_AXIS: case Z_AXIS: MAP(_MAP_SAVE_SET, Y, Z); break; } #elif IS_SCARA @@ -414,13 +362,13 @@ void report_current_position_projected() { // SCARA kinematics switch (axis) { default: break; - #if HAS_CURRENT_HOME(X) + #if X_HAS_HOME_CURRENT case A_AXIS: _SAVE_SET_CURRENT(X); break; #endif - #if HAS_CURRENT_HOME(Y) + #if Y_HAS_HOME_CURRENT case B_AXIS: _SAVE_SET_CURRENT(Y); break; #endif - #if HAS_CURRENT_HOME(Z) + #if Z_HAS_HOME_CURRENT case C_AXIS: _SAVE_SET_CURRENT(Z); break; #endif } @@ -429,13 +377,13 @@ void report_current_position_projected() { // TPARA or DELTA kinematics. // Z_AXIS is a special mode to apply homing current to all axes. - #if HAS_CURRENT_HOME(X) + #if X_HAS_HOME_CURRENT if (axis == A_AXIS || axis == Z_AXIS) _SAVE_SET_CURRENT(X); #endif - #if HAS_CURRENT_HOME(Y) + #if Y_HAS_HOME_CURRENT if (axis == B_AXIS || axis == Z_AXIS) _SAVE_SET_CURRENT(Y); #endif - #if HAS_CURRENT_HOME(Z) + #if Z_HAS_HOME_CURRENT if (axis == C_AXIS) _SAVE_SET_CURRENT(Z); #endif @@ -444,13 +392,13 @@ void report_current_position_projected() { // POLAR kinematics switch (axis) { default: break; - #if HAS_CURRENT_HOME(X) + #if X_HAS_HOME_CURRENT case A_AXIS: _SAVE_SET_CURRENT(X); break; #endif - #if HAS_CURRENT_HOME(Y) + #if Y_HAS_HOME_CURRENT case B_AXIS: _SAVE_SET_CURRENT(Y); break; #endif - #if HAS_CURRENT_HOME(Z) + #if Z_HAS_HOME_CURRENT case C_AXIS: _SAVE_SET_CURRENT(Z); break; #endif } @@ -461,13 +409,13 @@ void report_current_position_projected() { // Useful? switch (axis) { default: break; - #if HAS_CURRENT_HOME(X) + #if X_HAS_HOME_CURRENT case A_AXIS: _SAVE_SET_CURRENT(X); break; #endif - #if HAS_CURRENT_HOME(Y) + #if Y_HAS_HOME_CURRENT case B_AXIS: _SAVE_SET_CURRENT(Y); break; #endif - #if HAS_CURRENT_HOME(Z) + #if Z_HAS_HOME_CURRENT case C_AXIS: _SAVE_SET_CURRENT(Z); break; #endif } @@ -477,27 +425,9 @@ void report_current_position_projected() { // Foam cutter switch (axis) { default: break; - case X_AXIS: case I_AXIS: - #if HAS_CURRENT_HOME(X) - _SAVE_SET_CURRENT(X); - #endif - #if HAS_CURRENT_HOME(I) - _SAVE_SET_CURRENT(I); - #endif - break; - case Y_AXIS: case J_AXIS: - #if HAS_CURRENT_HOME(Y) - _SAVE_SET_CURRENT(Y); - #endif - #if HAS_CURRENT_HOME(J) - _SAVE_SET_CURRENT(J); - #endif - break; - case Z_AXIS: - #if HAS_CURRENT_HOME(Z) - _SAVE_SET_CURRENT(Z); - #endif - break; + case X_AXIS: case I_AXIS: MAP(_MAP_SAVE_SET, X, I); break; + case Y_AXIS: case J_AXIS: MAP(_MAP_SAVE_SET, Y, J); break; + case Z_AXIS: MAP(_MAP_SAVE_SET, Z); break; } #else @@ -505,58 +435,31 @@ void report_current_position_projected() { // Cartesian kinematics switch (axis) { default: break; - case X_AXIS: - #if HAS_CURRENT_HOME(X) - _SAVE_SET_CURRENT(X); - #endif - #if HAS_CURRENT_HOME(X2) - _SAVE_SET_CURRENT(X2); - #endif - break; - case Y_AXIS: - #if HAS_CURRENT_HOME(Y) - _SAVE_SET_CURRENT(Y); - #endif - #if HAS_CURRENT_HOME(Y2) - _SAVE_SET_CURRENT(Y2); - #endif - break; - case Z_AXIS: - #if HAS_CURRENT_HOME(Z) - _SAVE_SET_CURRENT(Z); - #endif - #if HAS_CURRENT_HOME(Z2) - _SAVE_SET_CURRENT(Z2); - #endif - #if HAS_CURRENT_HOME(Z3) - _SAVE_SET_CURRENT(Z3); - #endif - #if HAS_CURRENT_HOME(Z4) - _SAVE_SET_CURRENT(Z4); - #endif - break; + case X_AXIS: MAP(_MAP_SAVE_SET, X, X2); break; + case Y_AXIS: MAP(_MAP_SAVE_SET, Y, Y2); break; + case Z_AXIS: MAP(_MAP_SAVE_SET, Z, Z2, Z3, Z4); break; } #endif // kinematics switch (axis) { default: break; - #if HAS_CURRENT_HOME(I) && DISABLED(FOAMCUTTER_XYUV) + #if I_HAS_HOME_CURRENT && DISABLED(FOAMCUTTER_XYUV) case I_AXIS: _SAVE_SET_CURRENT(I); break; #endif - #if HAS_CURRENT_HOME(J) && DISABLED(FOAMCUTTER_XYUV) + #if J_HAS_HOME_CURRENT && DISABLED(FOAMCUTTER_XYUV) case J_AXIS: _SAVE_SET_CURRENT(J); break; #endif - #if HAS_CURRENT_HOME(K) + #if K_HAS_HOME_CURRENT case K_AXIS: _SAVE_SET_CURRENT(K); break; #endif - #if HAS_CURRENT_HOME(U) + #if U_HAS_HOME_CURRENT case U_AXIS: _SAVE_SET_CURRENT(U); break; #endif - #if HAS_CURRENT_HOME(V) + #if V_HAS_HOME_CURRENT case V_AXIS: _SAVE_SET_CURRENT(V); break; #endif - #if HAS_CURRENT_HOME(W) + #if W_HAS_HOME_CURRENT case W_AXIS: _SAVE_SET_CURRENT(W); break; #endif } @@ -578,6 +481,8 @@ void report_current_position_projected() { stepper##A.rms_current(saved_current_##A); \ debug_current(F(STR_##A), A##_CURRENT_HOME, saved_current_##A) + #define _MAP_RESTORE(A) OPTCODE(A##_HAS_HOME_CURRENT, _RESTORE_CURRENT(A)) + if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Restore driver current"); #if ANY(CORE_IS_XY, MARKFORGED_XY, MARKFORGED_YX) @@ -585,28 +490,8 @@ void report_current_position_projected() { // CORE and Markforged kinematics switch (axis) { default: break; - case X_AXIS: case Y_AXIS: - #if HAS_CURRENT_HOME(X) - _RESTORE_CURRENT(X); - #endif - #if HAS_CURRENT_HOME(Y) - _RESTORE_CURRENT(Y); - #endif - break; - case Z_AXIS: - #if HAS_CURRENT_HOME(Z) - _RESTORE_CURRENT(Z); - #endif - #if HAS_CURRENT_HOME(Z2) - _RESTORE_CURRENT(Z2); - #endif - #if HAS_CURRENT_HOME(Z3) - _RESTORE_CURRENT(Z3); - #endif - #if HAS_CURRENT_HOME(Z4) - _RESTORE_CURRENT(Z4); - #endif - break; + case X_AXIS: case Y_AXIS: MAP(_MAP_RESTORE, X, Y); break; + case Z_AXIS: MAP(_MAP_RESTORE, Z, Z2, Z3, Z4); break; } #elif CORE_IS_XZ @@ -614,22 +499,8 @@ void report_current_position_projected() { // CORE XZ / ZX switch (axis) { default: break; - case X_AXIS: case Z_AXIS: - #if HAS_CURRENT_HOME(X) - _RESTORE_CURRENT(X); - #endif - #if HAS_CURRENT_HOME(Z) - _RESTORE_CURRENT(Z); - #endif - break; - case Y_AXIS: - #if HAS_CURRENT_HOME(Y) - _RESTORE_CURRENT(Y); - #endif - #if HAS_CURRENT_HOME(Y2) - _RESTORE_CURRENT(Y2); - #endif - break; + case X_AXIS: case Z_AXIS: MAP(_MAP_RESTORE, X, Z); break; + case Y_AXIS: MAP(_MAP_RESTORE, Y, Y2); break; } #elif CORE_IS_YZ @@ -637,22 +508,8 @@ void report_current_position_projected() { // CORE YZ / ZY switch (axis) { default: break; - case X_AXIS: - #if HAS_CURRENT_HOME(X) - _RESTORE_CURRENT(X); - #endif - #if HAS_CURRENT_HOME(X2) - _RESTORE_CURRENT(X2); - #endif - break; - case Y_AXIS: case Z_AXIS: - #if HAS_CURRENT_HOME(Y) - _RESTORE_CURRENT(Y); - #endif - #if HAS_CURRENT_HOME(Z) - _RESTORE_CURRENT(Z); - #endif - break; + case X_AXIS: MAP(_MAP_RESTORE, X, X2); break; + case Y_AXIS: case Z_AXIS: MAP(_MAP_RESTORE, Y, Z); break; } #elif IS_SCARA // Unsupported for now? @@ -660,13 +517,13 @@ void report_current_position_projected() { // SCARA kinematics switch (axis) { default: break; - #if HAS_CURRENT_HOME(X) + #if X_HAS_HOME_CURRENT case A_AXIS: _RESTORE_CURRENT(X); break; #endif - #if HAS_CURRENT_HOME(Y) + #if Y_HAS_HOME_CURRENT case B_AXIS: _RESTORE_CURRENT(Y); break; #endif - #if HAS_CURRENT_HOME(Z) + #if Z_HAS_HOME_CURRENT case C_AXIS: _RESTORE_CURRENT(Z); break; #endif } @@ -675,13 +532,13 @@ void report_current_position_projected() { // TPARA or DELTA kinematics // Z_AXIS is a special mode to set homing current to all axes - #if HAS_CURRENT_HOME(X) + #if X_HAS_HOME_CURRENT if (axis == A_AXIS || axis == Z_AXIS) _RESTORE_CURRENT(X); #endif - #if HAS_CURRENT_HOME(Y) + #if Y_HAS_HOME_CURRENT if (axis == B_AXIS || axis == Z_AXIS) _RESTORE_CURRENT(Y); #endif - #if HAS_CURRENT_HOME(Z) + #if Z_HAS_HOME_CURRENT if (axis == C_AXIS) _RESTORE_CURRENT(Z); #endif @@ -690,13 +547,13 @@ void report_current_position_projected() { // POLAR kinematics switch (axis) { default: break; - #if HAS_CURRENT_HOME(X) + #if X_HAS_HOME_CURRENT case A_AXIS: _RESTORE_CURRENT(X); break; #endif - #if HAS_CURRENT_HOME(Y) + #if Y_HAS_HOME_CURRENT case B_AXIS: _RESTORE_CURRENT(Y); break; #endif - #if HAS_CURRENT_HOME(Z) + #if Z_HAS_HOME_CURRENT case C_AXIS: _RESTORE_CURRENT(Z); break; #endif } @@ -707,13 +564,13 @@ void report_current_position_projected() { // Useful? switch (axis) { default: break; - #if HAS_CURRENT_HOME(X) + #if X_HAS_HOME_CURRENT case A_AXIS: _RESTORE_CURRENT(X); break; #endif - #if HAS_CURRENT_HOME(Y) + #if Y_HAS_HOME_CURRENT case B_AXIS: _RESTORE_CURRENT(Y); break; #endif - #if HAS_CURRENT_HOME(Z) + #if Z_HAS_HOME_CURRENT case C_AXIS: _RESTORE_CURRENT(Z); break; #endif } @@ -723,27 +580,9 @@ void report_current_position_projected() { // Foam cutter switch (axis) { default: break; - case X_AXIS: case I_AXIS: - #if HAS_CURRENT_HOME(X) - _RESTORE_CURRENT(X); - #endif - #if HAS_CURRENT_HOME(I) - _RESTORE_CURRENT(I); - #endif - break; - case Y_AXIS: case J_AXIS: - #if HAS_CURRENT_HOME(Y) - _RESTORE_CURRENT(Y); - #endif - #if HAS_CURRENT_HOME(J) - _RESTORE_CURRENT(J); - #endif - break; - case Z_AXIS: - #if HAS_CURRENT_HOME(Z) - _RESTORE_CURRENT(Z); - #endif - break; + case X_AXIS: case I_AXIS: MAP(_MAP_RESTORE, X, I); break; + case Y_AXIS: case J_AXIS: MAP(_MAP_RESTORE, Y, J); break; + case Z_AXIS: MAP(_MAP_RESTORE, Z); break; } #else @@ -751,58 +590,31 @@ void report_current_position_projected() { // Cartesian kinematics switch (axis) { default: break; - case X_AXIS: - #if HAS_CURRENT_HOME(X) - _RESTORE_CURRENT(X); - #endif - #if HAS_CURRENT_HOME(X2) - _RESTORE_CURRENT(X2); - #endif - break; - case Y_AXIS: - #if HAS_CURRENT_HOME(Y) - _RESTORE_CURRENT(Y); - #endif - #if HAS_CURRENT_HOME(Y2) - _RESTORE_CURRENT(Y2); - #endif - break; - case Z_AXIS: - #if HAS_CURRENT_HOME(Z) - _RESTORE_CURRENT(Z); - #endif - #if HAS_CURRENT_HOME(Z2) - _RESTORE_CURRENT(Z2); - #endif - #if HAS_CURRENT_HOME(Z3) - _RESTORE_CURRENT(Z3); - #endif - #if HAS_CURRENT_HOME(Z4) - _RESTORE_CURRENT(Z4); - #endif - break; + case X_AXIS: MAP(_MAP_RESTORE, X, X2); break; + case Y_AXIS: MAP(_MAP_RESTORE, Y, Y2); break; + case Z_AXIS: MAP(_MAP_RESTORE, Z, Z2, Z3, Z4); break; } #endif // kinematics switch (axis) { default: break; - #if HAS_CURRENT_HOME(I) && DISABLED(FOAMCUTTER_XYUV) + #if I_HAS_HOME_CURRENT && DISABLED(FOAMCUTTER_XYUV) case I_AXIS: _RESTORE_CURRENT(I); break; #endif - #if HAS_CURRENT_HOME(J) && DISABLED(FOAMCUTTER_XYUV) + #if J_HAS_HOME_CURRENT && DISABLED(FOAMCUTTER_XYUV) case J_AXIS: _RESTORE_CURRENT(J); break; #endif - #if HAS_CURRENT_HOME(K) + #if K_HAS_HOME_CURRENT case K_AXIS: _RESTORE_CURRENT(K); break; #endif - #if HAS_CURRENT_HOME(U) + #if U_HAS_HOME_CURRENT case U_AXIS: _RESTORE_CURRENT(U); break; #endif - #if HAS_CURRENT_HOME(V) + #if V_HAS_HOME_CURRENT case V_AXIS: _RESTORE_CURRENT(V); break; #endif - #if HAS_CURRENT_HOME(W) + #if W_HAS_HOME_CURRENT case W_AXIS: _RESTORE_CURRENT(W); break; #endif } diff --git a/Marlin/src/module/motion.h b/Marlin/src/module/motion.h index 6d3bfaed0d..18376cf773 100644 --- a/Marlin/src/module/motion.h +++ b/Marlin/src/module/motion.h @@ -636,6 +636,9 @@ void home_if_needed(const bool keeplev=false); void set_home_offset(const AxisEnum axis, const_float_t v); #endif +// +// Trinamic Stepper Drivers +// #if USE_SENSORLESS struct sensorless_t; sensorless_t start_sensorless_homing_per_axis(const AxisEnum axis); diff --git a/Marlin/src/module/settings.cpp b/Marlin/src/module/settings.cpp index 8c33e73f00..a7e791951b 100644 --- a/Marlin/src/module/settings.cpp +++ b/Marlin/src/module/settings.cpp @@ -1393,72 +1393,28 @@ void MarlinSettings::postprocess() { per_stepper_uint16_t tmc_stepper_current{0}; #if HAS_TRINAMIC_CONFIG - #if AXIS_IS_TMC(X) - tmc_stepper_current.X = stepperX.getMilliamps(); - #endif - #if AXIS_IS_TMC(Y) - tmc_stepper_current.Y = stepperY.getMilliamps(); - #endif - #if AXIS_IS_TMC(Z) - tmc_stepper_current.Z = stepperZ.getMilliamps(); - #endif - #if AXIS_IS_TMC(I) - tmc_stepper_current.I = stepperI.getMilliamps(); - #endif - #if AXIS_IS_TMC(J) - tmc_stepper_current.J = stepperJ.getMilliamps(); - #endif - #if AXIS_IS_TMC(K) - tmc_stepper_current.K = stepperK.getMilliamps(); - #endif - #if AXIS_IS_TMC(U) - tmc_stepper_current.U = stepperU.getMilliamps(); - #endif - #if AXIS_IS_TMC(V) - tmc_stepper_current.V = stepperV.getMilliamps(); - #endif - #if AXIS_IS_TMC(W) - tmc_stepper_current.W = stepperW.getMilliamps(); - #endif - #if AXIS_IS_TMC(X2) - tmc_stepper_current.X2 = stepperX2.getMilliamps(); - #endif - #if AXIS_IS_TMC(Y2) - tmc_stepper_current.Y2 = stepperY2.getMilliamps(); - #endif - #if AXIS_IS_TMC(Z2) - tmc_stepper_current.Z2 = stepperZ2.getMilliamps(); - #endif - #if AXIS_IS_TMC(Z3) - tmc_stepper_current.Z3 = stepperZ3.getMilliamps(); - #endif - #if AXIS_IS_TMC(Z4) - tmc_stepper_current.Z4 = stepperZ4.getMilliamps(); - #endif - #if AXIS_IS_TMC(E0) - tmc_stepper_current.E0 = stepperE0.getMilliamps(); - #endif - #if AXIS_IS_TMC(E1) - tmc_stepper_current.E1 = stepperE1.getMilliamps(); - #endif - #if AXIS_IS_TMC(E2) - tmc_stepper_current.E2 = stepperE2.getMilliamps(); - #endif - #if AXIS_IS_TMC(E3) - tmc_stepper_current.E3 = stepperE3.getMilliamps(); - #endif - #if AXIS_IS_TMC(E4) - tmc_stepper_current.E4 = stepperE4.getMilliamps(); - #endif - #if AXIS_IS_TMC(E5) - tmc_stepper_current.E5 = stepperE5.getMilliamps(); - #endif - #if AXIS_IS_TMC(E6) - tmc_stepper_current.E6 = stepperE6.getMilliamps(); - #endif - #if AXIS_IS_TMC(E7) - tmc_stepper_current.E7 = stepperE7.getMilliamps(); - #endif + TERN_(X_IS_TRINAMIC, tmc_stepper_current.X = stepperX.getMilliamps()); + TERN_(Y_IS_TRINAMIC, tmc_stepper_current.Y = stepperY.getMilliamps()); + TERN_(Z_IS_TRINAMIC, tmc_stepper_current.Z = stepperZ.getMilliamps()); + TERN_(I_IS_TRINAMIC, tmc_stepper_current.I = stepperI.getMilliamps()); + TERN_(J_IS_TRINAMIC, tmc_stepper_current.J = stepperJ.getMilliamps()); + TERN_(K_IS_TRINAMIC, tmc_stepper_current.K = stepperK.getMilliamps()); + TERN_(U_IS_TRINAMIC, tmc_stepper_current.U = stepperU.getMilliamps()); + TERN_(V_IS_TRINAMIC, tmc_stepper_current.V = stepperV.getMilliamps()); + TERN_(W_IS_TRINAMIC, tmc_stepper_current.W = stepperW.getMilliamps()); + TERN_(X2_IS_TRINAMIC, tmc_stepper_current.X2 = stepperX2.getMilliamps()); + TERN_(Y2_IS_TRINAMIC, tmc_stepper_current.Y2 = stepperY2.getMilliamps()); + TERN_(Z2_IS_TRINAMIC, tmc_stepper_current.Z2 = stepperZ2.getMilliamps()); + TERN_(Z3_IS_TRINAMIC, tmc_stepper_current.Z3 = stepperZ3.getMilliamps()); + TERN_(Z4_IS_TRINAMIC, tmc_stepper_current.Z4 = stepperZ4.getMilliamps()); + TERN_(E0_IS_TRINAMIC, tmc_stepper_current.E0 = stepperE0.getMilliamps()); + TERN_(E1_IS_TRINAMIC, tmc_stepper_current.E1 = stepperE1.getMilliamps()); + TERN_(E2_IS_TRINAMIC, tmc_stepper_current.E2 = stepperE2.getMilliamps()); + TERN_(E3_IS_TRINAMIC, tmc_stepper_current.E3 = stepperE3.getMilliamps()); + TERN_(E4_IS_TRINAMIC, tmc_stepper_current.E4 = stepperE4.getMilliamps()); + TERN_(E5_IS_TRINAMIC, tmc_stepper_current.E5 = stepperE5.getMilliamps()); + TERN_(E6_IS_TRINAMIC, tmc_stepper_current.E6 = stepperE6.getMilliamps()); + TERN_(E7_IS_TRINAMIC, tmc_stepper_current.E7 = stepperE7.getMilliamps()); #endif EEPROM_WRITE(tmc_stepper_current); } @@ -2499,72 +2455,28 @@ void MarlinSettings::postprocess() { #define SET_CURR(Q) stepper##Q.rms_current(currents.Q ? currents.Q : Q##_CURRENT) if (!validating) { - #if AXIS_IS_TMC(X) - SET_CURR(X); - #endif - #if AXIS_IS_TMC(Y) - SET_CURR(Y); - #endif - #if AXIS_IS_TMC(Z) - SET_CURR(Z); - #endif - #if AXIS_IS_TMC(X2) - SET_CURR(X2); - #endif - #if AXIS_IS_TMC(Y2) - SET_CURR(Y2); - #endif - #if AXIS_IS_TMC(Z2) - SET_CURR(Z2); - #endif - #if AXIS_IS_TMC(Z3) - SET_CURR(Z3); - #endif - #if AXIS_IS_TMC(Z4) - SET_CURR(Z4); - #endif - #if AXIS_IS_TMC(I) - SET_CURR(I); - #endif - #if AXIS_IS_TMC(J) - SET_CURR(J); - #endif - #if AXIS_IS_TMC(K) - SET_CURR(K); - #endif - #if AXIS_IS_TMC(U) - SET_CURR(U); - #endif - #if AXIS_IS_TMC(V) - SET_CURR(V); - #endif - #if AXIS_IS_TMC(W) - SET_CURR(W); - #endif - #if AXIS_IS_TMC(E0) - SET_CURR(E0); - #endif - #if AXIS_IS_TMC(E1) - SET_CURR(E1); - #endif - #if AXIS_IS_TMC(E2) - SET_CURR(E2); - #endif - #if AXIS_IS_TMC(E3) - SET_CURR(E3); - #endif - #if AXIS_IS_TMC(E4) - SET_CURR(E4); - #endif - #if AXIS_IS_TMC(E5) - SET_CURR(E5); - #endif - #if AXIS_IS_TMC(E6) - SET_CURR(E6); - #endif - #if AXIS_IS_TMC(E7) - SET_CURR(E7); - #endif + TERN_(X_IS_TRINAMIC, SET_CURR(X)); + TERN_(Y_IS_TRINAMIC, SET_CURR(Y)); + TERN_(Z_IS_TRINAMIC, SET_CURR(Z)); + TERN_(I_IS_TRINAMIC, SET_CURR(I)); + TERN_(J_IS_TRINAMIC, SET_CURR(J)); + TERN_(K_IS_TRINAMIC, SET_CURR(K)); + TERN_(U_IS_TRINAMIC, SET_CURR(U)); + TERN_(V_IS_TRINAMIC, SET_CURR(V)); + TERN_(W_IS_TRINAMIC, SET_CURR(W)); + TERN_(X2_IS_TRINAMIC, SET_CURR(X2)); + TERN_(Y2_IS_TRINAMIC, SET_CURR(Y2)); + TERN_(Z2_IS_TRINAMIC, SET_CURR(Z2)); + TERN_(Z3_IS_TRINAMIC, SET_CURR(Z3)); + TERN_(Z4_IS_TRINAMIC, SET_CURR(Z4)); + TERN_(E0_IS_TRINAMIC, SET_CURR(E0)); + TERN_(E1_IS_TRINAMIC, SET_CURR(E1)); + TERN_(E2_IS_TRINAMIC, SET_CURR(E2)); + TERN_(E3_IS_TRINAMIC, SET_CURR(E3)); + TERN_(E4_IS_TRINAMIC, SET_CURR(E4)); + TERN_(E5_IS_TRINAMIC, SET_CURR(E5)); + TERN_(E6_IS_TRINAMIC, SET_CURR(E6)); + TERN_(E7_IS_TRINAMIC, SET_CURR(E7)); } #endif } diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp index 69c6f66fbc..1ec82ba340 100644 --- a/Marlin/src/module/stepper.cpp +++ b/Marlin/src/module/stepper.cpp @@ -2949,54 +2949,20 @@ void Stepper::init() { TERN_(HAS_MICROSTEPS, microstep_init()); // Init Dir Pins - TERN_(HAS_X_DIR, X_DIR_INIT()); + TERN_(HAS_X_DIR, X_DIR_INIT()); TERN_(HAS_X2_DIR, X2_DIR_INIT()); - #if HAS_Y_DIR - Y_DIR_INIT(); - #if ALL(HAS_Y2_STEPPER, HAS_Y2_DIR) - Y2_DIR_INIT(); - #endif - #endif - #if HAS_Z_DIR - Z_DIR_INIT(); - #if NUM_Z_STEPPERS >= 2 && HAS_Z2_DIR - Z2_DIR_INIT(); - #endif - #if NUM_Z_STEPPERS >= 3 && HAS_Z3_DIR - Z3_DIR_INIT(); - #endif - #if NUM_Z_STEPPERS >= 4 && HAS_Z4_DIR - Z4_DIR_INIT(); - #endif - #endif - SECONDARY_AXIS_CODE( - I_DIR_INIT(), J_DIR_INIT(), K_DIR_INIT(), - U_DIR_INIT(), V_DIR_INIT(), W_DIR_INIT() - ); - #if HAS_E0_DIR - E0_DIR_INIT(); - #endif - #if HAS_E1_DIR - E1_DIR_INIT(); - #endif - #if HAS_E2_DIR - E2_DIR_INIT(); - #endif - #if HAS_E3_DIR - E3_DIR_INIT(); - #endif - #if HAS_E4_DIR - E4_DIR_INIT(); - #endif - #if HAS_E5_DIR - E5_DIR_INIT(); - #endif - #if HAS_E6_DIR - E6_DIR_INIT(); - #endif - #if HAS_E7_DIR - E7_DIR_INIT(); - #endif + TERN_(HAS_Y_DIR, Y_DIR_INIT()); + TERN_(HAS_Y2_DIR, Y2_DIR_INIT()); + TERN_(HAS_Z_DIR, Z_DIR_INIT()); + TERN_(HAS_Z2_DIR, Z2_DIR_INIT()); + TERN_(HAS_Z3_DIR, Z3_DIR_INIT()); + TERN_(HAS_Z4_DIR, Z4_DIR_INIT()); + TERN_(HAS_I_DIR, I_DIR_INIT()); + TERN_(HAS_K_DIR, K_DIR_INIT()); + TERN_(HAS_K_DIR, K_DIR_INIT()); + TERN_(HAS_U_DIR, U_DIR_INIT()); + TERN_(HAS_V_DIR, V_DIR_INIT()); + TERN_(HAS_W_DIR, W_DIR_INIT()); // Init Enable Pins - steppers default to disabled. #if HAS_X_ENABLE @@ -3027,15 +2993,15 @@ void Stepper::init() { #endif Z_ENABLE_INIT(); if (Z_ENABLE_INIT_STATE) Z_ENABLE_WRITE(Z_ENABLE_INIT_STATE); - #if NUM_Z_STEPPERS >= 2 && HAS_Z2_ENABLE + #if HAS_Z2_ENABLE Z2_ENABLE_INIT(); if (Z_ENABLE_INIT_STATE) Z2_ENABLE_WRITE(Z_ENABLE_INIT_STATE); #endif - #if NUM_Z_STEPPERS >= 3 && HAS_Z3_ENABLE + #if HAS_Z3_ENABLE Z3_ENABLE_INIT(); if (Z_ENABLE_INIT_STATE) Z3_ENABLE_WRITE(Z_ENABLE_INIT_STATE); #endif - #if NUM_Z_STEPPERS >= 4 && HAS_Z4_ENABLE + #if HAS_Z4_ENABLE Z4_ENABLE_INIT(); if (Z_ENABLE_INIT_STATE) Z4_ENABLE_WRITE(Z_ENABLE_INIT_STATE); #endif @@ -3133,7 +3099,7 @@ void Stepper::init() { _WRITE_STEP(AXIS, !_STEP_STATE(PIN)); \ _DISABLE_AXIS(AXIS) - #define E_AXIS_INIT(NUM) AXIS_INIT(E## NUM, E) + #define E_AXIS_INIT(NUM) DEFER(AXIS_INIT)(E##NUM, E) // Init Step Pins #if HAS_X_STEP @@ -3167,49 +3133,21 @@ void Stepper::init() { #endif AXIS_INIT(Z, Z); #endif - #if HAS_I_STEP - AXIS_INIT(I, I); - #endif - #if HAS_J_STEP - AXIS_INIT(J, J); - #endif - #if HAS_K_STEP - AXIS_INIT(K, K); - #endif - #if HAS_U_STEP - AXIS_INIT(U, U); - #endif - #if HAS_V_STEP - AXIS_INIT(V, V); - #endif - #if HAS_W_STEP - AXIS_INIT(W, W); - #endif + TERN_(HAS_I_STEP, AXIS_INIT(I, I)); + TERN_(HAS_J_STEP, AXIS_INIT(J, J)); + TERN_(HAS_K_STEP, AXIS_INIT(K, K)); + TERN_(HAS_U_STEP, AXIS_INIT(U, U)); + TERN_(HAS_V_STEP, AXIS_INIT(V, V)); + TERN_(HAS_W_STEP, AXIS_INIT(W, W)); - #if E_STEPPERS && HAS_E0_STEP - E_AXIS_INIT(0); - #endif - #if (E_STEPPERS > 1 || ENABLED(E_DUAL_STEPPER_DRIVERS)) && HAS_E1_STEP - E_AXIS_INIT(1); - #endif - #if E_STEPPERS > 2 && HAS_E2_STEP - E_AXIS_INIT(2); - #endif - #if E_STEPPERS > 3 && HAS_E3_STEP - E_AXIS_INIT(3); - #endif - #if E_STEPPERS > 4 && HAS_E4_STEP - E_AXIS_INIT(4); - #endif - #if E_STEPPERS > 5 && HAS_E5_STEP - E_AXIS_INIT(5); - #endif - #if E_STEPPERS > 6 && HAS_E6_STEP - E_AXIS_INIT(6); - #endif - #if E_STEPPERS > 7 && HAS_E7_STEP - E_AXIS_INIT(7); - #endif + TERN_(HAS_E0_STEP, E_AXIS_INIT(0)); + TERN_(HAS_E1_STEP, E_AXIS_INIT(1)); + TERN_(HAS_E2_STEP, E_AXIS_INIT(2)); + TERN_(HAS_E3_STEP, E_AXIS_INIT(3)); + TERN_(HAS_E4_STEP, E_AXIS_INIT(4)); + TERN_(HAS_E5_STEP, E_AXIS_INIT(5)); + TERN_(HAS_E6_STEP, E_AXIS_INIT(6)); + TERN_(HAS_E7_STEP, E_AXIS_INIT(7)); #if DISABLED(I2S_STEPPER_STREAM) HAL_timer_start(MF_TIMER_STEP, 122); // Init Stepper ISR to 122 Hz for quick starting diff --git a/Marlin/src/module/stepper/indirection.h b/Marlin/src/module/stepper/indirection.h index 4c83cbd6a6..d18fe830cc 100644 --- a/Marlin/src/module/stepper/indirection.h +++ b/Marlin/src/module/stepper/indirection.h @@ -810,48 +810,24 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset #endif #ifndef ENABLE_STEPPER_U - #if HAS_U_ENABLE - #define ENABLE_STEPPER_U() U_ENABLE_WRITE( U_ENABLE_ON) - #else - #define ENABLE_STEPPER_U() NOOP - #endif + #define ENABLE_STEPPER_U() TERN(HAS_U_ENABLE, U_ENABLE_WRITE( U_ENABLE_ON), NOOP) #endif #ifndef DISABLE_STEPPER_U - #if HAS_U_ENABLE - #define DISABLE_STEPPER_U() U_ENABLE_WRITE(!U_ENABLE_ON) - #else - #define DISABLE_STEPPER_U() NOOP - #endif + #define DISABLE_STEPPER_U() TERN(HAS_U_ENABLE, U_ENABLE_WRITE(!U_ENABLE_ON), NOOP) #endif #ifndef ENABLE_STEPPER_V - #if HAS_V_ENABLE - #define ENABLE_STEPPER_V() V_ENABLE_WRITE( V_ENABLE_ON) - #else - #define ENABLE_STEPPER_V() NOOP - #endif + #define ENABLE_STEPPER_V() TERN(HAS_V_ENABLE, V_ENABLE_WRITE( V_ENABLE_ON), NOOP) #endif #ifndef DISABLE_STEPPER_V - #if HAS_V_ENABLE - #define DISABLE_STEPPER_V() V_ENABLE_WRITE(!V_ENABLE_ON) - #else - #define DISABLE_STEPPER_V() NOOP - #endif + #define DISABLE_STEPPER_V() TERN(HAS_V_ENABLE, V_ENABLE_WRITE(!V_ENABLE_ON), NOOP) #endif #ifndef ENABLE_STEPPER_W - #if HAS_W_ENABLE - #define ENABLE_STEPPER_W() W_ENABLE_WRITE( W_ENABLE_ON) - #else - #define ENABLE_STEPPER_W() NOOP - #endif + #define ENABLE_STEPPER_W() TERN(HAS_W_ENABLE, W_ENABLE_WRITE( W_ENABLE_ON), NOOP) #endif #ifndef DISABLE_STEPPER_W - #if HAS_W_ENABLE - #define DISABLE_STEPPER_W() W_ENABLE_WRITE(!W_ENABLE_ON) - #else - #define DISABLE_STEPPER_W() NOOP - #endif + #define DISABLE_STEPPER_W() TERN(HAS_W_ENABLE, W_ENABLE_WRITE(!W_ENABLE_ON), NOOP) #endif #ifndef ENABLE_STEPPER_E0 @@ -877,93 +853,45 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset #endif #ifndef ENABLE_STEPPER_E2 - #if E_STEPPERS > 2 && HAS_E2_ENABLE - #define ENABLE_STEPPER_E2() E2_ENABLE_WRITE( E_ENABLE_ON) - #else - #define ENABLE_STEPPER_E2() NOOP - #endif + #define ENABLE_STEPPER_E2() TERN(HAS_E2_ENABLE, E2_ENABLE_WRITE( E_ENABLE_ON), NOOP) #endif #ifndef DISABLE_STEPPER_E2 - #if E_STEPPERS > 2 && HAS_E2_ENABLE - #define DISABLE_STEPPER_E2() E2_ENABLE_WRITE(!E_ENABLE_ON) - #else - #define DISABLE_STEPPER_E2() NOOP - #endif + #define DISABLE_STEPPER_E2() TERN(HAS_E2_ENABLE, E2_ENABLE_WRITE(!E_ENABLE_ON), NOOP) #endif #ifndef ENABLE_STEPPER_E3 - #if E_STEPPERS > 3 && HAS_E3_ENABLE - #define ENABLE_STEPPER_E3() E3_ENABLE_WRITE( E_ENABLE_ON) - #else - #define ENABLE_STEPPER_E3() NOOP - #endif + #define ENABLE_STEPPER_E3() TERN(HAS_E3_ENABLE, E3_ENABLE_WRITE( E_ENABLE_ON), NOOP) #endif #ifndef DISABLE_STEPPER_E3 - #if E_STEPPERS > 3 && HAS_E3_ENABLE - #define DISABLE_STEPPER_E3() E3_ENABLE_WRITE(!E_ENABLE_ON) - #else - #define DISABLE_STEPPER_E3() NOOP - #endif + #define DISABLE_STEPPER_E3() TERN(HAS_E3_ENABLE, E3_ENABLE_WRITE(!E_ENABLE_ON), NOOP) #endif #ifndef ENABLE_STEPPER_E4 - #if E_STEPPERS > 4 && HAS_E4_ENABLE - #define ENABLE_STEPPER_E4() E4_ENABLE_WRITE( E_ENABLE_ON) - #else - #define ENABLE_STEPPER_E4() NOOP - #endif + #define ENABLE_STEPPER_E4() TERN(HAS_E4_ENABLE, E4_ENABLE_WRITE( E_ENABLE_ON), NOOP) #endif #ifndef DISABLE_STEPPER_E4 - #if E_STEPPERS > 4 && HAS_E4_ENABLE - #define DISABLE_STEPPER_E4() E4_ENABLE_WRITE(!E_ENABLE_ON) - #else - #define DISABLE_STEPPER_E4() NOOP - #endif + #define DISABLE_STEPPER_E4() TERN(HAS_E4_ENABLE, E4_ENABLE_WRITE(!E_ENABLE_ON), NOOP) #endif #ifndef ENABLE_STEPPER_E5 - #if E_STEPPERS > 5 && HAS_E5_ENABLE - #define ENABLE_STEPPER_E5() E5_ENABLE_WRITE( E_ENABLE_ON) - #else - #define ENABLE_STEPPER_E5() NOOP - #endif + #define ENABLE_STEPPER_E5() TERN(HAS_E5_ENABLE, E5_ENABLE_WRITE( E_ENABLE_ON), NOOP) #endif #ifndef DISABLE_STEPPER_E5 - #if E_STEPPERS > 5 && HAS_E5_ENABLE - #define DISABLE_STEPPER_E5() E5_ENABLE_WRITE(!E_ENABLE_ON) - #else - #define DISABLE_STEPPER_E5() NOOP - #endif + #define DISABLE_STEPPER_E5() TERN(HAS_E5_ENABLE, E5_ENABLE_WRITE(!E_ENABLE_ON), NOOP) #endif #ifndef ENABLE_STEPPER_E6 - #if E_STEPPERS > 6 && HAS_E6_ENABLE - #define ENABLE_STEPPER_E6() E6_ENABLE_WRITE( E_ENABLE_ON) - #else - #define ENABLE_STEPPER_E6() NOOP - #endif + #define ENABLE_STEPPER_E6() TERN(HAS_E6_ENABLE, E6_ENABLE_WRITE( E_ENABLE_ON), NOOP) #endif #ifndef DISABLE_STEPPER_E6 - #if E_STEPPERS > 6 && HAS_E6_ENABLE - #define DISABLE_STEPPER_E6() E6_ENABLE_WRITE(!E_ENABLE_ON) - #else - #define DISABLE_STEPPER_E6() NOOP - #endif + #define DISABLE_STEPPER_E6() TERN(HAS_E6_ENABLE, E6_ENABLE_WRITE(!E_ENABLE_ON), NOOP) #endif #ifndef ENABLE_STEPPER_E7 - #if E_STEPPERS > 7 && HAS_E7_ENABLE - #define ENABLE_STEPPER_E7() E7_ENABLE_WRITE( E_ENABLE_ON) - #else - #define ENABLE_STEPPER_E7() NOOP - #endif + #define ENABLE_STEPPER_E7() TERN(HAS_E7_ENABLE, E7_ENABLE_WRITE( E_ENABLE_ON), NOOP) #endif #ifndef DISABLE_STEPPER_E7 - #if E_STEPPERS > 7 && HAS_E7_ENABLE - #define DISABLE_STEPPER_E7() E7_ENABLE_WRITE(!E_ENABLE_ON) - #else - #define DISABLE_STEPPER_E7() NOOP - #endif + #define DISABLE_STEPPER_E7() TERN(HAS_E7_ENABLE, E7_ENABLE_WRITE(!E_ENABLE_ON), NOOP) #endif // @@ -1077,121 +1005,57 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset #endif #ifndef ENABLE_AXIS_E0 - #if E_STEPPERS && HAS_E0_ENABLE - #define ENABLE_AXIS_E0() ENABLE_STEPPER_E0() - #else - #define ENABLE_AXIS_E0() NOOP - #endif + #define ENABLE_AXIS_E0() TERN(HAS_E0_ENABLE, ENABLE_STEPPER_E0(), NOOP) #endif #ifndef DISABLE_AXIS_E0 - #if E_STEPPERS && HAS_E0_ENABLE - #define DISABLE_AXIS_E0() DISABLE_STEPPER_E0() - #else - #define DISABLE_AXIS_E0() NOOP - #endif + #define DISABLE_AXIS_E0() TERN(HAS_E0_ENABLE, DISABLE_STEPPER_E0(), NOOP) #endif #ifndef ENABLE_AXIS_E1 - #if E_STEPPERS > 1 && HAS_E1_ENABLE - #define ENABLE_AXIS_E1() ENABLE_STEPPER_E1() - #else - #define ENABLE_AXIS_E1() NOOP - #endif + #define ENABLE_AXIS_E1() TERN(HAS_E1_ENABLE, ENABLE_STEPPER_E1(), NOOP) #endif #ifndef DISABLE_AXIS_E1 - #if E_STEPPERS > 1 && HAS_E1_ENABLE - #define DISABLE_AXIS_E1() DISABLE_STEPPER_E1() - #else - #define DISABLE_AXIS_E1() NOOP - #endif + #define DISABLE_AXIS_E1() TERN(HAS_E1_ENABLE, DISABLE_STEPPER_E1(), NOOP) #endif #ifndef ENABLE_AXIS_E2 - #if E_STEPPERS > 2 && HAS_E2_ENABLE - #define ENABLE_AXIS_E2() ENABLE_STEPPER_E2() - #else - #define ENABLE_AXIS_E2() NOOP - #endif + #define ENABLE_AXIS_E2() TERN(HAS_E2_ENABLE, ENABLE_STEPPER_E2(), NOOP) #endif #ifndef DISABLE_AXIS_E2 - #if E_STEPPERS > 2 && HAS_E2_ENABLE - #define DISABLE_AXIS_E2() DISABLE_STEPPER_E2() - #else - #define DISABLE_AXIS_E2() NOOP - #endif + #define DISABLE_AXIS_E2() TERN(HAS_E2_ENABLE, DISABLE_STEPPER_E2(), NOOP) #endif #ifndef ENABLE_AXIS_E3 - #if E_STEPPERS > 3 && HAS_E3_ENABLE - #define ENABLE_AXIS_E3() ENABLE_STEPPER_E3() - #else - #define ENABLE_AXIS_E3() NOOP - #endif + #define ENABLE_AXIS_E3() TERN(HAS_E3_ENABLE, ENABLE_STEPPER_E3(), NOOP) #endif #ifndef DISABLE_AXIS_E3 - #if E_STEPPERS > 3 && HAS_E3_ENABLE - #define DISABLE_AXIS_E3() DISABLE_STEPPER_E3() - #else - #define DISABLE_AXIS_E3() NOOP - #endif + #define DISABLE_AXIS_E3() TERN(HAS_E3_ENABLE, DISABLE_STEPPER_E3(), NOOP) #endif #ifndef ENABLE_AXIS_E4 - #if E_STEPPERS > 4 && HAS_E4_ENABLE - #define ENABLE_AXIS_E4() ENABLE_STEPPER_E4() - #else - #define ENABLE_AXIS_E4() NOOP - #endif + #define ENABLE_AXIS_E4() TERN(HAS_E4_ENABLE, ENABLE_STEPPER_E4(), NOOP) #endif #ifndef DISABLE_AXIS_E4 - #if E_STEPPERS > 4 && HAS_E4_ENABLE - #define DISABLE_AXIS_E4() DISABLE_STEPPER_E4() - #else - #define DISABLE_AXIS_E4() NOOP - #endif + #define DISABLE_AXIS_E4() TERN(HAS_E4_ENABLE, DISABLE_STEPPER_E4(), NOOP) #endif #ifndef ENABLE_AXIS_E5 - #if E_STEPPERS > 5 && HAS_E5_ENABLE - #define ENABLE_AXIS_E5() ENABLE_STEPPER_E5() - #else - #define ENABLE_AXIS_E5() NOOP - #endif + #define ENABLE_AXIS_E5() TERN(HAS_E5_ENABLE, ENABLE_STEPPER_E5(), NOOP) #endif #ifndef DISABLE_AXIS_E5 - #if E_STEPPERS > 5 && HAS_E5_ENABLE - #define DISABLE_AXIS_E5() DISABLE_STEPPER_E5() - #else - #define DISABLE_AXIS_E5() NOOP - #endif + #define DISABLE_AXIS_E5() TERN(HAS_E5_ENABLE, DISABLE_STEPPER_E5(), NOOP) #endif #ifndef ENABLE_AXIS_E6 - #if E_STEPPERS > 6 && HAS_E6_ENABLE - #define ENABLE_AXIS_E6() ENABLE_STEPPER_E6() - #else - #define ENABLE_AXIS_E6() NOOP - #endif + #define ENABLE_AXIS_E6() TERN(HAS_E6_ENABLE, ENABLE_STEPPER_E6(), NOOP) #endif #ifndef DISABLE_AXIS_E6 - #if E_STEPPERS > 6 && HAS_E6_ENABLE - #define DISABLE_AXIS_E6() DISABLE_STEPPER_E6() - #else - #define DISABLE_AXIS_E6() NOOP - #endif + #define DISABLE_AXIS_E6() TERN(HAS_E6_ENABLE, DISABLE_STEPPER_E6(), NOOP) #endif #ifndef ENABLE_AXIS_E7 - #if E_STEPPERS > 7 && HAS_E7_ENABLE - #define ENABLE_AXIS_E7() ENABLE_STEPPER_E7() - #else - #define ENABLE_AXIS_E7() NOOP - #endif + #define ENABLE_AXIS_E7() TERN(HAS_E7_ENABLE, ENABLE_STEPPER_E7(), NOOP) #endif #ifndef DISABLE_AXIS_E7 - #if E_STEPPERS > 7 && HAS_E7_ENABLE - #define DISABLE_AXIS_E7() DISABLE_STEPPER_E7() - #else - #define DISABLE_AXIS_E7() NOOP - #endif + #define DISABLE_AXIS_E7() TERN(HAS_E7_ENABLE, DISABLE_STEPPER_E7(), NOOP) #endif diff --git a/Marlin/src/module/stepper/trinamic.cpp b/Marlin/src/module/stepper/trinamic.cpp index c0fb083d61..3ec8ff4325 100644 --- a/Marlin/src/module/stepper/trinamic.cpp +++ b/Marlin/src/module/stepper/trinamic.cpp @@ -847,72 +847,28 @@ enum StealthIndex : uint8_t { #endif // TMC5160 void restore_trinamic_drivers() { - #if AXIS_IS_TMC(X) - stepperX.push(); - #endif - #if AXIS_IS_TMC(X2) - stepperX2.push(); - #endif - #if AXIS_IS_TMC(Y) - stepperY.push(); - #endif - #if AXIS_IS_TMC(Y2) - stepperY2.push(); - #endif - #if AXIS_IS_TMC(Z) - stepperZ.push(); - #endif - #if AXIS_IS_TMC(Z2) - stepperZ2.push(); - #endif - #if AXIS_IS_TMC(Z3) - stepperZ3.push(); - #endif - #if AXIS_IS_TMC(Z4) - stepperZ4.push(); - #endif - #if AXIS_IS_TMC(I) - stepperI.push(); - #endif - #if AXIS_IS_TMC(J) - stepperJ.push(); - #endif - #if AXIS_IS_TMC(K) - stepperK.push(); - #endif - #if AXIS_IS_TMC(U) - stepperU.push(); - #endif - #if AXIS_IS_TMC(V) - stepperV.push(); - #endif - #if AXIS_IS_TMC(W) - stepperW.push(); - #endif - #if AXIS_IS_TMC(E0) - stepperE0.push(); - #endif - #if AXIS_IS_TMC(E1) - stepperE1.push(); - #endif - #if AXIS_IS_TMC(E2) - stepperE2.push(); - #endif - #if AXIS_IS_TMC(E3) - stepperE3.push(); - #endif - #if AXIS_IS_TMC(E4) - stepperE4.push(); - #endif - #if AXIS_IS_TMC(E5) - stepperE5.push(); - #endif - #if AXIS_IS_TMC(E6) - stepperE6.push(); - #endif - #if AXIS_IS_TMC(E7) - stepperE7.push(); - #endif + TERN_(X_IS_TRINAMIC, stepperX.push()); + TERN_(X2_IS_TRINAMIC, stepperX2.push()); + TERN_(Y_IS_TRINAMIC, stepperY.push()); + TERN_(Y2_IS_TRINAMIC, stepperY2.push()); + TERN_(Z_IS_TRINAMIC, stepperZ.push()); + TERN_(Z2_IS_TRINAMIC, stepperZ2.push()); + TERN_(Z3_IS_TRINAMIC, stepperZ3.push()); + TERN_(Z4_IS_TRINAMIC, stepperZ4.push()); + TERN_(I_IS_TRINAMIC, stepperI.push()); + TERN_(J_IS_TRINAMIC, stepperJ.push()); + TERN_(K_IS_TRINAMIC, stepperK.push()); + TERN_(U_IS_TRINAMIC, stepperU.push()); + TERN_(V_IS_TRINAMIC, stepperV.push()); + TERN_(W_IS_TRINAMIC, stepperW.push()); + TERN_(E0_IS_TRINAMIC, stepperE0.push()); + TERN_(E1_IS_TRINAMIC, stepperE1.push()); + TERN_(E2_IS_TRINAMIC, stepperE2.push()); + TERN_(E3_IS_TRINAMIC, stepperE3.push()); + TERN_(E4_IS_TRINAMIC, stepperE4.push()); + TERN_(E5_IS_TRINAMIC, stepperE5.push()); + TERN_(E6_IS_TRINAMIC, stepperE6.push()); + TERN_(E7_IS_TRINAMIC, stepperE7.push()); } void reset_trinamic_drivers() { @@ -923,88 +879,44 @@ void reset_trinamic_drivers() { ENABLED(STEALTHCHOP_U), ENABLED(STEALTHCHOP_V), ENABLED(STEALTHCHOP_W) ); - #if AXIS_IS_TMC(X) - TMC_INIT(X, STEALTH_AXIS_X); - #endif - #if AXIS_IS_TMC(X2) - TMC_INIT(X2, STEALTH_AXIS_X); - #endif - #if AXIS_IS_TMC(Y) - TMC_INIT(Y, STEALTH_AXIS_Y); - #endif - #if AXIS_IS_TMC(Y2) - TMC_INIT(Y2, STEALTH_AXIS_Y); - #endif - #if AXIS_IS_TMC(Z) - TMC_INIT(Z, STEALTH_AXIS_Z); - #endif - #if AXIS_IS_TMC(Z2) - TMC_INIT(Z2, STEALTH_AXIS_Z); - #endif - #if AXIS_IS_TMC(Z3) - TMC_INIT(Z3, STEALTH_AXIS_Z); - #endif - #if AXIS_IS_TMC(Z4) - TMC_INIT(Z4, STEALTH_AXIS_Z); - #endif - #if AXIS_IS_TMC(I) - TMC_INIT(I, STEALTH_AXIS_I); - #endif - #if AXIS_IS_TMC(J) - TMC_INIT(J, STEALTH_AXIS_J); - #endif - #if AXIS_IS_TMC(K) - TMC_INIT(K, STEALTH_AXIS_K); - #endif - #if AXIS_IS_TMC(U) - TMC_INIT(U, STEALTH_AXIS_U); - #endif - #if AXIS_IS_TMC(V) - TMC_INIT(V, STEALTH_AXIS_V); - #endif - #if AXIS_IS_TMC(W) - TMC_INIT(W, STEALTH_AXIS_W); - #endif - #if AXIS_IS_TMC(E0) - TMC_INIT(E0, STEALTH_AXIS_E); - #endif - #if AXIS_IS_TMC(E1) - TMC_INIT(E1, STEALTH_AXIS_E); - #endif - #if AXIS_IS_TMC(E2) - TMC_INIT(E2, STEALTH_AXIS_E); - #endif - #if AXIS_IS_TMC(E3) - TMC_INIT(E3, STEALTH_AXIS_E); - #endif - #if AXIS_IS_TMC(E4) - TMC_INIT(E4, STEALTH_AXIS_E); - #endif - #if AXIS_IS_TMC(E5) - TMC_INIT(E5, STEALTH_AXIS_E); - #endif - #if AXIS_IS_TMC(E6) - TMC_INIT(E6, STEALTH_AXIS_E); - #endif - #if AXIS_IS_TMC(E7) - TMC_INIT(E7, STEALTH_AXIS_E); - #endif + TERN_(X_IS_TRINAMIC, TMC_INIT(X, STEALTH_AXIS_X)); + TERN_(X2_IS_TRINAMIC, TMC_INIT(X2, STEALTH_AXIS_X)); + TERN_(Y_IS_TRINAMIC, TMC_INIT(Y, STEALTH_AXIS_Y)); + TERN_(Y2_IS_TRINAMIC, TMC_INIT(Y2, STEALTH_AXIS_Y)); + TERN_(Z_IS_TRINAMIC, TMC_INIT(Z, STEALTH_AXIS_Z)); + TERN_(Z2_IS_TRINAMIC, TMC_INIT(Z2, STEALTH_AXIS_Z)); + TERN_(Z3_IS_TRINAMIC, TMC_INIT(Z3, STEALTH_AXIS_Z)); + TERN_(Z4_IS_TRINAMIC, TMC_INIT(Z4, STEALTH_AXIS_Z)); + TERN_(I_IS_TRINAMIC, TMC_INIT(I, STEALTH_AXIS_I)); + TERN_(J_IS_TRINAMIC, TMC_INIT(J, STEALTH_AXIS_J)); + TERN_(K_IS_TRINAMIC, TMC_INIT(K, STEALTH_AXIS_K)); + TERN_(U_IS_TRINAMIC, TMC_INIT(U, STEALTH_AXIS_U)); + TERN_(V_IS_TRINAMIC, TMC_INIT(V, STEALTH_AXIS_V)); + TERN_(W_IS_TRINAMIC, TMC_INIT(W, STEALTH_AXIS_W)); + TERN_(E0_IS_TRINAMIC, TMC_INIT(E0, STEALTH_AXIS_E)); + TERN_(E1_IS_TRINAMIC, TMC_INIT(E1, STEALTH_AXIS_E)); + TERN_(E2_IS_TRINAMIC, TMC_INIT(E2, STEALTH_AXIS_E)); + TERN_(E3_IS_TRINAMIC, TMC_INIT(E3, STEALTH_AXIS_E)); + TERN_(E4_IS_TRINAMIC, TMC_INIT(E4, STEALTH_AXIS_E)); + TERN_(E5_IS_TRINAMIC, TMC_INIT(E5, STEALTH_AXIS_E)); + TERN_(E6_IS_TRINAMIC, TMC_INIT(E6, STEALTH_AXIS_E)); + TERN_(E7_IS_TRINAMIC, TMC_INIT(E7, STEALTH_AXIS_E)); #if USE_SENSORLESS - TERN_(X_SENSORLESS, stepperX.homing_threshold(X_STALL_SENSITIVITY)); + TERN_(X_SENSORLESS, stepperX.homing_threshold(X_STALL_SENSITIVITY)); TERN_(X2_SENSORLESS, stepperX2.homing_threshold(X2_STALL_SENSITIVITY)); - TERN_(Y_SENSORLESS, stepperY.homing_threshold(Y_STALL_SENSITIVITY)); + TERN_(Y_SENSORLESS, stepperY.homing_threshold(Y_STALL_SENSITIVITY)); TERN_(Y2_SENSORLESS, stepperY2.homing_threshold(Y2_STALL_SENSITIVITY)); - TERN_(Z_SENSORLESS, stepperZ.homing_threshold(Z_STALL_SENSITIVITY)); + TERN_(Z_SENSORLESS, stepperZ.homing_threshold(Z_STALL_SENSITIVITY)); TERN_(Z2_SENSORLESS, stepperZ2.homing_threshold(Z2_STALL_SENSITIVITY)); TERN_(Z3_SENSORLESS, stepperZ3.homing_threshold(Z3_STALL_SENSITIVITY)); TERN_(Z4_SENSORLESS, stepperZ4.homing_threshold(Z4_STALL_SENSITIVITY)); - TERN_(I_SENSORLESS, stepperI.homing_threshold(I_STALL_SENSITIVITY)); - TERN_(J_SENSORLESS, stepperJ.homing_threshold(J_STALL_SENSITIVITY)); - TERN_(K_SENSORLESS, stepperK.homing_threshold(K_STALL_SENSITIVITY)); - TERN_(U_SENSORLESS, stepperU.homing_threshold(U_STALL_SENSITIVITY)); - TERN_(V_SENSORLESS, stepperV.homing_threshold(V_STALL_SENSITIVITY)); - TERN_(W_SENSORLESS, stepperW.homing_threshold(W_STALL_SENSITIVITY)); + TERN_(I_SENSORLESS, stepperI.homing_threshold(I_STALL_SENSITIVITY)); + TERN_(J_SENSORLESS, stepperJ.homing_threshold(J_STALL_SENSITIVITY)); + TERN_(K_SENSORLESS, stepperK.homing_threshold(K_STALL_SENSITIVITY)); + TERN_(U_SENSORLESS, stepperU.homing_threshold(U_STALL_SENSITIVITY)); + TERN_(V_SENSORLESS, stepperV.homing_threshold(V_STALL_SENSITIVITY)); + TERN_(W_SENSORLESS, stepperW.homing_threshold(W_STALL_SENSITIVITY)); #endif #ifdef TMC_ADV diff --git a/Marlin/src/module/stepper/trinamic.h b/Marlin/src/module/stepper/trinamic.h index bf7eaf7f95..0fd48f18cb 100644 --- a/Marlin/src/module/stepper/trinamic.h +++ b/Marlin/src/module/stepper/trinamic.h @@ -116,7 +116,7 @@ void restore_trinamic_drivers(); void reset_trinamic_drivers(); // X Stepper -#if AXIS_IS_TMC(X) +#if X_IS_TRINAMIC extern TMC_CLASS(X, X) stepperX; static constexpr chopper_timing_t chopper_timing_X = CHOPPER_TIMING_X; #if ENABLED(SOFTWARE_DRIVER_ENABLE) @@ -130,7 +130,7 @@ void reset_trinamic_drivers(); #endif // Y Stepper -#if AXIS_IS_TMC(Y) +#if Y_IS_TRINAMIC extern TMC_CLASS(Y, Y) stepperY; static constexpr chopper_timing_t chopper_timing_Y = CHOPPER_TIMING_Y; #if ENABLED(SOFTWARE_DRIVER_ENABLE) @@ -144,7 +144,7 @@ void reset_trinamic_drivers(); #endif // Z Stepper -#if AXIS_IS_TMC(Z) +#if Z_IS_TRINAMIC extern TMC_CLASS(Z, Z) stepperZ; static constexpr chopper_timing_t chopper_timing_Z = CHOPPER_TIMING_Z; #if ENABLED(SOFTWARE_DRIVER_ENABLE) @@ -158,7 +158,7 @@ void reset_trinamic_drivers(); #endif // X2 Stepper -#if HAS_X2_ENABLE && AXIS_IS_TMC(X2) +#if X2_IS_TRINAMIC extern TMC_CLASS(X2, X) stepperX2; #ifndef CHOPPER_TIMING_X2 #define CHOPPER_TIMING_X2 CHOPPER_TIMING_X @@ -175,7 +175,7 @@ void reset_trinamic_drivers(); #endif // Y2 Stepper -#if HAS_Y2_ENABLE && AXIS_IS_TMC(Y2) +#if Y2_IS_TRINAMIC extern TMC_CLASS(Y2, Y) stepperY2; #ifndef CHOPPER_TIMING_Y2 #define CHOPPER_TIMING_Y2 CHOPPER_TIMING_Y @@ -192,7 +192,7 @@ void reset_trinamic_drivers(); #endif // Z2 Stepper -#if HAS_Z2_ENABLE && AXIS_IS_TMC(Z2) +#if Z2_IS_TRINAMIC extern TMC_CLASS(Z2, Z) stepperZ2; #ifndef CHOPPER_TIMING_Z2 #define CHOPPER_TIMING_Z2 CHOPPER_TIMING_Z @@ -209,7 +209,7 @@ void reset_trinamic_drivers(); #endif // Z3 Stepper -#if HAS_Z3_ENABLE && AXIS_IS_TMC(Z3) +#if Z3_IS_TRINAMIC extern TMC_CLASS(Z3, Z) stepperZ3; #ifndef CHOPPER_TIMING_Z3 #define CHOPPER_TIMING_Z3 CHOPPER_TIMING_Z @@ -226,7 +226,7 @@ void reset_trinamic_drivers(); #endif // Z4 Stepper -#if HAS_Z4_ENABLE && AXIS_IS_TMC(Z4) +#if Z4_IS_TRINAMIC extern TMC_CLASS(Z4, Z) stepperZ4; #ifndef CHOPPER_TIMING_Z4 #define CHOPPER_TIMING_Z4 CHOPPER_TIMING_Z @@ -243,7 +243,7 @@ void reset_trinamic_drivers(); #endif // I Stepper -#if AXIS_IS_TMC(I) +#if I_IS_TRINAMIC extern TMC_CLASS(I, I) stepperI; static constexpr chopper_timing_t chopper_timing_I = CHOPPER_TIMING_I; #if ENABLED(SOFTWARE_DRIVER_ENABLE) @@ -257,7 +257,7 @@ void reset_trinamic_drivers(); #endif // J Stepper -#if AXIS_IS_TMC(J) +#if J_IS_TRINAMIC extern TMC_CLASS(J, J) stepperJ; static constexpr chopper_timing_t chopper_timing_J = CHOPPER_TIMING_J; #if ENABLED(SOFTWARE_DRIVER_ENABLE) @@ -271,7 +271,7 @@ void reset_trinamic_drivers(); #endif // K Stepper -#if AXIS_IS_TMC(K) +#if K_IS_TRINAMIC extern TMC_CLASS(K, K) stepperK; static constexpr chopper_timing_t chopper_timing_K = CHOPPER_TIMING_K; #if ENABLED(SOFTWARE_DRIVER_ENABLE) @@ -285,7 +285,7 @@ void reset_trinamic_drivers(); #endif // U Stepper -#if AXIS_IS_TMC(U) +#if U_IS_TRINAMIC extern TMC_CLASS(U, U) stepperU; static constexpr chopper_timing_t chopper_timing_U = CHOPPER_TIMING_U; #if ENABLED(SOFTWARE_DRIVER_ENABLE) @@ -299,7 +299,7 @@ void reset_trinamic_drivers(); #endif // V Stepper -#if AXIS_IS_TMC(V) +#if V_IS_TRINAMIC extern TMC_CLASS(V, V) stepperV; static constexpr chopper_timing_t chopper_timing_V = CHOPPER_TIMING_V; #if ENABLED(SOFTWARE_DRIVER_ENABLE) @@ -313,7 +313,7 @@ void reset_trinamic_drivers(); #endif // W Stepper -#if AXIS_IS_TMC(W) +#if W_IS_TRINAMIC extern TMC_CLASS(W, W) stepperW; static constexpr chopper_timing_t chopper_timing_W = CHOPPER_TIMING_W; #if ENABLED(SOFTWARE_DRIVER_ENABLE) @@ -327,7 +327,7 @@ void reset_trinamic_drivers(); #endif // E0 Stepper -#if AXIS_IS_TMC(E0) +#if E0_IS_TRINAMIC extern TMC_CLASS_E(0) stepperE0; #ifndef CHOPPER_TIMING_E0 #define CHOPPER_TIMING_E0 CHOPPER_TIMING_E @@ -344,7 +344,7 @@ void reset_trinamic_drivers(); #endif // E1 Stepper -#if AXIS_IS_TMC(E1) +#if E1_IS_TRINAMIC extern TMC_CLASS_E(1) stepperE1; #ifndef CHOPPER_TIMING_E1 #define CHOPPER_TIMING_E1 CHOPPER_TIMING_E @@ -361,7 +361,7 @@ void reset_trinamic_drivers(); #endif // E2 Stepper -#if AXIS_IS_TMC(E2) +#if E2_IS_TRINAMIC extern TMC_CLASS_E(2) stepperE2; #ifndef CHOPPER_TIMING_E2 #define CHOPPER_TIMING_E2 CHOPPER_TIMING_E @@ -378,7 +378,7 @@ void reset_trinamic_drivers(); #endif // E3 Stepper -#if AXIS_IS_TMC(E3) +#if E3_IS_TRINAMIC extern TMC_CLASS_E(3) stepperE3; #ifndef CHOPPER_TIMING_E3 #define CHOPPER_TIMING_E3 CHOPPER_TIMING_E @@ -395,7 +395,7 @@ void reset_trinamic_drivers(); #endif // E4 Stepper -#if AXIS_IS_TMC(E4) +#if E4_IS_TRINAMIC extern TMC_CLASS_E(4) stepperE4; #ifndef CHOPPER_TIMING_E4 #define CHOPPER_TIMING_E4 CHOPPER_TIMING_E @@ -412,7 +412,7 @@ void reset_trinamic_drivers(); #endif // E5 Stepper -#if AXIS_IS_TMC(E5) +#if E5_IS_TRINAMIC extern TMC_CLASS_E(5) stepperE5; #ifndef CHOPPER_TIMING_E5 #define CHOPPER_TIMING_E5 CHOPPER_TIMING_E @@ -429,7 +429,7 @@ void reset_trinamic_drivers(); #endif // E6 Stepper -#if AXIS_IS_TMC(E6) +#if E6_IS_TRINAMIC extern TMC_CLASS_E(6) stepperE6; #ifndef CHOPPER_TIMING_E6 #define CHOPPER_TIMING_E6 CHOPPER_TIMING_E @@ -446,7 +446,7 @@ void reset_trinamic_drivers(); #endif // E7 Stepper -#if AXIS_IS_TMC(E7) +#if E7_IS_TRINAMIC extern TMC_CLASS_E(7) stepperE7; #ifndef CHOPPER_TIMING_E7 #define CHOPPER_TIMING_E7 CHOPPER_TIMING_E From 7bd74fecbbdf5013d9be612af6c48f1030348bbb Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Thu, 27 Mar 2025 02:29:58 -0500 Subject: [PATCH 151/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Lan?= =?UTF-8?q?guage=20tweaks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit lang --- Marlin/src/lcd/language/language_cz.h | 3 ++- Marlin/src/lcd/language/language_de.h | 3 ++- Marlin/src/lcd/language/language_en.h | 4 +++- Marlin/src/lcd/language/language_es.h | 3 ++- Marlin/src/lcd/language/language_fr.h | 3 ++- Marlin/src/lcd/language/language_fr_na.h | 3 ++- Marlin/src/lcd/language/language_gl.h | 3 ++- Marlin/src/lcd/language/language_hu.h | 3 ++- Marlin/src/lcd/language/language_it.h | 3 ++- Marlin/src/lcd/language/language_ro.h | 3 ++- Marlin/src/lcd/language/language_ru.h | 2 +- Marlin/src/lcd/language/language_sk.h | 3 ++- Marlin/src/lcd/language/language_sv.h | 3 ++- Marlin/src/lcd/language/language_tr.h | 3 ++- Marlin/src/lcd/language/language_uk.h | 3 ++- Marlin/src/lcd/language/language_vi.h | 2 +- Marlin/src/lcd/language/language_zh_CN.h | 3 ++- Marlin/src/lcd/menu/menu_tmc.cpp | 2 +- 18 files changed, 34 insertions(+), 18 deletions(-) diff --git a/Marlin/src/lcd/language/language_cz.h b/Marlin/src/lcd/language/language_cz.h index 814c9ffde8..9a01466227 100644 --- a/Marlin/src/lcd/language/language_cz.h +++ b/Marlin/src/lcd/language/language_cz.h @@ -534,7 +534,8 @@ namespace LanguageNarrow_cz { LSTR MSG_TMC_HYBRID_THRS = _UxGT("Hybridní práh"); LSTR MSG_TMC_HOMING_THRS = _UxGT("Domů bez senzorů"); LSTR MSG_TMC_STEPPING_MODE = _UxGT("Režim kroků"); - LSTR MSG_TMC_STEALTH_ENABLED = _UxGT("StealthChop povolen"); + LSTR MSG_TMC_STEALTHCHOP = _UxGT("StealthChop"); + LSTR MSG_SERVICE_RESET = _UxGT("Reset"); LSTR MSG_SERVICE_IN = _UxGT(" za:"); LSTR MSG_BACKLASH = _UxGT("Vůle"); diff --git a/Marlin/src/lcd/language/language_de.h b/Marlin/src/lcd/language/language_de.h index edc3d4361d..23730d321a 100644 --- a/Marlin/src/lcd/language/language_de.h +++ b/Marlin/src/lcd/language/language_de.h @@ -719,7 +719,8 @@ namespace LanguageNarrow_de { LSTR MSG_TMC_HYBRID_THRS = _UxGT("Hybrid threshold"); LSTR MSG_TMC_HOMING_THRS = _UxGT("Sensorloses Homing"); LSTR MSG_TMC_STEPPING_MODE = _UxGT("Schrittmodus"); - LSTR MSG_TMC_STEALTH_ENABLED = _UxGT("StealthChop einsch."); + LSTR MSG_TMC_STEALTHCHOP = _UxGT("StealthChop"); + LSTR MSG_SERVICE_RESET = _UxGT("Reset"); LSTR MSG_SERVICE_IN = _UxGT(" im:"); LSTR MSG_BACKLASH = _UxGT("Spiel"); diff --git a/Marlin/src/lcd/language/language_en.h b/Marlin/src/lcd/language/language_en.h index 5762fa150e..ca2e50d063 100644 --- a/Marlin/src/lcd/language/language_en.h +++ b/Marlin/src/lcd/language/language_en.h @@ -872,6 +872,7 @@ namespace LanguageNarrow_en { LSTR MSG_FILAMENT_CHANGE_PURGE = _UxGT(MSG_1_LINE("Purging...")); LSTR MSG_FILAMENT_CHANGE_CONT_PURGE = _UxGT(MSG_1_LINE("Click to finish")); LSTR MSG_FILAMENT_CHANGE_RESUME = _UxGT(MSG_1_LINE("Resuming...")); + LSTR MSG_TMC_DRIVERS = _UxGT("TMC Drivers"); LSTR MSG_TMC_CURRENT = _UxGT("Driver Current"); LSTR MSG_TMC_ACURRENT = STR_A _UxGT("Driver Current"); @@ -881,7 +882,8 @@ namespace LanguageNarrow_en { LSTR MSG_TMC_HYBRID_THRS = _UxGT("Hybrid Threshold"); LSTR MSG_TMC_HOMING_THRS = _UxGT("Sensorless Homing"); LSTR MSG_TMC_STEPPING_MODE = _UxGT("Stepping Mode"); - LSTR MSG_TMC_STEALTH_ENABLED = _UxGT("StealthChop Enabled"); + LSTR MSG_TMC_STEALTHCHOP = _UxGT("StealthChop"); + LSTR MSG_SERVICE_RESET = _UxGT("Reset"); LSTR MSG_SERVICE_IN = _UxGT(" in:"); LSTR MSG_BACKLASH = _UxGT("Backlash"); diff --git a/Marlin/src/lcd/language/language_es.h b/Marlin/src/lcd/language/language_es.h index 1c7d5199d3..058b550f67 100644 --- a/Marlin/src/lcd/language/language_es.h +++ b/Marlin/src/lcd/language/language_es.h @@ -543,7 +543,8 @@ namespace LanguageNarrow_es { LSTR MSG_TMC_HYBRID_THRS = _UxGT("Límite Hibrido"); LSTR MSG_TMC_HOMING_THRS = _UxGT("Origen sin sensores"); LSTR MSG_TMC_STEPPING_MODE = _UxGT("Modo de pasos"); - LSTR MSG_TMC_STEALTH_ENABLED = _UxGT("StealthChop Habilit."); + LSTR MSG_TMC_STEALTHCHOP = _UxGT("StealthChop"); + LSTR MSG_SERVICE_RESET = _UxGT("Reiniciar"); LSTR MSG_SERVICE_IN = _UxGT(" dentro:"); LSTR MSG_BACKLASH = _UxGT("Backlash"); diff --git a/Marlin/src/lcd/language/language_fr.h b/Marlin/src/lcd/language/language_fr.h index b499b32f7b..13bee9fbb8 100644 --- a/Marlin/src/lcd/language/language_fr.h +++ b/Marlin/src/lcd/language/language_fr.h @@ -573,7 +573,8 @@ namespace LanguageNarrow_fr { LSTR MSG_TMC_HYBRID_THRS = _UxGT("Seuil hybride"); LSTR MSG_TMC_HOMING_THRS = _UxGT("Home sans capteur"); LSTR MSG_TMC_STEPPING_MODE = _UxGT("Mode pas à pas"); - LSTR MSG_TMC_STEALTH_ENABLED = _UxGT("StealthChop activé"); + LSTR MSG_TMC_STEALTHCHOP = _UxGT("StealthChop"); + LSTR MSG_SERVICE_RESET = _UxGT("Réinit."); LSTR MSG_SERVICE_IN = _UxGT(" dans:"); LSTR MSG_BACKLASH_CORRECTION = _UxGT("Correction"); diff --git a/Marlin/src/lcd/language/language_fr_na.h b/Marlin/src/lcd/language/language_fr_na.h index 995a5ecd27..a3da3082de 100644 --- a/Marlin/src/lcd/language/language_fr_na.h +++ b/Marlin/src/lcd/language/language_fr_na.h @@ -576,7 +576,8 @@ namespace LanguageNarrow_fr_na { LSTR MSG_TMC_HYBRID_THRS = _UxGT("Seuil hybride"); LSTR MSG_TMC_HOMING_THRS = _UxGT("Home sans capteur"); LSTR MSG_TMC_STEPPING_MODE = _UxGT("Mode pas a pas"); - LSTR MSG_TMC_STEALTH_ENABLED = _UxGT("StealthChop active"); + LSTR MSG_TMC_STEALTHCHOP = _UxGT("StealthChop"); + LSTR MSG_SERVICE_RESET = _UxGT("Reinit."); LSTR MSG_SERVICE_IN = _UxGT(" dans:"); LSTR MSG_BACKLASH_CORRECTION = _UxGT("Correction"); diff --git a/Marlin/src/lcd/language/language_gl.h b/Marlin/src/lcd/language/language_gl.h index 37c1aa292a..3287ae2676 100644 --- a/Marlin/src/lcd/language/language_gl.h +++ b/Marlin/src/lcd/language/language_gl.h @@ -558,7 +558,8 @@ namespace LanguageNarrow_gl { LSTR MSG_TMC_HYBRID_THRS = _UxGT("Limiar Hibrido"); LSTR MSG_TMC_HOMING_THRS = _UxGT("Orixe sen Sensores"); LSTR MSG_TMC_STEPPING_MODE = _UxGT("Modo de pasos"); - LSTR MSG_TMC_STEALTH_ENABLED = _UxGT("StealthChop Habilit."); + LSTR MSG_TMC_STEALTHCHOP = _UxGT("StealthChop"); + LSTR MSG_SERVICE_RESET = _UxGT("Reiniciar"); LSTR MSG_SERVICE_IN = _UxGT(" dentro:"); LSTR MSG_BACKLASH = _UxGT("Reacción"); diff --git a/Marlin/src/lcd/language/language_hu.h b/Marlin/src/lcd/language/language_hu.h index d987416269..a626aa2209 100644 --- a/Marlin/src/lcd/language/language_hu.h +++ b/Marlin/src/lcd/language/language_hu.h @@ -630,7 +630,8 @@ namespace LanguageNarrow_hu { LSTR MSG_TMC_HYBRID_THRS = _UxGT("Hibrid küszöbérték"); LSTR MSG_TMC_HOMING_THRS = _UxGT("Motoros kezdöpont"); LSTR MSG_TMC_STEPPING_MODE = _UxGT("Léptetö mód"); - LSTR MSG_TMC_STEALTH_ENABLED = _UxGT("StealthChop mód"); + LSTR MSG_TMC_STEALTHCHOP = _UxGT("StealthChop"); + LSTR MSG_SERVICE_RESET = _UxGT("Újraindítás"); LSTR MSG_SERVICE_IN = _UxGT(" be:"); LSTR MSG_BACKLASH = _UxGT("Holtjáték"); diff --git a/Marlin/src/lcd/language/language_it.h b/Marlin/src/lcd/language/language_it.h index 0a7302b0f8..1e81514440 100644 --- a/Marlin/src/lcd/language/language_it.h +++ b/Marlin/src/lcd/language/language_it.h @@ -852,7 +852,8 @@ namespace LanguageNarrow_it { LSTR MSG_TMC_HYBRID_THRS = _UxGT("Soglia modo ibrido"); LSTR MSG_TMC_HOMING_THRS = _UxGT("Sensorless homing"); LSTR MSG_TMC_STEPPING_MODE = _UxGT("Modo Stepping"); - LSTR MSG_TMC_STEALTH_ENABLED = _UxGT("StealthChop abil."); + LSTR MSG_TMC_STEALTHCHOP = _UxGT("StealthChop"); + LSTR MSG_SERVICE_RESET = _UxGT("Resetta"); LSTR MSG_SERVICE_IN = _UxGT(" tra:"); LSTR MSG_BACKLASH = _UxGT("Gioco"); diff --git a/Marlin/src/lcd/language/language_ro.h b/Marlin/src/lcd/language/language_ro.h index ff82bb39ba..0b263a4ea6 100644 --- a/Marlin/src/lcd/language/language_ro.h +++ b/Marlin/src/lcd/language/language_ro.h @@ -570,7 +570,8 @@ namespace LanguageNarrow_ro { LSTR MSG_TMC_HYBRID_THRS = _UxGT("Hybrid Threshold"); LSTR MSG_TMC_HOMING_THRS = _UxGT("Sensorless Homing"); LSTR MSG_TMC_STEPPING_MODE = _UxGT("Stepping Mode"); - LSTR MSG_TMC_STEALTH_ENABLED = _UxGT("StealthChop Enabled"); + LSTR MSG_TMC_STEALTHCHOP = _UxGT("StealthChop"); + LSTR MSG_SERVICE_RESET = _UxGT("Reset"); LSTR MSG_SERVICE_IN = _UxGT(" in:"); LSTR MSG_BACKLASH = _UxGT("Backlash"); diff --git a/Marlin/src/lcd/language/language_ru.h b/Marlin/src/lcd/language/language_ru.h index 6b3fbebd08..92011f66a6 100644 --- a/Marlin/src/lcd/language/language_ru.h +++ b/Marlin/src/lcd/language/language_ru.h @@ -636,7 +636,7 @@ namespace LanguageNarrow_ru { LSTR MSG_TMC_HYBRID_THRS = _UxGT("Гибридный режим"); LSTR MSG_TMC_HOMING_THRS = _UxGT("Чувствительность"); LSTR MSG_TMC_STEPPING_MODE = _UxGT("Режим драйвера"); - LSTR MSG_TMC_STEALTH_ENABLED = _UxGT("Тихий режим вкл"); + LSTR MSG_TMC_STEALTHCHOP = _UxGT("Тихий режим вкл"); LSTR MSG_SERVICE_RESET = _UxGT("Сброс"); LSTR MSG_SERVICE_IN = _UxGT(" в:"); diff --git a/Marlin/src/lcd/language/language_sk.h b/Marlin/src/lcd/language/language_sk.h index 32683cf2ed..782f42f118 100644 --- a/Marlin/src/lcd/language/language_sk.h +++ b/Marlin/src/lcd/language/language_sk.h @@ -761,7 +761,8 @@ namespace LanguageNarrow_sk { LSTR MSG_TMC_HYBRID_THRS = _UxGT("Hybridný prah"); LSTR MSG_TMC_HOMING_THRS = _UxGT("Bezsenzor. domov"); LSTR MSG_TMC_STEPPING_MODE = _UxGT("Režim krokovania"); - LSTR MSG_TMC_STEALTH_ENABLED = _UxGT("StealthChop zapnutý"); + LSTR MSG_TMC_STEALTHCHOP = _UxGT("StealthChop"); + LSTR MSG_SERVICE_RESET = _UxGT("Vynulovať"); LSTR MSG_SERVICE_IN = _UxGT("za:"); LSTR MSG_BACKLASH = _UxGT("Kompenz. vôle"); diff --git a/Marlin/src/lcd/language/language_sv.h b/Marlin/src/lcd/language/language_sv.h index 8827252132..356a253b6e 100644 --- a/Marlin/src/lcd/language/language_sv.h +++ b/Marlin/src/lcd/language/language_sv.h @@ -614,7 +614,8 @@ namespace LanguageNarrow_sv { LSTR MSG_TMC_HYBRID_THRS = _UxGT("Hybrid Tröskelvärde"); LSTR MSG_TMC_HOMING_THRS = _UxGT("Sensorlös Hemning"); LSTR MSG_TMC_STEPPING_MODE = _UxGT("Stegningsläge"); - LSTR MSG_TMC_STEALTH_ENABLED = _UxGT("Smyghack Aktiverad"); + LSTR MSG_TMC_STEALTHCHOP = _UxGT("Smyghack"); + LSTR MSG_SERVICE_RESET = _UxGT("Återställ"); LSTR MSG_SERVICE_IN = _UxGT(" in:"); LSTR MSG_BACKLASH = _UxGT("Backlash"); diff --git a/Marlin/src/lcd/language/language_tr.h b/Marlin/src/lcd/language/language_tr.h index baebbe9d1e..b52ded8db8 100644 --- a/Marlin/src/lcd/language/language_tr.h +++ b/Marlin/src/lcd/language/language_tr.h @@ -787,7 +787,8 @@ namespace LanguageNarrow_tr { LSTR MSG_TMC_HYBRID_THRS = _UxGT("Hibrit Eşiği"); LSTR MSG_TMC_HOMING_THRS = _UxGT("Sensörsüz Sıfırlama"); LSTR MSG_TMC_STEPPING_MODE = _UxGT("Adım Modu"); - LSTR MSG_TMC_STEALTH_ENABLED = _UxGT("StealthChop Aktif"); + LSTR MSG_TMC_STEALTHCHOP = _UxGT("StealthChop"); + LSTR MSG_SERVICE_RESET = _UxGT("Resetle"); LSTR MSG_SERVICE_IN = _UxGT(" içinde:"); LSTR MSG_BACKLASH = _UxGT("Ters Tepki"); diff --git a/Marlin/src/lcd/language/language_uk.h b/Marlin/src/lcd/language/language_uk.h index 104d7f1ecf..c061b9ad02 100644 --- a/Marlin/src/lcd/language/language_uk.h +++ b/Marlin/src/lcd/language/language_uk.h @@ -663,7 +663,8 @@ namespace LanguageNarrow_uk { LSTR MSG_TMC_HYBRID_THRS = _UxGT("Гібридний поріг"); LSTR MSG_TMC_HOMING_THRS = _UxGT("Дім без кінцевиків"); LSTR MSG_TMC_STEPPING_MODE = _UxGT("Режим мікрокроку"); - LSTR MSG_TMC_STEALTH_ENABLED = _UxGT("Тихий режим увімк."); + LSTR MSG_TMC_STEALTHCHOP = _UxGT("Тихий режим увімк."); + LSTR MSG_SERVICE_RESET = _UxGT("Зкидання"); LSTR MSG_SERVICE_IN = _UxGT(" в:"); LSTR MSG_BACKLASH = _UxGT("Люфт"); diff --git a/Marlin/src/lcd/language/language_vi.h b/Marlin/src/lcd/language/language_vi.h index d1e98637b9..fb158e306b 100644 --- a/Marlin/src/lcd/language/language_vi.h +++ b/Marlin/src/lcd/language/language_vi.h @@ -436,7 +436,7 @@ namespace LanguageNarrow_vi { LSTR MSG_TMC_HYBRID_THRS = _UxGT("Ngưỡng Hỗn Hợp"); // Hybrid threshold LSTR MSG_TMC_HOMING_THRS = _UxGT("Vô cảm biến"); // Sensorless homing LSTR MSG_TMC_STEPPING_MODE = _UxGT("Chế độ từng bước"); // Stepping mode - LSTR MSG_TMC_STEALTH_ENABLED = _UxGT("CắtTàngHình được kích hoạt"); // StealthChop enabled + LSTR MSG_TMC_STEALTHCHOP = _UxGT("CắtTàngHình"); // StealthChop LSTR MSG_SHORT_DAY = _UxGT("n"); // d - ngày - One character only LSTR MSG_SHORT_HOUR = _UxGT("g"); // h - giờ - One character only diff --git a/Marlin/src/lcd/language/language_zh_CN.h b/Marlin/src/lcd/language/language_zh_CN.h index eb6a973205..680ff8c9b0 100644 --- a/Marlin/src/lcd/language/language_zh_CN.h +++ b/Marlin/src/lcd/language/language_zh_CN.h @@ -580,7 +580,8 @@ namespace LanguageNarrow_zh_CN { LSTR MSG_TMC_HYBRID_THRS = _UxGT("混合阈值"); LSTR MSG_TMC_HOMING_THRS = _UxGT("无感回零"); LSTR MSG_TMC_STEPPING_MODE = _UxGT("步进模式"); - LSTR MSG_TMC_STEALTH_ENABLED = _UxGT("StealthChop已使能"); + LSTR MSG_TMC_STEALTHCHOP = _UxGT("StealthChop已使能"); + LSTR MSG_SERVICE_RESET = _UxGT("复位"); LSTR MSG_SERVICE_IN = _UxGT(" 在:"); LSTR MSG_BACKLASH = _UxGT("回差"); diff --git a/Marlin/src/lcd/menu/menu_tmc.cpp b/Marlin/src/lcd/menu/menu_tmc.cpp index f73dd971df..2cf180ac97 100644 --- a/Marlin/src/lcd/menu/menu_tmc.cpp +++ b/Marlin/src/lcd/menu/menu_tmc.cpp @@ -116,7 +116,7 @@ void menu_tmc_current() { void menu_tmc_step_mode() { START_MENU(); - STATIC_ITEM(MSG_TMC_STEALTH_ENABLED); + STATIC_ITEM(MSG_TMC_STEALTHCHOP); BACK_ITEM(MSG_TMC_DRIVERS); TERN_( X_HAS_STEALTHCHOP, TMC_EDIT_STEP_MODE(X, STR_X)); TERN_(X2_HAS_STEALTHCHOP, TMC_EDIT_STEP_MODE(X2, STR_X2)); From 460bf112d8a52c67055c253569023178af8dd218 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Thu, 27 Mar 2025 03:33:27 -0500 Subject: [PATCH 152/787] =?UTF-8?q?=E2=9C=A8=20EDITABLE=5FHOMING=5FCURRENT?= =?UTF-8?q?=20(#27760)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/Configuration_adv.h | 2 + Marlin/src/core/language.h | 3 +- Marlin/src/feature/tmc_util.cpp | 4 + Marlin/src/feature/tmc_util.h | 26 ++++ Marlin/src/gcode/feature/trinamic/M906.cpp | 9 +- Marlin/src/gcode/feature/trinamic/M920.cpp | 144 +++++++++++++++++++++ Marlin/src/gcode/gcode.cpp | 7 +- Marlin/src/gcode/gcode.h | 5 + Marlin/src/lcd/language/language_en.h | 1 + Marlin/src/lcd/menu/menu_tmc.cpp | 34 ++++- Marlin/src/module/motion.cpp | 55 ++------ Marlin/src/module/settings.cpp | 51 ++++++++ buildroot/tests/STM32F103RC_btt | 5 +- ini/features.ini | 1 + 14 files changed, 291 insertions(+), 56 deletions(-) create mode 100644 Marlin/src/gcode/feature/trinamic/M920.cpp diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 7cc54b2a96..f24ece5986 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -2995,6 +2995,8 @@ #define HOLD_MULTIPLIER 0.5 // Scales down the holding current from run current + //#define EDITABLE_HOMING_CURRENT // Add a G-code and menu to modify the Homing Current + /** * Interpolate microsteps to 256 * Override for each driver with _INTERPOLATE settings below diff --git a/Marlin/src/core/language.h b/Marlin/src/core/language.h index dddc00dba8..3a50fcdc6b 100644 --- a/Marlin/src/core/language.h +++ b/Marlin/src/core/language.h @@ -312,8 +312,9 @@ #define STR_FILAMENT_RUNOUT_SENSOR "Filament runout sensor" #define STR_DRIVER_STEPPING_MODE "Driver stepping mode" #define STR_STEPPER_DRIVER_CURRENT "Stepper driver current" +#define STR_HOMING_CURRENT "Homing Current (mA)" #define STR_HYBRID_THRESHOLD "Hybrid Threshold" -#define STR_STALLGUARD_THRESHOLD "StallGuard threshold" +#define STR_STALLGUARD_THRESHOLD "StallGuard Threshold" #define STR_HOME_OFFSET "Home offset" #define STR_SOFT_ENDSTOPS "Soft endstops" #define STR_MATERIAL_HEATUP "Material heatup parameters" diff --git a/Marlin/src/feature/tmc_util.cpp b/Marlin/src/feature/tmc_util.cpp index 62972eb7f5..753cb003ff 100644 --- a/Marlin/src/feature/tmc_util.cpp +++ b/Marlin/src/feature/tmc_util.cpp @@ -43,6 +43,10 @@ #endif #endif +#if ENABLED(EDITABLE_HOMING_CURRENT) + homing_current_t homing_current_mA; +#endif + /** * Check for over temperature or short to ground error flags. * Report and log warning of overtemperature condition. diff --git a/Marlin/src/feature/tmc_util.h b/Marlin/src/feature/tmc_util.h index 27aae23f89..4cac2969a7 100644 --- a/Marlin/src/feature/tmc_util.h +++ b/Marlin/src/feature/tmc_util.h @@ -375,6 +375,32 @@ void test_tmc_connection(LOGICAL_AXIS_DECL_LC(const bool, true)); #endif // USE_SENSORLESS +#if HAS_HOMING_CURRENT + + // Axes that have a distinct homing current + struct homing_current_t { + OPTCODE(X_HAS_HOME_CURRENT, uint16_t X) + OPTCODE(Y_HAS_HOME_CURRENT, uint16_t Y) + OPTCODE(Z_HAS_HOME_CURRENT, uint16_t Z) + OPTCODE(X2_HAS_HOME_CURRENT, uint16_t X2) + OPTCODE(Y2_HAS_HOME_CURRENT, uint16_t Y2) + OPTCODE(Z2_HAS_HOME_CURRENT, uint16_t Z2) + OPTCODE(Z3_HAS_HOME_CURRENT, uint16_t Z3) + OPTCODE(Z4_HAS_HOME_CURRENT, uint16_t Z4) + OPTCODE(I_HAS_HOME_CURRENT, uint16_t I) + OPTCODE(J_HAS_HOME_CURRENT, uint16_t J) + OPTCODE(K_HAS_HOME_CURRENT, uint16_t K) + OPTCODE(U_HAS_HOME_CURRENT, uint16_t U) + OPTCODE(V_HAS_HOME_CURRENT, uint16_t V) + OPTCODE(W_HAS_HOME_CURRENT, uint16_t W) + }; + + #if ENABLED(EDITABLE_HOMING_CURRENT) + extern homing_current_t homing_current_mA; + #endif + +#endif // HAS_HOMING_CURRENT + #endif // HAS_TRINAMIC_CONFIG #if HAS_TMC_SPI diff --git a/Marlin/src/gcode/feature/trinamic/M906.cpp b/Marlin/src/gcode/feature/trinamic/M906.cpp index 43d980098e..74bbf9cae0 100644 --- a/Marlin/src/gcode/feature/trinamic/M906.cpp +++ b/Marlin/src/gcode/feature/trinamic/M906.cpp @@ -37,6 +37,8 @@ static void tmc_print_current(TMC &st) { /** * M906: Set motor current in milliamps. * + * With no parameters report driver currents. + * * Parameters: * X[current] - Set mA current for X driver(s) * Y[current] - Set mA current for Y driver(s) @@ -52,9 +54,14 @@ static void tmc_print_current(TMC &st) { * I[index] - Axis sub-index (Omit or 0 for X, Y, Z; 1 for X2, Y2, Z2; 2 for Z3; 3 for Z4.) * T[index] - Extruder index (Zero-based. Omit for E0 only.) * - * With no parameters report driver currents. + * With EDITABLE_HOMING_CURRENT: + * H - Set / Report Homing Current. Alias for M920. */ void GcodeSuite::M906() { + #if ENABLED(EDITABLE_HOMING_CURRENT) + if (parser.seen_test('H')) return M920(); + #endif + #define TMC_SAY_CURRENT(Q) tmc_print_current(stepper##Q) #define TMC_SET_CURRENT(Q) stepper##Q.rms_current(value) diff --git a/Marlin/src/gcode/feature/trinamic/M920.cpp b/Marlin/src/gcode/feature/trinamic/M920.cpp new file mode 100644 index 0000000000..2852f8bf44 --- /dev/null +++ b/Marlin/src/gcode/feature/trinamic/M920.cpp @@ -0,0 +1,144 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "../../../inc/MarlinConfigPre.h" + +#if ENABLED(EDITABLE_HOMING_CURRENT) + +#include "../../gcode.h" +#include "../../../feature/tmc_util.h" + +#if AXIS_COLLISION('I') + #define I_PARAM 'S' + #define I_PARAM_STR "S" + #warning "Use 'M920 S' instead of 'M920 I' for the stepper number." +#else + #define I_PARAM 'I' + #define I_PARAM_STR "I" +#endif + +/** + * M920: Set Homing Current for one or more axes + * + * Parameters: + * X[current] - Homing Current to use for X axis stepper(s) + * Y[current] - Homing Current to use for Y axis stepper(s) + * Z[current] - Homing Current to use for Z axis stepper(s) + * A[current] - Homing Current to use for A axis stepper(s) + * B[current] - Homing Current to use for B axis stepper(s) + * C[current] - Homing Current to use for C axis stepper(s) + * U[current] - Homing Current to use for U axis stepper(s) + * V[current] - Homing Current to use for V axis stepper(s) + * W[current] - Homing Current to use for W axis stepper(s) + * + * I - For multi-stepper axes, the zero-based index of the stepper to modify in each axis. + * If omitted all steppers of each axis will be set to the given axis current. + */ +void GcodeSuite::M920() { + bool report = true; + const uint8_t index = parser.byteval(I_PARAM); + LOOP_NUM_AXES(i) if (parser.seen(AXIS_CHAR(i))) { + const int16_t value = parser.value_int(); + report = false; + switch (i) { + #if X_HAS_HOME_CURRENT + case X_AXIS: + if (index < 1) homing_current_mA.X = value; + TERN_(X2_HAS_HOME_CURRENT, if (!index || index == 1) homing_current_mA.X2 = value); + break; + #endif + #if Y_HAS_HOME_CURRENT + case Y_AXIS: + if (index < 1) homing_current_mA.Y = value; + TERN_(Y2_HAS_HOME_CURRENT, if (!index || index == 1) homing_current_mA.Y2 = value); + break; + #endif + #if Z_HAS_HOME_CURRENT + case Z_AXIS: + if (index < 1) homing_current_mA.Z = value; + TERN_(Z2_HAS_HOME_CURRENT, if (!index || index == 1) homing_current_mA.Z2 = value); + TERN_(Z3_HAS_HOME_CURRENT, if (!index || index == 2) homing_current_mA.Z3 = value); + TERN_(Z4_HAS_HOME_CURRENT, if (!index || index == 3) homing_current_mA.Z4 = value); + break; + #endif + OPTCODE(I_HAS_HOME_CURRENT, case I_AXIS: homing_current_mA.I = value; break) + OPTCODE(J_HAS_HOME_CURRENT, case J_AXIS: homing_current_mA.J = value; break) + OPTCODE(K_HAS_HOME_CURRENT, case K_AXIS: homing_current_mA.K = value; break) + OPTCODE(U_HAS_HOME_CURRENT, case U_AXIS: homing_current_mA.U = value; break) + OPTCODE(V_HAS_HOME_CURRENT, case V_AXIS: homing_current_mA.V = value; break) + OPTCODE(W_HAS_HOME_CURRENT, case W_AXIS: homing_current_mA.W = value; break) + } + } + + if (report) M920_report(); +} + +void GcodeSuite::M920_report(const bool forReplay/*=true*/) { + TERN_(MARLIN_SMALL_BUILD, return); + + report_heading(forReplay, F(STR_HOMING_CURRENT)); + + auto say_M920 = [](const bool forReplay, int16_t index=-1) { + report_echo_start(forReplay); + SERIAL_ECHOPGM(" M920"); + if (index >= 0) SERIAL_ECHOPGM(" " I_PARAM_STR, index); + }; + + #if X_SENSORLESS || Y_SENSORLESS || Z_SENSORLESS + #if X2_SENSORLESS || Y2_SENSORLESS || Z2_SENSORLESS || Z3_SENSORLESS || Z4_SENSORLESS + say_M920(forReplay, 0); + #else + say_M920(forReplay); + #endif + TERN_(X_SENSORLESS, SERIAL_ECHOPGM_P(SP_X_STR, homing_current_mA.X)); + TERN_(Y_SENSORLESS, SERIAL_ECHOPGM_P(SP_Y_STR, homing_current_mA.Y)); + TERN_(Z_SENSORLESS, SERIAL_ECHOPGM_P(SP_Z_STR, homing_current_mA.Z)); + #if X2_SENSORLESS || Y2_SENSORLESS || Z2_SENSORLESS || Z3_SENSORLESS || Z4_SENSORLESS + say_M920(forReplay); + #endif + TERN_(I_SENSORLESS, SERIAL_ECHOPGM_P(SP_I_STR, homing_current_mA.I)); + TERN_(J_SENSORLESS, SERIAL_ECHOPGM_P(SP_J_STR, homing_current_mA.J)); + TERN_(K_SENSORLESS, SERIAL_ECHOPGM_P(SP_K_STR, homing_current_mA.K)); + TERN_(U_SENSORLESS, SERIAL_ECHOPGM_P(SP_U_STR, homing_current_mA.U)); + TERN_(V_SENSORLESS, SERIAL_ECHOPGM_P(SP_V_STR, homing_current_mA.V)); + TERN_(W_SENSORLESS, SERIAL_ECHOPGM_P(SP_W_STR, homing_current_mA.W)); + SERIAL_EOL(); + #endif + + #if X2_SENSORLESS || Y2_SENSORLESS || Z2_SENSORLESS + say_M920(forReplay, 1); + TERN_(X2_SENSORLESS, SERIAL_ECHOPGM_P(SP_X_STR, homing_current_mA.X2)); + TERN_(Y2_SENSORLESS, SERIAL_ECHOPGM_P(SP_Y_STR, homing_current_mA.Y2)); + TERN_(Z2_SENSORLESS, SERIAL_ECHOPGM_P(SP_Z_STR, homing_current_mA.Z2)); + SERIAL_EOL(); + #endif + #if Z3_SENSORLESS + say_M920(forReplay, 2); + SERIAL_ECHOLNPGM(" Z", homing_current_mA.Z3); + #endif + #if Z4_SENSORLESS + say_M920(forReplay, 3); + SERIAL_ECHOLNPGM(" Z", homing_current_mA.Z4); + #endif +} + +#endif // EDITABLE_HOMING_CURRENT diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp index 64326b32af..8a444053e6 100644 --- a/Marlin/src/gcode/gcode.cpp +++ b/Marlin/src/gcode/gcode.cpp @@ -1056,12 +1056,15 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) { case 912: M912(); break; // M912: Clear TMC2130 prewarn triggered flags #endif #if ENABLED(HYBRID_THRESHOLD) - case 913: M913(); break; // M913: Set HYBRID_THRESHOLD speed. + case 913: M913(); break; // M913: Set HYBRID_THRESHOLD speed #endif #if USE_SENSORLESS - case 914: M914(); break; // M914: Set StallGuard sensitivity. + case 914: M914(); break; // M914: Set StallGuard sensitivity #endif case 919: M919(); break; // M919: Set stepper Chopper Times + #if ENABLED(EDITABLE_HOMING_CURRENT) + case 920: M920(); break; // M920: Set Homing Current + #endif #endif #if HAS_MICROSTEPS diff --git a/Marlin/src/gcode/gcode.h b/Marlin/src/gcode/gcode.h index 7ba1c58d2a..1d39dc3a6b 100644 --- a/Marlin/src/gcode/gcode.h +++ b/Marlin/src/gcode/gcode.h @@ -320,6 +320,7 @@ * M914 - Set StallGuard sensitivity. (Requires SENSORLESS_HOMING or SENSORLESS_PROBING) * M919 - Set or Report motor Chopper Times (time_off, hysteresis_end, hysteresis_start) using axis codes XYZE, etc. * If no parameters are given, report. (Requires *_DRIVER_TYPE TMC(2130|2160|5130|5160|2208|2209|2660)) + * M920 - Set Homing Current. (Requires distinct *_CURRENT_HOME settings) * M936 - OTA update firmware. (Requires OTA_FIRMWARE_UPDATE) * M951 - Set Magnetic Parking Extruder parameters. (Requires MAGNETIC_PARKING_EXTRUDER) * M3426 - Read MCP3426 ADC over I2C. (Requires HAS_MCP3426_ADC) @@ -1259,6 +1260,10 @@ private: static void M914_report(const bool forReplay=true); #endif static void M919(); + #if ENABLED(EDITABLE_HOMING_CURRENT) + static void M920(); + static void M920_report(const bool forReplay=true); + #endif #endif #if HAS_MOTOR_CURRENT_SPI || HAS_MOTOR_CURRENT_PWM || HAS_MOTOR_CURRENT_I2C || HAS_MOTOR_CURRENT_DAC diff --git a/Marlin/src/lcd/language/language_en.h b/Marlin/src/lcd/language/language_en.h index ca2e50d063..571f85e8ce 100644 --- a/Marlin/src/lcd/language/language_en.h +++ b/Marlin/src/lcd/language/language_en.h @@ -883,6 +883,7 @@ namespace LanguageNarrow_en { LSTR MSG_TMC_HOMING_THRS = _UxGT("Sensorless Homing"); LSTR MSG_TMC_STEPPING_MODE = _UxGT("Stepping Mode"); LSTR MSG_TMC_STEALTHCHOP = _UxGT("StealthChop"); + LSTR MSG_TMC_HOMING_CURRENT = _UxGT("Homing Current"); LSTR MSG_SERVICE_RESET = _UxGT("Reset"); LSTR MSG_SERVICE_IN = _UxGT(" in:"); diff --git a/Marlin/src/lcd/menu/menu_tmc.cpp b/Marlin/src/lcd/menu/menu_tmc.cpp index 2cf180ac97..2ddb38f3a4 100644 --- a/Marlin/src/lcd/menu/menu_tmc.cpp +++ b/Marlin/src/lcd/menu/menu_tmc.cpp @@ -110,6 +110,33 @@ void menu_tmc_current() { #endif // SENSORLESS_HOMING +#if ENABLED(EDITABLE_HOMING_CURRENT) + + #define TMC_EDIT_HOMING_CURRENT(ST, STR) EDIT_ITEM_FAST_F(uint16_4, F(STR), &homing_current_mA.ST, ST##_CURRENT / 3, ST##_CURRENT) + + void menu_tmc_homing_current() { + START_MENU(); + STATIC_ITEM(MSG_TMC_HOMING_CURRENT); + BACK_ITEM(MSG_TMC_DRIVERS); + TERN_( X_HAS_HOME_CURRENT, TMC_EDIT_HOMING_CURRENT(X, STR_X)); + TERN_(X2_HAS_HOME_CURRENT, TMC_EDIT_HOMING_CURRENT(X2, STR_X2)); + TERN_( Y_HAS_HOME_CURRENT, TMC_EDIT_HOMING_CURRENT(Y, STR_Y)); + TERN_(Y2_HAS_HOME_CURRENT, TMC_EDIT_HOMING_CURRENT(Y2, STR_Y2)); + TERN_( Z_HAS_HOME_CURRENT, TMC_EDIT_HOMING_CURRENT(Z, STR_Z)); + TERN_(Z2_HAS_HOME_CURRENT, TMC_EDIT_HOMING_CURRENT(Z2, STR_Z2)); + TERN_(Z3_HAS_HOME_CURRENT, TMC_EDIT_HOMING_CURRENT(Z3, STR_Z3)); + TERN_(Z4_HAS_HOME_CURRENT, TMC_EDIT_HOMING_CURRENT(Z4, STR_Z4)); + TERN_( I_HAS_HOME_CURRENT, TMC_EDIT_HOMING_CURRENT(I, STR_I)); + TERN_( J_HAS_HOME_CURRENT, TMC_EDIT_HOMING_CURRENT(J, STR_J)); + TERN_( K_HAS_HOME_CURRENT, TMC_EDIT_HOMING_CURRENT(K, STR_K)); + TERN_( U_HAS_HOME_CURRENT, TMC_EDIT_HOMING_CURRENT(U, STR_U)); + TERN_( V_HAS_HOME_CURRENT, TMC_EDIT_HOMING_CURRENT(V, STR_V)); + TERN_( W_HAS_HOME_CURRENT, TMC_EDIT_HOMING_CURRENT(W, STR_W)); + END_MENU(); + } + +#endif // EDITABLE_HOMING_CURRENT + #if HAS_STEALTHCHOP #define TMC_EDIT_STEP_MODE(ST, STR) EDIT_ITEM_F(bool, F(STR), &stepper##ST.stored.stealthChop_enabled, []{ stepper##ST.refresh_stepping_mode(); }) @@ -143,9 +170,10 @@ void menu_tmc() { START_MENU(); BACK_ITEM(MSG_ADVANCED_SETTINGS); SUBMENU(MSG_TMC_CURRENT, menu_tmc_current); - TERN_(HYBRID_THRESHOLD, SUBMENU(MSG_TMC_HYBRID_THRS, menu_tmc_hybrid_thrs)); - TERN_(SENSORLESS_HOMING, SUBMENU(MSG_TMC_HOMING_THRS, menu_tmc_homing_thrs)); - TERN_(HAS_STEALTHCHOP, SUBMENU(MSG_TMC_STEPPING_MODE, menu_tmc_step_mode)); + TERN_(HYBRID_THRESHOLD, SUBMENU(MSG_TMC_HYBRID_THRS, menu_tmc_hybrid_thrs)); + TERN_(SENSORLESS_HOMING, SUBMENU(MSG_TMC_HOMING_THRS, menu_tmc_homing_thrs)); + TERN_(EDITABLE_HOMING_CURRENT, SUBMENU(MSG_TMC_HOMING_CURRENT, menu_tmc_homing_current)); + TERN_(HAS_STEALTHCHOP, SUBMENU(MSG_TMC_STEALTHCHOP, menu_tmc_step_mode)); END_MENU(); } diff --git a/Marlin/src/module/motion.cpp b/Marlin/src/module/motion.cpp index 386d46665d..fcaaf613e4 100644 --- a/Marlin/src/module/motion.cpp +++ b/Marlin/src/module/motion.cpp @@ -271,48 +271,7 @@ void report_current_position_projected() { #define debug_current(...) #endif - #if HAS_CURRENT_HOME_X - int16_t saved_current_X; - #endif - #if HAS_CURRENT_HOME_Y - int16_t saved_current_Y; - #endif - #if HAS_CURRENT_HOME_Z - int16_t saved_current_Z; - #endif - #if HAS_CURRENT_HOME_X2 - int16_t saved_current_X2; - #endif - #if HAS_CURRENT_HOME_Y2 - int16_t saved_current_Y2; - #endif - #if HAS_CURRENT_HOME_Z2 - int16_t saved_current_Z2; - #endif - #if HAS_CURRENT_HOME_Z3 - int16_t saved_current_Z3; - #endif - #if HAS_CURRENT_HOME_Z4 - int16_t saved_current_Z4; - #endif - #if HAS_CURRENT_HOME_I - int16_t saved_current_I; - #endif - #if HAS_CURRENT_HOME_J - int16_t saved_current_J; - #endif - #if HAS_CURRENT_HOME_K - int16_t saved_current_K; - #endif - #if HAS_CURRENT_HOME_U - int16_t saved_current_U; - #endif - #if HAS_CURRENT_HOME_V - int16_t saved_current_V; - #endif - #if HAS_CURRENT_HOME_W - int16_t saved_current_W; - #endif + homing_current_t saved_current_mA; /** * Set motors to their homing / probing currents. @@ -320,11 +279,13 @@ void report_current_position_projected() { */ void set_homing_current(const AxisEnum axis) { + #define HOMING_CURRENT(A) TERN(EDITABLE_HOMING_CURRENT, homing_current_mA.A, A##_CURRENT_HOME) + // Saves the running current of the motor at the moment the function is called and sets current to CURRENT_HOME #define _SAVE_SET_CURRENT(A) \ - saved_current_##A = stepper##A.getMilliamps(); \ - stepper##A.rms_current(A##_CURRENT_HOME); \ - debug_current(F(STR_##A), saved_current_##A, A##_CURRENT_HOME) + saved_current_mA.A = stepper##A.getMilliamps(); \ + stepper##A.rms_current(HOMING_CURRENT(A)); \ + debug_current(F(STR_##A), saved_current_mA.A, HOMING_CURRENT(A)) #define _MAP_SAVE_SET(A) OPTCODE(A##_HAS_HOME_CURRENT, _SAVE_SET_CURRENT(A)) @@ -478,8 +439,8 @@ void report_current_position_projected() { // Restore the saved current #define _RESTORE_CURRENT(A) \ - stepper##A.rms_current(saved_current_##A); \ - debug_current(F(STR_##A), A##_CURRENT_HOME, saved_current_##A) + stepper##A.rms_current(saved_current_mA.A); \ + debug_current(F(STR_##A), HOMING_CURRENT(A), saved_current_mA.A) #define _MAP_RESTORE(A) OPTCODE(A##_HAS_HOME_CURRENT, _RESTORE_CURRENT(A)) diff --git a/Marlin/src/module/settings.cpp b/Marlin/src/module/settings.cpp index a7e791951b..c2b4e3da38 100644 --- a/Marlin/src/module/settings.cpp +++ b/Marlin/src/module/settings.cpp @@ -469,6 +469,13 @@ typedef struct SettingsDataStruct { xyz_feedrate_t homing_feedrate_mm_m; // M210 X Y Z I J K U V W #endif + // + // TMC Homing Current + // + #if ENABLED(EDITABLE_HOMING_CURRENT) + homing_current_t homing_current_mA; // M920 X Y Z... + #endif + // // !NO_VOLUMETRIC // @@ -1355,6 +1362,14 @@ void MarlinSettings::postprocess() { EEPROM_WRITE(homing_feedrate_mm_m); #endif + // + // TMC Homing Current + // + #if ENABLED(EDITABLE_HOMING_CURRENT) + _FIELD_TEST(homing_current_mA); + EEPROM_WRITE(homing_current_mA); + #endif + // // Volumetric & Filament Size // @@ -2414,6 +2429,14 @@ void MarlinSettings::postprocess() { EEPROM_READ(homing_feedrate_mm_m); #endif + // + // TMC Homing Current + // + #if ENABLED(EDITABLE_HOMING_CURRENT) + _FIELD_TEST(homing_current_mA); + EEPROM_READ(homing_current_mA); + #endif + // // Volumetric & Filament Size // @@ -3626,6 +3649,29 @@ void MarlinSettings::reset() { // TERN_(EDITABLE_HOMING_FEEDRATE, homing_feedrate_mm_m = xyz_feedrate_t(HOMING_FEEDRATE_MM_M)); + // + // TMC Homing Current + // + #if ENABLED(EDITABLE_HOMING_CURRENT) + homing_current_t base_homing_current_mA = { + OPTITEM(X_HAS_HOME_CURRENT, X_CURRENT_HOME) + OPTITEM(Y_HAS_HOME_CURRENT, Y_CURRENT_HOME) + OPTITEM(Z_HAS_HOME_CURRENT, Z_CURRENT_HOME) + OPTITEM(X2_HAS_HOME_CURRENT, X2_CURRENT_HOME) + OPTITEM(Y2_HAS_HOME_CURRENT, Y2_CURRENT_HOME) + OPTITEM(Z2_HAS_HOME_CURRENT, Z2_CURRENT_HOME) + OPTITEM(Z3_HAS_HOME_CURRENT, Z3_CURRENT_HOME) + OPTITEM(Z4_HAS_HOME_CURRENT, Z4_CURRENT_HOME) + OPTITEM(I_HAS_HOME_CURRENT, I_CURRENT_HOME) + OPTITEM(J_HAS_HOME_CURRENT, J_CURRENT_HOME) + OPTITEM(K_HAS_HOME_CURRENT, K_CURRENT_HOME) + OPTITEM(U_HAS_HOME_CURRENT, U_CURRENT_HOME) + OPTITEM(V_HAS_HOME_CURRENT, V_CURRENT_HOME) + OPTITEM(W_HAS_HOME_CURRENT, W_CURRENT_HOME) + }; + homing_current_mA = base_homing_current_mA; + #endif + // // Volumetric & Filament Size // @@ -4058,6 +4104,11 @@ void MarlinSettings::reset() { TERN_(USE_SENSORLESS, gcode.M914_report(forReplay)); #endif + // + // TMC Homing Current + // + TERN_(EDITABLE_HOMING_CURRENT, gcode.M920_report(forReplay)); + // // TMC stepping mode // diff --git a/buildroot/tests/STM32F103RC_btt b/buildroot/tests/STM32F103RC_btt index 178170455f..2b05d42922 100755 --- a/buildroot/tests/STM32F103RC_btt +++ b/buildroot/tests/STM32F103RC_btt @@ -11,8 +11,9 @@ set -e # restore_configs opt_set MOTHERBOARD BOARD_BTT_SKR_MINI_E3_V1_0 SERIAL_PORT 1 SERIAL_PORT_2 -1 \ - X_DRIVER_TYPE TMC2209 Y_DRIVER_TYPE TMC2209 Z_DRIVER_TYPE TMC2209 E0_DRIVER_TYPE TMC2209 -opt_enable CR10_STOCKDISPLAY PINS_DEBUGGING Z_IDLE_HEIGHT \ + X_DRIVER_TYPE TMC2209 Y_DRIVER_TYPE TMC2209 Z_DRIVER_TYPE TMC2209 E0_DRIVER_TYPE TMC2209 \ + X_CURRENT_HOME X_CURRENT/2 Y_CURRENT_HOME Y_CURRENT/2 Z_CURRENT_HOME Y_CURRENT/2 +opt_enable CR10_STOCKDISPLAY PINS_DEBUGGING Z_IDLE_HEIGHT EDITABLE_HOMING_CURRENT \ FT_MOTION FT_MOTION_MENU BIQU_MICROPROBE_V1 PROBE_ENABLE_DISABLE Z_SAFE_HOMING AUTO_BED_LEVELING_BILINEAR \ ADAPTIVE_STEP_SMOOTHING NONLINEAR_EXTRUSION exec_test $1 $2 "BigTreeTech SKR Mini E3 1.0 - TMC2209 HW Serial, FT_MOTION" "$3" diff --git a/ini/features.ini b/ini/features.ini index f56175a3d6..1cff1a61f4 100644 --- a/ini/features.ini +++ b/ini/features.ini @@ -23,6 +23,7 @@ MKS_WIFI_MODULE = QRCode=https://github.com/makerbase-mks HAS_TRINAMIC_CONFIG = TMCStepper=https://github.com/MarlinFirmware/TMCStepper/archive/marlin-2.1.3.x.zip build_src_filter=+ + + + + HAS_T(RINAMIC_CONFIG|MC_SPI) = build_src_filter=+ +EDITABLE_HOMING_CURRENT = build_src_filter=+ SR_LCD_3W_NL = SailfishLCD=https://github.com/mikeshub/SailfishLCD/archive/6f53c19a8a.zip HAS_MOTOR_CURRENT_(I2C|DAC|SPI|PWM) = build_src_filter=+ HAS_MOTOR_CURRENT_I2C = SlowSoftI2CMaster From 5c59abaf6f273be325d92d79ae63e393e8c6038a Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Thu, 27 Mar 2025 12:11:04 +0000 Subject: [PATCH 153/787] [cron] Bump distribution date (2025-03-27) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 18f9ce19e8..c24e090c3d 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-03-26" +//#define STRING_DISTRIBUTION_DATE "2025-03-27" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 0d24f4c508..690de1c353 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-03-26" + #define STRING_DISTRIBUTION_DATE "2025-03-27" #endif /** From 9a8ad9d1013e7273ee7ef679ddf212f537c4708e Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Thu, 27 Mar 2025 17:34:33 -0500 Subject: [PATCH 154/787] =?UTF-8?q?=F0=9F=8E=A8=20Comment=20long=20functio?= =?UTF-8?q?ns=20end?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/HAL/RP2040/pinsDebug.h | 2 +- Marlin/src/MarlinCore.cpp | 10 +++++----- Marlin/src/module/probe.cpp | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Marlin/src/HAL/RP2040/pinsDebug.h b/Marlin/src/HAL/RP2040/pinsDebug.h index 964fb71086..f3842c4aff 100644 --- a/Marlin/src/HAL/RP2040/pinsDebug.h +++ b/Marlin/src/HAL/RP2040/pinsDebug.h @@ -107,7 +107,7 @@ uint8_t get_pin_mode(const pin_t Ard_num) { uint dir = gpio_get_dir( Ard_num); - if(dir) return MODE_PIN_OUTPUT; + if (dir) return MODE_PIN_OUTPUT; else return MODE_PIN_INPUT; } diff --git a/Marlin/src/MarlinCore.cpp b/Marlin/src/MarlinCore.cpp index 689f71f8e5..3c44a9b71f 100644 --- a/Marlin/src/MarlinCore.cpp +++ b/Marlin/src/MarlinCore.cpp @@ -736,7 +736,7 @@ inline void manage_inactivity(const bool no_stepper_sleep=false) { WRITE(FET_SAFETY_PIN, FET_SAFETY_INVERTED); } #endif -} +} // manage_inactivity() #if ALL(EP_BABYSTEPPING, EMERGENCY_PARSER) #include "feature/babystep.h" @@ -890,7 +890,7 @@ void idle(const bool no_stepper_sleep/*=false*/) { TERN_(MARLIN_DEV_MODE, idle_depth--); return; -} +} // idle() /** * Kill all activity and lock the machine. @@ -983,7 +983,7 @@ void stop() { safe_delay(350); // allow enough time for messages to get out before stopping marlin_state = MarlinState::MF_STOPPED; } -} +} // stop() inline void tmc_standby_setup() { #if PIN_EXISTS(X_STDBY) @@ -1052,7 +1052,7 @@ inline void tmc_standby_setup() { #if PIN_EXISTS(E7_STDBY) SET_INPUT_PULLDOWN(E7_STDBY_PIN); #endif -} +} // tmc_standby_setup() /** * Marlin Firmware entry-point. Abandon Hope All Ye Who Enter Here. @@ -1702,7 +1702,7 @@ void setup() { SETUP_LOG("setup() completed."); TERN_(MARLIN_TEST_BUILD, runStartupTests()); -} +} // setup() /** * The main Marlin program loop diff --git a/Marlin/src/module/probe.cpp b/Marlin/src/module/probe.cpp index e121bca812..4f7d7c7690 100644 --- a/Marlin/src/module/probe.cpp +++ b/Marlin/src/module/probe.cpp @@ -275,7 +275,7 @@ xyz_pos_t Probe::offset; // Initialized by settings.load #ifdef MAG_MOUNTED_PRE_DEPLOY constexpr mag_probe_move_t pre_deploy = MAG_MOUNTED_PRE_DEPLOY; do_blocking_move_to(pre_deploy.where, MMM_TO_MMS(pre_deploy.fr_mm_min)); - #endif + #endif #if HAS_MAG_MOUNTED_SERVO_PROBE servo[MAG_MOUNTED_PROBE_SERVO_NR].move(servo_angles[MAG_MOUNTED_PROBE_SERVO_NR][0]); #endif From b5068bbc17ed395103564f302aa0cbdde8c004c1 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Thu, 27 Mar 2025 17:36:16 -0500 Subject: [PATCH 155/787] =?UTF-8?q?=F0=9F=94=A8=20Reduce=20warnings=20on?= =?UTF-8?q?=20types?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/core/types.h | 77 ++++++++++++++++++++++----------------- Marlin/src/core/utility.h | 11 ------ 2 files changed, 44 insertions(+), 44 deletions(-) diff --git a/Marlin/src/core/types.h b/Marlin/src/core/types.h index 68adadc95d..395dc430f5 100644 --- a/Marlin/src/core/types.h +++ b/Marlin/src/core/types.h @@ -566,11 +566,11 @@ struct XYval { FI XYval& operator= (const XYZEval &rs) { set(XY_LIST(rs.x, rs.y)); return *this; } // Override other operators to get intuitive behaviors - #define XY_OP(OP) { x TERN_(HAS_X_AXIS, OP rs.x), y TERN_(HAS_Y_AXIS, OP rs.y) } - FI constexpr XYval operator+ (const XYval &rs) const { return { x + rs.x, y + rs.y }; } - FI constexpr XYval operator- (const XYval &rs) const { return { x - rs.x, y - rs.y }; } - FI constexpr XYval operator* (const XYval &rs) const { return { x * rs.x, y * rs.y }; } - FI constexpr XYval operator/ (const XYval &rs) const { return { x / rs.x, y / rs.y }; } + #define XY_OP(OP) { T(x TERN_(HAS_X_AXIS, OP rs.x)), T(y TERN_(HAS_Y_AXIS, OP rs.y)) } + FI constexpr XYval operator+ (const XYval &rs) const { return { T(x + rs.x), T(y + rs.y) }; } + FI constexpr XYval operator- (const XYval &rs) const { return { T(x - rs.x), T(y - rs.y) }; } + FI constexpr XYval operator* (const XYval &rs) const { return { T(x * rs.x), T(y * rs.y) }; } + FI constexpr XYval operator/ (const XYval &rs) const { return { T(x / rs.x), T(y / rs.y) }; } FI constexpr XYval operator+ (const XYZval &rs) const { return { XY_OP(+) }; } FI constexpr XYval operator- (const XYZval &rs) const { return { XY_OP(-) }; } FI constexpr XYval operator* (const XYZval &rs) const { return { XY_OP(*) }; } @@ -721,21 +721,21 @@ struct XYZval { FI XYZval& operator= (const XYZEval &rs) { set(NUM_AXIS_ELEM_LC(rs)); return *this; } // Override other operators to get intuitive behaviors - FI constexpr XYZval operator+ (const XYval &rs) const { return NUM_AXIS_ARRAY(x + rs.x, y + rs.y, z, i, j, k, u, v, w ); } - FI constexpr XYZval operator- (const XYval &rs) const { return NUM_AXIS_ARRAY(x - rs.x, y - rs.y, z, i, j, k, u, v, w ); } - FI constexpr XYZval operator* (const XYval &rs) const { return NUM_AXIS_ARRAY(x * rs.x, y * rs.y, z, i, j, k, u, v, w ); } - FI constexpr XYZval operator/ (const XYval &rs) const { return NUM_AXIS_ARRAY(x / rs.x, y / rs.y, z, i, j, k, u, v, w ); } - FI constexpr XYZval operator+ (const XYZval &rs) const { return NUM_AXIS_ARRAY(x + rs.x, y + rs.y, z + rs.z, i + rs.i, j + rs.j, k + rs.k, u + rs.u, v + rs.v, w + rs.w ); } - FI constexpr XYZval operator- (const XYZval &rs) const { return NUM_AXIS_ARRAY(x - rs.x, y - rs.y, z - rs.z, i - rs.i, j - rs.j, k - rs.k, u - rs.u, v - rs.v, w - rs.w ); } - FI constexpr XYZval operator* (const XYZval &rs) const { return NUM_AXIS_ARRAY(x * rs.x, y * rs.y, z * rs.z, i * rs.i, j * rs.j, k * rs.k, u * rs.u, v * rs.v, w * rs.w ); } - FI constexpr XYZval operator/ (const XYZval &rs) const { return NUM_AXIS_ARRAY(x / rs.x, y / rs.y, z / rs.z, i / rs.i, j / rs.j, k / rs.k, u / rs.u, v / rs.v, w / rs.w ); } - FI constexpr XYZval operator+ (const XYZEval &rs) const { return NUM_AXIS_ARRAY(x + rs.x, y + rs.y, z + rs.z, i + rs.i, j + rs.j, k + rs.k, u + rs.u, v + rs.v, w + rs.w ); } - FI constexpr XYZval operator- (const XYZEval &rs) const { return NUM_AXIS_ARRAY(x - rs.x, y - rs.y, z - rs.z, i - rs.i, j - rs.j, k - rs.k, u - rs.u, v - rs.v, w - rs.w ); } - FI constexpr XYZval operator* (const XYZEval &rs) const { return NUM_AXIS_ARRAY(x * rs.x, y * rs.y, z * rs.z, i * rs.i, j * rs.j, k * rs.k, u * rs.u, v * rs.v, w * rs.w ); } - FI constexpr XYZval operator/ (const XYZEval &rs) const { return NUM_AXIS_ARRAY(x / rs.x, y / rs.y, z / rs.z, i / rs.i, j / rs.j, k / rs.k, u / rs.u, v / rs.v, w / rs.w ); } - FI constexpr XYZval operator* (const float &p) const { return NUM_AXIS_ARRAY((T)(x * p), (T)(y * p), (T)(z * p), (T)(i * p), (T)(j * p), (T)(k * p), (T)(u * p), (T)(v * p), (T)(w * p)); } + FI constexpr XYZval operator+ (const XYval &rs) const { return NUM_AXIS_ARRAY(T(x + rs.x), T(y + rs.y), z, i, j, k, u, v, w ); } + FI constexpr XYZval operator- (const XYval &rs) const { return NUM_AXIS_ARRAY(T(x - rs.x), T(y - rs.y), z, i, j, k, u, v, w ); } + FI constexpr XYZval operator* (const XYval &rs) const { return NUM_AXIS_ARRAY(T(x * rs.x), T(y * rs.y), z, i, j, k, u, v, w ); } + FI constexpr XYZval operator/ (const XYval &rs) const { return NUM_AXIS_ARRAY(T(x / rs.x), T(y / rs.y), z, i, j, k, u, v, w ); } + FI constexpr XYZval operator+ (const XYZval &rs) const { return NUM_AXIS_ARRAY(T(x + rs.x), T(y + rs.y), T(z + rs.z), T(i + rs.i), T(j + rs.j), T(k + rs.k), T(u + rs.u), T(v + rs.v), T(w + rs.w) ); } + FI constexpr XYZval operator- (const XYZval &rs) const { return NUM_AXIS_ARRAY(T(x - rs.x), T(y - rs.y), T(z - rs.z), T(i - rs.i), T(j - rs.j), T(k - rs.k), T(u - rs.u), T(v - rs.v), T(w - rs.w) ); } + FI constexpr XYZval operator* (const XYZval &rs) const { return NUM_AXIS_ARRAY(T(x * rs.x), T(y * rs.y), T(z * rs.z), T(i * rs.i), T(j * rs.j), T(k * rs.k), T(u * rs.u), T(v * rs.v), T(w * rs.w) ); } + FI constexpr XYZval operator/ (const XYZval &rs) const { return NUM_AXIS_ARRAY(T(x / rs.x), T(y / rs.y), T(z / rs.z), T(i / rs.i), T(j / rs.j), T(k / rs.k), T(u / rs.u), T(v / rs.v), T(w / rs.w) ); } + FI constexpr XYZval operator+ (const XYZEval &rs) const { return NUM_AXIS_ARRAY(T(x + rs.x), T(y + rs.y), T(z + rs.z), T(i + rs.i), T(j + rs.j), T(k + rs.k), T(u + rs.u), T(v + rs.v), T(w + rs.w) ); } + FI constexpr XYZval operator- (const XYZEval &rs) const { return NUM_AXIS_ARRAY(T(x - rs.x), T(y - rs.y), T(z - rs.z), T(i - rs.i), T(j - rs.j), T(k - rs.k), T(u - rs.u), T(v - rs.v), T(w - rs.w) ); } + FI constexpr XYZval operator* (const XYZEval &rs) const { return NUM_AXIS_ARRAY(T(x * rs.x), T(y * rs.y), T(z * rs.z), T(i * rs.i), T(j * rs.j), T(k * rs.k), T(u * rs.u), T(v * rs.v), T(w * rs.w) ); } + FI constexpr XYZval operator/ (const XYZEval &rs) const { return NUM_AXIS_ARRAY(T(x / rs.x), T(y / rs.y), T(z / rs.z), T(i / rs.i), T(j / rs.j), T(k / rs.k), T(u / rs.u), T(v / rs.v), T(w / rs.w) ); } + FI constexpr XYZval operator* (const float &p) const { return NUM_AXIS_ARRAY(T(x * p), T(y * p), T(z * p), T(i * p), T(j * p), T(k * p), T(u * p), T(v * p), T(w * p)); } FI constexpr XYZval operator* (const int &p) const { return NUM_AXIS_ARRAY(x * p, y * p, z * p, i * p, j * p, k * p, u * p, v * p, w * p); } - FI constexpr XYZval operator/ (const float &p) const { return NUM_AXIS_ARRAY((T)(x / p), (T)(y / p), (T)(z / p), (T)(i / p), (T)(j / p), (T)(k / p), (T)(u / p), (T)(v / p), (T)(w / p)); } + FI constexpr XYZval operator/ (const float &p) const { return NUM_AXIS_ARRAY(T(x / p), T(y / p), T(z / p), T(i / p), T(j / p), T(k / p), T(u / p), T(v / p), T(w / p)); } FI constexpr XYZval operator/ (const int &p) const { return NUM_AXIS_ARRAY(x / p, y / p, z / p, i / p, j / p, k / p, u / p, v / p, w / p); } FI constexpr XYZval operator>>(const int &p) const { return NUM_AXIS_ARRAY(_RS(x), _RS(y), _RS(z), _RS(i), _RS(j), _RS(k), _RS(u), _RS(v), _RS(w)); } FI constexpr XYZval operator<<(const int &p) const { return NUM_AXIS_ARRAY(_LS(x), _LS(y), _LS(z), _LS(i), _LS(j), _LS(k), _LS(u), _LS(v), _LS(w)); } @@ -870,21 +870,21 @@ struct XYZEval { FI XYZEval& operator= (const XYZval &rs) { set(NUM_AXIS_ELEM_LC(rs)); return *this; } // Override other operators to get intuitive behaviors - FI constexpr XYZEval operator+ (const XYval &rs) const { return LOGICAL_AXIS_ARRAY(e, x + rs.x, y + rs.y, z, i, j, k, u, v, w); } - FI constexpr XYZEval operator- (const XYval &rs) const { return LOGICAL_AXIS_ARRAY(e, x - rs.x, y - rs.y, z, i, j, k, u, v, w); } - FI constexpr XYZEval operator* (const XYval &rs) const { return LOGICAL_AXIS_ARRAY(e, x * rs.x, y * rs.y, z, i, j, k, u, v, w); } - FI constexpr XYZEval operator/ (const XYval &rs) const { return LOGICAL_AXIS_ARRAY(e, x / rs.x, y / rs.y, z, i, j, k, u, v, w); } - FI constexpr XYZEval operator+ (const XYZval &rs) const { return LOGICAL_AXIS_ARRAY(e, x + rs.x, y + rs.y, z + rs.z, i + rs.i, j + rs.j, k + rs.k, u + rs.u, v + rs.v, w + rs.w); } - FI constexpr XYZEval operator- (const XYZval &rs) const { return LOGICAL_AXIS_ARRAY(e, x - rs.x, y - rs.y, z - rs.z, i - rs.i, j - rs.j, k - rs.k, u - rs.u, v - rs.v, w - rs.w); } - FI constexpr XYZEval operator* (const XYZval &rs) const { return LOGICAL_AXIS_ARRAY(e, x * rs.x, y * rs.y, z * rs.z, i * rs.i, j * rs.j, k * rs.k, u * rs.u, v * rs.v, w * rs.w); } - FI constexpr XYZEval operator/ (const XYZval &rs) const { return LOGICAL_AXIS_ARRAY(e, x / rs.x, y / rs.y, z / rs.z, i / rs.i, j / rs.j, k / rs.k, u / rs.u, v / rs.v, w / rs.w); } - FI constexpr XYZEval operator+ (const XYZEval &rs) const { return LOGICAL_AXIS_ARRAY(e + rs.e, x + rs.x, y + rs.y, z + rs.z, i + rs.i, j + rs.j, k + rs.k, u + rs.u, v + rs.v, w + rs.w); } - FI constexpr XYZEval operator- (const XYZEval &rs) const { return LOGICAL_AXIS_ARRAY(e - rs.e, x - rs.x, y - rs.y, z - rs.z, i - rs.i, j - rs.j, k - rs.k, u - rs.u, v - rs.v, w - rs.w); } - FI constexpr XYZEval operator* (const XYZEval &rs) const { return LOGICAL_AXIS_ARRAY(e * rs.e, x * rs.x, y * rs.y, z * rs.z, i * rs.i, j * rs.j, k * rs.k, u * rs.u, v * rs.v, w * rs.w); } - FI constexpr XYZEval operator/ (const XYZEval &rs) const { return LOGICAL_AXIS_ARRAY(e / rs.e, x / rs.x, y / rs.y, z / rs.z, i / rs.i, j / rs.j, k / rs.k, u / rs.u, v / rs.v, w / rs.w); } - FI constexpr XYZEval operator* (const float &p) const { return LOGICAL_AXIS_ARRAY((T)(e * p), (T)(x * p), (T)(y * p), (T)(z * p), (T)(i * p), (T)(j * p), (T)(k * p), (T)(u * p), (T)(v * p), (T)(w * p)); } + FI constexpr XYZEval operator+ (const XYval &rs) const { return LOGICAL_AXIS_ARRAY(e, T(x + rs.x), T(y + rs.y), z, i, j, k, u, v, w); } + FI constexpr XYZEval operator- (const XYval &rs) const { return LOGICAL_AXIS_ARRAY(e, T(x - rs.x), T(y - rs.y), z, i, j, k, u, v, w); } + FI constexpr XYZEval operator* (const XYval &rs) const { return LOGICAL_AXIS_ARRAY(e, T(x * rs.x), T(y * rs.y), z, i, j, k, u, v, w); } + FI constexpr XYZEval operator/ (const XYval &rs) const { return LOGICAL_AXIS_ARRAY(e, T(x / rs.x), T(y / rs.y), z, i, j, k, u, v, w); } + FI constexpr XYZEval operator+ (const XYZval &rs) const { return LOGICAL_AXIS_ARRAY(e, T(x + rs.x), T(y + rs.y), T(z + rs.z), T(i + rs.i), T(j + rs.j), T(k + rs.k), T(u + rs.u), T(v + rs.v), T(w + rs.w)); } + FI constexpr XYZEval operator- (const XYZval &rs) const { return LOGICAL_AXIS_ARRAY(e, T(x - rs.x), T(y - rs.y), T(z - rs.z), T(i - rs.i), T(j - rs.j), T(k - rs.k), T(u - rs.u), T(v - rs.v), T(w - rs.w)); } + FI constexpr XYZEval operator* (const XYZval &rs) const { return LOGICAL_AXIS_ARRAY(e, T(x * rs.x), T(y * rs.y), T(z * rs.z), T(i * rs.i), T(j * rs.j), T(k * rs.k), T(u * rs.u), T(v * rs.v), T(w * rs.w)); } + FI constexpr XYZEval operator/ (const XYZval &rs) const { return LOGICAL_AXIS_ARRAY(e, T(x / rs.x), T(y / rs.y), T(z / rs.z), T(i / rs.i), T(j / rs.j), T(k / rs.k), T(u / rs.u), T(v / rs.v), T(w / rs.w)); } + FI constexpr XYZEval operator+ (const XYZEval &rs) const { return LOGICAL_AXIS_ARRAY(T(e + rs.e), T(x + rs.x), T(y + rs.y), T(z + rs.z), T(i + rs.i), T(j + rs.j), T(k + rs.k), T(u + rs.u), T(v + rs.v), T(w + rs.w)); } + FI constexpr XYZEval operator- (const XYZEval &rs) const { return LOGICAL_AXIS_ARRAY(T(e - rs.e), T(x - rs.x), T(y - rs.y), T(z - rs.z), T(i - rs.i), T(j - rs.j), T(k - rs.k), T(u - rs.u), T(v - rs.v), T(w - rs.w)); } + FI constexpr XYZEval operator* (const XYZEval &rs) const { return LOGICAL_AXIS_ARRAY(T(e * rs.e), T(x * rs.x), T(y * rs.y), T(z * rs.z), T(i * rs.i), T(j * rs.j), T(k * rs.k), T(u * rs.u), T(v * rs.v), T(w * rs.w)); } + FI constexpr XYZEval operator/ (const XYZEval &rs) const { return LOGICAL_AXIS_ARRAY(T(e / rs.e), T(x / rs.x), T(y / rs.y), T(z / rs.z), T(i / rs.i), T(j / rs.j), T(k / rs.k), T(u / rs.u), T(v / rs.v), T(w / rs.w)); } + FI constexpr XYZEval operator* (const float &p) const { return LOGICAL_AXIS_ARRAY(T(e * p), T(x * p), T(y * p), T(z * p), T(i * p), T(j * p), T(k * p), T(u * p), T(v * p), T(w * p)); } FI constexpr XYZEval operator* (const int &p) const { return LOGICAL_AXIS_ARRAY(e * p, x * p, y * p, z * p, i * p, j * p, k * p, u * p, v * p, w * p); } - FI constexpr XYZEval operator/ (const float &p) const { return LOGICAL_AXIS_ARRAY((T)(e / p), (T)(x / p), (T)(y / p), (T)(z / p), (T)(i / p), (T)(j / p), (T)(k / p), (T)(u / p), (T)(v / p), (T)(w / p)); } + FI constexpr XYZEval operator/ (const float &p) const { return LOGICAL_AXIS_ARRAY(T(e / p), T(x / p), T(y / p), T(z / p), T(i / p), T(j / p), T(k / p), T(u / p), T(v / p), T(w / p)); } FI constexpr XYZEval operator/ (const int &p) const { return LOGICAL_AXIS_ARRAY(e / p, x / p, y / p, z / p, i / p, j / p, k / p, u / p, v / p, w / p); } FI constexpr XYZEval operator>>(const int &p) const { return LOGICAL_AXIS_ARRAY(_RS(e), _RS(x), _RS(y), _RS(z), _RS(i), _RS(j), _RS(k), _RS(u), _RS(v), _RS(w)); } FI constexpr XYZEval operator<<(const int &p) const { return LOGICAL_AXIS_ARRAY(_LS(e), _LS(x), _LS(y), _LS(z), _LS(i), _LS(j), _LS(k), _LS(u), _LS(v), _LS(w)); } @@ -1231,3 +1231,14 @@ public: #undef _LSE #undef _RSE #undef FI + +// Axis names for G-code parsing, reports, etc. +constexpr xyze_char_t axis_codes LOGICAL_AXIS_ARRAY('E', 'X', 'Y', 'Z', AXIS4_NAME, AXIS5_NAME, AXIS6_NAME, AXIS7_NAME, AXIS8_NAME, AXIS9_NAME); +#if NUM_AXES <= XYZ && !HAS_EXTRUDERS + #define AXIS_CHAR(A) ((char)('X' + A)) + #define IAXIS_CHAR AXIS_CHAR +#else + constexpr xyze_char_t iaxis_codes LOGICAL_AXIS_ARRAY('E', 'X', 'Y', 'Z', 'I', 'J', 'K', 'U', 'V', 'W'); + #define AXIS_CHAR(A) axis_codes[A] + #define IAXIS_CHAR(A) iaxis_codes[A] +#endif diff --git a/Marlin/src/core/utility.h b/Marlin/src/core/utility.h index c3324443ba..77e8bac016 100644 --- a/Marlin/src/core/utility.h +++ b/Marlin/src/core/utility.h @@ -82,17 +82,6 @@ public: // in the range 0-100 while avoiding rounding artifacts constexpr uint8_t ui8_to_percent(const uint8_t i) { return (int(i) * 100 + 127) / 255; } -// Axis names for G-code parsing, reports, etc. -const xyze_char_t axis_codes LOGICAL_AXIS_ARRAY('E', 'X', 'Y', 'Z', AXIS4_NAME, AXIS5_NAME, AXIS6_NAME, AXIS7_NAME, AXIS8_NAME, AXIS9_NAME); -#if NUM_AXES <= XYZ && !HAS_EXTRUDERS - #define AXIS_CHAR(A) ((char)('X' + A)) - #define IAXIS_CHAR AXIS_CHAR -#else - const xyze_char_t iaxis_codes LOGICAL_AXIS_ARRAY('E', 'X', 'Y', 'Z', 'I', 'J', 'K', 'U', 'V', 'W'); - #define AXIS_CHAR(A) axis_codes[A] - #define IAXIS_CHAR(A) iaxis_codes[A] -#endif - #if ENABLED(MARLIN_DEV_MODE) enum MarlinError : uint8_t { ERR_NONE, From c1e8d46d219493b2072e3df24c4dca0ac9b39998 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Thu, 27 Mar 2025 18:36:04 -0500 Subject: [PATCH 156/787] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20ELAPSED=20/=20PEND?= =?UTF-8?q?ING=20(ms,=20start,=20duration)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/MarlinCore.cpp | 4 ++-- Marlin/src/core/millis_t.h | 9 ++++----- Marlin/src/feature/controllerfan.cpp | 2 +- Marlin/src/feature/easythreed_ui.cpp | 10 +++++----- Marlin/src/feature/max7219.h | 2 +- Marlin/src/feature/mmu/mmu2.cpp | 8 ++++---- Marlin/src/feature/power.cpp | 2 +- Marlin/src/gcode/gcode.cpp | 4 ++-- Marlin/src/gcode/gcode.h | 4 ++-- Marlin/src/gcode/queue.cpp | 2 +- Marlin/src/lcd/HD44780/marlinui_HD44780.cpp | 2 +- Marlin/src/lcd/marlinui.cpp | 2 +- Marlin/src/lcd/tft/touch.cpp | 2 +- Marlin/src/libs/MAX31865.cpp | 2 +- Marlin/src/module/temperature.cpp | 12 ++++++------ Marlin/tests/core/test_types.cpp | 9 +++++++++ 16 files changed, 42 insertions(+), 34 deletions(-) diff --git a/Marlin/src/MarlinCore.cpp b/Marlin/src/MarlinCore.cpp index 3c44a9b71f..bfe69ba94e 100644 --- a/Marlin/src/MarlinCore.cpp +++ b/Marlin/src/MarlinCore.cpp @@ -678,14 +678,14 @@ inline void manage_inactivity(const bool no_stepper_sleep=false) { TERN_(HOTEND_IDLE_TIMEOUT, hotend_idle.check()); #if ANY(PSU_CONTROL, AUTO_POWER_CONTROL) && PIN_EXISTS(PS_ON_EDM) - if ( ELAPSED(ms, powerManager.last_state_change_ms + PS_EDM_RESPONSE) + if ( ELAPSED(ms, powerManager.last_state_change_ms, PS_EDM_RESPONSE) && (READ(PS_ON_PIN) != READ(PS_ON_EDM_PIN) || TERN0(PSU_OFF_REDUNDANT, extDigitalRead(PS_ON1_PIN) != extDigitalRead(PS_ON1_EDM_PIN))) ) kill(GET_TEXT_F(MSG_POWER_EDM_FAULT)); #endif #if ENABLED(EXTRUDER_RUNOUT_PREVENT) if (thermalManager.degHotend(active_extruder) > (EXTRUDER_RUNOUT_MINTEMP) - && ELAPSED(ms, gcode.previous_move_ms + SEC_TO_MS(EXTRUDER_RUNOUT_SECONDS)) + && ELAPSED(ms, gcode.previous_move_ms, SEC_TO_MS(EXTRUDER_RUNOUT_SECONDS)) && !planner.has_blocks_queued() ) { const int8_t e_stepper = TERN(HAS_SWITCHING_EXTRUDER, active_extruder >> 1, active_extruder); diff --git a/Marlin/src/core/millis_t.h b/Marlin/src/core/millis_t.h index 7c00b91a5b..1d3cc853b3 100644 --- a/Marlin/src/core/millis_t.h +++ b/Marlin/src/core/millis_t.h @@ -30,8 +30,7 @@ typedef uint32_t millis_t; #define MS_TO_SEC(N) millis_t((N)/1000UL) #define MS_TO_SEC_PRECISE(N) (float(N)/1000.0f) -#define FUTURE(START,DURA) (millis_t(millis()-(START))<(DURA)) -#define PAST(START,DURA) (!FUTURE(START,DURA)) - -#define PENDING(NOW,SOON) (int32_t((NOW)-(SOON))<0) -#define ELAPSED(NOW,SOON) (!PENDING(NOW,SOON)) +constexpr bool _PENDING(const millis_t now, const millis_t when) { return int32_t(when - now) > 0; } +constexpr bool _PENDING(const millis_t now, const millis_t start, const millis_t interval) { return (now - start) < interval; } +#define PENDING(V...) _PENDING(V) +#define ELAPSED(V...) !_PENDING(V) diff --git a/Marlin/src/feature/controllerfan.cpp b/Marlin/src/feature/controllerfan.cpp index 323d988a2d..585568b250 100644 --- a/Marlin/src/feature/controllerfan.cpp +++ b/Marlin/src/feature/controllerfan.cpp @@ -87,7 +87,7 @@ void ControllerFan::update() { * - If System is on idle and idle fan speed settings is activated. */ set_fan_speed( - settings.auto_mode && lastComponentOn && PENDING(ms, lastComponentOn + SEC_TO_MS(settings.duration)) + settings.auto_mode && lastComponentOn && PENDING(ms, lastComponentOn, SEC_TO_MS(settings.duration)) ? settings.active_speed : settings.idle_speed ); diff --git a/Marlin/src/feature/easythreed_ui.cpp b/Marlin/src/feature/easythreed_ui.cpp index 9617c62eb9..8974c5befd 100644 --- a/Marlin/src/feature/easythreed_ui.cpp +++ b/Marlin/src/feature/easythreed_ui.cpp @@ -78,9 +78,9 @@ void EasythreedUI::blinkLED() { prev_blink_interval_ms = blink_interval_ms; blink_start_ms = ms; } - if (PENDING(ms, blink_start_ms + blink_interval_ms)) + if (PENDING(ms, blink_start_ms, blink_interval_ms)) WRITE(EASYTHREED_LED_PIN, LOW); - else if (PENDING(ms, blink_start_ms + 2 * blink_interval_ms)) + else if (PENDING(ms, blink_start_ms, 2 * blink_interval_ms)) WRITE(EASYTHREED_LED_PIN, HIGH); else blink_start_ms = ms; @@ -107,7 +107,7 @@ void EasythreedUI::loadButton() { break; case FS_PRESS: - if (ELAPSED(millis(), filament_time + BTN_DEBOUNCE_MS)) { // After a short debounce delay... + if (ELAPSED(millis(), filament_time, BTN_DEBOUNCE_MS)) { // After a short debounce delay... if (!READ(BTN_RETRACT) || !READ(BTN_FEED)) { // ...if switch still toggled... thermalManager.setTargetHotend(EXTRUDE_MINTEMP + 10, 0); // Start heating up blink_interval_ms = LED_BLINK_7; // Set the LED to blink fast @@ -175,14 +175,14 @@ void EasythreedUI::printButton() { break; case KS_PRESS: - if (ELAPSED(ms, key_time + BTN_DEBOUNCE_MS)) // Wait for debounce interval to expire + if (ELAPSED(ms, key_time, BTN_DEBOUNCE_MS)) // Wait for debounce interval to expire key_status = READ(BTN_PRINT) ? KS_IDLE : KS_PROCEED; // Proceed if still pressed break; case KS_PROCEED: if (!READ(BTN_PRINT)) break; // Wait for the button to be released key_status = KS_IDLE; // Ready for the next press - if (PENDING(ms, key_time + 1200 - BTN_DEBOUNCE_MS)) { // Register a press < 1.2 seconds + if (PENDING(ms, key_time, 1200 - BTN_DEBOUNCE_MS)) { // Register a press < 1.2 seconds switch (print_key_flag) { case PF_START: { // The "Print" button starts an SD card print if (printingIsActive()) break; // Already printing? (find another line that checks for 'is planner doing anything else right now?') diff --git a/Marlin/src/feature/max7219.h b/Marlin/src/feature/max7219.h index a6b110fdf4..f476f7cde4 100644 --- a/Marlin/src/feature/max7219.h +++ b/Marlin/src/feature/max7219.h @@ -110,7 +110,7 @@ if (mode == ACCUMULATE_TOTAL) return; // update time_fraction every hundred milliseconds - if (instance_count == 0 && ELAPSED(now, last_calc_time + 100000)) { + if (instance_count == 0 && now - last_calc_time > 100000) { time_fraction = total_time * 128 / (now - last_calc_time); last_calc_time = now; total_time = 0; diff --git a/Marlin/src/feature/mmu/mmu2.cpp b/Marlin/src/feature/mmu/mmu2.cpp index d5f115e74c..96724d0d70 100644 --- a/Marlin/src/feature/mmu/mmu2.cpp +++ b/Marlin/src/feature/mmu/mmu2.cpp @@ -164,7 +164,7 @@ void MMU2::mmu_loop() { MMU2_SEND("S1"); // Read Version state = -2; } - else if (ELAPSED(millis(), prev_request + 30000)) { // 30sec after reset disable MMU + else if (ELAPSED(millis(), prev_request, 30000)) { // 30sec after reset disable MMU SERIAL_ECHOLNPGM("MMU not responding - DISABLED"); state = 0; } @@ -276,7 +276,7 @@ void MMU2::mmu_loop() { last_cmd = cmd; cmd = MMU_CMD_NONE; } - else if (ELAPSED(millis(), prev_P0_request + 300)) { + else if (ELAPSED(millis(), prev_P0_request, 300)) { MMU2_SEND("P0"); // Read FINDA state = 2; // wait for response } @@ -296,7 +296,7 @@ void MMU2::mmu_loop() { if (cmd == MMU_CMD_NONE) ready = true; state = 1; } - else if (ELAPSED(millis(), prev_request + MMU_P0_TIMEOUT)) // Resend request after timeout (3s) + else if (ELAPSED(millis(), prev_request, MMU_P0_TIMEOUT)) // Resend request after timeout (3s) state = 1; TERN_(HAS_PRUSA_MMU2S, check_filament()); @@ -335,7 +335,7 @@ void MMU2::mmu_loop() { last_cmd = MMU_CMD_NONE; } } - else if (ELAPSED(millis(), prev_request + MMU_CMD_TIMEOUT)) { + else if (ELAPSED(millis(), prev_request, MMU_CMD_TIMEOUT)) { // resend request after timeout if (last_cmd) { DEBUG_ECHOLNPGM("MMU retry"); diff --git a/Marlin/src/feature/power.cpp b/Marlin/src/feature/power.cpp index c6dc562836..a28d95d967 100644 --- a/Marlin/src/feature/power.cpp +++ b/Marlin/src/feature/power.cpp @@ -261,7 +261,7 @@ void Power::power_off() { nextPowerCheck = now + 2500UL; if (is_power_needed()) power_on(); - else if (!lastPowerOn || (POWER_TIMEOUT > 0 && ELAPSED(now, lastPowerOn + SEC_TO_MS(POWER_TIMEOUT)))) + else if (!lastPowerOn || (POWER_TIMEOUT > 0 && ELAPSED(now, lastPowerOn, SEC_TO_MS(POWER_TIMEOUT)))) power_off(); } } diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp index 8a444053e6..6dfc54d99e 100644 --- a/Marlin/src/gcode/gcode.cpp +++ b/Marlin/src/gcode/gcode.cpp @@ -246,8 +246,8 @@ void GcodeSuite::get_destination_from_command() { * Dwell waits immediately. It does not synchronize. */ void GcodeSuite::dwell(const millis_t time) { - const millis_t startMillis = millis(); - while (FUTURE(startMillis, time)) idle(); + const millis_t start_ms = millis(); + while (PENDING(millis(), start_ms, time)) idle(); } /** diff --git a/Marlin/src/gcode/gcode.h b/Marlin/src/gcode/gcode.h index 1d39dc3a6b..911820ee7b 100644 --- a/Marlin/src/gcode/gcode.h +++ b/Marlin/src/gcode/gcode.h @@ -433,14 +433,14 @@ public: static millis_t previous_move_ms, max_inactive_time; FORCE_INLINE static bool stepper_max_timed_out(const millis_t ms=millis()) { - return max_inactive_time && ELAPSED(ms, previous_move_ms + max_inactive_time); + return max_inactive_time && ELAPSED(ms, previous_move_ms, max_inactive_time); } FORCE_INLINE static void reset_stepper_timeout(const millis_t ms=millis()) { previous_move_ms = ms; } #if HAS_DISABLE_IDLE_AXES static millis_t stepper_inactive_time; FORCE_INLINE static bool stepper_inactive_timeout(const millis_t ms=millis()) { - return ELAPSED(ms, previous_move_ms + stepper_inactive_time); + return ELAPSED(ms, previous_move_ms, stepper_inactive_time); } #else static bool stepper_inactive_timeout(const millis_t) { return false; } diff --git a/Marlin/src/gcode/queue.cpp b/Marlin/src/gcode/queue.cpp index 3475450045..657bfab08b 100644 --- a/Marlin/src/gcode/queue.cpp +++ b/Marlin/src/gcode/queue.cpp @@ -426,7 +426,7 @@ void GCodeQueue::get_serial_commands() { // send "wait" to indicate Marlin is still waiting. #if NO_TIMEOUTS > 0 const millis_t ms = millis(); - if (ring_buffer.empty() && !any_serial_data_available() && ELAPSED(ms, last_command_time + NO_TIMEOUTS)) { + if (ring_buffer.empty() && !any_serial_data_available() && ELAPSED(ms, last_command_time, NO_TIMEOUTS)) { SERIAL_ECHOLNPGM(STR_WAIT); last_command_time = ms; } diff --git a/Marlin/src/lcd/HD44780/marlinui_HD44780.cpp b/Marlin/src/lcd/HD44780/marlinui_HD44780.cpp index 071a88e475..a0145d6165 100644 --- a/Marlin/src/lcd/HD44780/marlinui_HD44780.cpp +++ b/Marlin/src/lcd/HD44780/marlinui_HD44780.cpp @@ -755,7 +755,7 @@ void MarlinUI::draw_status_message(const bool blink) { // Draw the progress bar if the message has shown long enough // or if there is no message set. - if (ELAPSED(millis(), progress_bar_ms + PROGRESS_BAR_MSG_TIME) || !has_status()) { + if (ELAPSED(millis(), progress_bar_ms, PROGRESS_BAR_MSG_TIME) || !has_status()) { const uint8_t progress = get_progress_percent(); if (progress > 2) return draw_progress_bar(progress); } diff --git a/Marlin/src/lcd/marlinui.cpp b/Marlin/src/lcd/marlinui.cpp index 679c43b402..2114209b98 100644 --- a/Marlin/src/lcd/marlinui.cpp +++ b/Marlin/src/lcd/marlinui.cpp @@ -632,7 +632,7 @@ void MarlinUI::init() { // If the message will blink rather than expire... #if DISABLED(PROGRESS_MSG_ONCE) - if (ELAPSED(ms, progress_bar_ms + PROGRESS_BAR_MSG_TIME + PROGRESS_BAR_BAR_TIME)) + if (ELAPSED(ms, progress_bar_ms, PROGRESS_BAR_MSG_TIME + PROGRESS_BAR_BAR_TIME)) progress_bar_ms = ms; #endif diff --git a/Marlin/src/lcd/tft/touch.cpp b/Marlin/src/lcd/tft/touch.cpp index 932418331b..bb226e50c6 100644 --- a/Marlin/src/lcd/tft/touch.cpp +++ b/Marlin/src/lcd/tft/touch.cpp @@ -102,7 +102,7 @@ void Touch::idle() { if (touch_time) { #if ENABLED(TOUCH_SCREEN_CALIBRATION) - if (touch_control_type == NONE && ELAPSED(now, touch_time + TOUCH_SCREEN_HOLD_TO_CALIBRATE_MS) && ui.on_status_screen()) + if (touch_control_type == NONE && ELAPSED(now, touch_time, TOUCH_SCREEN_HOLD_TO_CALIBRATE_MS) && ui.on_status_screen()) ui.goto_screen(touch_screen_calibration); #endif return; diff --git a/Marlin/src/libs/MAX31865.cpp b/Marlin/src/libs/MAX31865.cpp index 3fe0694644..83b03e24fd 100644 --- a/Marlin/src/libs/MAX31865.cpp +++ b/Marlin/src/libs/MAX31865.cpp @@ -346,7 +346,7 @@ inline uint16_t MAX31865::readRawImmediate() { } else { TERN_(MAX31865_USE_READ_ERROR_DETECTION, const millis_t ms = millis()); - if (TERN0(MAX31865_USE_READ_ERROR_DETECTION, ABS((int)(lastRead - rtd)) > 500 && PENDING(ms, lastReadStamp + 1000))) { + if (TERN0(MAX31865_USE_READ_ERROR_DETECTION, ABS(int(lastRead - rtd)) > 500 && PENDING(ms, lastReadStamp, 1000UL))) { // If 2 readings within 1s differ too much (~20°C) it's a read error. lastFault = 0x01; lastRead |= 1; diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index 217405eae6..7da051f9d7 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -823,7 +823,7 @@ volatile bool Temperature::raw_temps_ready = false; ONHEATING(start_temp, current_temp, target); #endif - if (heating && current_temp > target && ELAPSED(ms, t2 + 5000UL)) { + if (heating && current_temp > target && ELAPSED(ms, t2, 5000UL)) { heating = false; SHV((bias - d) >> 1); t1 = ms; @@ -831,7 +831,7 @@ volatile bool Temperature::raw_temps_ready = false; maxT = target; } - if (!heating && current_temp < target && ELAPSED(ms, t1 + 5000UL)) { + if (!heating && current_temp < target && ELAPSED(ms, t1, 5000UL)) { heating = true; t2 = ms; t_low = t2 - t1; @@ -4666,7 +4666,7 @@ void Temperature::isr() { millis_t residency_start_ms = 0; bool first_loop = true; // Loop until the temperature has stabilized - #define TEMP_CONDITIONS (!residency_start_ms || PENDING(now, residency_start_ms + SEC_TO_MS(TEMP_RESIDENCY_TIME))) + #define TEMP_CONDITIONS (!residency_start_ms || PENDING(now, residency_start_ms, SEC_TO_MS(TEMP_RESIDENCY_TIME))) #else // Loop until the temperature is very close target #define TEMP_CONDITIONS (wants_to_cool ? isCoolingHotend(target_extruder) : isHeatingHotend(target_extruder)) @@ -4808,7 +4808,7 @@ void Temperature::isr() { millis_t residency_start_ms = 0; bool first_loop = true; // Loop until the temperature has stabilized - #define TEMP_BED_CONDITIONS (!residency_start_ms || PENDING(now, residency_start_ms + SEC_TO_MS(TEMP_BED_RESIDENCY_TIME))) + #define TEMP_BED_CONDITIONS (!residency_start_ms || PENDING(now, residency_start_ms, SEC_TO_MS(TEMP_BED_RESIDENCY_TIME))) #else // Loop until the temperature is very close target #define TEMP_BED_CONDITIONS (wants_to_cool ? isCoolingBed() : isHeatingBed()) @@ -5008,7 +5008,7 @@ void Temperature::isr() { millis_t residency_start_ms = 0; bool first_loop = true; // Loop until the temperature has stabilized - #define TEMP_CHAMBER_CONDITIONS (!residency_start_ms || PENDING(now, residency_start_ms + SEC_TO_MS(TEMP_CHAMBER_RESIDENCY_TIME))) + #define TEMP_CHAMBER_CONDITIONS (!residency_start_ms || PENDING(now, residency_start_ms, SEC_TO_MS(TEMP_CHAMBER_RESIDENCY_TIME))) #else // Loop until the temperature is very close target #define TEMP_CHAMBER_CONDITIONS (wants_to_cool ? isCoolingChamber() : isHeatingChamber()) @@ -5108,7 +5108,7 @@ void Temperature::isr() { millis_t residency_start_ms = 0; bool first_loop = true; // Loop until the temperature has stabilized - #define TEMP_COOLER_CONDITIONS (!residency_start_ms || PENDING(now, residency_start_ms + SEC_TO_MS(TEMP_COOLER_RESIDENCY_TIME))) + #define TEMP_COOLER_CONDITIONS (!residency_start_ms || PENDING(now, residency_start_ms, SEC_TO_MS(TEMP_COOLER_RESIDENCY_TIME))) #else // Loop until the temperature is very close target #define TEMP_COOLER_CONDITIONS (wants_to_cool ? isLaserHeating() : isLaserCooling()) diff --git a/Marlin/tests/core/test_types.cpp b/Marlin/tests/core/test_types.cpp index d569386265..317b961626 100644 --- a/Marlin/tests/core/test_types.cpp +++ b/Marlin/tests/core/test_types.cpp @@ -22,6 +22,7 @@ #include "../test/unit_tests.h" #include "src/core/types.h" +#include "src/core/millis_t.h" MARLIN_TEST(types, XYval_const_as_bools) { const XYval xy_const_true = {1, 2}; @@ -656,3 +657,11 @@ MARLIN_TEST(types, SString) { TEST_ASSERT_TRUE(strcmp_P(str, PSTR("Hello World!-123456------ < spaces!33\n^ eol! ... 1234.50*2345.602 = 2895645.67")) == 0); } + +MARLIN_TEST(types, PENDING) { + TEST_ASSERT_TRUE(PENDING(0x0000FFFF, 0x00010000)); // <= ~24.4 days + TEST_ASSERT_TRUE(ELAPSED(0x0090000A, 0x00900000)); // <= ~24.4 days + TEST_ASSERT_FALSE(PENDING(0x00000000, 0x80000000)); // > ~24.4 days + TEST_ASSERT_TRUE(PENDING(0x00000000, 0, 0x80000000)); // <= ~48.8 days + TEST_ASSERT_TRUE(PENDING(0x80000000, 0x7FFFFFF0, 0x0020)); // <= ~48.8 days +} From 448ff71899a46c71ace774dfd47767a76a226c54 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Thu, 27 Mar 2025 19:03:53 -0500 Subject: [PATCH 157/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Twe?= =?UTF-8?q?ak=20MAX7219=20test=20pattern?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/feature/max7219.cpp | 40 +++++++++++++++------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/Marlin/src/feature/max7219.cpp b/Marlin/src/feature/max7219.cpp index 51ec219e20..5a25ea6710 100644 --- a/Marlin/src/feature/max7219.cpp +++ b/Marlin/src/feature/max7219.cpp @@ -480,32 +480,30 @@ void Max7219::register_setup() { #if MAX7219_INIT_TEST uint8_t test_mode = 0; - millis_t next_patt_ms; bool patt_on; #if MAX7219_INIT_TEST == 2 #define MAX7219_LEDS (MAX7219_X_LEDS * MAX7219_Y_LEDS) - constexpr millis_t pattern_delay = 4; - - int8_t spiralx, spiraly, spiral_dir; + xy_int8_t spiral; + int8_t spiral_dir; uvalue_t(MAX7219_LEDS) spiral_count; - void Max7219::test_pattern() { - constexpr int8_t way[][2] = { { 1, 0 }, { 0, 1 }, { -1, 0 }, { 0, -1 } }; - led_set(spiralx, spiraly, patt_on); - const int8_t x = spiralx + way[spiral_dir][0], y = spiraly + way[spiral_dir][1]; - if (!WITHIN(x, 0, MAX7219_X_LEDS - 1) || !WITHIN(y, 0, MAX7219_Y_LEDS - 1) || BIT_7219(x, y) == patt_on) + void Max7219::run_test_pattern() { + constexpr xy_int8_t way[] = { { 1, 0 }, { 0, 1 }, { -1, 0 }, { 0, -1 } }; + led_set(spiral.x, spiral.y, patt_on); + const xy_int8_t xy = spiral + way[spiral_dir]; + if (!WITHIN(xy.x, 0, MAX7219_X_LEDS - 1) || !WITHIN(xy.y, 0, MAX7219_Y_LEDS - 1) || BIT_7219(xy.x, xy.y) == patt_on) spiral_dir = (spiral_dir + 1) & 0x3; - spiralx += way[spiral_dir][0]; - spiraly += way[spiral_dir][1]; + spiral += way[spiral_dir]; if (!spiral_count--) { if (!patt_on) test_mode = 0; else { spiral_count = MAX7219_LEDS; - spiralx = spiraly = spiral_dir = 0; + spiral.reset(); + spiral_dir = 0; patt_on = false; } } @@ -516,7 +514,11 @@ void Max7219::register_setup() { constexpr millis_t pattern_delay = 20; int8_t sweep_count, sweepx, sweep_dir; - void Max7219::test_pattern() { + void Max7219::run_test_pattern() { + static millis_t next_pattern_ms = 0; + const millis_t ms = millis(); + if (PENDING(ms, next_pattern_ms)) return; + next_pattern_ms = ms + pattern_delay; set_column(sweepx, patt_on ? 0xFFFFFFFF : 0x00000000); sweepx += sweep_dir; if (!WITHIN(sweepx, 0, MAX7219_X_LEDS - 1)) { @@ -527,26 +529,20 @@ void Max7219::register_setup() { else sweepx -= MAX7219_X_LEDS * sweep_dir; FLIP(patt_on); - next_patt_ms += 100; + next_pattern_ms += 100; if (++test_mode > 4) test_mode = 0; } } #endif - void Max7219::run_test_pattern() { - const millis_t ms = millis(); - if (PENDING(ms, next_patt_ms)) return; - next_patt_ms = ms + pattern_delay; - test_pattern(); - } - void Max7219::start_test_pattern() { clear(); test_mode = 1; patt_on = true; #if MAX7219_INIT_TEST == 2 - spiralx = spiraly = spiral_dir = 0; + spiral.reset(); + spiral_dir = 0; spiral_count = MAX7219_LEDS; #else sweep_dir = 1; From efa175820f2e379b569ae01cdc422a8ef12c1f4d Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Thu, 27 Mar 2025 20:55:59 -0500 Subject: [PATCH 158/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20All?= =?UTF-8?q?ow=20for=20tests=20on=20macOS=20/=20Windows?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 2 +- Marlin/src/pins/pins.h | 2 +- buildroot/share/PlatformIO/scripts/collect-code-tests.py | 6 +++--- buildroot/share/PlatformIO/scripts/preflight-checks.py | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 83b27e566a..23826497b6 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ help: @echo "make tests-all-local-docker : Run all tests locally, using docker" @echo "make unit-test-single-local : Run unit tests for a single config locally" @echo "make unit-test-single-local-docker : Run unit tests for a single config locally, using docker" - @echo "make unit-test-all-local : Run all code tests locally" + @echo "make unit-test-all-local : Run all code tests locally" @echo "make unit-test-all-local-docker : Run all code tests locally, using docker" @echo "make setup-local-docker : Setup local docker using buildx" @echo "" diff --git a/Marlin/src/pins/pins.h b/Marlin/src/pins/pins.h index 01ff13f8c2..55dc00c60d 100644 --- a/Marlin/src/pins/pins.h +++ b/Marlin/src/pins/pins.h @@ -985,7 +985,7 @@ // #elif MB(SIMULATED) - #include "native/pins_RAMPS_NATIVE.h" // Native or Simulation lin:linux_native mac:simulator_macos_debug mac:simulator_macos_release win:simulator_windows lin:simulator_linux_debug lin:simulator_linux_release + #include "native/pins_RAMPS_NATIVE.h" // Native or Simulation lin:linux_native lin:simulator_linux_debug lin:simulator_linux_release lin:linux_native_test mac:simulator_macos_debug mac:simulator_macos_release win:simulator_windows #else diff --git a/buildroot/share/PlatformIO/scripts/collect-code-tests.py b/buildroot/share/PlatformIO/scripts/collect-code-tests.py index 576e3dd06d..62f95f4b4b 100644 --- a/buildroot/share/PlatformIO/scripts/collect-code-tests.py +++ b/buildroot/share/PlatformIO/scripts/collect-code-tests.py @@ -1,6 +1,6 @@ # # collect-code-tests.py -# Convenience script to collect all code tests. Used by env:linux_native_test in native.ini. +# Convenience script to collect all code tests. Used by test envs in native.ini. # import pioutil @@ -32,7 +32,7 @@ if pioutil.is_pio_build(): "restore_configs", f"cp -f {path} ./Marlin/config.ini", "python ./buildroot/share/PlatformIO/scripts/configuration.py", - f"platformio test -e linux_native_test -f {name}", + f"platformio test -e {env['PIOENV']} -f {name}", "restore_configs", ], title = "Marlin: {}".format(name.lower().title().replace("_", " ")), @@ -46,7 +46,7 @@ if pioutil.is_pio_build(): name = "test-marlin", dependencies = None, actions = [ - f"platformio run -t marlin_{name} -e linux_native_test" + f"platformio run -t marlin_{name} -e {env['PIOENV']}" for name in targets ], title = "Marlin: Test all code test suites", diff --git a/buildroot/share/PlatformIO/scripts/preflight-checks.py b/buildroot/share/PlatformIO/scripts/preflight-checks.py index 94b39927e0..ea642809d5 100644 --- a/buildroot/share/PlatformIO/scripts/preflight-checks.py +++ b/buildroot/share/PlatformIO/scripts/preflight-checks.py @@ -95,7 +95,7 @@ if pioutil.is_pio_build(): # Make sure board is compatible with the build environment. Skip for _test, # since the board is manipulated as each unit test is executed. - if not result and build_env != "linux_native_test": + if not result and not build_env.endswith("_native_test"): err = "Error: Build environment '%s' is incompatible with %s. Use one of these environments: %s" % \ ( build_env, motherboard, ", ".join([ e[4:] for e in board_envs if e.startswith("env:") ]) ) raise SystemExit(err) From f6eaca6fcdd31d1d1ada67a7b3e3e15135e224f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferm=C3=ADn=20Olaiz?= Date: Fri, 28 Mar 2025 00:18:08 -0300 Subject: [PATCH 159/787] =?UTF-8?q?=F0=9F=A9=B9=20MKS=5FTINYBEE=20ADC=20re?= =?UTF-8?q?ference=20voltage=20warning=20(#27755)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/inc/Warnings.cpp | 7 +++++++ Marlin/src/pins/esp32/pins_MKS_TINYBEE.h | 19 +++++++++++++++---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/Marlin/src/inc/Warnings.cpp b/Marlin/src/inc/Warnings.cpp index 7c107220af..70a6905d9f 100644 --- a/Marlin/src/inc/Warnings.cpp +++ b/Marlin/src/inc/Warnings.cpp @@ -898,6 +898,13 @@ #warning "The (-1) AD595 Thermocouple Amplifier requires 5V input supply! Use AD8495 for 3.3V ADC." #endif +/** + * MKS_TINYBEE Analog Reference + */ +#if ENABLED(EMIT_ADC_REFERENCE_VOLTAGE_WARNING) + #warning "Check your ADC_REFERENCE_VOLTAGE on MKS TinyBee! Measure the Analog Reference voltage on the board. See pins_MKS_TINYBEE.h for details." +#endif + /** * No PWM on the Piezo Beeper? */ diff --git a/Marlin/src/pins/esp32/pins_MKS_TINYBEE.h b/Marlin/src/pins/esp32/pins_MKS_TINYBEE.h index 6b5411e09d..11f18f4496 100644 --- a/Marlin/src/pins/esp32/pins_MKS_TINYBEE.h +++ b/Marlin/src/pins/esp32/pins_MKS_TINYBEE.h @@ -115,10 +115,21 @@ //#define CONTROLLER_FAN_PIN 148 // FAN2 //#define E0_AUTO_FAN_PIN 148 // FAN2 -// -// ADC Reference Voltage -// -#define ADC_REFERENCE_VOLTAGE 2.565 // 2.5V reference VDDA +/** + * ADC Reference Voltage + * + * In some boards the voltage reference is a bit off due to low quality + * components. That is enough to throw off the ADC readings and thus the + * temperatures by more than 10°C in some cases. If you experience that + * problem, measure the reference voltage (VDDA) at the 2nd pin of + * TH1/TH2 (with the sensors disconnected) and set ADC_REFERENCE_VOLTAGE + * in your config. + */ + +#ifndef ADC_REFERENCE_VOLTAGE + #define EMIT_ADC_REFERENCE_VOLTAGE_WARNING + #define ADC_REFERENCE_VOLTAGE 2.565 +#endif /** * ------ ------ From 78d6fec6525924cf659a3d720a5960bfa1eea286 Mon Sep 17 00:00:00 2001 From: Boyd Date: Thu, 27 Mar 2025 22:31:45 -0700 Subject: [PATCH 160/787] =?UTF-8?q?=F0=9F=9A=80=20HAL=20for=20GD32=20MFL?= =?UTF-8?q?=20(Creality=20v4.2.2)=20(#27744)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci-build-tests.yml | 3 + Marlin/src/HAL/GD32_MFL/HAL.cpp | 120 ++ Marlin/src/HAL/GD32_MFL/HAL.h | 158 +++ Marlin/src/HAL/GD32_MFL/MarlinSPI.h | 26 + Marlin/src/HAL/GD32_MFL/MarlinSerial.cpp | 101 ++ Marlin/src/HAL/GD32_MFL/MarlinSerial.h | 75 ++ Marlin/src/HAL/GD32_MFL/MinSerial.cpp | 163 +++ Marlin/src/HAL/GD32_MFL/README.md | 8 + Marlin/src/HAL/GD32_MFL/SDCard.cpp | 1022 +++++++++++++++++ Marlin/src/HAL/GD32_MFL/SDCard.h | 214 ++++ Marlin/src/HAL/GD32_MFL/Servo.cpp | 122 ++ Marlin/src/HAL/GD32_MFL/Servo.h | 56 + .../HAL/GD32_MFL/dogm/u8g_com_mfl_swspi.cpp | 129 +++ Marlin/src/HAL/GD32_MFL/eeprom_bl24cxx.cpp | 93 ++ Marlin/src/HAL/GD32_MFL/eeprom_if_iic.cpp | 54 + Marlin/src/HAL/GD32_MFL/eeprom_wired.cpp | 96 ++ Marlin/src/HAL/GD32_MFL/endstop_interrupts.h | 61 + Marlin/src/HAL/GD32_MFL/fast_pwm.cpp | 97 ++ Marlin/src/HAL/GD32_MFL/fastio.h | 82 ++ .../src/HAL/GD32_MFL/inc/Conditionals_LCD.h | 26 + .../src/HAL/GD32_MFL/inc/Conditionals_adv.h | 26 + .../src/HAL/GD32_MFL/inc/Conditionals_post.h | 29 + .../src/HAL/GD32_MFL/inc/Conditionals_type.h | 22 + Marlin/src/HAL/GD32_MFL/inc/SanityCheck.h | 97 ++ Marlin/src/HAL/GD32_MFL/pinsDebug.h | 102 ++ Marlin/src/HAL/GD32_MFL/sdio.cpp | 233 ++++ Marlin/src/HAL/GD32_MFL/sdio.h | 36 + Marlin/src/HAL/GD32_MFL/spi_pins.h | 32 + Marlin/src/HAL/GD32_MFL/temp_soc.h | 29 + Marlin/src/HAL/GD32_MFL/timers.cpp | 233 ++++ Marlin/src/HAL/GD32_MFL/timers.h | 145 +++ Marlin/src/HAL/GD32_MFL/u8g/LCD_defines.h | 26 + Marlin/src/HAL/HC32/eeprom_wired.cpp | 3 + Marlin/src/HAL/HC32/pinsDebug.h | 3 + Marlin/src/HAL/HC32/spi_pins.h | 3 + Marlin/src/HAL/platforms.h | 2 + Marlin/src/HAL/shared/servo.h | 2 + Marlin/src/core/boards.h | 12 +- Marlin/src/inc/SanityCheck.h | 6 +- Marlin/src/inc/Warnings.cpp | 13 +- .../dogm/u8g/u8g_dev_st7920_128x64_HAL.cpp | 2 +- .../u8g/ultralcd_st7920_u8glib_rrd_AVR.cpp | 4 +- Marlin/src/libs/BL24CXX.cpp | 2 +- .../pins/gd32f3/pins_CREALITY_V422_GD32_MFL.h | 37 + Marlin/src/pins/pins.h | 7 + Marlin/src/pins/pinsDebug_list.h | 2 + Marlin/src/pins/stm32f1/env_validate.h | 7 +- README.md | 3 +- buildroot/tests/GD32F303RE_creality_mfl | 17 + ini/gd32.ini | 47 + platformio.ini | 1 + 51 files changed, 3873 insertions(+), 16 deletions(-) create mode 100644 Marlin/src/HAL/GD32_MFL/HAL.cpp create mode 100644 Marlin/src/HAL/GD32_MFL/HAL.h create mode 100644 Marlin/src/HAL/GD32_MFL/MarlinSPI.h create mode 100644 Marlin/src/HAL/GD32_MFL/MarlinSerial.cpp create mode 100644 Marlin/src/HAL/GD32_MFL/MarlinSerial.h create mode 100644 Marlin/src/HAL/GD32_MFL/MinSerial.cpp create mode 100644 Marlin/src/HAL/GD32_MFL/README.md create mode 100644 Marlin/src/HAL/GD32_MFL/SDCard.cpp create mode 100644 Marlin/src/HAL/GD32_MFL/SDCard.h create mode 100644 Marlin/src/HAL/GD32_MFL/Servo.cpp create mode 100644 Marlin/src/HAL/GD32_MFL/Servo.h create mode 100644 Marlin/src/HAL/GD32_MFL/dogm/u8g_com_mfl_swspi.cpp create mode 100644 Marlin/src/HAL/GD32_MFL/eeprom_bl24cxx.cpp create mode 100644 Marlin/src/HAL/GD32_MFL/eeprom_if_iic.cpp create mode 100644 Marlin/src/HAL/GD32_MFL/eeprom_wired.cpp create mode 100644 Marlin/src/HAL/GD32_MFL/endstop_interrupts.h create mode 100644 Marlin/src/HAL/GD32_MFL/fast_pwm.cpp create mode 100644 Marlin/src/HAL/GD32_MFL/fastio.h create mode 100644 Marlin/src/HAL/GD32_MFL/inc/Conditionals_LCD.h create mode 100644 Marlin/src/HAL/GD32_MFL/inc/Conditionals_adv.h create mode 100644 Marlin/src/HAL/GD32_MFL/inc/Conditionals_post.h create mode 100644 Marlin/src/HAL/GD32_MFL/inc/Conditionals_type.h create mode 100644 Marlin/src/HAL/GD32_MFL/inc/SanityCheck.h create mode 100644 Marlin/src/HAL/GD32_MFL/pinsDebug.h create mode 100644 Marlin/src/HAL/GD32_MFL/sdio.cpp create mode 100644 Marlin/src/HAL/GD32_MFL/sdio.h create mode 100644 Marlin/src/HAL/GD32_MFL/spi_pins.h create mode 100644 Marlin/src/HAL/GD32_MFL/temp_soc.h create mode 100644 Marlin/src/HAL/GD32_MFL/timers.cpp create mode 100644 Marlin/src/HAL/GD32_MFL/timers.h create mode 100644 Marlin/src/HAL/GD32_MFL/u8g/LCD_defines.h create mode 100644 Marlin/src/pins/gd32f3/pins_CREALITY_V422_GD32_MFL.h create mode 100755 buildroot/tests/GD32F303RE_creality_mfl create mode 100644 ini/gd32.ini diff --git a/.github/workflows/ci-build-tests.yml b/.github/workflows/ci-build-tests.yml index 320cda5b18..2fd316ec0f 100644 --- a/.github/workflows/ci-build-tests.yml +++ b/.github/workflows/ci-build-tests.yml @@ -151,6 +151,9 @@ jobs: # HC32 - HC32F460C_aquila_101 + # GD32F3 + - GD32F303RE_creality_mfl + # LPC176x - Lengthy tests - LPC1768 - LPC1769 diff --git a/Marlin/src/HAL/GD32_MFL/HAL.cpp b/Marlin/src/HAL/GD32_MFL/HAL.cpp new file mode 100644 index 0000000000..460ed52297 --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/HAL.cpp @@ -0,0 +1,120 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "../platforms.h" + +#ifdef ARDUINO_ARCH_MFL + +#include "../../inc/MarlinConfig.h" +#include "../shared/Delay.h" + +uint16_t MarlinHAL::adc_result; + +#if ENABLED(POSTMORTEM_DEBUGGING) + extern void install_min_serial(); +#endif + +#if ENABLED(MARLIN_DEV_MODE) + // Dump the clock frequencies of the system, AHB, APB1, APB2, and F_CPU. + static inline void HAL_clock_frequencies_dump() { + auto& rcuInstance = rcu::RCU::get_instance(); + uint32_t freq = rcuInstance.get_clock_frequency(rcu::Clock_Frequency::CK_SYS); + SERIAL_ECHOPGM("\nSYSTEM_CLOCK=", freq); + freq = rcuInstance.get_clock_frequency(rcu::Clock_Frequency::CK_AHB); + SERIAL_ECHOPGM("\nABH_CLOCK=", freq); + freq = rcuInstance.get_clock_frequency(rcu::Clock_Frequency::CK_APB1); + SERIAL_ECHOPGM("\nAPB1_CLOCK=", freq); + freq = rcuInstance.get_clock_frequency(rcu::Clock_Frequency::CK_APB2); + SERIAL_ECHOPGM("\nAPB2_CLOCK=", freq, + "\nF_CPU=", F_CPU); + // Done + SERIAL_ECHOPGM("\n--\n"); + } +#endif // MARLIN_DEV_MODE + +// Initializes the Marlin HAL +void MarlinHAL::init() { + constexpr unsigned int cpuFreq = F_CPU; + UNUSED(cpuFreq); + +#if PIN_EXISTS(LED) + OUT_WRITE(LED_PIN, LOW); +#endif + + SetTimerInterruptPriorities(); + + // Print clock frequencies to host serial + TERN_(MARLIN_DEV_MODE, HAL_clock_frequencies_dump()); + + // Register min serial + TERN_(POSTMORTEM_DEBUGGING, install_min_serial()); +} + +// Returns the reset source based on the flags set in the RCU module +uint8_t MarlinHAL::get_reset_source() { + return + (RCU_I.get_flag(rcu::Status_Flags::FLAG_FWDGTRST)) ? RST_WATCHDOG : + (RCU_I.get_flag(rcu::Status_Flags::FLAG_SWRST)) ? RST_SOFTWARE : + (RCU_I.get_flag(rcu::Status_Flags::FLAG_EPRST)) ? RST_EXTERNAL : + (RCU_I.get_flag(rcu::Status_Flags::FLAG_PORRST)) ? RST_POWER_ON : + (RCU_I.get_flag(rcu::Status_Flags::FLAG_LPRST)) ? RST_BROWN_OUT : + 0; +} + +// Returns the amount of free memory available in bytes +int MarlinHAL::freeMemory() { + volatile char top; + return &top - reinterpret_cast(_sbrk(0)); +} + +// Watchdog Timer +#if ENABLED(USE_WATCHDOG) + #define WDT_TIMEOUT_US TERN(WATCHDOG_DURATION_8S, 8000000, 4000000) // 4 or 8 second timeout + + #include + + FWatchdogTimer& watchdogTimer = FWatchdogTimer::get_instance(); + + // Initializes the watchdog timer + void MarlinHAL::watchdog_init() { + IF_DISABLED(DISABLE_WATCHDOG_INIT, watchdogTimer.begin(WDT_TIMEOUT_US)); + } + + // Refreshes the watchdog timer to prevent system reset + void MarlinHAL::watchdog_refresh() { + watchdogTimer.reload(); + #if DISABLED(PINS_DEBUGGING) && PIN_EXISTS(LED) + TOGGLE(LED_PIN); // Heartbeat indicator + #endif + } +#endif + +extern "C" { + extern unsigned int _ebss; // End of bss section +} + +// Resets the system to initiate a firmware flash. +WEAK void flashFirmware(const int16_t) { + hal.reboot(); +} + +#endif // ARDUINO_ARCH_MFL diff --git a/Marlin/src/HAL/GD32_MFL/HAL.h b/Marlin/src/HAL/GD32_MFL/HAL.h new file mode 100644 index 0000000000..a8a28cc7f3 --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/HAL.h @@ -0,0 +1,158 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +#define CPU_32_BIT + +#include "../../core/macros.h" +#include "../shared/Marduino.h" +#include "../shared/math_32bit.h" +#include "../shared/HAL_SPI.h" + +#include "temp_soc.h" +#include "fastio.h" +#include "Servo.h" + +#include "../../inc/MarlinConfigPre.h" + +#include +#include +#include + +// Default graphical display delays +#define CPU_ST7920_DELAY_1 300 +#define CPU_ST7920_DELAY_2 40 +#define CPU_ST7920_DELAY_3 340 + +// Serial Ports +#include "MarlinSerial.h" + +// Interrupts +#define CRITICAL_SECTION_START() const bool irqon = !__get_PRIMASK(); __disable_irq() +#define CRITICAL_SECTION_END() if (irqon) __enable_irq() + +#define cli() __disable_irq() +#define sei() __enable_irq() + +// Alias of __bss_end__ +#define __bss_end __bss_end__ + +// Types +typedef double isr_float_t; // FPU ops are used for single-precision, so use double for ISRs. +typedef uint8_t pin_t; // Parity with mfl platform + +// Servo +class libServo; +typedef libServo hal_servo_t; +#define PAUSE_SERVO_OUTPUT() libServo::pause_all_servos() +#define RESUME_SERVO_OUTPUT() libServo::resume_all_servos() + +// Debugging +#define JTAG_DISABLE() AFIO_I.set_remap(gpio::Pin_Remap_Select::SWJ_DP_ONLY_REMAP) +#define JTAGSWD_DISABLE() AFIO_I.set_remap(gpio::Pin_Remap_Select::SWJ_ALL_DISABLED_REMAP) +#define JTAGSWD_RESET() AFIO_I.set_remap(gpio::Pin_Remap_Select::FULL_SWJ_REMAP) + +// ADC +#ifdef ADC_RESOLUTION + #define HAL_ADC_RESOLUTION ADC_RESOLUTION +#else + #define HAL_ADC_RESOLUTION 12 +#endif + +#define HAL_ADC_VREF_MV 3300 + +// Disable Marlin's software oversampling. +// The MFL framework uses 16x hardware oversampling by default +#define HAL_ADC_FILTERED + +#define GET_PIN_MAP_PIN(index) index +#define GET_PIN_MAP_INDEX(pin) pin +#define PARSED_PIN_INDEX(code, dval) parser.intval(code, dval) + +#ifndef PLATFORM_M997_SUPPORT + #define PLATFORM_M997_SUPPORT +#endif + +void flashFirmware(const int16_t); + +#define HAL_CAN_SET_PWM_FREQ // This HAL supports PWM Frequency adjustment + +extern "C" char* _sbrk(int incr); +extern "C" char* dtostrf(double val, signed char width, unsigned char prec, char* sout); + +// MarlinHAL Class +class MarlinHAL { +public: + // Before setup() + MarlinHAL() {} + + // Watchdog + static void watchdog_init() IF_DISABLED(USE_WATCHDOG, {}); + static void watchdog_refresh() IF_DISABLED(USE_WATCHDOG, {}); + + static void init(); // called early in setup() + static void init_board() {} // called less early in setup() + static void reboot() { NVIC_SystemReset(); } // restart the firmware from 0x0 + + // Interrupts + static bool isr_state() { return !__get_PRIMASK(); } + static void isr_on() { sei(); } + static void isr_off() { cli(); } + static void delay_ms(const int ms) { delay(ms); } + + // Tasks called from idle() + static void idletask() {} + + // Reset + static uint8_t get_reset_source(); + static void clear_reset_source() { RCU_I.clear_all_reset_flags(); } + + // Free SRAM + static int freeMemory(); + + // ADC methods + static uint16_t adc_result; + + // Called by Temperature::init once at startup + static void adc_init() { analogReadResolution(HAL_ADC_RESOLUTION); } + + // Called by Temperature::init for each sensor at startup + static void adc_enable(const pin_t pin) { pinMode(pin, INPUT); } + + // Called from Temperature::isr to start ADC sampling on the given pin + static void adc_start(const pin_t pin) { adc_result = static_cast(analogRead(pin)); } + + // Check if ADC is ready for reading + static bool adc_ready() { return true; } + + // Current value of the ADC register + static uint16_t adc_value() { return adc_result; } + + // Set the PWM duty cycle for the pin to the given value. + // Optionally invert the duty cycle [default = false] + // Optionally change the maximum size of the provided value to enable finer PWM duty control [default = 255] + static void set_pwm_duty(const pin_t pin, const uint16_t value, const uint16_t scale = 255U, const bool invert = false); + + // Set the frequency of the timer for the given pin. + // All Timer PWM pins run at the same frequency. + static void set_pwm_frequency(const pin_t pin, const uint16_t f_desired); +}; diff --git a/Marlin/src/HAL/GD32_MFL/MarlinSPI.h b/Marlin/src/HAL/GD32_MFL/MarlinSPI.h new file mode 100644 index 0000000000..d0731f9e84 --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/MarlinSPI.h @@ -0,0 +1,26 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +#include + +using MarlinSPI = SPIClass; diff --git a/Marlin/src/HAL/GD32_MFL/MarlinSerial.cpp b/Marlin/src/HAL/GD32_MFL/MarlinSerial.cpp new file mode 100644 index 0000000000..c9b76a4ca4 --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/MarlinSerial.cpp @@ -0,0 +1,101 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "../platforms.h" + +#ifdef ARDUINO_ARCH_MFL + +#include "../../inc/MarlinConfig.h" +#include "MarlinSerial.h" + +#if ENABLED(EMERGENCY_PARSER) + #include "../../feature/e_parser.h" +#endif + +using namespace arduino; + +MarlinSerial& MarlinSerial::get_instance(usart::USART_Base Base, pin_size_t rxPin, pin_size_t txPin) { + UsartSerial& serial = UsartSerial::get_instance(Base, rxPin, txPin); + return *reinterpret_cast(&serial); +} + +#if USING_HW_SERIAL0 + MSerialT MSerial0(true, MarlinSerial::get_instance(usart::USART_Base::USART0_BASE, NO_PIN, NO_PIN)); +#endif +#if USING_HW_SERIAL1 + MSerialT MSerial1(true, MarlinSerial::get_instance(usart::USART_Base::USART1_BASE, NO_PIN, NO_PIN)); +#endif +#if USING_HW_SERIAL2 + MSerialT MSerial2(true, MarlinSerial::get_instance(usart::USART_Base::USART2_BASE, NO_PIN, NO_PIN)); +#endif +#if USING_HW_SERIAL3 + MSerialT MSerial3(true, MarlinSerial::get_instance(usart::USART_Base::UART3_BASE, NO_PIN, NO_PIN)); +#endif +#if USING_HW_SERIAL4 + MSerialT MSerial4(true, MarlinSerial::get_instance(usart::USART_Base::UART4_BASE, NO_PIN, NO_PIN)); +#endif + +#if ENABLED(EMERGENCY_PARSER) + // This callback needs to access the specific MarlinSerial instance + // We'll use a static pointer to track the current instance + static MarlinSerial* current_serial_instance = nullptr; + + static void emergency_callback() { + if (current_serial_instance) { + uint8_t last_data = current_serial_instance->get_last_data(); + emergency_parser.update(current_serial_instance->emergency_state, last_data); + } + } + + void MarlinSerial::register_emergency_callback(void (*callback)()) { + usart_.register_interrupt_callback(usart::Interrupt_Type::INTR_RBNEIE, callback); + } +#endif + +void MarlinSerial::begin(unsigned long baudrate, uint16_t config) { + UsartSerial::begin(baudrate, config); + #if DISABLED(SERIAL_DMA) + #if ENABLED(EMERGENCY_PARSER) + current_serial_instance = this; + register_emergency_callback(emergency_callback); + #endif + #endif +} + +void MarlinSerial::updateRxDmaBuffer() { + #if ENABLED(EMERGENCY_PARSER) + // Get the number of bytes available in the receive buffer + size_t available_bytes = usart_.available_for_read(true); + uint8_t data; + + // Process only the available data + for (size_t i = 0; i < available_bytes; ++i) { + if (usart_.read_rx_buffer(data)) { + emergency_parser.update(emergency_state, data); + } + } + #endif + // Call the base class implementation to handle any additional updates + UsartSerial::updateRxDmaBuffer(); +} + +#endif // ARDUINO_ARCH_MFL diff --git a/Marlin/src/HAL/GD32_MFL/MarlinSerial.h b/Marlin/src/HAL/GD32_MFL/MarlinSerial.h new file mode 100644 index 0000000000..f47c6da032 --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/MarlinSerial.h @@ -0,0 +1,75 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +#include "../../inc/MarlinConfigPre.h" + +#if ENABLED(EMERGENCY_PARSER) + #include "../../feature/e_parser.h" +#endif + +#include + +#include "../../core/serial_hook.h" + +#define SERIAL_INDEX_MIN 0 +#define SERIAL_INDEX_MAX 4 + +#include "../shared/serial_ports.h" + +#if defined(LCD_SERIAL_PORT) && ANY(HAS_DGUS_LCD, EXTENSIBLE_UI) + #define LCD_SERIAL_TX_BUFFER_FREE() LCD_SERIAL.availableForWrite() +#endif + +using namespace arduino; + +struct MarlinSerial : public UsartSerial { + static MarlinSerial& get_instance(usart::USART_Base Base, pin_size_t rxPin = NO_PIN, pin_size_t txPin = NO_PIN); + + void begin(unsigned long baudrate, uint16_t config); + inline void begin(unsigned long baudrate) { begin(baudrate, SERIAL_8N1); } + void updateRxDmaBuffer(); + + #if DISABLED(SERIAL_DMA) + FORCE_INLINE static uint8_t buffer_overruns() { return 0; } + #endif + + #if ENABLED(EMERGENCY_PARSER) + EmergencyParser::State emergency_state; + + // Accessor method to get the last received byte + uint8_t get_last_data() { return usart_.get_last_data(); } + + // Register the emergency callback + void register_emergency_callback(void (*callback)()); + #endif + +protected: + using UsartSerial::UsartSerial; +}; + +typedef Serial1Class MSerialT; +extern MSerialT MSerial0; +extern MSerialT MSerial1; +extern MSerialT MSerial2; +extern MSerialT MSerial3; +extern MSerialT MSerial4; diff --git a/Marlin/src/HAL/GD32_MFL/MinSerial.cpp b/Marlin/src/HAL/GD32_MFL/MinSerial.cpp new file mode 100644 index 0000000000..d5e8147798 --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/MinSerial.cpp @@ -0,0 +1,163 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#include "../platforms.h" + +#ifdef ARDUINO_ARCH_MFL + +#include "../../inc/MarlinConfigPre.h" + +#if ENABLED(POSTMORTEM_DEBUGGING) +#include "../shared/MinSerial.h" + +// Base addresses for USART peripherals +static constexpr uintptr_t USART_base[] = { + 0x40013800, // USART0 + 0x40004400, // USART1 + 0x40004800, // USART2 + 0x40004C00, // UART3 + 0x40005000 // UART4 +}; + +// Register offsets +static constexpr uint32_t STAT0_OFFSET = 0x00U; +static constexpr uint32_t DATA_OFFSET = 0x04U; +static constexpr uint32_t BAUD_OFFSET = 0x08U; +static constexpr uint32_t CTL0_OFFSET = 0x0CU; +static constexpr uint32_t CTL1_OFFSET = 0x14U; + +// Bit positions +static constexpr uint32_t TBE_BIT = 7; +static constexpr uint32_t TEN_BIT = 3; +static constexpr uint32_t UEN_BIT = 13; + +// NVIC interrupt numbers for USART +static constexpr int nvicUART[] = { 37, 38, 39, 52, 53 }; + +// RCU PCLK values for USART +static constexpr rcu::RCU_PCLK clockRegs[] = { + rcu::RCU_PCLK::PCLK_USART0, + rcu::RCU_PCLK::PCLK_USART1, + rcu::RCU_PCLK::PCLK_USART2, + rcu::RCU_PCLK::PCLK_UART3, + rcu::RCU_PCLK::PCLK_UART4 +}; + +// Memory barrier instructions +#define isb() __asm__ __volatile__ ("isb" : : : "memory") +#define dsb() __asm__ __volatile__ ("dsb" : : : "memory") +#define sw_barrier() __asm__ volatile("" : : : "memory") + +// Direct register access macros +#define USART_REG(offset) (*(volatile uint32_t*)(USART_base[SERIAL_PORT] + (offset))) +#define USART_STAT0 USART_REG(STAT0_OFFSET) +#define USART_DATA USART_REG(DATA_OFFSET) +#define USART_BAUD USART_REG(BAUD_OFFSET) +#define USART_CTL0 USART_REG(CTL0_OFFSET) +#define USART_CTL1 USART_REG(CTL1_OFFSET) + +// Bit manipulation macros +#define READ_BIT(reg, bit) (((reg) >> (bit)) & 1U) +#define SET_BIT(reg, bit) ((reg) |= (1U << (bit))) +#define CLEAR_BIT(reg, bit) ((reg) &= ~(1U << (bit))) + +// Initializes the MinSerial interface. +// This function sets up the USART interface for serial communication. +// If the selected serial port is not a hardware port, it disables the severe error reporting feature. +static void MinSerialBegin() { + #if !WITHIN(SERIAL_PORT, 0, 4) + #warning "Using POSTMORTEM_DEBUGGING requires a physical U(S)ART hardware in case of severe error." + #warning "Disabling the severe error reporting feature currently because the used serial port is not a HW port." + #else + int nvicIndex = nvicUART[SERIAL_PORT]; + + // NVIC base address for interrupt disable + struct NVICMin { + volatile uint32_t ISER[32]; + volatile uint32_t ICER[32]; + }; + NVICMin *nvicBase = (NVICMin*)0xE000E100; + + SBI32(nvicBase->ICER[nvicIndex >> 5], nvicIndex & 0x1F); + + // We require memory barriers to properly disable interrupts + // (https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the) + dsb(); + isb(); + + // Get the RCU PCLK for this USART + rcu::RCU_PCLK pclk = clockRegs[SERIAL_PORT]; + + // Disable then enable usart peripheral clocks + rcu::RCU_DEVICE.set_pclk_enable(pclk, false); + rcu::RCU_DEVICE.set_pclk_enable(pclk, true); + + // Save current baudrate + uint32_t baudrate = USART_BAUD; + + // Reset USART control registers + USART_CTL0 = 0; + USART_CTL1 = 0; // 1 stop bit + + // Restore baudrate + USART_BAUD = baudrate; + + // Enable transmitter and USART (8 bits, no parity, 1 stop bit) + SET_BIT(USART_CTL0, TEN_BIT); + SET_BIT(USART_CTL0, UEN_BIT); + #endif +} + +// Writes a single character to the serial port. +static void MinSerialWrite(char c) { + #if WITHIN(SERIAL_PORT, 0, 4) + // Wait until transmit buffer is empty + while (!READ_BIT(USART_STAT0, TBE_BIT)) { + hal.watchdog_refresh(); + sw_barrier(); + } + // Write character to data register + USART_DATA = c; + #endif +} + +// Installs the minimum serial interface. +// Sets the HAL_min_serial_init and HAL_min_serial_out function pointers to MinSerialBegin and MinSerialWrite respectively. +void install_min_serial() { + HAL_min_serial_init = &MinSerialBegin; + HAL_min_serial_out = &MinSerialWrite; +} + +extern "C" { + // A low-level assembly-based jump handler. + // Unconditionally branches to the CommonHandler_ASM function. + __attribute__((naked, aligned(4))) void JumpHandler_ASM() { + __asm__ __volatile__ ("b CommonHandler_ASM\n"); + } + void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) HardFault_Handler(); + void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) BusFault_Handler(); + void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) UsageFault_Handler(); + void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) MemManage_Handler(); + void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) NMI_Handler(); +} + +#endif // POSTMORTEM_DEBUGGING +#endif // ARDUINO_ARCH_MFL diff --git a/Marlin/src/HAL/GD32_MFL/README.md b/Marlin/src/HAL/GD32_MFL/README.md new file mode 100644 index 0000000000..af23a37f2f --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/README.md @@ -0,0 +1,8 @@ +# Generic GD32 HAL based on the MFL Arduino Core + +This HAL is eventually intended to act as the generic HAL for all GD32 chips using the MFL library. + +Currently it supports: + * GD32F303RET6 + +Targeting the official [MFL Arduino Core](https://github.com/bnmguy/ArduinoCore_MFL). diff --git a/Marlin/src/HAL/GD32_MFL/SDCard.cpp b/Marlin/src/HAL/GD32_MFL/SDCard.cpp new file mode 100644 index 0000000000..15d33d2596 --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/SDCard.cpp @@ -0,0 +1,1022 @@ +// +// MFL gd32f30x SDCARD using DMA through SDIO in C++ +// +// Copyright (C) 2025 B. Mourit +// +// This software is free software: you can redistribute it and/or modify it under the terms of the +// GNU Lesser General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License along with this software. +// If not, see . +// + +#include "../platforms.h" + +#ifdef ARDUINO_ARCH_MFL + +#include "../../inc/MarlinConfig.h" +#include "../shared/Delay.h" + +#include "SDCard.h" +#include +#include + +namespace sdio { + +CardDMA& CardDMA::get_instance() { + static CardDMA instance; + return instance; +} + +CardDMA::CardDMA() : + sdcard_csd_{0U, 0U, 0U, 0U}, + sdcard_cid_{0U, 0U, 0U, 0U}, + sdcard_scr_{0U, 0U}, + desired_clock_(Default_Desired_Clock), + stop_condition_(0U), + total_bytes_(0U), + count_(0U), + sdio_(SDIO::get_instance()), + config_(sdio_.get_config()), + dmaBase_(dma::DMA_Base::DMA1_BASE), + dmaChannel_(dma::DMA_Channel::CHANNEL3), + dma_(dma::DMA::get_instance(dmaBase_, dmaChannel_).value()), + sdcard_rca_(0U), + transfer_error_(SDIO_Error_Type::OK), + interface_version_(Interface_Version::UNKNOWN), + card_type_(Card_Type::UNKNOWN), + transfer_end_(false), + is_rx_(false), + multiblock_(false), + current_state_(Operational_State::READY) +{ +} + +// Initialize card and put in standby state +SDIO_Error_Type CardDMA::init() { + // Reset SDIO peripheral + sdio_.reset(); + sync_domains(); + + // Initialize SDIO peripheral + // If no SDIO_Config structure is provided the default is used. + // The default provides the parameters for initialization + // using a very low clock speed (typically <= 400KHz). + sdio_.init(); + sync_domains(); + + SDIO_Error_Type result = begin_startup_procedure(); + if (result != SDIO_Error_Type::OK) { + return result; + } + + return card_init(); +} + +// Startup command procedure according to SDIO specification +SDIO_Error_Type CardDMA::begin_startup_procedure() { + sdio_.set_power_mode(Power_Control::POWER_ON); + sdio_.set_clock_enable(true); + sync_domains(); + + // CMD0 (GO_IDLE_STATE) + if (send_command_and_check(Command_Index::CMD0, 0, Command_Response::RSP_NONE, Wait_Type::WT_NONE, [this]() { + return this->get_command_sent_result(); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::CMD0_FAILED; + } + + // CMD8 + if (send_command_and_check(Command_Index::CMD8, Check_Pattern, Command_Response::RSP_SHORT, Wait_Type::WT_NONE, [this]() { + return this->get_r7_result(); + }) != SDIO_Error_Type::OK) { + // V1.0 card + // CMD0 (GO_IDLE_STATE) + interface_version_ = Interface_Version::INTERFACE_V1_1; + if (send_command_and_check(Command_Index::CMD0, 0, Command_Response::RSP_NONE, Wait_Type::WT_NONE, [this]() { + return this->get_command_sent_result(); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::CMD0_FAILED; + } + } else { + // V2.0 card + // CMD55 + interface_version_ = Interface_Version::INTERFACE_V2_0; + if (send_command_and_check(Command_Index::CMD55, 0, Command_Response::RSP_SHORT, Wait_Type::WT_NONE, [this, cmd = Command_Index::CMD55]() { + return get_r1_result(cmd); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::CMD55_FAILED; + } + } + + if (send_command_and_check(Command_Index::CMD55, 0, Command_Response::RSP_SHORT, Wait_Type::WT_NONE, [this, cmd = Command_Index::CMD55]() { + return get_r1_result(cmd); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::CMD55_FAILED; + } + + return validate_voltage(); +} + +// Voltage validation +SDIO_Error_Type CardDMA::validate_voltage() { + uint32_t response = 0U; + uint32_t count = 0U; + bool valid_voltage = false; + + while ((count < Max_Voltage_Checks) && (valid_voltage == false)) { + if (send_command_and_check(Command_Index::CMD55, 0, Command_Response::RSP_SHORT, + Wait_Type::WT_NONE, [this, cmd = Command_Index::CMD55]() { + return get_r1_result(cmd); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::CMD55_FAILED; + } + + if (send_command_and_check(Command_Index::ACMD41, Voltage_Window | SDCARD_HCS | Switch_1_8V_Capacity, + Command_Response::RSP_SHORT, Wait_Type::WT_NONE, [this, cmd = Command_Index::INVALID, index = false, crc = true]() { + return check_sdio_status(cmd, index, crc); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::ACMD41_FAILED; + } + response = sdio_.get_response(Response_Type::RESPONSE0); + valid_voltage = (((response >> 31U) == 1U) ? true : false); + count++; + } + + if (count >= Max_Voltage_Checks) { + return SDIO_Error_Type::INVALID_VOLTAGE; + } + + card_type_ = (response & SDCARD_HCS) ? Card_Type::SDCARD_HIGH_CAPACITY : Card_Type::SDCARD_STANDARD_CAPACITY; + + #if ENABLED(MARLIN_DEV_MODE) + if (card_type_ == Card_Type::SDCARD_HIGH_CAPACITY) { + SERIAL_ECHOPGM("\n SDHC!"); + } else { + SERIAL_ECHOPGM("\n SDSC!"); + } + #endif + + return SDIO_Error_Type::OK; +} + +// Shutdown +void CardDMA::begin_shutdown_procedure() { + sdio_.set_power_mode(Power_Control::POWER_OFF); +} + +// Initialize card +SDIO_Error_Type CardDMA::card_init() { + if (sdio_.get_power_mode() == static_cast(Power_Control::POWER_OFF)) { + return SDIO_Error_Type::INVALID_OPERATION; + } + + // Skip CID/RCA for IO cards + if (card_type_ != Card_Type::SD_IO_CARD) { + if (send_command_and_check(Command_Index::CMD2, 0U, Command_Response::RSP_LONG, Wait_Type::WT_NONE, + [this, cmd = Command_Index::INVALID, index = false, crc = true]() { + return check_sdio_status(cmd, index, crc); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::CMD2_FAILED; + } + // Store CID + store_cid(); + + // Get RCA + uint16_t r6_rca; + if (send_command_and_check(Command_Index::CMD3, 0U, Command_Response::RSP_SHORT, Wait_Type::WT_NONE, + [this, cmd = Command_Index::CMD3, rca = &r6_rca]() { + return get_r6_result(cmd, rca); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::CMD3_FAILED; + } + // Store RCA + sdcard_rca_ = r6_rca; + if (send_command_and_check(Command_Index::CMD9, static_cast(sdcard_rca_ << RCA_Shift), + Command_Response::RSP_LONG, Wait_Type::WT_NONE, + [this, cmd = Command_Index::INVALID, index = false, crc = true]() { + return check_sdio_status(cmd, index, crc); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::CMD9_FAILED; + } + // Store CSD + store_csd(); + } + + Card_Info card_info; + SDIO_Error_Type result = get_card_specific_data(&card_info); + if (result != SDIO_Error_Type::OK) { + return result; + } + + if (select_deselect() != SDIO_Error_Type::OK) { + return SDIO_Error_Type::SELECT_DESELECT_FAILED; + } + + return SDIO_Error_Type::OK; +} + +SDIO_Error_Type CardDMA::store_cid() { + // Store the CID register values + sdcard_cid_[0] = sdio_.get_response(Response_Type::RESPONSE0); + sdcard_cid_[1] = sdio_.get_response(Response_Type::RESPONSE1); + sdcard_cid_[2] = sdio_.get_response(Response_Type::RESPONSE2); + sdcard_cid_[3] = sdio_.get_response(Response_Type::RESPONSE3); + + return SDIO_Error_Type::OK; +} + +SDIO_Error_Type CardDMA::store_csd() { + // Store the CSD register values + sdcard_csd_[0] = sdio_.get_response(Response_Type::RESPONSE0); + sdcard_csd_[1] = sdio_.get_response(Response_Type::RESPONSE1); + sdcard_csd_[2] = sdio_.get_response(Response_Type::RESPONSE2); + sdcard_csd_[3] = sdio_.get_response(Response_Type::RESPONSE3); + + return SDIO_Error_Type::OK; +} + +SDIO_Error_Type CardDMA::set_hardware_bus_width(Bus_Width width) { + if (card_type_ == Card_Type::SD_MMC || width == Bus_Width::WIDTH_8BIT) { + return SDIO_Error_Type::UNSUPPORTED_FUNCTION; + } + + // Retrieve SCR + SDIO_Error_Type result = get_scr(sdcard_rca_, sdcard_scr_); + if (result != SDIO_Error_Type::OK) { + return result; + } + + // Check and set bus width + // This function is only used to set a higher width than the default 1bit + // so no 1bit configuration logic is required. + if (width == Bus_Width::WIDTH_4BIT) { + // Send CMD55 (APP_CMD) + if (send_command_and_check(Command_Index::CMD55, static_cast(sdcard_rca_ << RCA_Shift), Command_Response::RSP_SHORT, + Wait_Type::WT_NONE, [this, cmd = Command_Index::CMD55]() { + return get_r1_result(cmd); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::CMD55_FAILED; + } + + // Send ACMD6 (SET_BUS_WIDTH) + if (send_command_and_check(Command_Index::ACMD6, 2U, Command_Response::RSP_SHORT, + Wait_Type::WT_NONE, [this, cmd = Command_Index::ACMD6]() { + return get_r1_result(cmd); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::ACMD6_FAILED; + } + + #if ENABLED(MARLIN_DEV_MODE) + SERIAL_ECHOPGM("\n wide bus set!"); + #endif + sdio_.set_bus_width(Bus_Width::WIDTH_4BIT); + + return SDIO_Error_Type::OK; + } + + return SDIO_Error_Type::UNSUPPORTED_FUNCTION; +} + +SDIO_Error_Type CardDMA::read(uint8_t* buf, uint32_t address, uint32_t count) { + if (current_state_ == Operational_State::READY) { + transfer_error_ = SDIO_Error_Type::OK; + current_state_ = Operational_State::BUSY; + is_rx_ = true; + multiblock_ = (count > 1); + + sdio_.clear_data_state_machine(Transfer_Direction::CARD_TO_SDIO); + + // Enable the interrupts + sdio_.set_interrupt_enable(Interrupt_Type::DTCRCERRIE, true); + sdio_.set_interrupt_enable(Interrupt_Type::DTTMOUTIE, true); + sdio_.set_interrupt_enable(Interrupt_Type::RXOREIE, true); + sdio_.set_interrupt_enable(Interrupt_Type::DTENDIE, true); + sdio_.set_interrupt_enable(Interrupt_Type::STBITEIE, true); + + total_bytes_ = BLOCK_SIZE * count; + + // Set DMA transfer parameters + set_dma_parameters(buf, (total_bytes_ / 4U), false); + sdio_.set_dma_enable(true); + + if (card_type_ != Card_Type::SDCARD_HIGH_CAPACITY) { + address *= 512U; + } + + // CMD16 set card block size + if (send_command_and_check(Command_Index::CMD16, BLOCK_SIZE, Command_Response::RSP_SHORT, + Wait_Type::WT_NONE, [this, cmd = Command_Index::CMD16]() { + return get_r1_result(cmd); + }) != SDIO_Error_Type::OK) { + sdio_.clear_multiple_interrupt_flags(clear_common_flags); + current_state_ = Operational_State::READY; + return SDIO_Error_Type::CMD16_FAILED; + } + + Block_Size block_size = get_data_block_size_index(BLOCK_SIZE); + + sdio_.set_data_state_machine_and_send(Data_Timeout, total_bytes_, block_size, + Transfer_Mode::BLOCK, Transfer_Direction::CARD_TO_SDIO, true); + + // CMD17/CMD18 (READ_SINGLE_BLOCK/READ_MULTIPLE_BLOCKS) send read command + Command_Index read_cmd = (count > 1U) ? Command_Index::CMD18 : Command_Index::CMD17; + if (send_command_and_check(read_cmd, address, + Command_Response::RSP_SHORT, Wait_Type::WT_NONE, [this, cmd = read_cmd]() { + return get_r1_result(cmd); + }) != SDIO_Error_Type::OK) { + sdio_.clear_multiple_interrupt_flags(clear_common_flags); + current_state_ = Operational_State::READY; + return (count > 1U) ? SDIO_Error_Type::CMD18_FAILED : SDIO_Error_Type::CMD17_FAILED; + } + return SDIO_Error_Type::OK; + } else { + return SDIO_Error_Type::BUSY; + } +} + +SDIO_Error_Type CardDMA::write(uint8_t* buf, uint32_t address, uint32_t count) { + // Enable the interrupts + sdio_.set_interrupt_enable(Interrupt_Type::DTCRCERRIE, true); + sdio_.set_interrupt_enable(Interrupt_Type::DTTMOUTIE, true); + sdio_.set_interrupt_enable(Interrupt_Type::STBITEIE, true); + sdio_.set_interrupt_enable(Interrupt_Type::TXUREIE, true); + + if (card_type_ != Card_Type::SDCARD_HIGH_CAPACITY) { + address *= 512U; + } + + // CMD16 + if (send_command_and_check(Command_Index::CMD16, BLOCK_SIZE, Command_Response::RSP_SHORT, + Wait_Type::WT_NONE, [this, cmd = Command_Index::CMD16]() { + return get_r1_result(cmd); + }) != SDIO_Error_Type::OK) { + sdio_.clear_multiple_interrupt_flags(clear_common_flags); + return SDIO_Error_Type::CMD16_FAILED; + } + + // CMD25/CMD24 (WRITE_MULTIPLE_BLOCK/WRITE_BLOCK) send write command + Command_Index write_cmd = (count > 1U) ? Command_Index::CMD25 : Command_Index::CMD24; + if (send_command_and_check(write_cmd, address, Command_Response::RSP_SHORT, + Wait_Type::WT_NONE, [this, cmd = write_cmd]() { + return get_r1_result(cmd); + }) != SDIO_Error_Type::OK) { + sdio_.clear_multiple_interrupt_flags(clear_common_flags); + return (count > 1U) ? SDIO_Error_Type::CMD25_FAILED : SDIO_Error_Type::CMD24_FAILED; + } + + total_bytes_ = BLOCK_SIZE * count; + // Start DMA transfer + set_dma_parameters(buf, (total_bytes_ / 4U), true); + sdio_.set_dma_enable(true); + + sdio_.clear_data_state_machine(Transfer_Direction::SDIO_TO_CARD); + Block_Size block_size = get_data_block_size_index(total_bytes_); + + sdio_.set_data_state_machine_and_send(Data_Timeout, total_bytes_, block_size, + Transfer_Mode::BLOCK, Transfer_Direction::SDIO_TO_CARD, true); + + while ((dma_.get_flag(dma::Status_Flags::FLAG_FTFIF)) || (dma_.get_flag(dma::Status_Flags::FLAG_ERRIF))) { + // Wait for the IRQ handler to clear + } + + return SDIO_Error_Type::OK; +} + +SDIO_Error_Type CardDMA::erase(uint32_t address_start, uint32_t address_end) { + SDIO_Error_Type result = SDIO_Error_Type::OK; + + // Card command classes CSD + uint8_t temp_byte = static_cast((sdcard_csd_[1] & (0xFFU << 24U)) >> 24U); + uint16_t classes = static_cast(temp_byte << 4U); + temp_byte = static_cast((sdcard_csd_[1] & (0xFFU << 16U)) >> 16U); + classes |= static_cast((temp_byte & 0xF0U) >> 4U); + + if ((classes & (1U << static_cast(Card_Command_Class::ERASE))) == Clear) { + return SDIO_Error_Type::UNSUPPORTED_FUNCTION; + } + + uint32_t delay_time = 120000U / sdio_.get_clock_divider(); + + if (sdio_.get_response(Response_Type::RESPONSE0) & Card_Locked) { + return SDIO_Error_Type::LOCK_UNLOCK_FAILED; + } + + // Size is fixed at 512 bytes for SDHC + if (card_type_ != Card_Type::SDCARD_HIGH_CAPACITY) { + address_start *= 512U; + address_end *= 512U; + } + + if ((card_type_ == Card_Type::SDCARD_STANDARD_CAPACITY) || (card_type_ == Card_Type::SDCARD_HIGH_CAPACITY)) { + // CMD32 (ERASE_WR_BLK_START) + if (send_command_and_check(Command_Index::CMD32, address_start, Command_Response::RSP_SHORT, + Wait_Type::WT_NONE, [this, cmd = Command_Index::CMD32]() { + return get_r1_result(cmd); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::CMD32_FAILED; + } + // CMD33 (ERASE_WR_BLK_END) + if (send_command_and_check(Command_Index::CMD33, address_end, Command_Response::RSP_SHORT, + Wait_Type::WT_NONE, [this, cmd = Command_Index::CMD33]() { + return get_r1_result(cmd); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::CMD33_FAILED; + } + } + + // CMD38 (ERASE) + if (send_command_and_check(Command_Index::CMD38, 0U, Command_Response::RSP_SHORT, + Wait_Type::WT_NONE, [this, cmd = Command_Index::CMD38]() { + return get_r1_result(cmd); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::CMD38_FAILED; + } + + // Loop until the counter reaches the calculated time + for (uint32_t count = 0U; count < delay_time; count++) {} + + Card_State card_state; + result = get_card_state(&card_state); + while ((result == SDIO_Error_Type::OK) && ((card_state == Card_State::PROGRAMMING) || (card_state == Card_State::RECEIVE_DATA))) { + result = get_card_state(&card_state); + } + + return result; +} + +void CardDMA::handle_interrupts() { + transfer_error_ = SDIO_Error_Type::OK; + + if (sdio_.get_interrupt_flag(Interrupt_Flags::FLAG_INTR_DTEND)) { + sdio_.clear_interrupt_flag(Clear_Flags::FLAG_DTENDC); + // Disable all interrupts + disable_all_interrupts(); + sdio_.set_data_state_machine_enable(false); + + if ((multiblock_) && (!is_rx_)) { + transfer_error_ = stop_transfer(); + if (transfer_error_ != SDIO_Error_Type::OK) {} + } + + if (!is_rx_) { + sdio_.set_dma_enable(false); + current_state_ = Operational_State::READY; + } + } else if (sdio_.get_interrupt_flag(Interrupt_Flags::FLAG_INTR_DTCRCERR) || + sdio_.get_interrupt_flag(Interrupt_Flags::FLAG_INTR_DTTMOUT) || + sdio_.get_interrupt_flag(Interrupt_Flags::FLAG_INTR_STBITE) || + sdio_.get_interrupt_flag(Interrupt_Flags::FLAG_INTR_TXURE) || + sdio_.get_interrupt_flag(Interrupt_Flags::FLAG_INTR_RXORE)) { + + if (sdio_.get_interrupt_flag(Interrupt_Flags::FLAG_INTR_DTCRCERR)) { + transfer_error_ = SDIO_Error_Type::DATA_CRC_ERROR; + } + if (sdio_.get_interrupt_flag(Interrupt_Flags::FLAG_INTR_DTTMOUT)) { + transfer_error_ = SDIO_Error_Type::DATA_TIMEOUT; + } + if (sdio_.get_interrupt_flag(Interrupt_Flags::FLAG_INTR_STBITE)) { + transfer_error_ = SDIO_Error_Type::START_BIT_ERROR; + } + if (sdio_.get_interrupt_flag(Interrupt_Flags::FLAG_INTR_TXURE)) { + transfer_error_ = SDIO_Error_Type::TX_FIFO_UNDERRUN; + } + if (sdio_.get_interrupt_flag(Interrupt_Flags::FLAG_INTR_RXORE)) { + transfer_error_ = SDIO_Error_Type::RX_FIFO_OVERRUN; + } + sdio_.clear_multiple_interrupt_flags(clear_data_flags); + sdio_.clear_interrupt_flag(Clear_Flags::FLAG_STBITEC); + disable_all_interrupts(); + + dma_.set_transfer_abandon(); + } +} + +SDIO_Error_Type CardDMA::select_deselect() { + // CMD7 (SELECT/DESELECT_CARD) + if (send_command_and_check(Command_Index::CMD7, static_cast(sdcard_rca_ << RCA_Shift), + Command_Response::RSP_SHORT, Wait_Type::WT_NONE, [this, cmd = Command_Index::CMD7]() { + return get_r1_result(cmd); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::CMD7_FAILED; + } + return SDIO_Error_Type::OK; +} + +SDIO_Error_Type CardDMA::get_card_interface_status(uint32_t* status) { + if (status == nullptr) return SDIO_Error_Type::INVALID_PARAMETER; + + // CMD13 (SEND_STATUS) + if (send_command_and_check(Command_Index::CMD13, static_cast(sdcard_rca_ << RCA_Shift), + Command_Response::RSP_SHORT, Wait_Type::WT_NONE, [this, cmd = Command_Index::CMD13]() { + return get_r1_result(cmd); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::CMD13_FAILED; + } + + *status = sdio_.get_response(Response_Type::RESPONSE0); + + return SDIO_Error_Type::OK; +} + +SDIO_Error_Type CardDMA::get_sdcard_status(uint32_t* status) { + uint32_t count = 0U; + + // CMD16 (SET_BLOCKLEN) + if (send_command_and_check(Command_Index::CMD16, 64U, + Command_Response::RSP_SHORT, Wait_Type::WT_NONE, [this, cmd = Command_Index::CMD16]() { + return get_r1_result(cmd); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::CMD16_FAILED; + } + + // CMD55 (APP_CMD) + if (send_command_and_check(Command_Index::CMD55, static_cast(sdcard_rca_ << RCA_Shift), + Command_Response::RSP_SHORT, Wait_Type::WT_NONE, [this, cmd = Command_Index::CMD55]() { + return get_r1_result(cmd); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::CMD55_FAILED; + } + + sdio_.set_data_state_machine_and_send(Data_Timeout, 64U, Block_Size::BYTES_64, Transfer_Mode::BLOCK, Transfer_Direction::CARD_TO_SDIO, true); + + // ACMD13 (SD_STATUS) + if (send_command_and_check(Command_Index::ACMD13, 0U, + Command_Response::RSP_SHORT, Wait_Type::WT_NONE, [this, cmd = Command_Index::ACMD13]() { + return get_r1_result(cmd); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::ACMD13_FAILED; + } + + while (!sdio_.check_scr_flags()) { + if (sdio_.get_flag(Status_Flags::FLAG_RFH)) { + for (count = 0U; count < FIFO_Half_Words; count++) { + *(status + count) = sdio_.read_fifo_word(); + } + status += FIFO_Half_Words; + } + + //SDIO_Error_Type result = SDIO_Error_Type::OK; + if (sdio_.get_flag(Status_Flags::FLAG_DTCRCERR)) { + sdio_.clear_flag(Clear_Flags::FLAG_DTCRCERRC); + return SDIO_Error_Type::DATA_CRC_ERROR; + } else if (sdio_.get_flag(Status_Flags::FLAG_DTTMOUT)) { + sdio_.clear_flag(Clear_Flags::FLAG_DTTMOUTC); + return SDIO_Error_Type::DATA_TIMEOUT; + } else if (sdio_.get_flag(Status_Flags::FLAG_RXORE)) { + sdio_.clear_flag(Clear_Flags::FLAG_RXOREC); + return SDIO_Error_Type::RX_FIFO_OVERRUN; + } else if (sdio_.get_flag(Status_Flags::FLAG_STBITE)) { + sdio_.clear_flag(Clear_Flags::FLAG_STBITEC); + return SDIO_Error_Type::START_BIT_ERROR; + } + while (sdio_.get_flag(Status_Flags::FLAG_RXDTVAL)) { + *status = sdio_.read_fifo_word(); + ++status; + } + + sdio_.clear_multiple_interrupt_flags(clear_data_flags); + status -= 16U; + for (count = 0U; count < 16U; count++) { + status[count] = ((status[count] & 0xFFU) << 24U) | + ((status[count] & (0xFFU << 8U)) << 8U) | + ((status[count] & (0xFFU << 16U)) >> 8U) | + ((status[count] & (0xFFU << 24U)) >> 24U); + } + } + + return SDIO_Error_Type::OK; +} + +void CardDMA::check_dma_complete() { + while ((dma_.get_flag(dma::Status_Flags::FLAG_FTFIF)) || (dma_.get_flag(dma::Status_Flags::FLAG_ERRIF))) { + // Wait for the IRQ handler to clear + } +} + +SDIO_Error_Type CardDMA::stop_transfer() { + // CMD12 (STOP_TRANSMISSION) + if (send_command_and_check(Command_Index::CMD12, 0, Command_Response::RSP_SHORT, Wait_Type::WT_NONE, [this, cmd = Command_Index::CMD12]() { + return get_r1_result(cmd); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::CMD12_FAILED; + } + return SDIO_Error_Type::OK; +} + +Transfer_State CardDMA::get_transfer_state() { + Transfer_State transfer_state = Transfer_State::IDLE; + if (sdio_.get_flag(Status_Flags::FLAG_TXRUN) | sdio_.get_flag(Status_Flags::FLAG_RXRUN)) { + transfer_state = Transfer_State::BUSY; + } + + return transfer_state; +} + +uint32_t CardDMA::get_card_capacity() const { + auto extract_bits = [](uint32_t value, uint8_t start_bit, uint8_t length) -> uint32_t { + return (value >> start_bit) & ((1U << length) - 1U); + }; + + uint32_t capacity = 0U; + uint32_t device_size = 0U; + + if (card_type_ == Card_Type::SDCARD_STANDARD_CAPACITY) { + // Extract fields from CSD data using bit manipulation + uint8_t device_size_high = static_cast(extract_bits(sdcard_csd_[1], 8U, 2U)); // Bits [73:72] + uint8_t device_size_mid = static_cast(extract_bits(sdcard_csd_[1], 0U, 8U)); // Bits [71:64] + uint8_t device_size_low = static_cast(extract_bits(sdcard_csd_[2], 24U, 2U)); // Bits [63:62] + + device_size = static_cast((device_size_high) << 10U) | + static_cast((device_size_mid) << 2U) | + static_cast((device_size_low)); + + uint8_t device_size_multiplier_high = static_cast(extract_bits(sdcard_csd_[2], 16U, 2U)); // Bits [49:48] + uint8_t device_size_multiplier_low = static_cast(extract_bits(sdcard_csd_[2], 8U, 1U)); // Bit [47] + uint8_t device_size_multiplier = static_cast((device_size_multiplier_high << 1U) | device_size_multiplier_low); + uint8_t read_block_length = static_cast(extract_bits(sdcard_csd_[1], 16U, 4U)); // Bits [83:80] + + // Capacity = (device_size + 1) * MULT * BLOCK_LEN + uint32_t mult = static_cast(1U << (device_size_multiplier + 2U)); // MULT = 2 ^ (C_SIZE_MULT + 2) + uint32_t block_length = static_cast(1U << read_block_length); // BLOCK_LEN = 2 ^ READ_BL_LEN + + capacity = (device_size + 1U) * mult * block_length; + capacity /= KILOBYTE; // Convert capacity to kilobytes + + } else if (card_type_ == Card_Type::SDCARD_HIGH_CAPACITY) { + // High-capacity card calculation + uint8_t device_size_high = static_cast(extract_bits(sdcard_csd_[1], 0U, 6U)); // Bits [69:64] + uint8_t device_size_mid = static_cast(extract_bits(sdcard_csd_[2], 24U, 8U)); // Bits [55:48] + uint8_t device_size_low = static_cast(extract_bits(sdcard_csd_[2], 16U, 8U)); // Bits [47:40] + + device_size = static_cast((device_size_high) << 16U) | + static_cast((device_size_mid) << 8U) | + static_cast(device_size_low); + + // Capacity in kilobytes + capacity = (device_size + 1U) * BLOCK_SIZE; + } + + return capacity; +} + +SDIO_Error_Type CardDMA::get_card_specific_data(Card_Info* info) { + if (info == nullptr) return SDIO_Error_Type::INVALID_PARAMETER; + + // Store basic card information + info->type = card_type_; + info->relative_address = sdcard_rca_; + + // Helper function to convert 32-bit registers to byte array + auto convert_registers_to_bytes = [](const uint32_t* registers, uint8_t* bytes, size_t reg_count) { + for (size_t i = 0U; i < reg_count; ++i) { + for (size_t j = 0U; j < 4U; ++j) { + bytes[i * 4U + j] = (registers[i] >> (24U - j * 8U)) & 0xFFU; + } + } + }; + + // Process CID data + uint8_t cid_bytes[16]; + convert_registers_to_bytes(sdcard_cid_, cid_bytes, 4); + + info->cid = { + .manufacture_id = cid_bytes[0], + .oem_id = static_cast( + (cid_bytes[1] << 8U) | + cid_bytes[2] + ), + .name0 = static_cast( + (cid_bytes[3] << 24U) | + (cid_bytes[4] << 16U) | + (cid_bytes[5] << 8U) | + cid_bytes[6] + ), + .name1 = cid_bytes[7], + .revision = cid_bytes[8], + .serial_number = static_cast( + (cid_bytes[9] << 24U) | + (cid_bytes[10] << 16U) | + (cid_bytes[11] << 8U) | + cid_bytes[12] + ), + .manufacture_date = static_cast( + ((cid_bytes[13] & 0x0FU) << 8U) | + cid_bytes[14] + ), + .checksum = static_cast(((cid_bytes[15] & 0xFEU) >> 1U)) + }; + + // Process CSD data + uint8_t csd_bytes[16]; + convert_registers_to_bytes(sdcard_csd_, csd_bytes, 4U); + + // Fill common CSD fields + info->csd = { + .transfer_speed = csd_bytes[3], + .card_command_class = static_cast((csd_bytes[4] << 4U) | ((csd_bytes[5] & 0xF0U) >> 4U)), + }; + + // Process card-type specific CSD fields and calculate capacity + if (card_type_ == Card_Type::SDCARD_STANDARD_CAPACITY) { + process_sdsc_specific_csd(info, csd_bytes); + } else if (card_type_ == Card_Type::SDCARD_HIGH_CAPACITY) { + process_sdhc_specific_csd(info, csd_bytes); + } + + // Fill remaining common CSD fields + process_common_csd_tail(info, csd_bytes); + + return SDIO_Error_Type::OK; +} + +constexpr Block_Size CardDMA::get_data_block_size_index(uint16_t size) { + switch (size) { + case 1: return Block_Size::BYTES_1; + case 2: return Block_Size::BYTES_2; + case 4: return Block_Size::BYTES_4; + case 8: return Block_Size::BYTES_8; + case 16: return Block_Size::BYTES_16; + case 32: return Block_Size::BYTES_32; + case 64: return Block_Size::BYTES_64; + case 128: return Block_Size::BYTES_128; + case 256: return Block_Size::BYTES_256; + case 512: return Block_Size::BYTES_512; + case 1024: return Block_Size::BYTES_1024; + case 2048: return Block_Size::BYTES_2048; + case 4096: return Block_Size::BYTES_4096; + case 8192: return Block_Size::BYTES_8192; + case 16384: return Block_Size::BYTES_16384; + default: return Block_Size::BYTES_1; + } +} + +SDIO_Error_Type CardDMA::get_card_state(Card_State* card_state) { + // CMD13 (SEND_STATUS) + if (send_command_and_check(Command_Index::CMD13, static_cast(sdcard_rca_ << RCA_Shift), + Command_Response::RSP_SHORT, Wait_Type::WT_NONE, [this, cmd = Command_Index::CMD13]() { + return get_r1_result(cmd); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::CMD13_FAILED; + } + + uint32_t response = sdio_.get_response(Response_Type::RESPONSE0); + *card_state = static_cast((response >> 9U) & CardStateMask); + if ((response & All_R1_Error_Bits) == 0U) { + return SDIO_Error_Type::OK; + } + + if (response & All_R1_Error_Bits) { + for (const auto& entry : errorTableR1) { + if (response & entry.mask) { + return entry.errorType; + } + } + return SDIO_Error_Type::ERROR; + } + + return SDIO_Error_Type::OK; +} + +SDIO_Error_Type CardDMA::get_command_sent_result() { + volatile uint32_t timeout = 0x00FFFFFFU; + + while ((sdio_.get_flag(Status_Flags::FLAG_CMDSEND) == false) && (timeout != 0U)) { + timeout = timeout - 1U; + } + if (timeout == 0U) return SDIO_Error_Type::RESPONSE_TIMEOUT; + sdio_.clear_multiple_interrupt_flags(clear_command_flags); + + return SDIO_Error_Type::OK; +} + +SDIO_Error_Type CardDMA::check_sdio_status(Command_Index index, bool check_index, bool ignore_crc) { + // Wait until one of the relevant flags is set + bool flag_set = sdio_.wait_cmd_flags(); + + if (!flag_set) { + return SDIO_Error_Type::RESPONSE_TIMEOUT; + } + + // Check the cmd received bit first, since noise can sometimes + // cause the timeout bit to get erroneously set + // If cmd was received we can safely ignore other checks + if (sdio_.get_flag(Status_Flags::FLAG_CMDRECV)) { + // If cmd was received, check the index + // Responses that dont do an index check will send an invalid cmd index + if (check_index && (index != Command_Index::INVALID)) { + uint8_t idx = sdio_.get_command_index(); + if (idx != static_cast(index)) { + return SDIO_Error_Type::ILLEGAL_COMMAND; + } + } + // Clear all flags before returning + sdio_.clear_multiple_interrupt_flags(clear_command_flags); + return SDIO_Error_Type::OK; + } + + // Timeout check + if (sdio_.get_flag(Status_Flags::FLAG_CMDTMOUT)) { + sdio_.clear_flag(Clear_Flags::FLAG_CMDTMOUTC); + return SDIO_Error_Type::RESPONSE_TIMEOUT; + } + + // CRC check + if (!ignore_crc) { + if (sdio_.get_flag(Status_Flags::FLAG_CCRCERR)) { + sdio_.clear_flag(Clear_Flags::FLAG_CCRCERRC); + return SDIO_Error_Type::COMMAND_CRC_ERROR; + } + } + + // Responses that dont do an index check will send an invalid cmd index + if (check_index && (index != Command_Index::INVALID)) { + uint8_t idx = sdio_.get_command_index(); + if (idx != static_cast(index)) { + return SDIO_Error_Type::ILLEGAL_COMMAND; + } + } + + // Clear all flags before returning + sdio_.clear_multiple_interrupt_flags(clear_command_flags); + + return SDIO_Error_Type::OK; +} + +SDIO_Error_Type CardDMA::get_r1_result(Command_Index index) { + SDIO_Error_Type result = check_sdio_status(index, true, false); + if (result != SDIO_Error_Type::OK) { + return result; + } + + // Get the R1 response and check for errors + uint32_t response = sdio_.get_response(Response_Type::RESPONSE0); + + if (response & All_R1_Error_Bits) { + for (const auto& entry : errorTableR1) { + if (response & entry.mask) { + return entry.errorType; + } + } + return SDIO_Error_Type::ERROR; + } + + return SDIO_Error_Type::OK; +} + +SDIO_Error_Type CardDMA::get_r6_result(Command_Index index, uint16_t* rca) { + SDIO_Error_Type result = check_sdio_status(index, true, false); + if (result != SDIO_Error_Type::OK) return result; + + uint32_t response = sdio_.get_response(Response_Type::RESPONSE0); + + if (response & R6_Error_Bits) { + for (const auto& entry : errorTableR6) { + if (response & entry.mask) { + return entry.errorType; + } + } + return SDIO_Error_Type::ERROR; + } + *rca = static_cast(response >> 16U); + + return SDIO_Error_Type::OK; +} + +SDIO_Error_Type CardDMA::get_r7_result() { + return check_sdio_status(Command_Index::INVALID, false, false); +} + +SDIO_Error_Type CardDMA::get_scr(uint16_t rca, uint32_t* scr) { + uint32_t temp_scr[2] = {0U, 0U}; + uint32_t index_scr = 0U; + uint32_t* src_data = scr; + + // CMD16 (SET_BLOCKLEN) + if (send_command_and_check(Command_Index::CMD16, 8U, Command_Response::RSP_SHORT, + Wait_Type::WT_NONE, [this, cmd = Command_Index::CMD16]() { + return get_r1_result(cmd); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::CMD16_FAILED; + } + + // CMD55 (APP_CMD) + if (send_command_and_check(Command_Index::CMD55, static_cast(sdcard_rca_ << RCA_Shift), + Command_Response::RSP_SHORT, Wait_Type::WT_NONE, [this, cmd = Command_Index::CMD55]() { + return get_r1_result(cmd); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::CMD55_FAILED; + } + + // Set data parameters + sdio_.set_data_state_machine_and_send(Data_Timeout, 8U, Block_Size::BYTES_8, + Transfer_Mode::BLOCK, Transfer_Direction::CARD_TO_SDIO, true); + + // ACMD51 (SEND_SCR) + if (send_command_and_check(Command_Index::ACMD51, 0U, Command_Response::RSP_SHORT, + Wait_Type::WT_NONE, [this, cmd = Command_Index::ACMD51]() { + return get_r1_result(cmd); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::ACMD51_FAILED; + } + + // Store SCR + while (!sdio_.check_scr_flags()) { + if (sdio_.get_flag(Status_Flags::FLAG_RXDTVAL)) { + *(temp_scr + index_scr) = sdio_.read_fifo_word(); + ++index_scr; + } + } + + if (sdio_.get_flag(Status_Flags::FLAG_DTTMOUT)) { + sdio_.clear_flag(Clear_Flags::FLAG_DTTMOUTC); + return SDIO_Error_Type::DATA_TIMEOUT; + } else if (sdio_.get_flag(Status_Flags::FLAG_DTCRCERR)) { + sdio_.clear_flag(Clear_Flags::FLAG_DTCRCERRC); + return SDIO_Error_Type::DATA_CRC_ERROR; + } else if (sdio_.get_flag(Status_Flags::FLAG_RXORE)) { + sdio_.clear_flag(Clear_Flags::FLAG_RXOREC); + return SDIO_Error_Type::RX_FIFO_OVERRUN; + } + + sdio_.clear_multiple_interrupt_flags(clear_data_flags); + + constexpr uint32_t Zero_Seven = (0xFFU << 0U); + constexpr uint32_t Eight_Fifteen = (0xFFU << 8U); + constexpr uint32_t Sixteen_Twentythree = (0xFFU << 16U); + constexpr uint32_t TwentyFour_Thirtyone = (0xFFU << 24U); + + // adjust SCR value + *src_data = ((temp_scr[1] & Zero_Seven) << 24U) | ((temp_scr[1] & Eight_Fifteen) << 8U) | + ((temp_scr[1] & Sixteen_Twentythree) >> 8U) | ((temp_scr[1] & TwentyFour_Thirtyone) >> 24U); + + src_data = src_data + 1U; + *src_data = ((temp_scr[0] & Zero_Seven) << 24U) | ((temp_scr[0] & Eight_Fifteen) << 8U) | + ((temp_scr[0] & Sixteen_Twentythree) >> 8U) | ((temp_scr[0] & TwentyFour_Thirtyone) >> 24U); + + return SDIO_Error_Type::OK; +} + +// DMA for rx/tx is always DMA1 channel 3 +void CardDMA::set_dma_parameters(uint8_t* buf, uint32_t count, bool is_write) { + constexpr uint32_t flag_bits = (1U << static_cast(dma::INTF_Bits::GIF3)); + + dma_.clear_flags(flag_bits); + + // Disable and reset DMA + dma_.set_channel_enable(false); + dma_.clear_channel(); + + dma_.init({ + count, + static_cast(reinterpret_cast(buf)), + static_cast(reinterpret_cast(sdio_.reg_address(SDIO_Regs::FIFO))), + dma::Bit_Width::WIDTH_32BIT, + dma::Bit_Width::WIDTH_32BIT, + dma::Increase_Mode::INCREASE_DISABLE, + dma::Increase_Mode::INCREASE_ENABLE, + dma::Channel_Priority::MEDIUM_PRIORITY, + is_write ? dma::Transfer_Direction::M2P : dma::Transfer_Direction::P2M + }); + + dma_.set_memory_to_memory_enable(false); + dma_.set_circulation_mode_enable(false); + + // Enable DMA interrupts for transfer complete and error + dma_.set_interrupt_enable(dma::Interrupt_Type::INTR_FTFIE, true); + dma_.set_interrupt_enable(dma::Interrupt_Type::INTR_ERRIE, true); + + // Start the DMA channel + dma_.set_channel_enable(true); +} + +SDIO_Error_Type CardDMA::wait_for_card_ready() { + volatile uint32_t timeout = 0x00FFFFFFU; + uint32_t response = sdio_.get_response(Response_Type::RESPONSE0); + + while (((response & static_cast(R1_Status::READY_FOR_DATA)) == 0U) && (timeout != 0U)) { + // Continue to send CMD13 to poll the state of card until buffer empty or timeout + timeout = timeout - 1U; + // CMD13 (SEND_STATUS) + if (send_command_and_check(Command_Index::CMD13, static_cast(sdcard_rca_ << RCA_Shift), + Command_Response::RSP_SHORT, Wait_Type::WT_NONE, [this, cmd = Command_Index::CMD13]() { + return get_r1_result(cmd); + }) != SDIO_Error_Type::OK) { + return SDIO_Error_Type::CMD13_FAILED; + } + response = sdio_.get_response(Response_Type::RESPONSE0); + } + + return (timeout == 0U) ? SDIO_Error_Type::ERROR : SDIO_Error_Type::OK; +} + +} // namespace sdio + +sdio::CardDMA& CardDMA_I = sdio::CardDMA::get_instance(); + +#endif // ARDUINO_ARCH_MFL diff --git a/Marlin/src/HAL/GD32_MFL/SDCard.h b/Marlin/src/HAL/GD32_MFL/SDCard.h new file mode 100644 index 0000000000..b14063b69f --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/SDCard.h @@ -0,0 +1,214 @@ +// +// MFL gd32f30x SDCARD using DMA through SDIO in C++ +// +// Copyright (C) 2025 B. Mourit +// +// This software is free software: you can redistribute it and/or modify it under the terms of the +// GNU Lesser General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License along with this software. +// If not, see . +// +#pragma once + +#include "../../inc/MarlinConfig.h" + +#include "SDIO.hpp" + +namespace sdio { + +class DMA; + +class CardDMA { +public: + static CardDMA& get_instance(); + + SDIO_Error_Type init(); + SDIO_Error_Type card_init(); + SDIO_Error_Type begin_startup_procedure(); + void begin_shutdown_procedure(); + // Configuration + SDIO_Error_Type set_hardware_bus_width(Bus_Width width); + // Main read/write functions for single and multiblock transfers + SDIO_Error_Type read(uint8_t* buf, uint32_t address, uint32_t count); + SDIO_Error_Type write(uint8_t* buf, uint32_t address, uint32_t count); + // DMA transfers + // Other card functions + SDIO_Error_Type erase(uint32_t address_start, uint32_t address_end); + // Interrupt handler + void handle_interrupts(); + // Card select + SDIO_Error_Type select_deselect(); + + SDIO_Error_Type get_card_interface_status(uint32_t* status); + SDIO_Error_Type get_sdcard_status(uint32_t* status); + + void check_dma_complete(); + SDIO_Error_Type stop_transfer(); + + Transfer_State get_transfer_state(); + uint32_t get_card_capacity() const; + + SDIO_Error_Type send_bus_width_command(uint32_t width_value); + + SDIO_Error_Type get_card_specific_data(Card_Info* info); + constexpr Block_Size get_data_block_size_index(uint16_t size); + + SDIO_Error_Type get_card_state(Card_State* card_state); + SDIO_Error_Type check_sdio_status(Command_Index index = Command_Index::INVALID, bool check_index = false, bool ignore_crc = false); + + // DMA configuration + void set_dma_parameters(uint8_t* buf, uint32_t count, bool is_write); + + // SDIO configuration + void sdio_configure(const SDIO_Config config) { sdio_.init(config); } + + // Varaible stored parameters + SDIO_Error_Type get_scr(uint16_t rca, uint32_t* scr); + SDIO_Error_Type store_cid(); + SDIO_Error_Type store_csd(); + + // Accessor methods + SDIO_Config& get_config() { return config_; } + dma::DMA& get_dma_instance() { return dma_; } + void set_data_end_interrupt() { sdio_.set_interrupt_enable(Interrupt_Type::DTENDIE, true); } + void set_sdio_dma_enable(bool enable) { sdio_.set_dma_enable(enable); } + bool get_is_sdio_rx() { return is_rx_; } + void clear_sdio_data_flags() { sdio_.clear_multiple_interrupt_flags(clear_data_flags); } + void clear_sdio_cmd_flags() { sdio_.clear_multiple_interrupt_flags(clear_command_flags); } + void clear_sdio_common_flags() { sdio_.clear_multiple_interrupt_flags(clear_common_flags); } + Operational_State get_state() { return current_state_; } + void set_state(Operational_State state) { current_state_ = state; } + void set_transfer_end(bool value) { transfer_end_ = value; } + void set_transfer_error(SDIO_Error_Type error) { transfer_error_ = error; } + + inline SDIO_Error_Type set_desired_clock(uint32_t desired_clock, bool wide_bus, bool low_power) { + sdio_.init({ + desired_clock, + Clock_Edge::RISING_EDGE, + wide_bus ? Bus_Width::WIDTH_4BIT : Bus_Width::WIDTH_1BIT, + false, + low_power, + false + }); + sync_domains(); + desired_clock_ = desired_clock; + + return SDIO_Error_Type::OK; + } + +private: + CardDMA(); + + // Prevent copying or assigning + CardDMA(const CardDMA&) = delete; + CardDMA& operator=(const CardDMA&) = delete; + + // Helper function + SDIO_Error_Type wait_for_card_ready(); + + // Member variables + alignas(4) uint32_t sdcard_csd_[4]; + alignas(4) uint32_t sdcard_cid_[4]; + alignas(4) uint32_t sdcard_scr_[2]; + uint32_t desired_clock_; + uint32_t stop_condition_; + uint32_t total_bytes_; + uint32_t count_; + SDIO& sdio_; + SDIO_Config& config_; + const dma::DMA_Base dmaBase_; + const dma::DMA_Channel dmaChannel_; + dma::DMA& dma_; + uint16_t sdcard_rca_; + SDIO_Error_Type transfer_error_; + Interface_Version interface_version_; + Card_Type card_type_; + volatile bool transfer_end_; + volatile bool is_rx_; + volatile bool multiblock_; + volatile Operational_State current_state_; + + // Private helper methods + SDIO_Error_Type validate_voltage(); + SDIO_Error_Type get_r1_result(Command_Index index); + //SDIO_Error_Type get_r2_r3_result(); + SDIO_Error_Type get_r6_result(Command_Index index, uint16_t* rca); + SDIO_Error_Type get_r7_result(); + //SDIO_Error_Type get_r1_error_type(uint32_t response); + SDIO_Error_Type get_command_sent_result(); + + inline void sync_domains() { + delayMicroseconds(8); + } + + inline bool validate_transfer_params(uint32_t* buf, uint16_t size) { + if (buf == nullptr) return false; + // Size must be > 0, <= 2048 and power of 2 + if ((size == 0U) || (size > 2048U) || (size & (size - 1U))) { + return false; + } + return true; + } + + void process_sdsc_specific_csd(Card_Info* info, const uint8_t* csd_bytes) { + info->csd.device_size = (static_cast(csd_bytes[6] & 0x03U) << 10U) | + (static_cast(csd_bytes[7]) << 2U) | + (static_cast((csd_bytes[8] & 0xC0U) >> 6U)); + info->csd.device_size_multiplier = static_cast((csd_bytes[9] & 0x03U) << 1U | + (csd_bytes[10] & 0x80U) >> 7U); + + info->block_size = static_cast(1 << info->csd.read_block_length); + info->capacity = static_cast((info->csd.device_size + 1U) * + (1U << (info->csd.device_size_multiplier + 2U)) * + info->block_size); + } + + void process_sdhc_specific_csd(Card_Info* info, const uint8_t* csd_bytes) { + info->csd.device_size = static_cast((csd_bytes[7] & 0x3FU) << 16U) | + static_cast((csd_bytes[8]) << 8U) | + static_cast(csd_bytes[9]); + + info->block_size = BLOCK_SIZE; + info->capacity = static_cast((info->csd.device_size + 1U) * + BLOCK_SIZE * KILOBYTE); + } + + void process_common_csd_tail(Card_Info* info, const uint8_t* csd_bytes) { + info->csd.sector_size = static_cast(((csd_bytes[9] & 0x3FU) << 1U) | + (csd_bytes[10] & 0x80U) >> 7U); + info->csd.speed_factor = static_cast((csd_bytes[11] & 0x1CU) >> 2U); + info->csd.write_block_length = static_cast(((csd_bytes[11] & 0x03U) << 2U) | + ((csd_bytes[12] & 0xC0U) >> 6U)); + info->csd.checksum = static_cast((csd_bytes[15] & 0xFEU) >> 1U); + } + + inline void disable_all_interrupts() { + sdio_.set_interrupt_enable(Interrupt_Type::DTCRCERRIE, false); + sdio_.set_interrupt_enable(Interrupt_Type::DTTMOUTIE, false); + sdio_.set_interrupt_enable(Interrupt_Type::DTENDIE, false); + sdio_.set_interrupt_enable(Interrupt_Type::STBITEIE, false); + sdio_.set_interrupt_enable(Interrupt_Type::TFHIE, false); + sdio_.set_interrupt_enable(Interrupt_Type::RFHIE, false); + sdio_.set_interrupt_enable(Interrupt_Type::TXUREIE, false); + sdio_.set_interrupt_enable(Interrupt_Type::RXOREIE, false); + } + + template + inline SDIO_Error_Type send_command_and_check(Command_Index command, uint32_t argument, + Command_Response response, Wait_Type type, CheckFunc check_result) { + sdio_.set_command_state_machine(command, argument, response, type); + sync_domains(); + sdio_.set_command_state_machine_enable(true); + return check_result(); + } +}; + +} // namespace sdio + +extern sdio::CardDMA& CardDMA_I; diff --git a/Marlin/src/HAL/GD32_MFL/Servo.cpp b/Marlin/src/HAL/GD32_MFL/Servo.cpp new file mode 100644 index 0000000000..d5f8533544 --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/Servo.cpp @@ -0,0 +1,122 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#include "../platforms.h" + +#ifdef ARDUINO_ARCH_MFL + +#include "../../inc/MarlinConfig.h" + +#if HAS_SERVOS + +#include "Servo.h" + +static uint_fast8_t servoCount = 0; +static libServo* servos[NUM_SERVOS] = {0}; +constexpr millis_t servoDelay[] = SERVO_DELAY; +static_assert(COUNT(servoDelay) == NUM_SERVOS, "SERVO_DELAY must be an array NUM_SERVOS long."); + +// Initialize to the default timer priority. This will be overridden by a call from timers.cpp. +// This allows all timer interrupt priorities to be managed from a single location in the HAL. +static uint32_t servo_interrupt_priority = NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 12, 0); + +// This must be called after the MFL Servo class has initialized the timer. +// To be safe this is currently called after every call to attach(). +static void fixServoTimerInterruptPriority() { + NVIC_SetPriority(getTimerUpIRQ(TIMER_SERVO), servo_interrupt_priority); +} + +// Default constructor for libServo class. +// Initializes the servo delay, pause state, and pause value. +// Registers the servo instance in the servos array. +libServo::libServo() : delay(servoDelay[servoCount]), + was_attached_before_pause(false), + value_before_pause(0) { + servos[servoCount++] = this; +} + +// Attaches a servo to a specified pin. +int8_t libServo::attach(const int pin) { + if (servoCount >= MAX_SERVOS) return -1; + if (pin > 0) servo_pin = pin; + auto result = mflServo.attach(servo_pin); + fixServoTimerInterruptPriority(); + return result; +} + +// Attaches a servo to a specified pin with minimum and maximum pulse widths. +int8_t libServo::attach(const int pin, const int min, const int max) { + if (servoCount >= MAX_SERVOS) return -1; + if (pin > 0) servo_pin = pin; + auto result = mflServo.attach(servo_pin, min, max); + fixServoTimerInterruptPriority(); + return result; +} + +// Moves the servo to a specified position. +void libServo::move(const int value) { + if (attach(0) >= 0) { + mflServo.write(value); + safe_delay(delay); + TERN_(DEACTIVATE_SERVOS_AFTER_MOVE, detach()); + } +} + +// Pause the servo by detaching it and storing its current state. +void libServo::pause() { + was_attached_before_pause = mflServo.attached(); + if (was_attached_before_pause) { + value_before_pause = mflServo.read(); + mflServo.detach(); + } +} + +// Resume a previously paused servo. +// If the servo was attached before the pause, this function re-attaches +// the servo and moves it to the position it was in before the pause. +void libServo::resume() { + if (was_attached_before_pause) { + attach(); + move(value_before_pause); + } +} + +// Pause all servos by stopping their timers. +void libServo::pause_all_servos() { + for (auto& servo : servos) + if (servo) servo->pause(); +} + +// Resume all paused servos by starting their timers. +void libServo::resume_all_servos() { + for (auto& servo : servos) + if (servo) servo->resume(); +} + +// Set the interrupt priority for the servo. +// @param preemptPriority The preempt priority level. +// @param subPriority The sub priority level. +void libServo::setInterruptPriority(uint32_t preemptPriority, uint32_t subPriority) { + servo_interrupt_priority = NVIC_EncodePriority(NVIC_GetPriorityGrouping(), preemptPriority, subPriority); +} + +#endif // HAS_SERVOS +#endif // ARDUINO_ARCH_MFL diff --git a/Marlin/src/HAL/GD32_MFL/Servo.h b/Marlin/src/HAL/GD32_MFL/Servo.h new file mode 100644 index 0000000000..80cff46ff8 --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/Servo.h @@ -0,0 +1,56 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +#include + +#include "../../core/millis_t.h" + +// Inherit and expand on the official library +class libServo { +public: + libServo(); + + int8_t attach(const int pin = 0); // pin == 0 uses value from previous call + int8_t attach(const int pin, const int min, const int max); + void detach() { mflServo.detach(); } + + int read() { return mflServo.read(); } + void move(const int value); + + void pause(); + void resume(); + + static void pause_all_servos(); + static void resume_all_servos(); + + static void setInterruptPriority(uint32_t preemptPriority, uint32_t subPriority); + +private: + Servo mflServo; + + int servoPin = 0; + millis_t delay = 0; + + bool was_attached_before_pause; + int value_before_pause; +}; diff --git a/Marlin/src/HAL/GD32_MFL/dogm/u8g_com_mfl_swspi.cpp b/Marlin/src/HAL/GD32_MFL/dogm/u8g_com_mfl_swspi.cpp new file mode 100644 index 0000000000..b36cbfe44d --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/dogm/u8g_com_mfl_swspi.cpp @@ -0,0 +1,129 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm / Ryan Power + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifdef ARDUINO_ARCH_MFL + +#include "../../../inc/MarlinConfig.h" + +#if ALL(HAS_MARLINUI_U8GLIB, FORCE_SOFT_SPI) + +#include +#include "../../shared/HAL_SPI.h" + +#define nop asm volatile ("\tnop\n") + +static inline uint8_t swSpiTransfer_mode_0(uint8_t b) { + for (uint8_t i = 0; i < 8; ++i) { + const uint8_t state = (b & 0x80) ? HIGH : LOW; + WRITE(DOGLCD_SCK, HIGH); + WRITE(DOGLCD_MOSI, state); + b <<= 1; + WRITE(DOGLCD_SCK, LOW); + } + return b; +} + +static inline uint8_t swSpiTransfer_mode_3(uint8_t b) { + for (uint8_t i = 0; i < 8; ++i) { + const uint8_t state = (b & 0x80) ? HIGH : LOW; + WRITE(DOGLCD_SCK, LOW); + WRITE(DOGLCD_MOSI, state); + b <<= 1; + WRITE(DOGLCD_SCK, HIGH); + } + return b; +} + +static void u8g_sw_spi_shift_out(uint8_t val) { + #if U8G_SPI_USE_MODE_3 + swSpiTransfer_mode_3(val); + #else + swSpiTransfer_mode_0(val); + #endif +} + +static void swSpiInit() { + #if PIN_EXISTS(LCD_RESET) + SET_OUTPUT(LCD_RESET_PIN); + #endif + SET_OUTPUT(DOGLCD_A0); + OUT_WRITE(DOGLCD_SCK, LOW); + OUT_WRITE(DOGLCD_MOSI, LOW); + OUT_WRITE(DOGLCD_CS, HIGH); +} + +uint8_t u8g_com_HAL_MFL_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr) { + switch (msg) { + case U8G_COM_MSG_INIT: + swSpiInit(); + break; + case U8G_COM_MSG_STOP: + break; + case U8G_COM_MSG_RESET: + #if PIN_EXISTS(LCD_RESET) + WRITE(LCD_RESET_PIN, arg_val); + #endif + break; + case U8G_COM_MSG_CHIP_SELECT: + #if U8G_SPI_USE_MODE_3 // This LCD SPI is running mode 3 while SD card is running mode 0 + if (arg_val) { // SCK idle state needs to be set to the proper idle state before + // the next chip select goes active + WRITE(DOGLCD_SCK, HIGH); // Set SCK to mode 3 idle state before CS goes active + WRITE(DOGLCD_CS, LOW); + nop; // Hold SCK high for a few ns + nop; + } + else { + WRITE(DOGLCD_CS, HIGH); + WRITE(DOGLCD_SCK, LOW); // Set SCK to mode 0 idle state after CS goes inactive + } + #else + WRITE(DOGLCD_CS, !arg_val); + #endif + break; + case U8G_COM_MSG_WRITE_BYTE: + u8g_sw_spi_shift_out(arg_val); + break; + case U8G_COM_MSG_WRITE_SEQ: { + uint8_t* ptr = (uint8_t*)arg_ptr; + while (arg_val > 0) { + u8g_sw_spi_shift_out(*ptr++); + arg_val--; + } + } break; + case U8G_COM_MSG_WRITE_SEQ_P: { + uint8_t* ptr = (uint8_t*)arg_ptr; + while (arg_val > 0) { + u8g_sw_spi_shift_out(u8g_pgm_read(ptr)); + ptr++; + arg_val--; + } + } break; + case U8G_COM_MSG_ADDRESS: // Define cmd (arg_val = 0) or data mode (arg_val = 1) + WRITE(DOGLCD_A0, arg_val); + break; + } + return 1; +} + +#endif // HAS_MARLINUI_U8GLIB && FORCE_SOFT_SPI +#endif // ARDUINO_ARCH_MFL diff --git a/Marlin/src/HAL/GD32_MFL/eeprom_bl24cxx.cpp b/Marlin/src/HAL/GD32_MFL/eeprom_bl24cxx.cpp new file mode 100644 index 0000000000..2d3329c7f6 --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/eeprom_bl24cxx.cpp @@ -0,0 +1,93 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * PersistentStore for Arduino-style EEPROM interface + * with simple implementations supplied by Marlin. + */ + +#include "../platforms.h" + +#ifdef ARDUINO_ARCH_MFL + +#include "../../inc/MarlinConfig.h" + +#if ENABLED(IIC_BL24CXX_EEPROM) + +#include "../shared/eeprom_if.h" +#include "../shared/eeprom_api.h" + +#ifndef MARLIN_EEPROM_SIZE + #error "MARLIN_EEPROM_SIZE is required for IIC_BL24CXX_EEPROM." +#endif + +size_t PersistentStore::capacity() { + return MARLIN_EEPROM_SIZE - eeprom_exclude_size; +} + +bool PersistentStore::access_start() { + eeprom_init(); + return true; +} + +bool PersistentStore::access_finish() { + return true; +} + +bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc) { + uint16_t written = 0; + while (size--) { + uint8_t v = *value; + uint8_t * const p = (uint8_t * const)REAL_EEPROM_ADDR(pos); + // EPROM has only ~100,000 write cycles, + // so only write bytes that have changed! + if (v != eeprom_read_byte(p)) { + eeprom_write_byte(p, v); + if (++written & 0x7F) delay(4); else safe_delay(4); + if (eeprom_read_byte(p) != v) { + SERIAL_ECHO_MSG(STR_ERR_EEPROM_WRITE); + return true; + } + } + + crc16(crc, &v, 1); + pos++; + value++; + } + + return false; +} + +bool PersistentStore::read_data(int &pos, uint8_t *value, size_t size, uint16_t *crc, const bool writing/*=true*/) { + do { + const uint8_t c = eeprom_read_byte((uint8_t*)REAL_EEPROM_ADDR(pos)); + if (writing) *value = c; + crc16(crc, &c, 1); + pos++; + value++; + } while (--size); + + return false; +} + +#endif // IIC_BL24CXX_EEPROM +#endif // ARDUINO_ARCH_MFL diff --git a/Marlin/src/HAL/GD32_MFL/eeprom_if_iic.cpp b/Marlin/src/HAL/GD32_MFL/eeprom_if_iic.cpp new file mode 100644 index 0000000000..96eebea122 --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/eeprom_if_iic.cpp @@ -0,0 +1,54 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * Platform-independent Arduino functions for I2C EEPROM. + * Enable USE_SHARED_EEPROM if not supplied by the framework. + */ + +#include "../platforms.h" + +#ifdef ARDUINO_ARCH_MFL + +#include "../../inc/MarlinConfig.h" + +#if ENABLED(IIC_BL24CXX_EEPROM) + +#include "../../libs/BL24CXX.h" +#include "../shared/eeprom_if.h" + +void eeprom_init() { + BL24CXX::init(); +} + +void eeprom_write_byte(uint8_t *pos, uint8_t value) { + const unsigned eeprom_address = (unsigned)pos; + return BL24CXX::writeOneByte(eeprom_address, value); +} + +uint8_t eeprom_read_byte(uint8_t *pos) { + const unsigned eeprom_address = (unsigned)pos; + return BL24CXX::readOneByte(eeprom_address); +} + +#endif // IIC_BL24CXX_EEPROM +#endif // ARDUINO_ARCH_MFL diff --git a/Marlin/src/HAL/GD32_MFL/eeprom_wired.cpp b/Marlin/src/HAL/GD32_MFL/eeprom_wired.cpp new file mode 100644 index 0000000000..58a6f85e7f --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/eeprom_wired.cpp @@ -0,0 +1,96 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#include "../platforms.h" + +#ifdef ARDUINO_ARCH_MFL + +#include "../../inc/MarlinConfig.h" + +#if USE_WIRED_EEPROM + +/** + * PersistentStore for Arduino-style EEPROM interface + * with simple implementations supplied by Marlin. + */ + +#include "../shared/eeprom_if.h" +#include "../shared/eeprom_api.h" + +#ifndef MARLIN_EEPROM_SIZE + #define MARLIN_EEPROM_SIZE size_t(E2END + 1) +#endif + +size_t PersistentStore::capacity() { + return MARLIN_EEPROM_SIZE - eeprom_exclude_size; +} + +bool PersistentStore::access_start() { + eeprom_init(); + return true; +} + +bool PersistentStore::access_finish() { + return true; +} + +bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc) { + uint16_t written = 0; + while (size--) { + uint8_t v = *value; + uint8_t * const p = (uint8_t * const)REAL_EEPROM_ADDR(pos); + // EEPROM has only ~100,000 write cycles, + // so only write bytes that have changed! + if (v != eeprom_read_byte(p)) { + eeprom_write_byte(p, v); + // Avoid triggering watchdog during long EEPROM writes + if (++written & 0x7F) + delay(2); + else + safe_delay(2); + if (eeprom_read_byte(p) != v) { + SERIAL_ECHO_MSG(STR_ERR_EEPROM_WRITE); + return true; + } + } + crc16(crc, &v, 1); + pos++; + value++; + } + + return false; +} + +bool PersistentStore::read_data(int &pos, uint8_t *value, size_t size, uint16_t *crc, const bool writing/*=true*/) { + do { + const uint8_t c = eeprom_read_byte((uint8_t*)REAL_EEPROM_ADDR(pos)); + if (writing) + *value = c; + crc16(crc, &c, 1); + pos++; + value++; + } while (--size); + + return false; +} + +#endif // USE_WIRED_EEPROM +#endif // ARDUINO_ARCH_MFL diff --git a/Marlin/src/HAL/GD32_MFL/endstop_interrupts.h b/Marlin/src/HAL/GD32_MFL/endstop_interrupts.h new file mode 100644 index 0000000000..175dec3959 --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/endstop_interrupts.h @@ -0,0 +1,61 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +#include "../../module/endstops.h" + +// One ISR for all EXT-Interrupts +void endstop_ISR() { endstops.update(); } + +void setup_endstop_interrupts() { + #define _ATTACH(P) attachInterrupt(P, endstop_ISR, CHANGE) + TERN_(USE_X_MAX, _ATTACH(X_MAX_PIN)); + TERN_(USE_X_MIN, _ATTACH(X_MIN_PIN)); + TERN_(USE_Y_MAX, _ATTACH(Y_MAX_PIN)); + TERN_(USE_Y_MIN, _ATTACH(Y_MIN_PIN)); + TERN_(USE_Z_MAX, _ATTACH(Z_MAX_PIN)); + TERN_(USE_Z_MIN, _ATTACH(Z_MIN_PIN)); + TERN_(USE_X2_MAX, _ATTACH(X2_MAX_PIN)); + TERN_(USE_X2_MIN, _ATTACH(X2_MIN_PIN)); + TERN_(USE_Y2_MAX, _ATTACH(Y2_MAX_PIN)); + TERN_(USE_Y2_MIN, _ATTACH(Y2_MIN_PIN)); + TERN_(USE_Z2_MAX, _ATTACH(Z2_MAX_PIN)); + TERN_(USE_Z2_MIN, _ATTACH(Z2_MIN_PIN)); + TERN_(USE_Z3_MAX, _ATTACH(Z3_MAX_PIN)); + TERN_(USE_Z3_MIN, _ATTACH(Z3_MIN_PIN)); + TERN_(USE_Z4_MAX, _ATTACH(Z4_MAX_PIN)); + TERN_(USE_Z4_MIN, _ATTACH(Z4_MIN_PIN)); + TERN_(USE_Z_MIN_PROBE, _ATTACH(Z_MIN_PROBE_PIN)); + TERN_(USE_CALIBRATION, _ATTACH(CALIBRATION_PIN)); + TERN_(USE_I_MAX, _ATTACH(I_MAX_PIN)); + TERN_(USE_I_MIN, _ATTACH(I_MIN_PIN)); + TERN_(USE_J_MAX, _ATTACH(J_MAX_PIN)); + TERN_(USE_J_MIN, _ATTACH(J_MIN_PIN)); + TERN_(USE_K_MAX, _ATTACH(K_MAX_PIN)); + TERN_(USE_K_MIN, _ATTACH(K_MIN_PIN)); + TERN_(USE_U_MAX, _ATTACH(U_MAX_PIN)); + TERN_(USE_U_MIN, _ATTACH(U_MIN_PIN)); + TERN_(USE_V_MAX, _ATTACH(V_MAX_PIN)); + TERN_(USE_V_MIN, _ATTACH(V_MIN_PIN)); + TERN_(USE_W_MAX, _ATTACH(W_MAX_PIN)); + TERN_(USE_W_MIN, _ATTACH(W_MIN_PIN)); +} diff --git a/Marlin/src/HAL/GD32_MFL/fast_pwm.cpp b/Marlin/src/HAL/GD32_MFL/fast_pwm.cpp new file mode 100644 index 0000000000..9fba673efc --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/fast_pwm.cpp @@ -0,0 +1,97 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "../platforms.h" + +#ifdef ARDUINO_ARCH_MFL + +#include "../../inc/MarlinConfig.h" + +#include +#include +#include "timers.h" + +static uint16_t timer_frequency[TIMER_COUNT]; + +void MarlinHAL::set_pwm_duty(const pin_t pin, const uint16_t value, const uint16_t scale, const bool invert) { + // Calculate duty cycle based on inversion flag + const uint16_t duty = invert ? scale - value : value; + + // Check if the pin supports PWM + if (PWM_PIN(pin)) { + // Get the timer peripheral base associated with the pin + const auto timer_base = getPinOpsPeripheralBase(TIMER_PinOps, static_cast(pin)); + + // Initialize the timer instance + auto& TimerInstance = GeneralTimer::get_instance(timer_base); + + // Get channel and previous channel mode + const auto channel = getPackedPinChannel(getPackedPinOps(TIMER_PinOps, static_cast(pin))); + const InputOutputMode previous = TimerInstance.getChannelMode(channel); + + if (timer_frequency[static_cast(timer_base)] == 0) { + set_pwm_frequency(pin, PWM_FREQUENCY); + } + + // Set the PWM duty cycle + TimerInstance.setCaptureCompare(channel, duty, CCFormat::B8); + + // Configure pin as PWM output + pinOpsPinout(TIMER_PinOps, static_cast(pin)); + + // Set channel mode if not already set and start timer + if (previous != InputOutputMode::PWM0) { + TimerInstance.setChannelMode(channel, InputOutputMode::PWM0, static_cast(pin)); + TimerInstance.start(); + } + } else { + pinMode(pin, OUTPUT); + digitalWrite(pin, duty < scale / 2 ? LOW : HIGH); + } +} + +void MarlinHAL::set_pwm_frequency(const pin_t pin, const uint16_t f_desired) { + // Check if the pin supports PWM + if (!PWM_PIN(pin)) return; + + // Get the timer peripheral base associated with the pin + const auto timer_base = getPinOpsPeripheralBase(TIMER_PinOps, static_cast(pin)); + + // Guard against modifying protected timers + #ifdef STEP_TIMER + if (timer_base == static_cast(STEP_TIMER)) return; + #endif + #ifdef TEMP_TIMER + if (timer_base == static_cast(TEMP_TIMER)) return; + #endif + #if defined(PULSE_TIMER) && MF_TIMER_PULSE != MF_TIMER_STEP + if (timer_base == static_cast(PULSE_TIMER)) return; + #endif + + // Initialize the timer instance + auto& TimerInstance = GeneralTimer::get_instance(timer_base); + + TimerInstance.setRolloverValue(f_desired, TimerFormat::HERTZ); + timer_frequency[timer_base_to_index(timer_base)] = f_desired; +} + +#endif // ARDUINO_ARCH_MFL diff --git a/Marlin/src/HAL/GD32_MFL/fastio.h b/Marlin/src/HAL/GD32_MFL/fastio.h new file mode 100644 index 0000000000..8185be73a4 --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/fastio.h @@ -0,0 +1,82 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +// Fast I/O interfaces for GD32F303RE + +#include +#include +#include + +static inline void fast_write_pin_wrapper(pin_size_t IO, bool V) { + if (V) gpio::fast_set_pin(getPortFromPin(IO), getPinInPort(IO)); + else gpio::fast_clear_pin(getPortFromPin(IO), getPinInPort(IO)); +} + +static inline bool fast_read_pin_wrapper(pin_size_t IO) { + return gpio::fast_read_pin(getPortFromPin(IO), getPinInPort(IO)); +} + +static inline void fast_toggle_pin_wrapper(pin_size_t IO) { + gpio::fast_toggle_pin(getPortFromPin(IO), getPinInPort(IO)); +} + +// ------------------------ +// Defines +// ------------------------ + +#ifndef PWM + #define PWM OUTPUT +#endif + +#define _WRITE(IO, V) fast_write_pin_wrapper(IO, V) +#define _READ(IO) fast_read_pin_wrapper(IO) +#define _TOGGLE(IO) fast_toggle_pin_wrapper(IO) + +#define _GET_MODE(IO) +#define _SET_MODE(IO, M) pinMode((IO), (M)) +#define _SET_OUTPUT(IO) pinMode((IO), OUTPUT) +#define _SET_OUTPUT_OD(IO) pinMode((IO), OUTPUT_OPEN_DRAIN) + +#define WRITE(IO, V) _WRITE((IO), (V)) +#define READ(IO) _READ(IO) +#define TOGGLE(IO) _TOGGLE(IO) + +#define OUT_WRITE(IO, V) do { _SET_OUTPUT(IO); WRITE((IO), (V)); } while (0) +#define OUT_WRITE_OD(IO, V) do { _SET_OUTPUT_OD(IO); WRITE((IO), (V)); } while (0) + +#define SET_INPUT(IO) _SET_MODE((IO), INPUT) +#define SET_INPUT_PULLUP(IO) _SET_MODE((IO), INPUT_PULLUP) +#define SET_INPUT_PULLDOWN(IO) _SET_MODE((IO), INPUT_PULLDOWN) +#define SET_OUTPUT(IO) OUT_WRITE((IO), LOW) +#define SET_OUTPUT_OD(IO) OUT_WRITE_OD((IO), LOW) +#define SET_PWM(IO) _SET_MODE((IO), PWM) + +#define IS_INPUT(IO) +#define IS_OUTPUT(IO) + +#define PWM_PIN(P) isPinInPinOps(TIMER_PinOps, P) +#define NO_COMPILE_TIME_PWM + +// Wrappers for digitalRead and digitalWrite +#define extDigitalRead(IO) digitalRead(IO) +#define extDigitalWrite(IO, V) digitalWrite((IO), (V)) diff --git a/Marlin/src/HAL/GD32_MFL/inc/Conditionals_LCD.h b/Marlin/src/HAL/GD32_MFL/inc/Conditionals_LCD.h new file mode 100644 index 0000000000..379ecfa7f0 --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/inc/Conditionals_LCD.h @@ -0,0 +1,26 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +#if ALL(HAS_MARLINUI_U8GLIB, FORCE_SOFT_SPI) + #define U8G_SW_SPI_MFL 1 +#endif diff --git a/Marlin/src/HAL/GD32_MFL/inc/Conditionals_adv.h b/Marlin/src/HAL/GD32_MFL/inc/Conditionals_adv.h new file mode 100644 index 0000000000..6df84f6f92 --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/inc/Conditionals_adv.h @@ -0,0 +1,26 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +#if ALL(HAS_MEDIA, USBD_USE_CDC_MSC) + #define HAS_SD_HOST_DRIVE 1 +#endif diff --git a/Marlin/src/HAL/GD32_MFL/inc/Conditionals_post.h b/Marlin/src/HAL/GD32_MFL/inc/Conditionals_post.h new file mode 100644 index 0000000000..a3db122682 --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/inc/Conditionals_post.h @@ -0,0 +1,29 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +// If no real or emulated EEPROM selected, fall back to SD emulation +#if USE_FALLBACK_EEPROM + #define SDCARD_EEPROM_EMULATION +#elif ANY(I2C_EEPROM, SPI_EEPROM) + #define USE_SHARED_EEPROM 1 +#endif diff --git a/Marlin/src/HAL/GD32_MFL/inc/Conditionals_type.h b/Marlin/src/HAL/GD32_MFL/inc/Conditionals_type.h new file mode 100644 index 0000000000..92cc457df5 --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/inc/Conditionals_type.h @@ -0,0 +1,22 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once diff --git a/Marlin/src/HAL/GD32_MFL/inc/SanityCheck.h b/Marlin/src/HAL/GD32_MFL/inc/SanityCheck.h new file mode 100644 index 0000000000..366765dcd5 --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/inc/SanityCheck.h @@ -0,0 +1,97 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +// Test MFL GD32 specific configuration values for errors at compile-time. +#if ENABLED(SDCARD_EEPROM_EMULATION) && !HAS_MEDIA + #undef SDCARD_EEPROM_EMULATION // avoid additional error noise + #if USE_FALLBACK_EEPROM + #warning "EEPROM type not specified. Fallback is SDCARD_EEPROM_EMULATION." + #endif + #error "SDCARD_EEPROM_EMULATION requires SDSUPPORT. Enable SDSUPPORT or choose another EEPROM emulation." +#endif + +#if ENABLED(FLASH_EEPROM_LEVELING) + #error "FLASH_EEPROM_LEVELING is not supported on GD32." +#endif + +#if ENABLED(SERIAL_STATS_MAX_RX_QUEUED) + #error "SERIAL_STATS_MAX_RX_QUEUED is not supported on GD32." +#elif ENABLED(SERIAL_STATS_DROPPED_RX) + #error "SERIAL_STATS_DROPPED_RX is not supported on GD32." +#endif + +#if TEMP_SENSOR_SOC && defined(ATEMP) && TEMP_SOC_PIN != ATEMP + #error "TEMP_SENSOR_SOC requires 'TEMP_SOC_PIN ATEMP' on GD32" +#endif + +// Check for common serial pin conflicts +#define _CHECK_SERIAL_PIN(N) (( \ + BTN_EN1 == N || BTN_EN2 == N || DOGLCD_CS == N || HEATER_BED_PIN == N || FAN0_PIN == N || \ + SDIO_D2_PIN == N || SDIO_D3_PIN == N || SDIO_CK_PIN == N || SDIO_CMD_PIN == N || \ + Y_STEP_PIN == N || Y_ENABLE_PIN == N || E0_ENABLE_PIN == N || POWER_LOSS_PIN == N \ + )) + +#define CHECK_SERIAL_PIN(T, N) defined(UART##N##_##T##_PIN) && _CHECK_SERIAL_PIN(UART##N##_##T##_PIN) + +#if SERIAL_IN_USE(0) + #if CHECK_SERIAL_PIN(TX, 0) + #error "Serial Port 0 TX IO pins conflict with another pin on the board." + #endif + #if CHECK_SERIAL_PIN(RX, 0) + #error "Serial Port 0 RX IO pins conflict with another pin on the board." + #endif +#endif +#if SERIAL_IN_USE(1) + #if CHECK_SERIAL_PIN(TX, 1) + #error "Serial Port 1 TX IO pins conflict with another pin on the board." + #endif + #if CHECK_SERIAL_PIN(RX, 1) + #error "Serial Port 1 RX IO pins conflict with another pin on the board." + #endif +#endif +#if SERIAL_IN_USE(2) + #if CHECK_SERIAL_PIN(TX, 2) + #error "Serial Port 2 TX IO pins conflict with another pin on the board." + #endif + #if CHECK_SERIAL_PIN(RX, 2) + #error "Serial Port 2 RX IO pins conflict with another pin on the board." + #endif +#endif +#if SERIAL_IN_USE(3) + #if CHECK_SERIAL_PIN(TX, 3) + #error "Serial Port 3 TX IO pins conflict with another pin on the board." + #endif + #if CHECK_SERIAL_PIN(RX, 3) + #error "Serial Port 3 RX IO pins conflict with another pin on the board." + #endif +#endif +#if SERIAL_IN_USE(4) + #if CHECK_SERIAL_PIN(TX, 4) + #error "Serial Port 4 TX IO pins conflict with another pin on the board." + #endif + #if CHECK_SERIAL_PIN(RX, 4) + #error "Serial Port 4 RX IO pins conflict with another pin on the board." + #endif +#endif +#undef CHECK_SERIAL_PIN +#undef _CHECK_SERIAL_PIN diff --git a/Marlin/src/HAL/GD32_MFL/pinsDebug.h b/Marlin/src/HAL/GD32_MFL/pinsDebug.h new file mode 100644 index 0000000000..d3b3794df2 --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/pinsDebug.h @@ -0,0 +1,102 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +/** + * Pins Debugging for GD32 + * + * - NUMBER_PINS_TOTAL + * - MULTI_NAME_PAD + * - getPinByIndex(index) + * - printPinNameByIndex(index) + * - getPinIsDigitalByIndex(index) + * - digitalPinToAnalogIndex(pin) + * - getValidPinMode(pin) + * - isValidPin(pin) + * - isAnalogPin(pin) + * - digitalRead_mod(pin) + * - pwm_status(pin) + * - printPinPWM(pin) + * - printPinPort(pin) + * - printPinNumber(pin) + * - printPinAnalog(pin) + */ + +#include "../../inc/MarlinConfig.h" +#include +#include +#include + +#ifndef TOTAL_PIN_COUNT + #error "Expected TOTAL_PIN_COUNT not found." +#endif + +#define NUM_DIGITAL_PINS TOTAL_PIN_COUNT +#define NUMBER_PINS_TOTAL TOTAL_PIN_COUNT + +#define getPinByIndex(x) pin_t(pin_array[x].pin) +#define isValidPin(P) WITHIN(P, 0, (NUM_DIGITAL_PINS - 1)) +#define digitalRead_mod(P) extDigitalRead(P) +#define printPinNumber(P) do { sprintf_P(buffer, PSTR("%3hd "), pin_t(P)); SERIAL_ECHO(buffer); } while (0) +#define printPinAnalog(P) do { sprintf_P(buffer, PSTR(" (A%2d) "), pin_t(getAdcChannelFromPin(P))); SERIAL_ECHO(buffer); } while (0) +#define printPinNameByIndex(x) do { sprintf_P(buffer, PSTR("%-" STRINGIFY(MAX_NAME_LENGTH) "s"), pin_array[x].name); SERIAL_ECHO(buffer); } while (0) + +#define MULTI_NAME_PAD 21 // Space needed to be pretty if not first name assigned to a pin + +#ifndef M43_NEVER_TOUCH + #define M43_NEVER_TOUCH(x) WITHIN(x, 9, 10) // SERIAL pins: PA9(TX) PA10(RX) +#endif + +bool isAnalogPin(const pin_t pin) { + if (!isValidPin(pin)) return false; + + if (getAdcChannel(pin) != adc::ADC_Channel::INVALID) { + auto& instance = gpio::GPIO::get_instance(getPortFromPin(pin)).value(); + return instance.get_pin_mode(getPinInPort(pin)) == gpio::Pin_Mode::ANALOG && !M43_NEVER_TOUCH(pin); + } + + return false; +} + +bool getValidPinMode(const pin_t pin) { + if (!isValidPin(pin)) return false; + + auto& instance = gpio::GPIO::get_instance(getPortFromPin(pin)).value(); + gpio::Pin_Mode mode = instance.get_pin_mode(getPinInPort(pin)); + + return mode != gpio::Pin_Mode::ANALOG && mode != gpio::Pin_Mode::INPUT_FLOATING && + mode != gpio::Pin_Mode::INPUT_PULLUP && mode != gpio::Pin_Mode::INPUT_PULLDOWN; +} + +bool getPinIsDigitalByIndex(const int16_t index) { + const pin_t pin = getPinByIndex(index); + return (!isAnalogPin(pin)); +} + +int8_t digitalPinToAnalogIndex(const pin_t pin) { + if (!isValidPin(pin) || !isAnalogPin(pin)) return -1; + return pin; // Analog and digital pin indexes are shared +} + +bool pwm_status(const pin_t pin) { return false; } +void printPinPWM(const pin_t pin) { /* TODO */ } +void printPinPort(const pin_t pin) { /* TODO */ } diff --git a/Marlin/src/HAL/GD32_MFL/sdio.cpp b/Marlin/src/HAL/GD32_MFL/sdio.cpp new file mode 100644 index 0000000000..4b6d75d74f --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/sdio.cpp @@ -0,0 +1,233 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "../platforms.h" + +#ifdef ARDUINO_ARCH_MFL + +#include "../../inc/MarlinConfig.h" + +#if ENABLED(ONBOARD_SDIO) + +#include +#include +#include "SDCard.h" +#include "sdio.h" + +using namespace sdio; + +#define TARGET_CLOCK 6000000U +#define BLOCK_SIZE 512U +#define CARD_TIMEOUT 500 // ms +#define READ_RETRIES 3U + +inline constexpr uint32_t TARGET_SDIO_CLOCK = TARGET_CLOCK; +inline constexpr uint32_t SDIO_BLOCK_SIZE = BLOCK_SIZE; +inline constexpr uint32_t SD_TIMEOUT = CARD_TIMEOUT; +inline constexpr uint8_t SDIO_READ_RETRIES = READ_RETRIES; + +Card_State cardState = Card_State::READY; + +bool SDIO_SetBusWidth(Bus_Width width) { + return (CardDMA_I.set_hardware_bus_width(width) == SDIO_Error_Type::OK); +} + +void mfl_sdio_init() { + pinOpsPinout(SD_CMD_PinOps, static_cast(SDIO_CMD_PIN)); + pinOpsPinout(SD_CK_PinOps, static_cast(SDIO_CK_PIN)); + pinOpsPinout(SD_DATA0_PinOps, static_cast(SDIO_D0_PIN)); + pinOpsPinout(SD_DATA1_PinOps, static_cast(SDIO_D1_PIN)); + pinOpsPinout(SD_DATA2_PinOps, static_cast(SDIO_D2_PIN)); + pinOpsPinout(SD_DATA3_PinOps, static_cast(SDIO_D3_PIN)); + + NVIC_EnableIRQ(DMA1_Channel3_4_IRQn); + NVIC_EnableIRQ(SDIO_IRQn); +} + +bool SDIO_Init() { + SDIO_Error_Type result = SDIO_Error_Type::OK; + uint8_t retryCount = SDIO_READ_RETRIES; + + mfl_sdio_init(); + + uint8_t retries = retryCount; + for (;;) { + hal.watchdog_refresh(); + result = CardDMA_I.init(); + if (result == SDIO_Error_Type::OK) break; + if (!--retries) return false; + } + + CardDMA_I.set_desired_clock(TARGET_SDIO_CLOCK, false, false); + + retries = retryCount; + for (;;) { + hal.watchdog_refresh(); + if (SDIO_SetBusWidth(Bus_Width::WIDTH_4BIT)) break; + if (!--retries) break; + } + + CardDMA_I.set_desired_clock(TARGET_SDIO_CLOCK, true, true); + + // Fallback + if (!retries) { + mfl_sdio_init(); + retries = retryCount; + for (;;) { + hal.watchdog_refresh(); + result = CardDMA_I.init(); + if (result == SDIO_Error_Type::OK) break; + if (!--retries) return false; + } + CardDMA_I.set_desired_clock(TARGET_SDIO_CLOCK, false, true); + } + + return true; +} + +static bool SDIO_ReadWriteBlock_DMA(uint32_t block, const uint8_t* src, uint8_t* dst) { + hal.watchdog_refresh(); + SDIO_Error_Type result = SDIO_Error_Type::OK; + + // Write + if (src) { + result = CardDMA_I.write(reinterpret_cast(const_cast(src)), block, 1); + } + // Read + else { + result = CardDMA_I.read(dst, block, 1); + } + + if (result != SDIO_Error_Type::OK) { + return false; + } + + millis_t timeout = millis() + SD_TIMEOUT; + while (CardDMA_I.get_state() != sdio::Operational_State::READY) { + if (ELAPSED(millis(), timeout)) { + return false; + } + } + + CardDMA_I.check_dma_complete(); + + timeout = millis() + SD_TIMEOUT; + do { + result = CardDMA_I.get_card_state(&cardState); + if (ELAPSED(millis(), timeout)) { + return false; + } + } while (result == SDIO_Error_Type::OK && cardState != sdio::Card_State::TRANSFER); + + return true; +} + +bool SDIO_ReadBlock(uint32_t block, uint8_t* dst) { + // Check if the address is aligned to 4 bytes + if (reinterpret_cast(dst) & 0x03) { + return false; + } + + uint8_t retries = SDIO_READ_RETRIES; + while (retries--) { + if (SDIO_ReadWriteBlock_DMA(block, nullptr, dst)) { + return true; + } + } + + return false; +} + +bool SDIO_WriteBlock(uint32_t block, const uint8_t* src) { + // Check if the address is aligned to 4 bytes + if (reinterpret_cast(src) & 0x03) { + return false; + } + + uint8_t retries = SDIO_READ_RETRIES; + while (retries--) { + if (SDIO_ReadWriteBlock_DMA(block, src, nullptr)) { + return true; + delay(10); + } + } + + return false; +} + +bool SDIO_IsReady() { + return (CardDMA_I.get_state() == sdio::Operational_State::READY); +} + +uint32_t SDIO_GetCardSize() { + return CardDMA_I.get_card_capacity(); +} + +// DMA interrupt handler +void DMA1_IRQHandler() { + auto& dma_instance = CardDMA_I.get_dma_instance(); + bool is_receive = CardDMA_I.get_is_sdio_rx(); + + // Check for Transfer Complete Interrupt + if (dma_instance.get_interrupt_flag(dma::Interrupt_Flags::INTR_FLAG_FTFIF)) { + dma_instance.set_interrupt_enable(dma::Interrupt_Type::INTR_FTFIE, false); + dma_instance.set_interrupt_enable(dma::Interrupt_Type::INTR_ERRIE, false); + dma_instance.clear_interrupt_flag(dma::Interrupt_Flags::INTR_FLAG_FTFIF); + if (is_receive) { + CardDMA_I.set_sdio_dma_enable(false); + CardDMA_I.clear_sdio_data_flags(); + CardDMA_I.set_state(sdio::Operational_State::READY); + } else { + CardDMA_I.set_data_end_interrupt(); + } + // Signal that transfer is complete + CardDMA_I.set_transfer_end(true); + } + + else if (dma_instance.get_interrupt_flag(dma::Interrupt_Flags::INTR_FLAG_ERRIF)) { + dma_instance.set_interrupt_enable(dma::Interrupt_Type::INTR_HTFIE, false); + dma_instance.set_interrupt_enable(dma::Interrupt_Type::INTR_ERRIE, false); + dma_instance.set_interrupt_enable(dma::Interrupt_Type::INTR_FTFIE, false); + // Clear all flags + dma_instance.clear_interrupt_flag(dma::Interrupt_Flags::INTR_FLAG_GIF); + // Signal that an error occurred + CardDMA_I.set_transfer_error(SDIO_Error_Type::ERROR); + CardDMA_I.set_state(sdio::Operational_State::READY); + } +} + + +extern "C" { + + void SDIO_IRQHandler(void) { + CardDMA_I.handle_interrupts(); + } + + void DMA1_Channel3_4_IRQHandler(void) { + DMA1_IRQHandler(); + } + +} // extern "C" + + +#endif // ONBOARD_SDIO +#endif // ARDUINO_ARCH_MFL diff --git a/Marlin/src/HAL/GD32_MFL/sdio.h b/Marlin/src/HAL/GD32_MFL/sdio.h new file mode 100644 index 0000000000..b6b027ba77 --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/sdio.h @@ -0,0 +1,36 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +#include +#include + +#define SDIO_D0_PIN PC8 +#define SDIO_D1_PIN PC9 +#define SDIO_D2_PIN PC10 +#define SDIO_D3_PIN PC11 +#define SDIO_CK_PIN PC12 +#define SDIO_CMD_PIN PD2 + +void sdio_mfl_init(); +bool SDIO_SetBusWidth(sdio::Bus_Width width); +void DMA1_IRQHandler(dma::DMA_Channel channel); diff --git a/Marlin/src/HAL/GD32_MFL/spi_pins.h b/Marlin/src/HAL/GD32_MFL/spi_pins.h new file mode 100644 index 0000000000..c8a5836838 --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/spi_pins.h @@ -0,0 +1,32 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +// Define SPI Pins: SCK, MISO, MOSI +#ifndef SD_SCK_PIN + #define SD_SCK_PIN PIN_SPI_SCK +#endif +#ifndef SD_MISO_PIN + #define SD_MISO_PIN PIN_SPI_MISO +#endif +#ifndef SD_MOSI_PIN + #define SD_MOSI_PIN PIN_SPI_MOSI +#endif diff --git a/Marlin/src/HAL/GD32_MFL/temp_soc.h b/Marlin/src/HAL/GD32_MFL/temp_soc.h new file mode 100644 index 0000000000..eeb144c422 --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/temp_soc.h @@ -0,0 +1,29 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +#define TS_TYPICAL_V 1.405 +#define TS_TYPICAL_TEMP 25 +#define TS_TYPICAL_SLOPE 4.5 + +// TODO: Implement voltage scaling (calibrated Vrefint) and ADC resolution scaling (when applicable) +#define TEMP_SOC_SENSOR(RAW) ((TS_TYPICAL_V - (RAW) / float(OVERSAMPLENR) / float(HAL_ADC_RANGE) * (float(ADC_VREF_MV) / 1000)) / ((TS_TYPICAL_SLOPE) / 1000) + TS_TYPICAL_TEMP) diff --git a/Marlin/src/HAL/GD32_MFL/timers.cpp b/Marlin/src/HAL/GD32_MFL/timers.cpp new file mode 100644 index 0000000000..bdcf5ed0ed --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/timers.cpp @@ -0,0 +1,233 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#include "../platforms.h" + +#ifdef ARDUINO_ARCH_MFL + +#include "../../inc/MarlinConfig.h" +#include "timers.h" + +// ------------------------ +// Local defines +// ------------------------ + +#define SWSERIAL_TIMER_IRQ_PRIORITY_DEFAULT 1 // Requires tight bit timing to communicate reliably with TMC drivers +#define SERVO_TIMER_IRQ_PRIORITY_DEFAULT 1 // Requires tight PWM timing to control a BLTouch reliably +#define STEP_TIMER_IRQ_PRIORITY_DEFAULT 2 +#define TEMP_TIMER_IRQ_PRIORITY_DEFAULT 14 // Low priority avoids interference with other hardware and timers + +#ifndef TIMER_IRQ_PRIORITY + #define TIMER_IRQ_PRIORITY 12 +#endif + +#ifndef STEP_TIMER_IRQ_PRIORITY + #define STEP_TIMER_IRQ_PRIORITY STEP_TIMER_IRQ_PRIORITY_DEFAULT +#endif + +#ifndef TEMP_TIMER_IRQ_PRIORITY + #define TEMP_TIMER_IRQ_PRIORITY TEMP_TIMER_IRQ_PRIORITY_DEFAULT +#endif + +#if HAS_TMC_SW_SERIAL + #include + #ifndef SWSERIAL_TIMER_IRQ_PRIORITY + #define SWSERIAL_TIMER_IRQ_PRIORITY SWSERIAL_TIMER_IRQ_PRIORITY_DEFAULT + #endif +#endif + +#if HAS_SERVOS + #include "Servo.h" + #ifndef SERVO_TIMER_IRQ_PRIORITY + #define SERVO_TIMER_IRQ_PRIORITY SERVO_TIMER_IRQ_PRIORITY_DEFAULT + #endif +#endif + +#if ENABLED(SPEAKER) + // The MFL framework default timer priority is 12. The TEMP timer must have lower priority + // than this due to the long running temperature ISR, and STEP timer should higher priority. + #if !(TIMER_IRQ_PRIORITY > STEP_TIMER_IRQ_PRIORITY && TIMER_IRQ_PRIORITY < TEMP_TIMER_IRQ_PRIORITY) + #error "Default timer interrupt priority is unspecified or set to a value which may degrade performance." + #endif +#endif + +#ifndef HAL_TIMER_RATE + #define HAL_TIMER_RATE GetStepperTimerClkFreq() +#endif + +#ifndef STEP_TIMER + #define STEP_TIMER MF_TIMER_STEP +#endif +#ifndef TEMP_TIMER + #define TEMP_TIMER MF_TIMER_TEMP +#endif + +GeneralTimer& Step_Timer = GeneralTimer::get_instance(static_cast(STEP_TIMER)); +GeneralTimer& Temp_Timer = GeneralTimer::get_instance(static_cast(TEMP_TIMER)); + +bool is_step_timer_initialized = false; +bool is_temp_timer_initialized = false; + +// ------------------------ +// Public functions +// ------------------------ + +// Retrieves the clock frequency of the stepper timer +uint32_t GetStepperTimerClkFreq() { + return Step_Timer.getTimerClockFrequency(); +} + +/** + * @brief Starts a hardware timer + * + * If the timer is not already initialized, this function will initialize it with the given frequency. + * The timer is started immediately after initialization + * + * @param timer The timer base index to start + * @param frequency The frequency at which the timer should run + * @return None + */ +void HAL_timer_start(const uint8_t timer_number, const uint32_t frequency) { + if (HAL_timer_initialized(timer_number) || (timer_number != MF_TIMER_STEP && timer_number != MF_TIMER_TEMP)) + return; + + const bool is_step = (timer_number == MF_TIMER_STEP); + const uint8_t priority = is_step ? + static_cast(STEP_TIMER_IRQ_PRIORITY) : + static_cast(TEMP_TIMER_IRQ_PRIORITY); + + // Get the reference of the timer instance + GeneralTimer& timer = is_step ? Step_Timer : Temp_Timer; + + if (is_step) { + timer.setPrescaler(STEPPER_TIMER_PRESCALE); + timer.setRolloverValue(_MIN(static_cast(HAL_TIMER_TYPE_MAX), + (HAL_TIMER_RATE) / (STEPPER_TIMER_PRESCALE)), + TimerFormat::TICK); + is_step_timer_initialized = true; + } + else { + timer.setRolloverValue(frequency, TimerFormat::HERTZ); + is_temp_timer_initialized = true; + } + + timer.setAutoReloadEnable(false); + timer.setInterruptPriority(priority, 0U); + HAL_timer_enable_interrupt(timer_number); + timer.start(); +} + +/** + * @brief Enables the interrupt for the specified timer + * + * @param handle The timer handle for which to enable the interrupt + * @return None + */ +void HAL_timer_enable_interrupt(const uint8_t timer_number) { + if (!HAL_timer_initialized(timer_number)) return; + + GeneralTimer& timer = (timer_number == MF_TIMER_STEP) ? Step_Timer : Temp_Timer; + + if (timer_number == MF_TIMER_STEP && !timer.hasInterrupt()) + timer.attachInterrupt(Step_Handler); + else if (timer_number == MF_TIMER_TEMP && !timer.hasInterrupt()) + timer.attachInterrupt(Temp_Handler); +} + +/** + * @brief Disables the interrupt for the specified timer + * + * @param handle The timer handle for which to disable the interrupt + * @return None + */ +void HAL_timer_disable_interrupt(const uint8_t timer_number) { + if (!HAL_timer_initialized(timer_number)) return; + + GeneralTimer& timer = (timer_number == MF_TIMER_STEP) ? Step_Timer : Temp_Timer; + if (timer_number == MF_TIMER_STEP || timer_number == MF_TIMER_TEMP) + timer.detachInterrupt(); +} + +/** + * @brief Checks if the interrupt is enabled for the specified timer + * + * @param handle The timer handle to check + * @return True if the interrupt is enabled, false otherwise + */ +bool HAL_timer_interrupt_enabled(const uint8_t timer_number) { + if (!HAL_timer_initialized(timer_number)) return false; + + GeneralTimer& timer = (timer_number == MF_TIMER_STEP) ? Step_Timer : Temp_Timer; + return (timer_number == MF_TIMER_STEP || timer_number == MF_TIMER_TEMP) + ? timer.hasInterrupt() + : false; +} + +// Sets the interrupt priorities for timers used by TMC SW serial and servos. +void SetTimerInterruptPriorities() { + TERN_(HAS_TMC_SW_SERIAL, SoftwareSerial::setInterruptPriority(SWSERIAL_TIMER_IRQ_PRIORITY, 0)); + TERN_(HAS_SERVOS, libServo::setInterruptPriority(SERVO_TIMER_IRQ_PRIORITY, 0)); +} + +// ------------------------ +// Detect timer conflicts +// ------------------------ + +TERN_(SPEAKER, static constexpr timer::TIMER_Base timer_tone[] = {static_cast(TIMER_TONE)}); +TERN_(HAS_SERVOS, static constexpr timer::TIMER_Base timer_servo[] = {static_cast(TIMER_SERVO)}); + +enum TimerPurpose { + PURPOSE_TONE, + PURPOSE_SERVO, + PURPOSE_STEP, + PURPOSE_TEMP +}; + +// List of timers to check for conflicts +// Includes the timer purpose to ease debugging when evaluating at build-time +// This cannot yet account for timers used for PWM output, such as for fans +static constexpr struct { TimerPurpose p; int t; } timers_in_use[] = { + #if ENABLED(SPEAKER) + { PURPOSE_TONE, timer_base_to_index(timer_tone[0]) }, // Set in variant.h + #endif + #if HAS_SERVOS + { PURPOSE_SERVO, timer_base_to_index(timer_servo[0]) }, // Set in variant.h + #endif + { PURPOSE_STEP, MF_TIMER_STEP }, + { PURPOSE_TEMP, MF_TIMER_TEMP }, +}; + +// Verifies if there are any timer conflicts in the timers_in_use array +static constexpr bool verify_no_timer_conflicts() { + for (uint8_t i = 0; i < COUNT(timers_in_use); i++) + for (uint8_t j = i + 1; j < COUNT(timers_in_use); j++) + if (timers_in_use[i].t == timers_in_use[j].t) + return false; + + return true; +} + +// If this assertion fails at compile time, review the timers_in_use array. +// If default_envs is defined properly in platformio.ini, VSCode can evaluate the array +// when hovering over it, making it easy to identify the conflicting timers +static_assert(verify_no_timer_conflicts(), "One or more timer conflict detected. Examine \"timers_in_use\" to help identify conflict."); + +#endif // ARDUINO_ARCH_MFL diff --git a/Marlin/src/HAL/GD32_MFL/timers.h b/Marlin/src/HAL/GD32_MFL/timers.h new file mode 100644 index 0000000000..539f599a16 --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/timers.h @@ -0,0 +1,145 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +#include "../../inc/MarlinConfig.h" + +#include + +// ------------------------ +// Defines +// ------------------------ + +// Timer configuration constants +#define STEPPER_TIMER_RATE 2000000 +#define TEMP_TIMER_FREQUENCY 1000 + +// Timer instance definitions +#define MF_TIMER_STEP 3 +#define MF_TIMER_TEMP 1 +#define MF_TIMER_PULSE MF_TIMER_STEP + +#define hal_timer_t uint32_t +#define HAL_TIMER_TYPE_MAX UINT16_MAX + +extern uint32_t GetStepperTimerClkFreq(); + +// Timer prescaler calculations +#define STEPPER_TIMER_PRESCALE (GetStepperTimerClkFreq() / STEPPER_TIMER_RATE) // Prescaler = 30 +#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE +#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000) // Stepper timer ticks per µs +#define PULSE_TIMER_RATE STEPPER_TIMER_RATE +#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US + +// Timer interrupt priorities +#define STEP_TIMER_IRQ_PRIORITY 2 +#define TEMP_TIMER_IRQ_PRIORITY 14 + +#define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_STEP) +#define DISABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_STEP) +#define STEPPER_ISR_ENABLED() HAL_timer_interrupt_enabled(MF_TIMER_STEP) +#define ENABLE_TEMPERATURE_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_TEMP) +#define DISABLE_TEMPERATURE_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_TEMP) + +extern void Step_Handler(); +extern void Temp_Handler(); + +#ifndef HAL_STEP_TIMER_ISR + #define HAL_STEP_TIMER_ISR() void Step_Handler() +#endif +#ifndef HAL_TEMP_TIMER_ISR + #define HAL_TEMP_TIMER_ISR() void Temp_Handler() +#endif + +extern GeneralTimer& Step_Timer; +extern GeneralTimer& Temp_Timer; + +extern bool is_step_timer_initialized; +extern bool is_temp_timer_initialized; + +// Build-time mapping between timer base and index. Used in timers.cpp and fast_pwm.cpp +static inline constexpr struct {timer::TIMER_Base base; uint8_t timer_number;} base_to_index[] = { + { timer::TIMER_Base::TIMER0_BASE, 0 }, + { timer::TIMER_Base::TIMER1_BASE, 1 }, + { timer::TIMER_Base::TIMER2_BASE, 2 }, + { timer::TIMER_Base::TIMER3_BASE, 3 }, + { timer::TIMER_Base::TIMER4_BASE, 4 }, + { timer::TIMER_Base::TIMER5_BASE, 5 }, + { timer::TIMER_Base::TIMER6_BASE, 6 }, + { timer::TIMER_Base::TIMER7_BASE, 7 } +}; + +// Converts a timer base to an integer timer index. +constexpr int timer_base_to_index(timer::TIMER_Base base) { + for (const auto& timer : base_to_index) { + if (timer.base == base) { + return static_cast(timer.timer_number); + } + } + return -1; +} + +// ------------------------ +// Public functions +// ------------------------ + +void HAL_timer_start(const uint8_t timer, const uint32_t frequency); +void HAL_timer_enable_interrupt(const uint8_t timer); +void HAL_timer_disable_interrupt(const uint8_t timer); +bool HAL_timer_interrupt_enabled(const uint8_t timer); + +// Configure timer priorities for peripherals such as Software Serial or Servos. +// Exposed here to allow all timer priority information to reside in timers.cpp +void SetTimerInterruptPriorities(); + +// FORCE_INLINE because these are used in performance-critical situations +FORCE_INLINE bool HAL_timer_initialized(const uint8_t timer_number) { + return (timer_number == MF_TIMER_STEP) ? is_step_timer_initialized : + (timer_number == MF_TIMER_TEMP) ? is_temp_timer_initialized : + false; +} + +FORCE_INLINE static hal_timer_t HAL_timer_get_count(const uint8_t timer_number) { + if (!HAL_timer_initialized(timer_number)) return 0U; + + GeneralTimer& timer = (timer_number == MF_TIMER_STEP) ? Step_Timer : Temp_Timer; + + return (timer_number == MF_TIMER_STEP || timer_number == MF_TIMER_TEMP) + ? timer.getCounter(TimerFormat::TICK) + : 0U; +} + +FORCE_INLINE static void HAL_timer_set_compare(const uint8_t timer_number, const hal_timer_t value) { + if (!HAL_timer_initialized(timer_number)) return; + + const uint32_t new_value = static_cast(value + 1U); + GeneralTimer& timer = (timer_number == MF_TIMER_STEP) ? Step_Timer : Temp_Timer; + + if (timer_number == MF_TIMER_STEP || timer_number == MF_TIMER_TEMP) { + timer.setRolloverValue(new_value, TimerFormat::TICK); + if (value < static_cast(timer.getCounter(TimerFormat::TICK))) + timer.refresh(); + } +} + +#define HAL_timer_isr_prologue(T) NOOP +#define HAL_timer_isr_epilogue(T) NOOP diff --git a/Marlin/src/HAL/GD32_MFL/u8g/LCD_defines.h b/Marlin/src/HAL/GD32_MFL/u8g/LCD_defines.h new file mode 100644 index 0000000000..720d958779 --- /dev/null +++ b/Marlin/src/HAL/GD32_MFL/u8g/LCD_defines.h @@ -0,0 +1,26 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +// MFL LCD-specific defines +uint8_t u8g_com_HAL_MFL_sw_spi_fn(u8g_t* u8g, uint8_t msg, uint8_t arg_val, void* arg_ptr); // u8g_com_mfl_swspi.cpp +#define U8G_COM_HAL_SW_SPI_FN u8g_com_HAL_MFL_sw_spi_fn diff --git a/Marlin/src/HAL/HC32/eeprom_wired.cpp b/Marlin/src/HAL/HC32/eeprom_wired.cpp index d9be65b4c0..aea5fc87db 100644 --- a/Marlin/src/HAL/HC32/eeprom_wired.cpp +++ b/Marlin/src/HAL/HC32/eeprom_wired.cpp @@ -2,6 +2,9 @@ * Marlin 3D Printer Firmware * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or diff --git a/Marlin/src/HAL/HC32/pinsDebug.h b/Marlin/src/HAL/HC32/pinsDebug.h index e80b5a081e..9f8e23ce44 100644 --- a/Marlin/src/HAL/HC32/pinsDebug.h +++ b/Marlin/src/HAL/HC32/pinsDebug.h @@ -2,6 +2,9 @@ * Marlin 3D Printer Firmware * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or diff --git a/Marlin/src/HAL/HC32/spi_pins.h b/Marlin/src/HAL/HC32/spi_pins.h index 8a8e054b9b..5f1a94e920 100644 --- a/Marlin/src/HAL/HC32/spi_pins.h +++ b/Marlin/src/HAL/HC32/spi_pins.h @@ -2,6 +2,9 @@ * Marlin 3D Printer Firmware * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or diff --git a/Marlin/src/HAL/platforms.h b/Marlin/src/HAL/platforms.h index 36fb792776..e7eea44308 100644 --- a/Marlin/src/HAL/platforms.h +++ b/Marlin/src/HAL/platforms.h @@ -37,6 +37,8 @@ #define HAL_PATH(PATH, NAME) XSTR(PATH/HAL/LPC1768/NAME) #elif defined(ARDUINO_ARCH_HC32) #define HAL_PATH(PATH, NAME) XSTR(PATH/HAL/HC32/NAME) +#elif defined(ARDUINO_ARCH_MFL) + #define HAL_PATH(PATH, NAME) XSTR(PATH/HAL/GD32_MFL/NAME) #elif defined(__STM32F1__) || defined(TARGET_STM32F1) #define HAL_PATH(PATH, NAME) XSTR(PATH/HAL/STM32F1/NAME) #elif defined(ARDUINO_ARCH_STM32) diff --git a/Marlin/src/HAL/shared/servo.h b/Marlin/src/HAL/shared/servo.h index fa75445ed7..0101fcb628 100644 --- a/Marlin/src/HAL/shared/servo.h +++ b/Marlin/src/HAL/shared/servo.h @@ -76,6 +76,8 @@ #include "../LPC1768/Servo.h" #elif defined(ARDUINO_ARCH_HC32) #include "../HC32/Servo.h" +#elif defined(ARDUINO_ARCH_MFL) + #include "../GD32_MFL/Servo.h" #elif defined(__STM32F1__) || defined(TARGET_STM32F1) #include "../STM32F1/Servo.h" #elif defined(ARDUINO_ARCH_STM32) diff --git a/Marlin/src/core/boards.h b/Marlin/src/core/boards.h index c6713d0c98..3d34e3717e 100644 --- a/Marlin/src/core/boards.h +++ b/Marlin/src/core/boards.h @@ -383,7 +383,7 @@ #define BOARD_CHITU3D_V6 5036 // Chitu3D TronXY X5SA V6 Board (STM32F103ZE) #define BOARD_CHITU3D_V9 5037 // Chitu3D TronXY X5SA V9 Board (STM32F103ZE) #define BOARD_CREALITY_V4 5038 // Creality v4.x (STM32F103RC / STM32F103RE) -#define BOARD_CREALITY_V422 5039 // Creality v4.2.2 (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V422 5039 // Creality v4.2.2 (STM32F103RC / STM32F103RE) ... GD32 Variant Below! #define BOARD_CREALITY_V423 5040 // Creality v4.2.3 (STM32F103RC / STM32F103RE) #define BOARD_CREALITY_V425 5041 // Creality v4.2.5 (STM32F103RC / STM32F103RE) #define BOARD_CREALITY_V427 5042 // Creality v4.2.7 (STM32F103RC / STM32F103RE) @@ -552,12 +552,18 @@ #define BOARD_AQUILA_V101 7200 // Voxelab Aquila V1.0.0/V1.0.1/V1.0.2/V1.0.3 as found in the Voxelab Aquila X2 and C2 #define BOARD_CREALITY_ENDER2P_V24S4 7201 // Creality Ender 2 Pro v2.4.S4_170 (HC32f460kcta) +// +// GD32 ARM Cortex-M4 +// + +#define BOARD_CREALITY_V422_GD32_MFL 7300 // Creality V4.2.2 MFL (GD32F303RE) ... STM32 Variant Above! + // // Raspberry Pi // -#define BOARD_RP2040 6200 // Generic RP2040 Test board -#define BOARD_BTT_SKR_PICO 6201 // BigTreeTech SKR Pico 1.x +#define BOARD_RP2040 6200 // Generic RP2040 Test board +#define BOARD_BTT_SKR_PICO 6201 // BigTreeTech SKR Pico 1.x // // Custom board diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index 3c4cd44561..1a86bb37de 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -241,10 +241,10 @@ static_assert(COUNT(arm) == LOGICAL_AXES, "AXIS_RELATIVE_MODES must contain " _L #error "SERIAL_XON_XOFF and SERIAL_STATS_* features not supported on USB-native AVR devices." #endif -// Serial DMA is only available for some STM32 MCUs and HC32 +// Serial DMA is only available for some STM32 MCUs, HC32 and GD32 #if ENABLED(SERIAL_DMA) - #ifdef ARDUINO_ARCH_HC32 - // checks for HC32 are located in HAL/HC32/inc/SanityCheck.h + #if ANY(ARDUINO_ARCH_HC32, ARDUINO_ARCH_MFL) + // See HAL/.../inc/SanityCheck.h #elif DISABLED(HAL_STM32) || NONE(STM32F0xx, STM32F1xx, STM32F2xx, STM32F4xx, STM32F7xx, STM32H7xx) #error "SERIAL_DMA is only available for some STM32 MCUs and requires HAL/STM32." #elif !defined(HAL_UART_MODULE_ENABLED) || defined(HAL_UART_MODULE_ONLY) diff --git a/Marlin/src/inc/Warnings.cpp b/Marlin/src/inc/Warnings.cpp index 70a6905d9f..119e2205ab 100644 --- a/Marlin/src/inc/Warnings.cpp +++ b/Marlin/src/inc/Warnings.cpp @@ -696,9 +696,16 @@ #warning "Don't forget to update your TFT settings in Configuration.h." #endif -#if ENABLED(EMIT_CREALITY_422_WARNING) && DISABLED(NO_CREALITY_422_DRIVER_WARNING) - // Driver labels: A=TMC2208, B=TMC2209, C=HR4988, E=A4988, H=TMC2225, H8=HR4988 - #warning "Creality 4.2.2 boards come with a variety of stepper drivers. Check the board label (typically on SD Card module) and set the correct *_DRIVER_TYPE! (A/H: TMC2208_STANDALONE B: TMC2209_STANDALONE C/E/H8: A4988). (Define NO_CREALITY_422_DRIVER_WARNING to suppress this warning.)" +#if ENABLED(EMIT_CREALITY_422_WARNING) + #if DISABLED(NO_CREALITY_422_MCU_WARNING) + #warning "Double-check your 4.2.2 board for STM32 / GD32. Use BOARD_CREALITY_V422 or BOARD_CREALITY_V422_GD32_MFL as appropriate for your MCU." + #warning "GD32 Serial Ports are numbered starting from 0. STM32 Serial Ports are numbered starting from 1." + #warning "(Define NO_CREALITY_422_MCU_WARNING to suppress these warnings.)" + #endif + #if DISABLED(NO_CREALITY_422_DRIVER_WARNING) + // Driver labels: A=TMC2208, B=TMC2209, C=HR4988, E=A4988, H=TMC2225, H8=HR4988 + #warning "Creality 4.2.2 boards come with a variety of stepper drivers. Check the board label (typically on SD Card module) and set the correct *_DRIVER_TYPE! (A/H: TMC2208_STANDALONE B: TMC2209_STANDALONE C/E/H8: A4988). (Define NO_CREALITY_422_DRIVER_WARNING to suppress this warning.)" + #endif #endif #if ENABLED(PRINTCOUNTER_SYNC) diff --git a/Marlin/src/lcd/dogm/u8g/u8g_dev_st7920_128x64_HAL.cpp b/Marlin/src/lcd/dogm/u8g/u8g_dev_st7920_128x64_HAL.cpp index 6c330db204..76d15ce8a2 100644 --- a/Marlin/src/lcd/dogm/u8g/u8g_dev_st7920_128x64_HAL.cpp +++ b/Marlin/src/lcd/dogm/u8g/u8g_dev_st7920_128x64_HAL.cpp @@ -199,7 +199,7 @@ u8g_dev_t u8g_dev_st7920_128x64_HAL_4x_sw_spi = { u8g_dev_st7920_128x64_HAL_4x_f U8G_PB_DEV(u8g_dev_st7920_128x64_HAL_hw_spi, LCD_PIXEL_WIDTH, LCD_PIXEL_HEIGHT, PAGE_HEIGHT, u8g_dev_st7920_128x64_HAL_fn, U8G_COM_ST7920_HAL_HW_SPI); u8g_dev_t u8g_dev_st7920_128x64_HAL_4x_hw_spi = { u8g_dev_st7920_128x64_HAL_4x_fn, &u8g_dev_st7920_128x64_HAL_4x_pb, U8G_COM_ST7920_HAL_HW_SPI }; -#if NONE(__AVR__, ARDUINO_ARCH_STM32, ARDUINO_ARCH_ESP32) || defined(U8G_HAL_LINKS) +#if NONE(__AVR__, ARDUINO_ARCH_STM32, ARDUINO_ARCH_ESP32, ARDUINO_ARCH_MFL) || defined(U8G_HAL_LINKS) // Also use this device for HAL version of RRD class. This results in the same device being used // for the ST7920 for HAL systems no matter what is selected in marlinui_DOGM.h. u8g_dev_t u8g_dev_st7920_128x64_rrd_sw_spi = { u8g_dev_st7920_128x64_HAL_4x_fn, &u8g_dev_st7920_128x64_HAL_4x_pb, U8G_COM_ST7920_HAL_SW_SPI }; diff --git a/Marlin/src/lcd/dogm/u8g/ultralcd_st7920_u8glib_rrd_AVR.cpp b/Marlin/src/lcd/dogm/u8g/ultralcd_st7920_u8glib_rrd_AVR.cpp index 6f8990bf20..f7b50741ac 100644 --- a/Marlin/src/lcd/dogm/u8g/ultralcd_st7920_u8glib_rrd_AVR.cpp +++ b/Marlin/src/lcd/dogm/u8g/ultralcd_st7920_u8glib_rrd_AVR.cpp @@ -25,7 +25,7 @@ #include "../../../inc/MarlinConfigPre.h" -#if ANY(__AVR__, ARDUINO_ARCH_STM32, ARDUINO_ARCH_ESP32) +#if ANY(__AVR__, ARDUINO_ARCH_STM32, ARDUINO_ARCH_ESP32, ARDUINO_ARCH_MFL) #include "../../../inc/MarlinConfig.h" @@ -193,4 +193,4 @@ u8g_dev_t u8g_dev_st7920_128x64_rrd_sw_spi = { u8g_dev_rrd_st7920_128x64_fn, &u8 #endif #endif // IS_U8GLIB_ST7920 -#endif // __AVR__ || ARDUINO_ARCH_STM32 || ARDUINO_ARCH_ESP32 +#endif // __AVR__ || ARDUINO_ARCH_STM32 || ARDUINO_ARCH_ESP32 || ARDUINO_ARCH_MFL diff --git a/Marlin/src/libs/BL24CXX.cpp b/Marlin/src/libs/BL24CXX.cpp index 767561143c..43c68887b1 100644 --- a/Marlin/src/libs/BL24CXX.cpp +++ b/Marlin/src/libs/BL24CXX.cpp @@ -48,7 +48,7 @@ #ifdef __STM32F1__ #define SDA_IN() do{ PIN_MAP[IIC_EEPROM_SDA].gpio_device->regs->CRH &= 0XFFFF0FFF; PIN_MAP[IIC_EEPROM_SDA].gpio_device->regs->CRH |= 8 << 12; }while(0) #define SDA_OUT() do{ PIN_MAP[IIC_EEPROM_SDA].gpio_device->regs->CRH &= 0XFFFF0FFF; PIN_MAP[IIC_EEPROM_SDA].gpio_device->regs->CRH |= 3 << 12; }while(0) -#elif defined(STM32F1) || defined(STM32F4) || defined(ARDUINO_ARCH_HC32) +#elif ANY(STM32F1, STM32F4, ARDUINO_ARCH_HC32, ARDUINO_ARCH_MFL) #define SDA_IN() SET_INPUT(IIC_EEPROM_SDA) #define SDA_OUT() SET_OUTPUT(IIC_EEPROM_SDA) #endif diff --git a/Marlin/src/pins/gd32f3/pins_CREALITY_V422_GD32_MFL.h b/Marlin/src/pins/gd32f3/pins_CREALITY_V422_GD32_MFL.h new file mode 100644 index 0000000000..70b171eef9 --- /dev/null +++ b/Marlin/src/pins/gd32f3/pins_CREALITY_V422_GD32_MFL.h @@ -0,0 +1,37 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +/** + * Creality MFL GD32 V4.2.2 (GD32F303RE) board pin assignments + */ + +#define ALLOW_GD32F3 + +#ifndef BOARD_INFO_NAME + #define BOARD_INFO_NAME "Creality V4.2.2 MFL" +#endif +#ifndef DEFAULT_MACHINE_NAME + #define DEFAULT_MACHINE_NAME "Ender-3 MFL" +#endif + +#include "../stm32f1/pins_CREALITY_V4.h" diff --git a/Marlin/src/pins/pins.h b/Marlin/src/pins/pins.h index 55dc00c60d..2e0919062c 100644 --- a/Marlin/src/pins/pins.h +++ b/Marlin/src/pins/pins.h @@ -964,6 +964,13 @@ #elif MB(CREALITY_ENDER2P_V24S4) #include "hc32f4/pins_CREALITY_ENDER2P_V24S4.h" // HC32F460 env:HC32F460C_e2p24s4 +// +// GD32 ARM Cortex-M4 +// + +#elif MB(CREALITY_V422_GD32_MFL) + #include "gd32f3/pins_CREALITY_V422_GD32_MFL.h" // GD32F303RE env:GD32F303RE_creality_mfl + // // Raspberry Pi RP2040 // diff --git a/Marlin/src/pins/pinsDebug_list.h b/Marlin/src/pins/pinsDebug_list.h index e93f232545..fe7f1d21ee 100644 --- a/Marlin/src/pins/pinsDebug_list.h +++ b/Marlin/src/pins/pinsDebug_list.h @@ -27,6 +27,8 @@ #if TARGET_LPC1768 #define ANALOG_OK(PN) (WITHIN(PN, P0_02, P0_03) || WITHIN(PN, P0_23, P0_26) || WITHIN(PN, P1_30, P1_31)) +#elif ARDUINO_ARCH_MFL + #define ANALOG_OK(PN) (WITHIN(PN, 0, 7) || WITHIN(PN, 16, 17) || WITHIN(PN, 32, 37)) #else #define ANALOG_OK(PN) WITHIN(PN, 0, NUM_ANALOG_INPUTS - 1) #endif diff --git a/Marlin/src/pins/stm32f1/env_validate.h b/Marlin/src/pins/stm32f1/env_validate.h index 47399a062d..34b07723e7 100644 --- a/Marlin/src/pins/stm32f1/env_validate.h +++ b/Marlin/src/pins/stm32f1/env_validate.h @@ -23,13 +23,16 @@ #define ENV_VALIDATE_H #if NOT_TARGET(__STM32F1__, STM32F1) - #if DISABLED(ALLOW_STM32F4) + #if NONE(ALLOW_STM32F4, ALLOW_GD32F3) #error "Oops! Select an STM32F1 board in 'Tools > Board.'" - #elif NOT_TARGET(STM32F4) + #elif ENABLED(ALLOW_STM32F4) && NOT_TARGET(STM32F4) #error "Oops! Select an STM32F4 board in 'Tools > Board.'" + #elif ENABLED(ALLOW_GD32F3) && NOT_TARGET(ARDUINO_ARCH_MFL) + #error "Oops! Make sure you have a GD32F3 MFL environment selected." #endif #endif #undef ALLOW_STM32F4 +#undef ALLOW_GD32F3 #endif diff --git a/README.md b/README.md index 160c288aad..50b86d3213 100644 --- a/README.md +++ b/README.md @@ -58,12 +58,13 @@ Every new HAL opens up a world of hardware. At this time we need HALs for RP2040 [Teensy++ 2.0](//www.microchip.com/en-us/product/AT90USB1286)|AT90USB1286|Printrboard [Arduino Due](//www.arduino.cc/en/Guide/ArduinoDue)|SAM3X8E|RAMPS-FD, RADDS, RAMPS4DUE [ESP32](//github.com/espressif/arduino-esp32)|ESP32|FYSETC E4, E4d@BOX, MRR + [GD32](//www.gigadevice.com/)|GD32 ARM Cortex-M4|Creality MFL GD32 V4.2.2 [HC32](//www.huazhoucn.com/)|HC32|Ender-2 Pro, Voxelab Aquila [LPC1768](//www.nxp.com/products/processors-and-microcontrollers/arm-microcontrollers/general-purpose-mcus/lpc1700-cortex-m3/512-kb-flash-64-kb-sram-ethernet-usb-lqfp100-package:LPC1768FBD100)|ARM® Cortex-M3|MKS SBASE, Re-ARM, Selena Compact [LPC1769](//www.nxp.com/products/processors-and-microcontrollers/arm-microcontrollers/general-purpose-mcus/lpc1700-cortex-m3/512-kb-flash-64-kb-sram-ethernet-usb-lqfp100-package:LPC1769FBD100)|ARM® Cortex-M3|Smoothieboard, Azteeg X5 mini, TH3D EZBoard + [Pico RP2040](//www.raspberrypi.com/documentation/microcontrollers/pico-series.html)|Dual Cortex M0+|BigTreeTech SKR Pico [STM32F103](//www.st.com/en/microcontrollers-microprocessors/stm32f103.html)|ARM® Cortex-M3|Malyan M200, GTM32 Pro, MKS Robin, BTT SKR Mini [STM32F401](//www.st.com/en/microcontrollers-microprocessors/stm32f401.html)|ARM® Cortex-M4|ARMED, Rumba32, SKR Pro, Lerdge, FYSETC S6, Artillery Ruby - [Pico RP2040](//www.raspberrypi.com/documentation/microcontrollers/pico-series.html)|Dual Cortex M0+|BigTreeTech SKR Pico [STM32F7x6](//www.st.com/en/microcontrollers-microprocessors/stm32f7x6.html)|ARM® Cortex-M7|The Borg, RemRam V1 [STM32G0B1RET6](//www.st.com/en/microcontrollers-microprocessors/stm32g0x1.html)|ARM® Cortex-M0+|BigTreeTech SKR mini E3 V3.0 [STM32H743xIT6](//www.st.com/en/microcontrollers-microprocessors/stm32h743-753.html)|ARM® Cortex-M7|BigTreeTech SKR V3.0, SKR EZ V3.0, SKR SE BX V2.0/V3.0 diff --git a/buildroot/tests/GD32F303RE_creality_mfl b/buildroot/tests/GD32F303RE_creality_mfl new file mode 100755 index 0000000000..6e0b9ff866 --- /dev/null +++ b/buildroot/tests/GD32F303RE_creality_mfl @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +# +# Build tests for GD32F303RE_creality_mfl +# + +# exit on first failure +set -e + +restore_configs +opt_set MOTHERBOARD BOARD_CREALITY_V422_GD32_MFL SERIAL_PORT 0 +opt_enable EEPROM_SETTINGS SDSUPPORT EMERGENCY_PARSER FAN_SOFT_PWM PINS_DEBUGGING +opt_add NO_CREALITY_422_DRIVER_WARNING +opt_add NO_AUTO_ASSIGN_WARNING +exec_test $1 $2 "Creality V4.2.2 MFL GD32 Default Configuration" "$3" + +# cleanup +restore_configs diff --git a/ini/gd32.ini b/ini/gd32.ini new file mode 100644 index 0000000000..2e5bcea3b5 --- /dev/null +++ b/ini/gd32.ini @@ -0,0 +1,47 @@ +# +# Marlin Firmware +# PlatformIO Configuration File +# + +#################################### +# +# HAL/MFL GD32 Environments +# +#################################### + +[gd32_base] +platform = https://github.com/bmourit/platform-mfl/archive/refs/tags/V1.0.2.zip +board_build.core = gd32 +build_src_filter = ${common.default_src_filter} + + +build_unflags = -std=gnu++11 -std=gnu++14 -std=gnu++17 +build_flags = -std=gnu++23 + -DARDUINO_ARCH_MFL + -DPLATFORM_M997_SUPPORT + -DTIMER_IRQ_PRIORITY=12 + -DADC_RESOLUTION=12 + -DCORE_DEBUG + -Wno-deprecated-declarations + -Wno-volatile +extra_scripts = ${common.extra_scripts} + +# +# Creality (GD32F303RE) +# +[env:GD32F303RE_creality_mfl] +extends = gd32_base +board = mfl_creality_422 +board_build.offset = 0x7000 +board_build.rename = firmware-{time}.bin +board_upload.offset_address = 0x08007000 +build_flags = ${gd32_base.build_flags} + -DMCU_GD32F303RE + -DGD32F303RE + -DTIMER_TONE=2 + -DSS_TIMER=3 + -DTIMER_SERVO=4 + -DTRANSFER_CLOCK_DIV=8 + -fsingle-precision-constant +extra_scripts = ${gd32_base.extra_scripts} + buildroot/share/PlatformIO/scripts/offset_and_rename.py + +monitor_speed = 115200 diff --git a/platformio.ini b/platformio.ini index ed1670dc6d..d69fdc6cea 100644 --- a/platformio.ini +++ b/platformio.ini @@ -22,6 +22,7 @@ extra_configs = ini/esp32.ini ini/features.ini ini/hc32.ini + ini/gd32.ini ini/lpc176x.ini ini/native.ini ini/samd21.ini From 849e432d62ecd9ebe23cb81b66829755b19362f9 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Fri, 28 Mar 2025 06:09:42 +0000 Subject: [PATCH 161/787] [cron] Bump distribution date (2025-03-28) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index c24e090c3d..4947d61a01 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-03-27" +//#define STRING_DISTRIBUTION_DATE "2025-03-28" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 690de1c353..18f02773cf 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-03-27" + #define STRING_DISTRIBUTION_DATE "2025-03-28" #endif /** From aad10ea1c7c1aac37d83c3d8537b4040f6f0e259 Mon Sep 17 00:00:00 2001 From: ellensp <530024+ellensp@users.noreply.github.com> Date: Sun, 30 Mar 2025 14:58:16 +1300 Subject: [PATCH 162/787] =?UTF-8?q?=F0=9F=90=9B=20Fix=20E=20DIR=20init=20(?= =?UTF-8?q?#27770)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Followup to add72fd045 --- Marlin/src/module/stepper.cpp | 10 +- Marlin/src/module/stepper/indirection.h | 240 +++++++++++++----------- 2 files changed, 137 insertions(+), 113 deletions(-) diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp index 1ec82ba340..a86a33dda3 100644 --- a/Marlin/src/module/stepper.cpp +++ b/Marlin/src/module/stepper.cpp @@ -2958,11 +2958,19 @@ void Stepper::init() { TERN_(HAS_Z3_DIR, Z3_DIR_INIT()); TERN_(HAS_Z4_DIR, Z4_DIR_INIT()); TERN_(HAS_I_DIR, I_DIR_INIT()); - TERN_(HAS_K_DIR, K_DIR_INIT()); + TERN_(HAS_J_DIR, J_DIR_INIT()); TERN_(HAS_K_DIR, K_DIR_INIT()); TERN_(HAS_U_DIR, U_DIR_INIT()); TERN_(HAS_V_DIR, V_DIR_INIT()); TERN_(HAS_W_DIR, W_DIR_INIT()); + TERN_(HAS_E0_DIR, E0_DIR_INIT()); + TERN_(HAS_E1_DIR, E1_DIR_INIT()); + TERN_(HAS_E2_DIR, E2_DIR_INIT()); + TERN_(HAS_E3_DIR, E3_DIR_INIT()); + TERN_(HAS_E4_DIR, E4_DIR_INIT()); + TERN_(HAS_E5_DIR, E5_DIR_INIT()); + TERN_(HAS_E6_DIR, E6_DIR_INIT()); + TERN_(HAS_E7_DIR, E7_DIR_INIT()); // Init Enable Pins - steppers default to disabled. #if HAS_X_ENABLE diff --git a/Marlin/src/module/stepper/indirection.h b/Marlin/src/module/stepper/indirection.h index d18fe830cc..e55b8ac45d 100644 --- a/Marlin/src/module/stepper/indirection.h +++ b/Marlin/src/module/stepper/indirection.h @@ -353,140 +353,156 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset #endif // E0 Stepper -#ifndef E0_ENABLE_INIT - #define E0_ENABLE_INIT() SET_OUTPUT(E0_ENABLE_PIN) - #define E0_ENABLE_WRITE(STATE) WRITE(E0_ENABLE_PIN,STATE) - #define E0_ENABLE_READ() bool(READ(E0_ENABLE_PIN)) +#if E_STEPPERS > 0 + #ifndef E0_ENABLE_INIT + #define E0_ENABLE_INIT() SET_OUTPUT(E0_ENABLE_PIN) + #define E0_ENABLE_WRITE(STATE) WRITE(E0_ENABLE_PIN,STATE) + #define E0_ENABLE_READ() bool(READ(E0_ENABLE_PIN)) + #endif + #ifndef E0_DIR_INIT + #define E0_DIR_INIT() SET_OUTPUT(E0_DIR_PIN) + #define E0_DIR_WRITE(STATE) WRITE(E0_DIR_PIN,INVERT_DIR(E0, STATE)) + #define E0_DIR_READ() INVERT_DIR(E0, bool(READ(E0_DIR_PIN))) + #endif + #define E0_STEP_INIT() SET_OUTPUT(E0_STEP_PIN) + #ifndef E0_STEP_WRITE + #define E0_STEP_WRITE(STATE) WRITE(E0_STEP_PIN,STATE) + #endif + #define E0_STEP_READ() bool(READ(E0_STEP_PIN)) #endif -#ifndef E0_DIR_INIT - #define E0_DIR_INIT() SET_OUTPUT(E0_DIR_PIN) - #define E0_DIR_WRITE(STATE) WRITE(E0_DIR_PIN,INVERT_DIR(E0, STATE)) - #define E0_DIR_READ() INVERT_DIR(E0, bool(READ(E0_DIR_PIN))) -#endif -#define E0_STEP_INIT() SET_OUTPUT(E0_STEP_PIN) -#ifndef E0_STEP_WRITE - #define E0_STEP_WRITE(STATE) WRITE(E0_STEP_PIN,STATE) -#endif -#define E0_STEP_READ() bool(READ(E0_STEP_PIN)) // E1 Stepper -#ifndef E1_ENABLE_INIT - #define E1_ENABLE_INIT() SET_OUTPUT(E1_ENABLE_PIN) - #define E1_ENABLE_WRITE(STATE) WRITE(E1_ENABLE_PIN,STATE) - #define E1_ENABLE_READ() bool(READ(E1_ENABLE_PIN)) +#if E_STEPPERS > 1 || ENABLED(E_DUAL_STEPPER_DRIVERS) + #ifndef E1_ENABLE_INIT + #define E1_ENABLE_INIT() SET_OUTPUT(E1_ENABLE_PIN) + #define E1_ENABLE_WRITE(STATE) WRITE(E1_ENABLE_PIN,STATE) + #define E1_ENABLE_READ() bool(READ(E1_ENABLE_PIN)) + #endif + #ifndef E1_DIR_INIT + #define E1_DIR_INIT() SET_OUTPUT(E1_DIR_PIN) + #define E1_DIR_WRITE(STATE) WRITE(E1_DIR_PIN,INVERT_DIR(E1, STATE)) + #define E1_DIR_READ() INVERT_DIR(E1, bool(READ(E1_DIR_PIN))) + #endif + #define E1_STEP_INIT() SET_OUTPUT(E1_STEP_PIN) + #ifndef E1_STEP_WRITE + #define E1_STEP_WRITE(STATE) WRITE(E1_STEP_PIN,STATE) + #endif + #define E1_STEP_READ() bool(READ(E1_STEP_PIN)) #endif -#ifndef E1_DIR_INIT - #define E1_DIR_INIT() SET_OUTPUT(E1_DIR_PIN) - #define E1_DIR_WRITE(STATE) WRITE(E1_DIR_PIN,INVERT_DIR(E1, STATE)) - #define E1_DIR_READ() INVERT_DIR(E1, bool(READ(E1_DIR_PIN))) -#endif -#define E1_STEP_INIT() SET_OUTPUT(E1_STEP_PIN) -#ifndef E1_STEP_WRITE - #define E1_STEP_WRITE(STATE) WRITE(E1_STEP_PIN,STATE) -#endif -#define E1_STEP_READ() bool(READ(E1_STEP_PIN)) // E2 Stepper -#ifndef E2_ENABLE_INIT - #define E2_ENABLE_INIT() SET_OUTPUT(E2_ENABLE_PIN) - #define E2_ENABLE_WRITE(STATE) WRITE(E2_ENABLE_PIN,STATE) - #define E2_ENABLE_READ() bool(READ(E2_ENABLE_PIN)) +#if E_STEPPERS > 2 + #ifndef E2_ENABLE_INIT + #define E2_ENABLE_INIT() SET_OUTPUT(E2_ENABLE_PIN) + #define E2_ENABLE_WRITE(STATE) WRITE(E2_ENABLE_PIN,STATE) + #define E2_ENABLE_READ() bool(READ(E2_ENABLE_PIN)) + #endif + #ifndef E2_DIR_INIT + #define E2_DIR_INIT() SET_OUTPUT(E2_DIR_PIN) + #define E2_DIR_WRITE(STATE) WRITE(E2_DIR_PIN,INVERT_DIR(E2, STATE)) + #define E2_DIR_READ() INVERT_DIR(E2, bool(READ(E2_DIR_PIN))) + #endif + #define E2_STEP_INIT() SET_OUTPUT(E2_STEP_PIN) + #ifndef E2_STEP_WRITE + #define E2_STEP_WRITE(STATE) WRITE(E2_STEP_PIN,STATE) + #endif + #define E2_STEP_READ() bool(READ(E2_STEP_PIN)) #endif -#ifndef E2_DIR_INIT - #define E2_DIR_INIT() SET_OUTPUT(E2_DIR_PIN) - #define E2_DIR_WRITE(STATE) WRITE(E2_DIR_PIN,INVERT_DIR(E2, STATE)) - #define E2_DIR_READ() INVERT_DIR(E2, bool(READ(E2_DIR_PIN))) -#endif -#define E2_STEP_INIT() SET_OUTPUT(E2_STEP_PIN) -#ifndef E2_STEP_WRITE - #define E2_STEP_WRITE(STATE) WRITE(E2_STEP_PIN,STATE) -#endif -#define E2_STEP_READ() bool(READ(E2_STEP_PIN)) // E3 Stepper -#ifndef E3_ENABLE_INIT - #define E3_ENABLE_INIT() SET_OUTPUT(E3_ENABLE_PIN) - #define E3_ENABLE_WRITE(STATE) WRITE(E3_ENABLE_PIN,STATE) - #define E3_ENABLE_READ() bool(READ(E3_ENABLE_PIN)) +#if E_STEPPERS > 3 + #ifndef E3_ENABLE_INIT + #define E3_ENABLE_INIT() SET_OUTPUT(E3_ENABLE_PIN) + #define E3_ENABLE_WRITE(STATE) WRITE(E3_ENABLE_PIN,STATE) + #define E3_ENABLE_READ() bool(READ(E3_ENABLE_PIN)) + #endif + #ifndef E3_DIR_INIT + #define E3_DIR_INIT() SET_OUTPUT(E3_DIR_PIN) + #define E3_DIR_WRITE(STATE) WRITE(E3_DIR_PIN,INVERT_DIR(E3, STATE)) + #define E3_DIR_READ() INVERT_DIR(E3, bool(READ(E3_DIR_PIN))) + #endif + #define E3_STEP_INIT() SET_OUTPUT(E3_STEP_PIN) + #ifndef E3_STEP_WRITE + #define E3_STEP_WRITE(STATE) WRITE(E3_STEP_PIN,STATE) + #endif + #define E3_STEP_READ() bool(READ(E3_STEP_PIN)) #endif -#ifndef E3_DIR_INIT - #define E3_DIR_INIT() SET_OUTPUT(E3_DIR_PIN) - #define E3_DIR_WRITE(STATE) WRITE(E3_DIR_PIN,INVERT_DIR(E3, STATE)) - #define E3_DIR_READ() INVERT_DIR(E3, bool(READ(E3_DIR_PIN))) -#endif -#define E3_STEP_INIT() SET_OUTPUT(E3_STEP_PIN) -#ifndef E3_STEP_WRITE - #define E3_STEP_WRITE(STATE) WRITE(E3_STEP_PIN,STATE) -#endif -#define E3_STEP_READ() bool(READ(E3_STEP_PIN)) // E4 Stepper -#ifndef E4_ENABLE_INIT - #define E4_ENABLE_INIT() SET_OUTPUT(E4_ENABLE_PIN) - #define E4_ENABLE_WRITE(STATE) WRITE(E4_ENABLE_PIN,STATE) - #define E4_ENABLE_READ() bool(READ(E4_ENABLE_PIN)) +#if E_STEPPERS > 4 + #ifndef E4_ENABLE_INIT + #define E4_ENABLE_INIT() SET_OUTPUT(E4_ENABLE_PIN) + #define E4_ENABLE_WRITE(STATE) WRITE(E4_ENABLE_PIN,STATE) + #define E4_ENABLE_READ() bool(READ(E4_ENABLE_PIN)) + #endif + #ifndef E4_DIR_INIT + #define E4_DIR_INIT() SET_OUTPUT(E4_DIR_PIN) + #define E4_DIR_WRITE(STATE) WRITE(E4_DIR_PIN,INVERT_DIR(E4, STATE)) + #define E4_DIR_READ() INVERT_DIR(E4, bool(READ(E4_DIR_PIN))) + #endif + #define E4_STEP_INIT() SET_OUTPUT(E4_STEP_PIN) + #ifndef E4_STEP_WRITE + #define E4_STEP_WRITE(STATE) WRITE(E4_STEP_PIN,STATE) + #endif + #define E4_STEP_READ() bool(READ(E4_STEP_PIN)) #endif -#ifndef E4_DIR_INIT - #define E4_DIR_INIT() SET_OUTPUT(E4_DIR_PIN) - #define E4_DIR_WRITE(STATE) WRITE(E4_DIR_PIN,INVERT_DIR(E4, STATE)) - #define E4_DIR_READ() INVERT_DIR(E4, bool(READ(E4_DIR_PIN))) -#endif -#define E4_STEP_INIT() SET_OUTPUT(E4_STEP_PIN) -#ifndef E4_STEP_WRITE - #define E4_STEP_WRITE(STATE) WRITE(E4_STEP_PIN,STATE) -#endif -#define E4_STEP_READ() bool(READ(E4_STEP_PIN)) // E5 Stepper -#ifndef E5_ENABLE_INIT - #define E5_ENABLE_INIT() SET_OUTPUT(E5_ENABLE_PIN) - #define E5_ENABLE_WRITE(STATE) WRITE(E5_ENABLE_PIN,STATE) - #define E5_ENABLE_READ() bool(READ(E5_ENABLE_PIN)) +#if E_STEPPERS > 5 + #ifndef E5_ENABLE_INIT + #define E5_ENABLE_INIT() SET_OUTPUT(E5_ENABLE_PIN) + #define E5_ENABLE_WRITE(STATE) WRITE(E5_ENABLE_PIN,STATE) + #define E5_ENABLE_READ() bool(READ(E5_ENABLE_PIN)) + #endif + #ifndef E5_DIR_INIT + #define E5_DIR_INIT() SET_OUTPUT(E5_DIR_PIN) + #define E5_DIR_WRITE(STATE) WRITE(E5_DIR_PIN,INVERT_DIR(E5, STATE)) + #define E5_DIR_READ() INVERT_DIR(E5, bool(READ(E5_DIR_PIN))) + #endif + #define E5_STEP_INIT() SET_OUTPUT(E5_STEP_PIN) + #ifndef E5_STEP_WRITE + #define E5_STEP_WRITE(STATE) WRITE(E5_STEP_PIN,STATE) + #endif + #define E5_STEP_READ() bool(READ(E5_STEP_PIN)) #endif -#ifndef E5_DIR_INIT - #define E5_DIR_INIT() SET_OUTPUT(E5_DIR_PIN) - #define E5_DIR_WRITE(STATE) WRITE(E5_DIR_PIN,INVERT_DIR(E5, STATE)) - #define E5_DIR_READ() INVERT_DIR(E5, bool(READ(E5_DIR_PIN))) -#endif -#define E5_STEP_INIT() SET_OUTPUT(E5_STEP_PIN) -#ifndef E5_STEP_WRITE - #define E5_STEP_WRITE(STATE) WRITE(E5_STEP_PIN,STATE) -#endif -#define E5_STEP_READ() bool(READ(E5_STEP_PIN)) // E6 Stepper -#ifndef E6_ENABLE_INIT - #define E6_ENABLE_INIT() SET_OUTPUT(E6_ENABLE_PIN) - #define E6_ENABLE_WRITE(STATE) WRITE(E6_ENABLE_PIN,STATE) - #define E6_ENABLE_READ() bool(READ(E6_ENABLE_PIN)) +#if E_STEPPERS > 6 + #ifndef E6_ENABLE_INIT + #define E6_ENABLE_INIT() SET_OUTPUT(E6_ENABLE_PIN) + #define E6_ENABLE_WRITE(STATE) WRITE(E6_ENABLE_PIN,STATE) + #define E6_ENABLE_READ() bool(READ(E6_ENABLE_PIN)) + #endif + #ifndef E6_DIR_INIT + #define E6_DIR_INIT() SET_OUTPUT(E6_DIR_PIN) + #define E6_DIR_WRITE(STATE) WRITE(E6_DIR_PIN,INVERT_DIR(E6, STATE)) + #define E6_DIR_READ() INVERT_DIR(E6, bool(READ(E6_DIR_PIN))) + #endif + #define E6_STEP_INIT() SET_OUTPUT(E6_STEP_PIN) + #ifndef E6_STEP_WRITE + #define E6_STEP_WRITE(STATE) WRITE(E6_STEP_PIN,STATE) + #endif + #define E6_STEP_READ() bool(READ(E6_STEP_PIN)) #endif -#ifndef E6_DIR_INIT - #define E6_DIR_INIT() SET_OUTPUT(E6_DIR_PIN) - #define E6_DIR_WRITE(STATE) WRITE(E6_DIR_PIN,INVERT_DIR(E6, STATE)) - #define E6_DIR_READ() INVERT_DIR(E6, bool(READ(E6_DIR_PIN))) -#endif -#define E6_STEP_INIT() SET_OUTPUT(E6_STEP_PIN) -#ifndef E6_STEP_WRITE - #define E6_STEP_WRITE(STATE) WRITE(E6_STEP_PIN,STATE) -#endif -#define E6_STEP_READ() bool(READ(E6_STEP_PIN)) // E7 Stepper -#ifndef E7_ENABLE_INIT - #define E7_ENABLE_INIT() SET_OUTPUT(E7_ENABLE_PIN) - #define E7_ENABLE_WRITE(STATE) WRITE(E7_ENABLE_PIN,STATE) - #define E7_ENABLE_READ() bool(READ(E7_ENABLE_PIN)) +#if E_STEPPERS > 7 + #ifndef E7_ENABLE_INIT + #define E7_ENABLE_INIT() SET_OUTPUT(E7_ENABLE_PIN) + #define E7_ENABLE_WRITE(STATE) WRITE(E7_ENABLE_PIN,STATE) + #define E7_ENABLE_READ() bool(READ(E7_ENABLE_PIN)) + #endif + #ifndef E7_DIR_INIT + #define E7_DIR_INIT() SET_OUTPUT(E7_DIR_PIN) + #define E7_DIR_WRITE(STATE) WRITE(E7_DIR_PIN,INVERT_DIR(E7, STATE)) + #define E7_DIR_READ() INVERT_DIR(E7, bool(READ(E7_DIR_PIN))) + #endif + #define E7_STEP_INIT() SET_OUTPUT(E7_STEP_PIN) + #ifndef E7_STEP_WRITE + #define E7_STEP_WRITE(STATE) WRITE(E7_STEP_PIN,STATE) + #endif + #define E7_STEP_READ() bool(READ(E7_STEP_PIN)) #endif -#ifndef E7_DIR_INIT - #define E7_DIR_INIT() SET_OUTPUT(E7_DIR_PIN) - #define E7_DIR_WRITE(STATE) WRITE(E7_DIR_PIN,INVERT_DIR(E7, STATE)) - #define E7_DIR_READ() INVERT_DIR(E7, bool(READ(E7_DIR_PIN))) -#endif -#define E7_STEP_INIT() SET_OUTPUT(E7_STEP_PIN) -#ifndef E7_STEP_WRITE - #define E7_STEP_WRITE(STATE) WRITE(E7_STEP_PIN,STATE) -#endif -#define E7_STEP_READ() bool(READ(E7_STEP_PIN)) /** * Extruder indirection for the single E axis From fd17cc962b4788185f9f2e04c96ce608691afc4a Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Sun, 30 Mar 2025 06:08:25 +0000 Subject: [PATCH 163/787] [cron] Bump distribution date (2025-03-30) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 4947d61a01..a0cbd5cf9b 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-03-28" +//#define STRING_DISTRIBUTION_DATE "2025-03-30" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 18f02773cf..b717290a77 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-03-28" + #define STRING_DISTRIBUTION_DATE "2025-03-30" #endif /** From 73ed54308a6da8244ac10de04fb19d173fa54c83 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sun, 30 Mar 2025 14:56:55 -0500 Subject: [PATCH 164/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Mov?= =?UTF-8?q?e=20ENABLE=20to=20indirection.h?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Followup to add72fd045 --- Marlin/src/inc/Conditionals-5-post.h | 24 ++-- Marlin/src/module/stepper.cpp | 149 ++++-------------------- Marlin/src/module/stepper/indirection.h | 71 ++++++++++- 3 files changed, 107 insertions(+), 137 deletions(-) diff --git a/Marlin/src/inc/Conditionals-5-post.h b/Marlin/src/inc/Conditionals-5-post.h index 93be95c95d..f83c063d11 100644 --- a/Marlin/src/inc/Conditionals-5-post.h +++ b/Marlin/src/inc/Conditionals-5-post.h @@ -1065,17 +1065,19 @@ #define HAS_X_MS_PINS 1 #endif - #if PIN_EXISTS(X2_ENABLE) || ALL(SOFTWARE_DRIVER_ENABLE, X2_IS_TRINAMIC) - #define HAS_X2_ENABLE 1 - #endif - #if PIN_EXISTS(X2_DIR) - #define HAS_X2_DIR 1 - #endif - #if PIN_EXISTS(X2_STEP) - #define HAS_X2_STEP 1 - #endif - #if PIN_EXISTS(X2_MS1) - #define HAS_X2_MS_PINS 1 + #if HAS_X2_STEPPER + #if PIN_EXISTS(X2_ENABLE) || ALL(SOFTWARE_DRIVER_ENABLE, X2_IS_TRINAMIC) + #define HAS_X2_ENABLE 1 + #endif + #if PIN_EXISTS(X2_DIR) + #define HAS_X2_DIR 1 + #endif + #if PIN_EXISTS(X2_STEP) + #define HAS_X2_STEP 1 + #endif + #if PIN_EXISTS(X2_MS1) + #define HAS_X2_MS_PINS 1 + #endif #endif #endif diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp index a86a33dda3..f55465ea56 100644 --- a/Marlin/src/module/stepper.cpp +++ b/Marlin/src/module/stepper.cpp @@ -2972,131 +2972,30 @@ void Stepper::init() { TERN_(HAS_E6_DIR, E6_DIR_INIT()); TERN_(HAS_E7_DIR, E7_DIR_INIT()); - // Init Enable Pins - steppers default to disabled. - #if HAS_X_ENABLE - #ifndef X_ENABLE_INIT_STATE - #define X_ENABLE_INIT_STATE !X_ENABLE_ON - #endif - X_ENABLE_INIT(); - if (X_ENABLE_INIT_STATE) X_ENABLE_WRITE(X_ENABLE_INIT_STATE); - #if ALL(HAS_X2_STEPPER, HAS_X2_ENABLE) - X2_ENABLE_INIT(); - if (X_ENABLE_INIT_STATE) X2_ENABLE_WRITE(X_ENABLE_INIT_STATE); - #endif - #endif - #if HAS_Y_ENABLE - #ifndef Y_ENABLE_INIT_STATE - #define Y_ENABLE_INIT_STATE !Y_ENABLE_ON - #endif - Y_ENABLE_INIT(); - if (Y_ENABLE_INIT_STATE) Y_ENABLE_WRITE(Y_ENABLE_INIT_STATE); - #if ALL(HAS_Y2_STEPPER, HAS_Y2_ENABLE) - Y2_ENABLE_INIT(); - if (Y_ENABLE_INIT_STATE) Y2_ENABLE_WRITE(Y_ENABLE_INIT_STATE); - #endif - #endif - #if HAS_Z_ENABLE - #ifndef Z_ENABLE_INIT_STATE - #define Z_ENABLE_INIT_STATE !Z_ENABLE_ON - #endif - Z_ENABLE_INIT(); - if (Z_ENABLE_INIT_STATE) Z_ENABLE_WRITE(Z_ENABLE_INIT_STATE); - #if HAS_Z2_ENABLE - Z2_ENABLE_INIT(); - if (Z_ENABLE_INIT_STATE) Z2_ENABLE_WRITE(Z_ENABLE_INIT_STATE); - #endif - #if HAS_Z3_ENABLE - Z3_ENABLE_INIT(); - if (Z_ENABLE_INIT_STATE) Z3_ENABLE_WRITE(Z_ENABLE_INIT_STATE); - #endif - #if HAS_Z4_ENABLE - Z4_ENABLE_INIT(); - if (Z_ENABLE_INIT_STATE) Z4_ENABLE_WRITE(Z_ENABLE_INIT_STATE); - #endif - #endif - #if HAS_I_ENABLE - I_ENABLE_INIT(); - if (!I_ENABLE_ON) I_ENABLE_WRITE(HIGH); - #endif - #if HAS_J_ENABLE - J_ENABLE_INIT(); - if (!J_ENABLE_ON) J_ENABLE_WRITE(HIGH); - #endif - #if HAS_K_ENABLE - K_ENABLE_INIT(); - if (!K_ENABLE_ON) K_ENABLE_WRITE(HIGH); - #endif - #if HAS_U_ENABLE - U_ENABLE_INIT(); - if (!U_ENABLE_ON) U_ENABLE_WRITE(HIGH); - #endif - #if HAS_V_ENABLE - V_ENABLE_INIT(); - if (!V_ENABLE_ON) V_ENABLE_WRITE(HIGH); - #endif - #if HAS_W_ENABLE - W_ENABLE_INIT(); - if (!W_ENABLE_ON) W_ENABLE_WRITE(HIGH); - #endif - #if HAS_E0_ENABLE - #ifndef E_ENABLE_INIT_STATE - #define E_ENABLE_INIT_STATE !E_ENABLE_ON - #endif - #ifndef E0_ENABLE_INIT_STATE - #define E0_ENABLE_INIT_STATE E_ENABLE_INIT_STATE - #endif - E0_ENABLE_INIT(); - if (E0_ENABLE_INIT_STATE) E0_ENABLE_WRITE(E0_ENABLE_INIT_STATE); - #endif - #if HAS_E1_ENABLE - #ifndef E1_ENABLE_INIT_STATE - #define E1_ENABLE_INIT_STATE E_ENABLE_INIT_STATE - #endif - E1_ENABLE_INIT(); - if (E1_ENABLE_INIT_STATE) E1_ENABLE_WRITE(E1_ENABLE_INIT_STATE); - #endif - #if HAS_E2_ENABLE - #ifndef E2_ENABLE_INIT_STATE - #define E2_ENABLE_INIT_STATE E_ENABLE_INIT_STATE - #endif - E2_ENABLE_INIT(); - if (E2_ENABLE_INIT_STATE) E2_ENABLE_WRITE(E2_ENABLE_INIT_STATE); - #endif - #if HAS_E3_ENABLE - #ifndef E3_ENABLE_INIT_STATE - #define E3_ENABLE_INIT_STATE E_ENABLE_INIT_STATE - #endif - E3_ENABLE_INIT(); - if (E3_ENABLE_INIT_STATE) E3_ENABLE_WRITE(E3_ENABLE_INIT_STATE); - #endif - #if HAS_E4_ENABLE - #ifndef E4_ENABLE_INIT_STATE - #define E4_ENABLE_INIT_STATE E_ENABLE_INIT_STATE - #endif - E4_ENABLE_INIT(); - if (E4_ENABLE_INIT_STATE) E4_ENABLE_WRITE(E4_ENABLE_INIT_STATE); - #endif - #if HAS_E5_ENABLE - #ifndef E5_ENABLE_INIT_STATE - #define E5_ENABLE_INIT_STATE E_ENABLE_INIT_STATE - #endif - E5_ENABLE_INIT(); - if (E5_ENABLE_INIT_STATE) E5_ENABLE_WRITE(E5_ENABLE_INIT_STATE); - #endif - #if HAS_E6_ENABLE - #ifndef E6_ENABLE_INIT_STATE - #define E6_ENABLE_INIT_STATE E_ENABLE_INIT_STATE - #endif - E6_ENABLE_INIT(); - if (E6_ENABLE_INIT_STATE) E6_ENABLE_WRITE(E6_ENABLE_INIT_STATE); - #endif - #if HAS_E7_ENABLE - #ifndef E7_ENABLE_INIT_STATE - #define E7_ENABLE_INIT_STATE E_ENABLE_INIT_STATE - #endif - E7_ENABLE_INIT(); - if (E7_ENABLE_INIT_STATE) E7_ENABLE_WRITE(E7_ENABLE_INIT_STATE); - #endif + // Init Enable Pins - Steppers default to disabled. + #define _INIT_CONFIG_ENABLE(A) do{ A##_ENABLE_INIT(); if (A##_ENABLE_INIT_STATE) A##_ENABLE_WRITE(HIGH); }while(0) + TERN_(HAS_X_ENABLE, _INIT_CONFIG_ENABLE(X)); + TERN_(HAS_X2_ENABLE, _INIT_CONFIG_ENABLE(X2)); + TERN_(HAS_Y_ENABLE, _INIT_CONFIG_ENABLE(Y)); + TERN_(HAS_Y2_ENABLE, _INIT_CONFIG_ENABLE(Y2)); + TERN_(HAS_Z_ENABLE, _INIT_CONFIG_ENABLE(Z)); + TERN_(HAS_Z2_ENABLE, _INIT_CONFIG_ENABLE(Z2)); + TERN_(HAS_Z3_ENABLE, _INIT_CONFIG_ENABLE(Z3)); + TERN_(HAS_Z4_ENABLE, _INIT_CONFIG_ENABLE(Z4)); + TERN_(HAS_I_ENABLE, _INIT_CONFIG_ENABLE(I)); + TERN_(HAS_J_ENABLE, _INIT_CONFIG_ENABLE(J)); + TERN_(HAS_K_ENABLE, _INIT_CONFIG_ENABLE(K)); + TERN_(HAS_U_ENABLE, _INIT_CONFIG_ENABLE(U)); + TERN_(HAS_V_ENABLE, _INIT_CONFIG_ENABLE(V)); + TERN_(HAS_W_ENABLE, _INIT_CONFIG_ENABLE(W)); + TERN_(HAS_E0_ENABLE, _INIT_CONFIG_ENABLE(E0)); + TERN_(HAS_E1_ENABLE, _INIT_CONFIG_ENABLE(E1)); + TERN_(HAS_E2_ENABLE, _INIT_CONFIG_ENABLE(E2)); + TERN_(HAS_E3_ENABLE, _INIT_CONFIG_ENABLE(E3)); + TERN_(HAS_E4_ENABLE, _INIT_CONFIG_ENABLE(E4)); + TERN_(HAS_E5_ENABLE, _INIT_CONFIG_ENABLE(E5)); + TERN_(HAS_E6_ENABLE, _INIT_CONFIG_ENABLE(E6)); + TERN_(HAS_E7_ENABLE, _INIT_CONFIG_ENABLE(E7)); #define _STEP_INIT(AXIS) AXIS ##_STEP_INIT() #define _WRITE_STEP(AXIS, HIGHLOW) AXIS ##_STEP_WRITE(HIGHLOW) diff --git a/Marlin/src/module/stepper/indirection.h b/Marlin/src/module/stepper/indirection.h index e55b8ac45d..19594df66c 100644 --- a/Marlin/src/module/stepper/indirection.h +++ b/Marlin/src/module/stepper/indirection.h @@ -80,6 +80,9 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset // X Stepper #if HAS_X_AXIS + #ifndef X_ENABLE_INIT_STATE + #define X_ENABLE_INIT_STATE !X_ENABLE_ON + #endif #ifndef X_ENABLE_INIT #define X_ENABLE_INIT() SET_OUTPUT(X_ENABLE_PIN) #define X_ENABLE_WRITE(STATE) WRITE(X_ENABLE_PIN,STATE) @@ -99,6 +102,9 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset // Y Stepper #if HAS_Y_AXIS + #ifndef Y_ENABLE_INIT_STATE + #define Y_ENABLE_INIT_STATE !Y_ENABLE_ON + #endif #ifndef Y_ENABLE_INIT #define Y_ENABLE_INIT() SET_OUTPUT(Y_ENABLE_PIN) #define Y_ENABLE_WRITE(STATE) WRITE(Y_ENABLE_PIN,STATE) @@ -118,6 +124,9 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset // Z Stepper #if HAS_Z_AXIS + #ifndef Z_ENABLE_INIT_STATE + #define Z_ENABLE_INIT_STATE !Z_ENABLE_ON + #endif #ifndef Z_ENABLE_INIT #define Z_ENABLE_INIT() SET_OUTPUT(Z_ENABLE_PIN) #define Z_ENABLE_WRITE(STATE) WRITE(Z_ENABLE_PIN,STATE) @@ -137,6 +146,9 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset // X2 Stepper #if HAS_X2_ENABLE + #ifndef X2_ENABLE_INIT_STATE + #define X2_ENABLE_INIT_STATE X_ENABLE_INIT_STATE + #endif #ifndef X2_ENABLE_INIT #define X2_ENABLE_INIT() SET_OUTPUT(X2_ENABLE_PIN) #define X2_ENABLE_WRITE(STATE) WRITE(X2_ENABLE_PIN,STATE) @@ -156,6 +168,9 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset // Y2 Stepper #if HAS_Y2_ENABLE + #ifndef Y2_ENABLE_INIT_STATE + #define Y2_ENABLE_INIT_STATE Y_ENABLE_INIT_STATE + #endif #ifndef Y2_ENABLE_INIT #define Y2_ENABLE_INIT() SET_OUTPUT(Y2_ENABLE_PIN) #define Y2_ENABLE_WRITE(STATE) WRITE(Y2_ENABLE_PIN,STATE) @@ -177,6 +192,9 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset // Z2 Stepper #if HAS_Z2_ENABLE + #ifndef Z2_ENABLE_INIT_STATE + #define Z2_ENABLE_INIT_STATE Z_ENABLE_INIT_STATE + #endif #ifndef Z2_ENABLE_INIT #define Z2_ENABLE_INIT() SET_OUTPUT(Z2_ENABLE_PIN) #define Z2_ENABLE_WRITE(STATE) WRITE(Z2_ENABLE_PIN,STATE) @@ -198,6 +216,9 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset // Z3 Stepper #if HAS_Z3_ENABLE + #ifndef Z3_ENABLE_INIT_STATE + #define Z3_ENABLE_INIT_STATE Z_ENABLE_INIT_STATE + #endif #ifndef Z3_ENABLE_INIT #define Z3_ENABLE_INIT() SET_OUTPUT(Z3_ENABLE_PIN) #define Z3_ENABLE_WRITE(STATE) WRITE(Z3_ENABLE_PIN,STATE) @@ -219,6 +240,9 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset // Z4 Stepper #if HAS_Z4_ENABLE + #ifndef Z4_ENABLE_INIT_STATE + #define Z4_ENABLE_INIT_STATE Z_ENABLE_INIT_STATE + #endif #ifndef Z4_ENABLE_INIT #define Z4_ENABLE_INIT() SET_OUTPUT(Z4_ENABLE_PIN) #define Z4_ENABLE_WRITE(STATE) WRITE(Z4_ENABLE_PIN,STATE) @@ -240,6 +264,9 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset // I Stepper #if HAS_I_AXIS + #ifndef I_ENABLE_INIT_STATE + #define I_ENABLE_INIT_STATE !I_ENABLE_ON + #endif #ifndef I_ENABLE_INIT #define I_ENABLE_INIT() SET_OUTPUT(I_ENABLE_PIN) #define I_ENABLE_WRITE(STATE) WRITE(I_ENABLE_PIN,STATE) @@ -259,6 +286,9 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset // J Stepper #if HAS_J_AXIS + #ifndef J_ENABLE_INIT_STATE + #define J_ENABLE_INIT_STATE !J_ENABLE_ON + #endif #ifndef J_ENABLE_INIT #define J_ENABLE_INIT() SET_OUTPUT(J_ENABLE_PIN) #define J_ENABLE_WRITE(STATE) WRITE(J_ENABLE_PIN,STATE) @@ -278,6 +308,9 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset // K Stepper #if HAS_K_AXIS + #ifndef K_ENABLE_INIT_STATE + #define K_ENABLE_INIT_STATE !K_ENABLE_ON + #endif #ifndef K_ENABLE_INIT #define K_ENABLE_INIT() SET_OUTPUT(K_ENABLE_PIN) #define K_ENABLE_WRITE(STATE) WRITE(K_ENABLE_PIN,STATE) @@ -297,6 +330,9 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset // U Stepper #if HAS_U_AXIS + #ifndef U_ENABLE_INIT_STATE + #define U_ENABLE_INIT_STATE !U_ENABLE_ON + #endif #ifndef U_ENABLE_INIT #define U_ENABLE_INIT() SET_OUTPUT(U_ENABLE_PIN) #define U_ENABLE_WRITE(STATE) WRITE(U_ENABLE_PIN,STATE) @@ -316,6 +352,9 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset // V Stepper #if HAS_V_AXIS + #ifndef V_ENABLE_INIT_STATE + #define V_ENABLE_INIT_STATE !V_ENABLE_ON + #endif #ifndef V_ENABLE_INIT #define V_ENABLE_INIT() SET_OUTPUT(V_ENABLE_PIN) #define V_ENABLE_WRITE(STATE) WRITE(V_ENABLE_PIN,STATE) @@ -335,6 +374,9 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset // W Stepper #if HAS_W_AXIS + #ifndef W_ENABLE_INIT_STATE + #define W_ENABLE_INIT_STATE !W_ENABLE_ON + #endif #ifndef W_ENABLE_INIT #define W_ENABLE_INIT() SET_OUTPUT(W_ENABLE_PIN) #define W_ENABLE_WRITE(STATE) WRITE(W_ENABLE_PIN,STATE) @@ -353,7 +395,13 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset #endif // E0 Stepper -#if E_STEPPERS > 0 +#if HAS_EXTRUDERS + #ifndef E_ENABLE_INIT_STATE + #define E_ENABLE_INIT_STATE !E_ENABLE_ON + #endif + #ifndef E0_ENABLE_INIT_STATE + #define E0_ENABLE_INIT_STATE E_ENABLE_INIT_STATE + #endif #ifndef E0_ENABLE_INIT #define E0_ENABLE_INIT() SET_OUTPUT(E0_ENABLE_PIN) #define E0_ENABLE_WRITE(STATE) WRITE(E0_ENABLE_PIN,STATE) @@ -373,6 +421,9 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset // E1 Stepper #if E_STEPPERS > 1 || ENABLED(E_DUAL_STEPPER_DRIVERS) + #ifndef E1_ENABLE_INIT_STATE + #define E1_ENABLE_INIT_STATE E_ENABLE_INIT_STATE + #endif #ifndef E1_ENABLE_INIT #define E1_ENABLE_INIT() SET_OUTPUT(E1_ENABLE_PIN) #define E1_ENABLE_WRITE(STATE) WRITE(E1_ENABLE_PIN,STATE) @@ -392,6 +443,9 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset // E2 Stepper #if E_STEPPERS > 2 + #ifndef E2_ENABLE_INIT_STATE + #define E2_ENABLE_INIT_STATE E_ENABLE_INIT_STATE + #endif #ifndef E2_ENABLE_INIT #define E2_ENABLE_INIT() SET_OUTPUT(E2_ENABLE_PIN) #define E2_ENABLE_WRITE(STATE) WRITE(E2_ENABLE_PIN,STATE) @@ -411,6 +465,9 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset // E3 Stepper #if E_STEPPERS > 3 + #ifndef E3_ENABLE_INIT_STATE + #define E3_ENABLE_INIT_STATE E_ENABLE_INIT_STATE + #endif #ifndef E3_ENABLE_INIT #define E3_ENABLE_INIT() SET_OUTPUT(E3_ENABLE_PIN) #define E3_ENABLE_WRITE(STATE) WRITE(E3_ENABLE_PIN,STATE) @@ -430,6 +487,9 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset // E4 Stepper #if E_STEPPERS > 4 + #ifndef E4_ENABLE_INIT_STATE + #define E4_ENABLE_INIT_STATE E_ENABLE_INIT_STATE + #endif #ifndef E4_ENABLE_INIT #define E4_ENABLE_INIT() SET_OUTPUT(E4_ENABLE_PIN) #define E4_ENABLE_WRITE(STATE) WRITE(E4_ENABLE_PIN,STATE) @@ -449,6 +509,9 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset // E5 Stepper #if E_STEPPERS > 5 + #ifndef E5_ENABLE_INIT_STATE + #define E5_ENABLE_INIT_STATE E_ENABLE_INIT_STATE + #endif #ifndef E5_ENABLE_INIT #define E5_ENABLE_INIT() SET_OUTPUT(E5_ENABLE_PIN) #define E5_ENABLE_WRITE(STATE) WRITE(E5_ENABLE_PIN,STATE) @@ -468,6 +531,9 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset // E6 Stepper #if E_STEPPERS > 6 + #ifndef E6_ENABLE_INIT_STATE + #define E6_ENABLE_INIT_STATE E_ENABLE_INIT_STATE + #endif #ifndef E6_ENABLE_INIT #define E6_ENABLE_INIT() SET_OUTPUT(E6_ENABLE_PIN) #define E6_ENABLE_WRITE(STATE) WRITE(E6_ENABLE_PIN,STATE) @@ -487,6 +553,9 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset // E7 Stepper #if E_STEPPERS > 7 + #ifndef E7_ENABLE_INIT_STATE + #define E7_ENABLE_INIT_STATE E_ENABLE_INIT_STATE + #endif #ifndef E7_ENABLE_INIT #define E7_ENABLE_INIT() SET_OUTPUT(E7_ENABLE_PIN) #define E7_ENABLE_WRITE(STATE) WRITE(E7_ENABLE_PIN,STATE) From 43177af21c279e48f41f2ad8bcaf9a0c294e6b3b Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sun, 30 Mar 2025 14:57:01 -0500 Subject: [PATCH 165/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Dig?= =?UTF-8?q?ipot=20settings=20cleanup?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/module/settings.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Marlin/src/module/settings.cpp b/Marlin/src/module/settings.cpp index c2b4e3da38..4205261a3c 100644 --- a/Marlin/src/module/settings.cpp +++ b/Marlin/src/module/settings.cpp @@ -3712,7 +3712,7 @@ void MarlinSettings::reset() { #if HAS_MOTOR_CURRENT_PWM constexpr uint32_t tmp_motor_current_setting[MOTOR_CURRENT_COUNT] = PWM_MOTOR_CURRENT; for (uint8_t q = 0; q < MOTOR_CURRENT_COUNT; ++q) - stepper.set_digipot_current(q, (stepper.motor_current_setting[q] = tmp_motor_current_setting[q])); + stepper.set_digipot_current(q, tmp_motor_current_setting[q]); #endif // @@ -3720,10 +3720,8 @@ void MarlinSettings::reset() { // #if HAS_MOTOR_CURRENT_SPI static constexpr uint32_t tmp_motor_current_setting[] = DIGIPOT_MOTOR_CURRENT; - DEBUG_ECHOLNPGM("Writing Digipot"); for (uint8_t q = 0; q < COUNT(tmp_motor_current_setting); ++q) stepper.set_digipot_current(q, tmp_motor_current_setting[q]); - DEBUG_ECHOLNPGM("Digipot Written"); #endif // From d2b47c354c496896866de07907e355ff96e453dd Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Mon, 31 Mar 2025 00:31:54 +0000 Subject: [PATCH 166/787] [cron] Bump distribution date (2025-03-31) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index a0cbd5cf9b..d49c6c4e3b 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-03-30" +//#define STRING_DISTRIBUTION_DATE "2025-03-31" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index b717290a77..5ee57c2fc0 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-03-30" + #define STRING_DISTRIBUTION_DATE "2025-03-31" #endif /** From 15ce5d06127553050d20f1e92cca8b67bdbddf66 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sun, 30 Mar 2025 23:30:31 -0500 Subject: [PATCH 167/787] =?UTF-8?q?=F0=9F=94=A8=F0=9F=A9=B9=20Misc.=20code?= =?UTF-8?q?=20corrections,=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/gcode/feature/digipot/M907-M910.cpp | 29 ++++++++++++++----- Marlin/src/inc/Conditionals-6-type.h | 2 +- Marlin/src/inc/SanityCheck.h | 8 ++--- Marlin/src/module/stepper.cpp | 2 +- 4 files changed, 27 insertions(+), 14 deletions(-) diff --git a/Marlin/src/gcode/feature/digipot/M907-M910.cpp b/Marlin/src/gcode/feature/digipot/M907-M910.cpp index ab1c316705..b1bd9b4f95 100644 --- a/Marlin/src/gcode/feature/digipot/M907-M910.cpp +++ b/Marlin/src/gcode/feature/digipot/M907-M910.cpp @@ -51,10 +51,25 @@ void GcodeSuite::M907() { if (!parser.seen("BS" STR_AXES_LOGICAL)) return M907_report(); - if (parser.seenval('S')) for (uint8_t i = 0; i < MOTOR_CURRENT_COUNT; ++i) stepper.set_digipot_current(i, parser.value_int()); - LOOP_LOGICAL_AXES(i) if (parser.seenval(IAXIS_CHAR(i))) stepper.set_digipot_current(i, parser.value_int()); // X Y Z (I J K U V W) E (map to drivers according to DIGIPOT_CHANNELS. Default with NUM_AXES 3: map X Y Z E to X Y Z E0) - // Additional extruders use B,C. - // TODO: Change these parameters because 'E' is used and D should be reserved for debugging. B? + // S - Set current in mA for all axes + if (parser.seenval('S')) + for (uint8_t i = 0; i < MOTOR_CURRENT_COUNT; ++i) + stepper.set_digipot_current(i, parser.value_int()); + + // X Y Z (I J K U V W) E (map to drivers according to DIGIPOT_CHANNELS. + // Default with NUM_AXES 3: map X Y Z E to X Y Z E0) + LOOP_LOGICAL_AXES(i) + if (parser.seenval(IAXIS_CHAR(i))) + stepper.set_digipot_current(i, parser.value_int()); + + /** + * Additional extruders use B,C in this legacy protocol + * TODO: Update to allow for an index with X, Y, Z, E axis to isolate a single stepper + * and use configured axis names instead of IJKUVW. i.e., Match the behavior of + * other G-codes that set stepper-specific parameters. If necessary deprecate G-codes. + * Bonus Points: Standardize a method that all G-codes can use to refer to one or + * more steppers/drivers and apply to various G-codes. + */ #if E_STEPPERS >= 2 if (parser.seenval('B')) stepper.set_digipot_current(E_AXIS + 1, parser.value_int()); #if E_STEPPERS >= 3 @@ -72,14 +87,12 @@ void GcodeSuite::M907() { if (!parser.seen("S" #if HAS_X_Y_XY_I_J_K_U_V_W - "XY" SECONDARY_AXIS_GANG("I", "J", "K", "U", "V", "W") + NUM_AXIS_GANG("X", "Y",, "I", "J", "K", "U", "V", "W") #endif #if PIN_EXISTS(MOTOR_CURRENT_PWM_Z) "Z" #endif - #if HAS_MOTOR_CURRENT_PWM_E - "E" - #endif + TERN_(HAS_MOTOR_CURRENT_PWM_E, "E") )) return M907_report(); if (parser.seenval('S')) for (uint8_t a = 0; a < MOTOR_CURRENT_COUNT; ++a) stepper.set_digipot_current(a, parser.value_int()); diff --git a/Marlin/src/inc/Conditionals-6-type.h b/Marlin/src/inc/Conditionals-6-type.h index bd8e3b78b4..9f0c0c3564 100644 --- a/Marlin/src/inc/Conditionals-6-type.h +++ b/Marlin/src/inc/Conditionals-6-type.h @@ -38,7 +38,7 @@ #endif // If an axis's Homing Current differs from standard current... -#define HAS_HOME_CURRENT(N) (N##_CURRENT_HOME > 0 && N##_CURRENT_HOME != N##_CURRENT) +#define HAS_HOME_CURRENT(N) TERN0(EDITABLE_HOMING_CURRENT, N##_IS_TRINAMIC && N##_HOME_DIR != 0) || (N##_CURRENT_HOME > 0 && N##_CURRENT_HOME != N##_CURRENT) #if HAS_HOME_CURRENT(X) #define X_HAS_HOME_CURRENT 1 #endif diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index 1a86bb37de..62e16b0156 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -1890,7 +1890,7 @@ static_assert(NUM_SERVOS <= NUM_SERVO_PLUGS, "NUM_SERVOS (or some servo index) i /** * ULTIPANEL encoder */ -#if IS_ULTIPANEL && NONE(IS_NEWPANEL, SR_LCD_2W_NL) && !PIN_EXISTS(SHIFT_CLK) +#if IS_ULTIPANEL && NONE(HAS_ROTARY_ENCODER, SR_LCD_2W_NL, SR_LCD_3W_NL) && !PIN_EXISTS(SHIFT_CLK) #error "ULTIPANEL controllers require some kind of encoder." #endif @@ -4041,11 +4041,11 @@ static_assert(_PLUS_TEST(3), "DEFAULT_MAX_ACCELERATION values must be positive." #elif _PIN_CONFLICT(CONTROLLERFAN) #error "SPINDLE_LASER_PWM_PIN conflicts with CONTROLLERFAN_PIN." #elif _PIN_CONFLICT(MOTOR_CURRENT_PWM_XY) - #error "SPINDLE_LASER_PWM_PIN conflicts with MOTOR_CURRENT_PWM_XY." + #error "SPINDLE_LASER_PWM_PIN conflicts with MOTOR_CURRENT_PWM_XY_PIN." #elif _PIN_CONFLICT(MOTOR_CURRENT_PWM_Z) - #error "SPINDLE_LASER_PWM_PIN conflicts with MOTOR_CURRENT_PWM_Z." + #error "SPINDLE_LASER_PWM_PIN conflicts with MOTOR_CURRENT_PWM_Z_PIN." #elif _PIN_CONFLICT(MOTOR_CURRENT_PWM_E) - #error "SPINDLE_LASER_PWM_PIN conflicts with MOTOR_CURRENT_PWM_E." + #error "SPINDLE_LASER_PWM_PIN conflicts with MOTOR_CURRENT_PWM_E_PIN." #endif #endif #undef _PIN_CONFLICT diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp index f55465ea56..3ee2d6e91c 100644 --- a/Marlin/src/module/stepper.cpp +++ b/Marlin/src/module/stepper.cpp @@ -3673,7 +3673,7 @@ void Stepper::report_positions() { #if HAS_MOTOR_CURRENT_SPI || HAS_MOTOR_CURRENT_PWM void Stepper::set_digipot_current(const uint8_t driver, const int16_t current) { - if (WITHIN(driver, 0, MOTOR_CURRENT_COUNT - 1)) + if (WITHIN(driver, 0, COUNT(motor_current_setting) - 1)) motor_current_setting[driver] = current; // update motor_current_setting if (!initialized) return; From d638ee02c6ece3df4c552866ce1f1009a00b5bc1 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Tue, 1 Apr 2025 00:34:19 +0000 Subject: [PATCH 168/787] [cron] Bump distribution date (2025-04-01) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index d49c6c4e3b..bb3996fb73 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-03-31" +//#define STRING_DISTRIBUTION_DATE "2025-04-01" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 5ee57c2fc0..64a8aded74 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-03-31" + #define STRING_DISTRIBUTION_DATE "2025-04-01" #endif /** From 766dfda80e57335d11aee8501cc36606f7d2d2f9 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Mon, 31 Mar 2025 21:55:58 -0500 Subject: [PATCH 169/787] =?UTF-8?q?=F0=9F=94=A8=F0=9F=A9=B9=20Pass=20Ultip?= =?UTF-8?q?anel=20with=20ADC=5FKEYPAD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/inc/SanityCheck.h | 2 +- buildroot/tests/sanguino1284p | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index 62e16b0156..cdd87b1e93 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -1890,7 +1890,7 @@ static_assert(NUM_SERVOS <= NUM_SERVO_PLUGS, "NUM_SERVOS (or some servo index) i /** * ULTIPANEL encoder */ -#if IS_ULTIPANEL && NONE(HAS_ROTARY_ENCODER, SR_LCD_2W_NL, SR_LCD_3W_NL) && !PIN_EXISTS(SHIFT_CLK) +#if IS_ULTIPANEL && NONE(HAS_ROTARY_ENCODER, SR_LCD_2W_NL, SR_LCD_3W_NL) && !ANY_PIN(SHIFT_CLK, ADC_KEYPAD) #error "ULTIPANEL controllers require some kind of encoder." #endif diff --git a/buildroot/tests/sanguino1284p b/buildroot/tests/sanguino1284p index 345383cc70..0e861892d8 100755 --- a/buildroot/tests/sanguino1284p +++ b/buildroot/tests/sanguino1284p @@ -14,7 +14,7 @@ opt_set MOTHERBOARD BOARD_SANGUINOLOLU_12 \ LCD_LANGUAGE de \ CONTROLLER_FAN_PIN 27 opt_enable MINIPANEL USE_CONTROLLER_FAN CONTROLLER_FAN_EDITABLE -exec_test $1 $2 "Default Configuration | MINIPANAL | CONTROLLER_FAN" "$3" +exec_test $1 $2 "Default Configuration | MINIPANEL | CONTROLLER_FAN" "$3" # # Start with default configurations... From 99b790cc92a3af0c58058271d3669723149c178d Mon Sep 17 00:00:00 2001 From: Boyd Date: Mon, 31 Mar 2025 20:30:23 -0700 Subject: [PATCH 170/787] =?UTF-8?q?=F0=9F=94=A8=20Fix=20GCC14=20/=20C++23?= =?UTF-8?q?=20volatile=20warnings=20(#27768)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/module/planner.cpp | 4 +++- Marlin/src/module/planner.h | 6 +++++- ini/gd32.ini | 1 - 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index 630557180b..561d13fa2a 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -1582,7 +1582,9 @@ void Planner::quick_stop() { const bool was_enabled = stepper.suspend(); // Drop all queue entries - block_buffer_nonbusy = block_buffer_head = block_buffer_tail; + const uint8_t tail_value = block_buffer_tail; // Read tail value once + block_buffer_head = tail_value; + block_buffer_nonbusy = tail_value; // Restart the block delay for the first movement - As the queue was // forced to empty, there's no risk the ISR will touch this. diff --git a/Marlin/src/module/planner.h b/Marlin/src/module/planner.h index b2df5824de..318be33131 100644 --- a/Marlin/src/module/planner.h +++ b/Marlin/src/module/planner.h @@ -816,7 +816,11 @@ class Planner { FORCE_INLINE static uint8_t nonbusy_movesplanned() { return block_dec_mod(block_buffer_head, block_buffer_nonbusy); } // Remove all blocks from the buffer - FORCE_INLINE static void clear_block_buffer() { block_buffer_nonbusy = block_buffer_head = block_buffer_tail = 0; } + FORCE_INLINE static void clear_block_buffer() { + block_buffer_tail = 0; + block_buffer_head = 0; + block_buffer_nonbusy = 0; + } // Check if movement queue is full FORCE_INLINE static bool is_full() { return block_buffer_tail == next_block_index(block_buffer_head); } diff --git a/ini/gd32.ini b/ini/gd32.ini index 2e5bcea3b5..1286772786 100644 --- a/ini/gd32.ini +++ b/ini/gd32.ini @@ -21,7 +21,6 @@ build_flags = -std=gnu++23 -DADC_RESOLUTION=12 -DCORE_DEBUG -Wno-deprecated-declarations - -Wno-volatile extra_scripts = ${common.extra_scripts} # From 59423da42fe3d94003ec98e2de9bb432bf350512 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Mon, 31 Mar 2025 21:19:14 -0500 Subject: [PATCH 171/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20HAS?= =?UTF-8?q?=5FMOTOR=5FCURRENT=5FPWM=5FZ?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/HAL/DUE/fastio/G2_PWM.cpp | 25 ++--- .../src/gcode/feature/digipot/M907-M910.cpp | 96 +++++++++++++------ Marlin/src/inc/Conditionals-5-post.h | 5 +- Marlin/src/lcd/menu/menu_advanced.cpp | 2 +- Marlin/src/module/stepper.cpp | 6 +- Marlin/src/pins/pinsDebug_list.h | 2 +- 6 files changed, 88 insertions(+), 48 deletions(-) diff --git a/Marlin/src/HAL/DUE/fastio/G2_PWM.cpp b/Marlin/src/HAL/DUE/fastio/G2_PWM.cpp index 5cf86f147c..403e3356e1 100644 --- a/Marlin/src/HAL/DUE/fastio/G2_PWM.cpp +++ b/Marlin/src/HAL/DUE/fastio/G2_PWM.cpp @@ -56,16 +56,12 @@ #else #define G2_PWM_Y 0 #endif -#if PIN_EXISTS(MOTOR_CURRENT_PWM_Z) +#if HAS_MOTOR_CURRENT_PWM_Z #define G2_PWM_Z 1 #else #define G2_PWM_Z 0 #endif -#if HAS_MOTOR_CURRENT_PWM_E - #define G2_PWM_E 1 -#else - #define G2_PWM_E 0 -#endif +#define G2_PWM_E HAS_MOTOR_CURRENT_PWM_E #define G2_MASK_X(V) (G2_PWM_X * (V)) #define G2_MASK_Y(V) (G2_PWM_Y * (V)) #define G2_MASK_Z(V) (G2_PWM_Z * (V)) @@ -80,17 +76,22 @@ PWM_map ISR_table[NUM_PWMS] = PWM_MAP_INIT; void Stepper::digipot_init() { - #if PIN_EXISTS(MOTOR_CURRENT_PWM_X) - OUT_WRITE(MOTOR_CURRENT_PWM_X_PIN, 0); // init pins + #if G2_PWM_X + OUT_WRITE(MOTOR_CURRENT_PWM_X_PIN, LOW); // init pins #endif - #if PIN_EXISTS(MOTOR_CURRENT_PWM_Y) - OUT_WRITE(MOTOR_CURRENT_PWM_Y_PIN, 0); + #if G2_PWM_Y + OUT_WRITE(MOTOR_CURRENT_PWM_Y_PIN, LOW); #endif #if G2_PWM_Z - OUT_WRITE(MOTOR_CURRENT_PWM_Z_PIN, 0); + OUT_WRITE(MOTOR_CURRENT_PWM_Z_PIN, LOW); #endif #if G2_PWM_E - OUT_WRITE(MOTOR_CURRENT_PWM_E_PIN, 0); + #if PIN_EXISTS(MOTOR_CURRENT_PWM_E) + OUT_WRITE(MOTOR_CURRENT_PWM_E_PIN, LOW); + #endif + #if PIN_EXISTS(MOTOR_CURRENT_PWM_E0) + OUT_WRITE(MOTOR_CURRENT_PWM_E0_PIN, LOW); + #endif #endif #define WPKEY (0x50574D << 8) // “PWM” in ASCII diff --git a/Marlin/src/gcode/feature/digipot/M907-M910.cpp b/Marlin/src/gcode/feature/digipot/M907-M910.cpp index b1bd9b4f95..a73f88ca89 100644 --- a/Marlin/src/gcode/feature/digipot/M907-M910.cpp +++ b/Marlin/src/gcode/feature/digipot/M907-M910.cpp @@ -46,6 +46,7 @@ * Set percentage of max current for all axes (Requires HAS_DIGIPOT_DAC) */ void GcodeSuite::M907() { + #if HAS_MOTOR_CURRENT_SPI if (!parser.seen("BS" STR_AXES_LOGICAL)) @@ -56,8 +57,9 @@ void GcodeSuite::M907() { for (uint8_t i = 0; i < MOTOR_CURRENT_COUNT; ++i) stepper.set_digipot_current(i, parser.value_int()); - // X Y Z (I J K U V W) E (map to drivers according to DIGIPOT_CHANNELS. - // Default with NUM_AXES 3: map X Y Z E to X Y Z E0) + // X Y Z I J K U V W E + // Map to drivers according to pots addresses. + // Default with NUM_AXES 3: map X Y Z E to X Y Z E0. LOOP_LOGICAL_AXES(i) if (parser.seenval(IAXIS_CHAR(i))) stepper.set_digipot_current(i, parser.value_int()); @@ -83,56 +85,88 @@ void GcodeSuite::M907() { #define HAS_X_Y_XY_I_J_K_U_V_W 1 #endif - #if HAS_X_Y_XY_I_J_K_U_V_W || HAS_MOTOR_CURRENT_PWM_E || PIN_EXISTS(MOTOR_CURRENT_PWM_Z) + #if ANY(HAS_X_Y_XY_I_J_K_U_V_W, HAS_MOTOR_CURRENT_PWM_E, HAS_MOTOR_CURRENT_PWM_Z) if (!parser.seen("S" #if HAS_X_Y_XY_I_J_K_U_V_W NUM_AXIS_GANG("X", "Y",, "I", "J", "K", "U", "V", "W") #endif - #if PIN_EXISTS(MOTOR_CURRENT_PWM_Z) - "Z" - #endif + TERN_(HAS_MOTOR_CURRENT_PWM_Z, "Z") TERN_(HAS_MOTOR_CURRENT_PWM_E, "E") )) return M907_report(); - if (parser.seenval('S')) for (uint8_t a = 0; a < MOTOR_CURRENT_COUNT; ++a) stepper.set_digipot_current(a, parser.value_int()); + // S - Set all stepper current to the same value + if (parser.seenval('S')) { + const int16_t v = parser.value_int(); + for (uint8_t a = 0; a < MOTOR_CURRENT_COUNT; ++a) + stepper.set_digipot_current(a, v); + } - #if HAS_X_Y_XY_I_J_K_U_V_W - if (NUM_AXIS_GANG( - parser.seenval('X'), || parser.seenval('Y'), || false, - || parser.seenval('I'), || parser.seenval('J'), || parser.seenval('K'), - || parser.seenval('U'), || parser.seenval('V'), || parser.seenval('W') - )) stepper.set_digipot_current(0, parser.value_int()); - #endif - #if PIN_EXISTS(MOTOR_CURRENT_PWM_Z) - if (parser.seenval('Z')) stepper.set_digipot_current(1, parser.value_int()); - #endif - #if HAS_MOTOR_CURRENT_PWM_E - if (parser.seenval('E')) stepper.set_digipot_current(2, parser.value_int()); - #endif + // X Y I J K U V W - All aliases to set the current for "most axes." + // Only the value of the last given parameter is used. + if (ENABLED(HAS_X_Y_XY_I_J_K_U_V_W) && NUM_AXIS_GANG( + parser.seenval('X'), || parser.seenval('Y'), || false, + || parser.seenval('I'), || parser.seenval('J'), || parser.seenval('K'), + || parser.seenval('U'), || parser.seenval('V'), || parser.seenval('W') + )) + stepper.set_digipot_current(0, parser.value_int()); + + // Z - Set the current just for the Z axis + if (TERN0(HAS_MOTOR_CURRENT_PWM_Z, parser.seenval('Z'))) + stepper.set_digipot_current(1, parser.value_int()); + + // Z - Set the current just for the Extruder + if (TERN0(HAS_MOTOR_CURRENT_PWM_E, parser.seenval('E'))) + stepper.set_digipot_current(2, parser.value_int()); #endif #endif // HAS_MOTOR_CURRENT_PWM #if HAS_MOTOR_CURRENT_I2C - // this one uses actual amps in floating point - if (parser.seenval('S')) for (uint8_t q = 0; q < DIGIPOT_I2C_NUM_CHANNELS; ++q) digipot_i2c.set_current(q, parser.value_float()); - LOOP_LOGICAL_AXES(i) if (parser.seenval(IAXIS_CHAR(i))) digipot_i2c.set_current(i, parser.value_float()); // X Y Z (I J K U V W) E (map to drivers according to pots adresses. Default with NUM_AXES 3 X Y Z E: map to X Y Z E0) + // This current driver takes actual Amps in floating point + // rather than milli-amps or some scalar unit. + + // S - Set the same current in Amps on all channels + if (parser.seenval('S')) { + const float v = parser.value_float(); + for (uint8_t q = 0; q < DIGIPOT_I2C_NUM_CHANNELS; ++q) + digipot_i2c.set_current(q, v); + } + + // X Y Z I J K U V W E + // Map to drivers according to pots addresses. + // Default with NUM_AXES 3: map X Y Z E to X Y Z E0. + LOOP_LOGICAL_AXES(i) + if (parser.seenval(IAXIS_CHAR(i))) + digipot_i2c.set_current(i, parser.value_float()); + // Additional extruders use B,C,D. - // TODO: Change these parameters because 'E' is used and because 'D' should be reserved for debugging. B? + // TODO: Make parameters work like other axis-specific / stepper-specific. See above. #if E_STEPPERS >= 2 for (uint8_t i = E_AXIS + 1; i < _MAX(DIGIPOT_I2C_NUM_CHANNELS, (NUM_AXES + 3)); i++) - if (parser.seenval('B' + i - (E_AXIS + 1))) digipot_i2c.set_current(i, parser.value_float()); + if (parser.seenval('B' + i - (E_AXIS + 1))) + digipot_i2c.set_current(i, parser.value_float()); #endif - #endif + + #endif // HAS_MOTOR_CURRENT_I2C #if HAS_MOTOR_CURRENT_DAC + + // S - Set the same current percentage on all axes if (parser.seenval('S')) { const float dac_percent = parser.value_float(); - LOOP_LOGICAL_AXES(i) stepper_dac.set_current_percent(i, dac_percent); + LOOP_LOGICAL_AXES(i) + stepper_dac.set_current_percent(i, dac_percent); } - LOOP_LOGICAL_AXES(i) if (parser.seenval(IAXIS_CHAR(i))) stepper_dac.set_current_percent(i, parser.value_float()); // X Y Z (I J K U V W) E (map to drivers according to DAC_STEPPER_ORDER. Default with NUM_AXES 3: X Y Z E map to X Y Z E0) + + // X Y Z I J K U V W E + // Map to drivers according to pots addresses. + // Default with NUM_AXES 3: map X Y Z E to X Y Z E0. + LOOP_LOGICAL_AXES(i) + if (parser.seenval(IAXIS_CHAR(i))) + stepper_dac.set_current_percent(i, parser.value_float()); + #endif } @@ -144,8 +178,10 @@ void GcodeSuite::M907() { report_heading_etc(forReplay, F(STR_STEPPER_MOTOR_CURRENTS)); #if HAS_MOTOR_CURRENT_PWM SERIAL_ECHOLNPGM_P( // PWM-based has 3 values: - PSTR(" M907 X"), stepper.motor_current_setting[0] // X, Y, (I, J, K, U, V, W) - , SP_Z_STR, stepper.motor_current_setting[1] // Z + PSTR(" M907 X"), stepper.motor_current_setting[0] // X, Y, (I, J, K, U, V, W) + #if HAS_MOTOR_CURRENT_PWM_Z + , SP_Z_STR, stepper.motor_current_setting[1] // Z + #endif #if HAS_MOTOR_CURRENT_PWM_E , SP_E_STR, stepper.motor_current_setting[2] // E #endif diff --git a/Marlin/src/inc/Conditionals-5-post.h b/Marlin/src/inc/Conditionals-5-post.h index f83c063d11..9b16f515d6 100644 --- a/Marlin/src/inc/Conditionals-5-post.h +++ b/Marlin/src/inc/Conditionals-5-post.h @@ -2993,7 +2993,10 @@ #if ANY_PIN(MOTOR_CURRENT_PWM_E, MOTOR_CURRENT_PWM_E0, MOTOR_CURRENT_PWM_E1) #define HAS_MOTOR_CURRENT_PWM_E 1 #endif -#if HAS_MOTOR_CURRENT_PWM_E || ANY_PIN(MOTOR_CURRENT_PWM_X, MOTOR_CURRENT_PWM_Y, MOTOR_CURRENT_PWM_XY, MOTOR_CURRENT_PWM_Z, MOTOR_CURRENT_PWM_I, MOTOR_CURRENT_PWM_J, MOTOR_CURRENT_PWM_K, MOTOR_CURRENT_PWM_U, MOTOR_CURRENT_PWM_V, MOTOR_CURRENT_PWM_W) +#if PIN_EXISTS(MOTOR_CURRENT_PWM_Z) + #define HAS_MOTOR_CURRENT_PWM_Z 1 +#endif +#if HAS_MOTOR_CURRENT_PWM_Z || HAS_MOTOR_CURRENT_PWM_E || ANY_PIN(MOTOR_CURRENT_PWM_X, MOTOR_CURRENT_PWM_Y, MOTOR_CURRENT_PWM_XY, MOTOR_CURRENT_PWM_I, MOTOR_CURRENT_PWM_J, MOTOR_CURRENT_PWM_K, MOTOR_CURRENT_PWM_U, MOTOR_CURRENT_PWM_V, MOTOR_CURRENT_PWM_W) #define HAS_MOTOR_CURRENT_PWM 1 #endif diff --git a/Marlin/src/lcd/menu/menu_advanced.cpp b/Marlin/src/lcd/menu/menu_advanced.cpp index b886902d91..99ece89f27 100644 --- a/Marlin/src/lcd/menu/menu_advanced.cpp +++ b/Marlin/src/lcd/menu/menu_advanced.cpp @@ -88,7 +88,7 @@ void menu_backlash(); #if ANY_PIN(MOTOR_CURRENT_PWM_XY, MOTOR_CURRENT_PWM_X, MOTOR_CURRENT_PWM_Y) EDIT_CURRENT_PWM(STR_A STR_B, 0); #endif - #if PIN_EXISTS(MOTOR_CURRENT_PWM_Z) + #if HAS_MOTOR_CURRENT_PWM_Z EDIT_CURRENT_PWM(STR_C, 1); #endif #if HAS_MOTOR_CURRENT_PWM_E diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp index 3ee2d6e91c..85c7521960 100644 --- a/Marlin/src/module/stepper.cpp +++ b/Marlin/src/module/stepper.cpp @@ -3654,7 +3654,7 @@ void Stepper::report_positions() { #if ANY_PIN(MOTOR_CURRENT_PWM_XY, MOTOR_CURRENT_PWM_X, MOTOR_CURRENT_PWM_Y, MOTOR_CURRENT_PWM_I, MOTOR_CURRENT_PWM_J, MOTOR_CURRENT_PWM_K, MOTOR_CURRENT_PWM_U, MOTOR_CURRENT_PWM_V, MOTOR_CURRENT_PWM_W) case 0: #endif - #if PIN_EXISTS(MOTOR_CURRENT_PWM_Z) + #if HAS_MOTOR_CURRENT_PWM_Z case 1: #endif #if HAS_MOTOR_CURRENT_PWM_E @@ -3719,7 +3719,7 @@ void Stepper::report_positions() { #endif break; case 1: - #if PIN_EXISTS(MOTOR_CURRENT_PWM_Z) + #if HAS_MOTOR_CURRENT_PWM_Z _WRITE_CURRENT_PWM(Z); #endif break; @@ -3784,7 +3784,7 @@ void Stepper::report_positions() { #if PIN_EXISTS(MOTOR_CURRENT_PWM_W) INIT_CURRENT_PWM(W); #endif - #if PIN_EXISTS(MOTOR_CURRENT_PWM_Z) + #if HAS_MOTOR_CURRENT_PWM_Z INIT_CURRENT_PWM(Z); #endif #if PIN_EXISTS(MOTOR_CURRENT_PWM_E) diff --git a/Marlin/src/pins/pinsDebug_list.h b/Marlin/src/pins/pinsDebug_list.h index fe7f1d21ee..ad17fe2436 100644 --- a/Marlin/src/pins/pinsDebug_list.h +++ b/Marlin/src/pins/pinsDebug_list.h @@ -1119,7 +1119,7 @@ #if PIN_EXISTS(MOTOR_CURRENT_PWM_XY) REPORT_NAME_DIGITAL(__LINE__, MOTOR_CURRENT_PWM_XY_PIN) #endif -#if PIN_EXISTS(MOTOR_CURRENT_PWM_Z) +#if HAS_MOTOR_CURRENT_PWM_Z REPORT_NAME_DIGITAL(__LINE__, MOTOR_CURRENT_PWM_Z_PIN) #endif #if PIN_EXISTS(MOTOR_CURRENT_PWM_I) From 2004198b078e8809540e3cd56dfaaf3bbf610ee3 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Mon, 31 Mar 2025 22:53:31 -0500 Subject: [PATCH 172/787] =?UTF-8?q?=F0=9F=94=A8=F0=9F=A9=B9=20Pass=20Ultip?= =?UTF-8?q?anel=20with=20TOUCH=5FSCREEN?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/inc/SanityCheck.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index cdd87b1e93..b09bc9854a 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -1888,9 +1888,9 @@ static_assert(NUM_SERVOS <= NUM_SERVO_PLUGS, "NUM_SERVOS (or some servo index) i #endif /** - * ULTIPANEL encoder + * ULTIPANEL expects an encoder */ -#if IS_ULTIPANEL && NONE(HAS_ROTARY_ENCODER, SR_LCD_2W_NL, SR_LCD_3W_NL) && !ANY_PIN(SHIFT_CLK, ADC_KEYPAD) +#if IS_ULTIPANEL && NONE(HAS_ROTARY_ENCODER, SR_LCD_2W_NL, SR_LCD_3W_NL, TOUCH_SCREEN) && !ANY_PIN(SHIFT_CLK, ADC_KEYPAD) #error "ULTIPANEL controllers require some kind of encoder." #endif From 546a014a59a0488452ed3f4e0d2aab2ec1615e47 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Mon, 31 Mar 2025 23:33:32 -0500 Subject: [PATCH 173/787] =?UTF-8?q?=F0=9F=94=A8=F0=9F=A9=B9=20Pass=20Ultip?= =?UTF-8?q?anel=20with=20HAS=5FTOUCH=5FBUTTONS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/inc/SanityCheck.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index b09bc9854a..ad05fba2a3 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -1890,7 +1890,7 @@ static_assert(NUM_SERVOS <= NUM_SERVO_PLUGS, "NUM_SERVOS (or some servo index) i /** * ULTIPANEL expects an encoder */ -#if IS_ULTIPANEL && NONE(HAS_ROTARY_ENCODER, SR_LCD_2W_NL, SR_LCD_3W_NL, TOUCH_SCREEN) && !ANY_PIN(SHIFT_CLK, ADC_KEYPAD) +#if IS_ULTIPANEL && NONE(HAS_ROTARY_ENCODER, SR_LCD_2W_NL, SR_LCD_3W_NL, TOUCH_SCREEN, HAS_TOUCH_BUTTONS) && !ANY_PIN(SHIFT_CLK, ADC_KEYPAD) #error "ULTIPANEL controllers require some kind of encoder." #endif From a80e790cf651d3b2dc85c4bb8a9ab77dcb70ec28 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 1 Apr 2025 01:22:15 -0500 Subject: [PATCH 174/787] =?UTF-8?q?=F0=9F=94=A8=F0=9F=A9=B9=20Pass=20Ultip?= =?UTF-8?q?anel=20with=20HAS=5FSLOW=5FBUTTONS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/inc/SanityCheck.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index ad05fba2a3..5b1aa0bb2b 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -1890,7 +1890,7 @@ static_assert(NUM_SERVOS <= NUM_SERVO_PLUGS, "NUM_SERVOS (or some servo index) i /** * ULTIPANEL expects an encoder */ -#if IS_ULTIPANEL && NONE(HAS_ROTARY_ENCODER, SR_LCD_2W_NL, SR_LCD_3W_NL, TOUCH_SCREEN, HAS_TOUCH_BUTTONS) && !ANY_PIN(SHIFT_CLK, ADC_KEYPAD) +#if IS_ULTIPANEL && NONE(HAS_ROTARY_ENCODER, SR_LCD_2W_NL, SR_LCD_3W_NL, TOUCH_SCREEN, HAS_TOUCH_BUTTONS, HAS_SLOW_BUTTONS) && !ANY_PIN(SHIFT_CLK, ADC_KEYPAD) #error "ULTIPANEL controllers require some kind of encoder." #endif From 26551c17c2248d2209190f6f1727fa599e2c8d10 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 1 Apr 2025 02:38:40 -0500 Subject: [PATCH 175/787] =?UTF-8?q?=F0=9F=94=A8=F0=9F=A9=B9=20Drop=20old?= =?UTF-8?q?=20ULTIPANEL=20sanity=20check?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/inc/SanityCheck.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index 5b1aa0bb2b..1505b8b896 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -1888,12 +1888,8 @@ static_assert(NUM_SERVOS <= NUM_SERVO_PLUGS, "NUM_SERVOS (or some servo index) i #endif /** - * ULTIPANEL expects an encoder + * Encoder pulses must be positive */ -#if IS_ULTIPANEL && NONE(HAS_ROTARY_ENCODER, SR_LCD_2W_NL, SR_LCD_3W_NL, TOUCH_SCREEN, HAS_TOUCH_BUTTONS, HAS_SLOW_BUTTONS) && !ANY_PIN(SHIFT_CLK, ADC_KEYPAD) - #error "ULTIPANEL controllers require some kind of encoder." -#endif - #if ENCODER_PULSES_PER_STEP < 0 #error "ENCODER_PULSES_PER_STEP should not be negative, use REVERSE_MENU_DIRECTION instead." #endif From 30a10077cffd5ae939a20aea0d9e7f881cb62ace Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 1 Apr 2025 03:11:43 -0500 Subject: [PATCH 176/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Men?= =?UTF-8?q?u=20code=20cleanup?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/lcd/marlinui.cpp | 44 +++++++++++++-------------- Marlin/src/lcd/menu/menu_filament.cpp | 17 ++++------- Marlin/src/lcd/menu/menu_item.h | 5 ++- 3 files changed, 29 insertions(+), 37 deletions(-) diff --git a/Marlin/src/lcd/marlinui.cpp b/Marlin/src/lcd/marlinui.cpp index 2114209b98..384bf65211 100644 --- a/Marlin/src/lcd/marlinui.cpp +++ b/Marlin/src/lcd/marlinui.cpp @@ -527,29 +527,27 @@ void MarlinUI::init() { #define ADC_MIN_KEY_DELAY 100 if (keypad_buttons) { - #if HAS_ENCODER_ACTION - refresh(LCDVIEW_REDRAW_NOW); - #if HAS_MARLINUI_MENU - if (encoderDirection == -(ENCODERBASE)) { // HAS_ADC_BUTTONS forces REVERSE_MENU_DIRECTION, so this indicates menu navigation - if (RRK(EN_KEYPAD_UP)) encoderPosition += ENCODER_STEPS_PER_MENU_ITEM; - else if (RRK(EN_KEYPAD_DOWN)) encoderPosition -= ENCODER_STEPS_PER_MENU_ITEM; - else if (RRK(EN_KEYPAD_LEFT)) { MenuItem_back::action(); quick_feedback(); } - else if (RRK(EN_KEYPAD_RIGHT)) { return_to_status(); quick_feedback(); } - } - else - #endif - { - #if HAS_MARLINUI_MENU - if (RRK(EN_KEYPAD_UP)) encoderPosition -= epps; - else if (RRK(EN_KEYPAD_DOWN)) encoderPosition += epps; - else if (RRK(EN_KEYPAD_LEFT)) { MenuItem_back::action(); quick_feedback(); } - else if (RRK(EN_KEYPAD_RIGHT)) encoderPosition = 0; - #else - if (RRK(EN_KEYPAD_UP) || RRK(EN_KEYPAD_LEFT)) encoderPosition -= epps; - else if (RRK(EN_KEYPAD_DOWN) || RRK(EN_KEYPAD_RIGHT)) encoderPosition += epps; - #endif + refresh(LCDVIEW_REDRAW_NOW); + #if HAS_MARLINUI_MENU + if (encoderDirection == -(ENCODERBASE)) { // HAS_ADC_BUTTONS forces REVERSE_MENU_DIRECTION, so this indicates menu navigation + if (RRK(EN_KEYPAD_UP)) encoderPosition += ENCODER_STEPS_PER_MENU_ITEM; + else if (RRK(EN_KEYPAD_DOWN)) encoderPosition -= ENCODER_STEPS_PER_MENU_ITEM; + else if (RRK(EN_KEYPAD_LEFT)) { MenuItem_back::action(); quick_feedback(); } + else if (RRK(EN_KEYPAD_RIGHT)) { return_to_status(); quick_feedback(); } } + else #endif + { + #if HAS_MARLINUI_MENU + if (RRK(EN_KEYPAD_UP)) encoderPosition -= epps; + else if (RRK(EN_KEYPAD_DOWN)) encoderPosition += epps; + else if (RRK(EN_KEYPAD_LEFT)) { MenuItem_back::action(); quick_feedback(); } + else if (RRK(EN_KEYPAD_RIGHT)) encoderPosition = 0; + #else + if (RRK(EN_KEYPAD_UP) || RRK(EN_KEYPAD_LEFT)) encoderPosition -= epps; + else if (RRK(EN_KEYPAD_DOWN) || RRK(EN_KEYPAD_RIGHT)) encoderPosition += epps; + #endif + } next_button_update_ms = millis() + ADC_MIN_KEY_DELAY; return true; } @@ -1337,11 +1335,11 @@ void MarlinUI::init() { const int8_t pulses = epps * encoderDirection; if (BUTTON_PRESSED(UP)) { - encoderDiff = (ENCODER_STEPS_PER_MENU_ITEM) * pulses; + encoderDiff = pulses * (ENCODER_STEPS_PER_MENU_ITEM); next_button_update_ms = now + 300; } else if (BUTTON_PRESSED(DOWN)) { - encoderDiff = -(ENCODER_STEPS_PER_MENU_ITEM) * pulses; + encoderDiff = pulses * -(ENCODER_STEPS_PER_MENU_ITEM); next_button_update_ms = now + 300; } else if (BUTTON_PRESSED(LEFT)) { diff --git a/Marlin/src/lcd/menu/menu_filament.cpp b/Marlin/src/lcd/menu/menu_filament.cpp index 46ebf85ba4..8d6e1b8adb 100644 --- a/Marlin/src/lcd/menu/menu_filament.cpp +++ b/Marlin/src/lcd/menu/menu_filament.cpp @@ -235,18 +235,15 @@ static FSTR_P pause_header() { // Portions from STATIC_ITEM... #define HOTEND_STATUS_ITEM() do { \ - if (_menuLineNr == _thisItemNr) { \ + if ( MY_LINE()) { \ if (ui.should_draw()) { \ IF_DISABLED(HAS_GRAPHICAL_TFT, MenuItem_static::draw(_lcdLineNr, GET_TEXT_F(MSG_FILAMENT_CHANGE_NOZZLE), SS_INVERT)); \ ui.draw_hotend_status(_lcdLineNr, hotend_status_extruder); \ } \ - if (_skipStatic && encoderLine <= _thisItemNr) { \ - ui.encoderPosition += ENCODER_STEPS_PER_MENU_ITEM; \ - ++encoderLine; \ - } \ + STATIC_SKIP(); \ ui.refresh(LCDVIEW_CALL_REDRAW_NEXT); \ } \ - ++_thisItemNr; \ + NEXT_ITEM(); \ }while(0) void menu_pause_option() { @@ -307,11 +304,9 @@ void lcd_pause_waiting_message() { _lcd_pause_message(GET_TEXT_F(MSG_ADVANCED_P void lcd_pause_resume_message() { _lcd_pause_message(GET_TEXT_F(MSG_FILAMENT_CHANGE_RESUME)); } void lcd_pause_purge_message() { - #if ENABLED(ADVANCED_PAUSE_CONTINUOUS_PURGE) - _lcd_pause_message(GET_TEXT_F(MSG_FILAMENT_CHANGE_CONT_PURGE)); - #else - _lcd_pause_message(GET_TEXT_F(MSG_FILAMENT_CHANGE_PURGE)); - #endif + _lcd_pause_message(GET_TEXT_F( + TERN(ADVANCED_PAUSE_CONTINUOUS_PURGE, MSG_FILAMENT_CHANGE_CONT_PURGE, MSG_FILAMENT_CHANGE_PURGE) + )); } FORCE_INLINE screenFunc_t ap_message_screen(const PauseMessage message) { diff --git a/Marlin/src/lcd/menu/menu_item.h b/Marlin/src/lcd/menu/menu_item.h index d81b1a8843..df2c90425c 100644 --- a/Marlin/src/lcd/menu/menu_item.h +++ b/Marlin/src/lcd/menu/menu_item.h @@ -401,7 +401,7 @@ class MenuItem_bool : public MenuEditItemBase { #define PSTRING_ITEM_F_P(FLABEL, PVAL, STYL) do{ \ constexpr int m = 20; \ char msg[m + 1]; \ - if (_menuLineNr == _thisItemNr) { \ + if (MY_LINE()) { \ msg[0] = ':'; msg[1] = ' '; \ strlcpy_P(msg + 2, PVAL, m - 1); \ if (msg[m - 1] & 0x80) msg[m - 1] = '\0'; \ @@ -410,8 +410,7 @@ class MenuItem_bool : public MenuEditItemBase { }while(0) #define PSTRING_ITEM_N_F_P(N, V...) do{ \ - if (_menuLineNr == _thisItemNr) \ - MenuItemBase::init(N); \ + if (MY_LINE()) MenuItemBase::init(N); \ PSTRING_ITEM_F_P(V); \ }while(0) From 13db322f0ef5ef6ccb093c0794eb73a653a4e548 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 1 Apr 2025 04:32:04 -0500 Subject: [PATCH 177/787] =?UTF-8?q?=F0=9F=8E=A8=20GD32=20MFL=20followup?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Followup to #27744 --- Marlin/src/HAL/GD32_MFL/MinSerial.cpp | 2 +- Marlin/src/HAL/GD32_MFL/SDCard.h | 12 ++++++------ Marlin/src/HAL/GD32_MFL/timers.cpp | 10 +++++----- Marlin/src/HAL/GD32_MFL/timers.h | 4 ++-- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Marlin/src/HAL/GD32_MFL/MinSerial.cpp b/Marlin/src/HAL/GD32_MFL/MinSerial.cpp index d5e8147798..2cc79c8853 100644 --- a/Marlin/src/HAL/GD32_MFL/MinSerial.cpp +++ b/Marlin/src/HAL/GD32_MFL/MinSerial.cpp @@ -95,7 +95,7 @@ static void MinSerialBegin() { volatile uint32_t ICER[32]; }; NVICMin *nvicBase = (NVICMin*)0xE000E100; - + SBI32(nvicBase->ICER[nvicIndex >> 5], nvicIndex & 0x1F); // We require memory barriers to properly disable interrupts diff --git a/Marlin/src/HAL/GD32_MFL/SDCard.h b/Marlin/src/HAL/GD32_MFL/SDCard.h index b14063b69f..467482a605 100644 --- a/Marlin/src/HAL/GD32_MFL/SDCard.h +++ b/Marlin/src/HAL/GD32_MFL/SDCard.h @@ -160,12 +160,12 @@ private: info->csd.device_size = (static_cast(csd_bytes[6] & 0x03U) << 10U) | (static_cast(csd_bytes[7]) << 2U) | (static_cast((csd_bytes[8] & 0xC0U) >> 6U)); - info->csd.device_size_multiplier = static_cast((csd_bytes[9] & 0x03U) << 1U | + info->csd.device_size_multiplier = static_cast((csd_bytes[9] & 0x03U) << 1U | (csd_bytes[10] & 0x80U) >> 7U); info->block_size = static_cast(1 << info->csd.read_block_length); - info->capacity = static_cast((info->csd.device_size + 1U) * - (1U << (info->csd.device_size_multiplier + 2U)) * + info->capacity = static_cast((info->csd.device_size + 1U) * + (1U << (info->csd.device_size_multiplier + 2U)) * info->block_size); } @@ -175,15 +175,15 @@ private: static_cast(csd_bytes[9]); info->block_size = BLOCK_SIZE; - info->capacity = static_cast((info->csd.device_size + 1U) * + info->capacity = static_cast((info->csd.device_size + 1U) * BLOCK_SIZE * KILOBYTE); } void process_common_csd_tail(Card_Info* info, const uint8_t* csd_bytes) { - info->csd.sector_size = static_cast(((csd_bytes[9] & 0x3FU) << 1U) | + info->csd.sector_size = static_cast(((csd_bytes[9] & 0x3FU) << 1U) | (csd_bytes[10] & 0x80U) >> 7U); info->csd.speed_factor = static_cast((csd_bytes[11] & 0x1CU) >> 2U); - info->csd.write_block_length = static_cast(((csd_bytes[11] & 0x03U) << 2U) | + info->csd.write_block_length = static_cast(((csd_bytes[11] & 0x03U) << 2U) | ((csd_bytes[12] & 0xC0U) >> 6U)); info->csd.checksum = static_cast((csd_bytes[15] & 0xFEU) >> 1U); } diff --git a/Marlin/src/HAL/GD32_MFL/timers.cpp b/Marlin/src/HAL/GD32_MFL/timers.cpp index bdcf5ed0ed..5b2c2de7ef 100644 --- a/Marlin/src/HAL/GD32_MFL/timers.cpp +++ b/Marlin/src/HAL/GD32_MFL/timers.cpp @@ -97,10 +97,10 @@ uint32_t GetStepperTimerClkFreq() { /** * @brief Starts a hardware timer - * + * * If the timer is not already initialized, this function will initialize it with the given frequency. * The timer is started immediately after initialization - * + * * @param timer The timer base index to start * @param frequency The frequency at which the timer should run * @return None @@ -137,7 +137,7 @@ void HAL_timer_start(const uint8_t timer_number, const uint32_t frequency) { /** * @brief Enables the interrupt for the specified timer - * + * * @param handle The timer handle for which to enable the interrupt * @return None */ @@ -154,7 +154,7 @@ void HAL_timer_enable_interrupt(const uint8_t timer_number) { /** * @brief Disables the interrupt for the specified timer - * + * * @param handle The timer handle for which to disable the interrupt * @return None */ @@ -168,7 +168,7 @@ void HAL_timer_disable_interrupt(const uint8_t timer_number) { /** * @brief Checks if the interrupt is enabled for the specified timer - * + * * @param handle The timer handle to check * @return True if the interrupt is enabled, false otherwise */ diff --git a/Marlin/src/HAL/GD32_MFL/timers.h b/Marlin/src/HAL/GD32_MFL/timers.h index 539f599a16..0eb6bd563a 100644 --- a/Marlin/src/HAL/GD32_MFL/timers.h +++ b/Marlin/src/HAL/GD32_MFL/timers.h @@ -123,8 +123,8 @@ FORCE_INLINE static hal_timer_t HAL_timer_get_count(const uint8_t timer_number) GeneralTimer& timer = (timer_number == MF_TIMER_STEP) ? Step_Timer : Temp_Timer; - return (timer_number == MF_TIMER_STEP || timer_number == MF_TIMER_TEMP) - ? timer.getCounter(TimerFormat::TICK) + return (timer_number == MF_TIMER_STEP || timer_number == MF_TIMER_TEMP) + ? timer.getCounter(TimerFormat::TICK) : 0U; } From 2f7d88d5c3f6b102bc97193dc6f7f17e0094c6f9 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Wed, 2 Apr 2025 00:30:08 +0000 Subject: [PATCH 178/787] [cron] Bump distribution date (2025-04-02) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index bb3996fb73..7ca68426b9 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-04-01" +//#define STRING_DISTRIBUTION_DATE "2025-04-02" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 64a8aded74..ac704f4af4 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-04-01" + #define STRING_DISTRIBUTION_DATE "2025-04-02" #endif /** From 9758f5e0ce28ae934ea4e96aa68a84ee272b5917 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 1 Apr 2025 23:28:20 -0500 Subject: [PATCH 179/787] =?UTF-8?q?=F0=9F=93=9D=20Informative=20PID=20comm?= =?UTF-8?q?ents?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/Configuration.h | 16 +++++++++------- Marlin/Configuration_adv.h | 14 +++++++------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 9a96169646..08ef067328 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -696,8 +696,9 @@ #define PID_K1 0.95 // Smoothing factor within any PID loop #if ENABLED(PIDTEMP) - //#define MIN_POWER 0 - //#define PID_DEBUG // Print PID debug data to the serial port. Use 'M303 D' to toggle activation. + //#define MIN_POWER 0 // Min power to improve PID stability (0..PID_MAX). + // Get the power from the temperature report ('M105' => @:nnn) and try P*2-20 to P*2-10. + //#define PID_DEBUG // Print PID debug data to the serial port. Use 'M303 D' to enable/disable. //#define PID_PARAMS_PER_HOTEND // Use separate PID parameters for each extruder (useful for mismatched extruders) // Set/get with G-code: M301 E[extruder number, 0-2] @@ -796,8 +797,9 @@ //#define PIDTEMPBED #if ENABLED(PIDTEMPBED) - //#define MIN_BED_POWER 0 - //#define PID_BED_DEBUG // Print Bed PID debug data to the serial port. + //#define MIN_BED_POWER 0 // Min power to improve PID stability (0..MAX_BED_POWER). + // Get the power from the temperature report ('M105' => B@:nnn) and try P*2-20 to P*2-10. + //#define PID_BED_DEBUG // Print Bed PID debug data to the serial port. Use 'M303 D' to enable/disable. // 120V 250W silicone heater into 4mm borosilicate (MendelMax 1.5+) // from FOPDT model - kp=.39 Tp=405 Tdead=66, Tc set to 79.2, aggressive factor of .15 (vs .1, 1, 10) @@ -878,12 +880,12 @@ #define MAX_CHAMBER_POWER 255 // limits duty cycle to chamber heater; 255=full current #if ENABLED(PIDTEMPCHAMBER) - #define MIN_CHAMBER_POWER 0 - //#define PID_CHAMBER_DEBUG // Print Chamber PID debug data to the serial port. + #define MIN_CHAMBER_POWER 0 // Min power to improve PID stability. (0..MAX_CHAMBER_POWER) + // Get the power from the temperature report ('M105' => C@:nnn) and try P*2-20 to P*2-10. + //#define PID_CHAMBER_DEBUG // Print Chamber PID debug data to the serial port. Use 'M303 D' to enable/disable. // Lasko "MyHeat Personal Heater" (200w) modified with a Fotek SSR-10DA to control only the heating element // and placed inside the small Creality printer enclosure tent. - // #define DEFAULT_chamberKp 37.04 #define DEFAULT_chamberKi 1.40 #define DEFAULT_chamberKd 655.17 diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index f24ece5986..2e0ca3d4a1 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -1342,20 +1342,20 @@ //#define CALIBRATION_SCRIPT_PRE "M117 Starting Auto-Calibration\nT0\nG28\nG12\nM117 Calibrating..." //#define CALIBRATION_SCRIPT_POST "M500\nM117 Calibration data saved" - #define CALIBRATION_FEEDRATE_SLOW 60 // mm/min - #define CALIBRATION_FEEDRATE_FAST 1200 // mm/min - #define CALIBRATION_FEEDRATE_TRAVEL 3000 // mm/min + #define CALIBRATION_FEEDRATE_SLOW 60 // (mm/min) + #define CALIBRATION_FEEDRATE_FAST 1200 // (mm/min) + #define CALIBRATION_FEEDRATE_TRAVEL 3000 // (mm/min) // The following parameters refer to the conical section of the nozzle tip. - #define CALIBRATION_NOZZLE_TIP_HEIGHT 1.0 // mm - #define CALIBRATION_NOZZLE_OUTER_DIAMETER 2.0 // mm + #define CALIBRATION_NOZZLE_TIP_HEIGHT 1.0 // (mm) + #define CALIBRATION_NOZZLE_OUTER_DIAMETER 2.0 // (mm) // Uncomment to enable reporting (required for "G425 V", but consumes flash). //#define CALIBRATION_REPORTING // The true location and dimension the cube/bolt/washer on the bed. - #define CALIBRATION_OBJECT_CENTER { 264.0, -22.0, -2.0 } // mm - #define CALIBRATION_OBJECT_DIMENSIONS { 10.0, 10.0, 10.0 } // mm + #define CALIBRATION_OBJECT_CENTER { 264.0, -22.0, -2.0 } // (mm) + #define CALIBRATION_OBJECT_DIMENSIONS { 10.0, 10.0, 10.0 } // (mm) // Comment out any sides which are unreachable by the probe. For best // auto-calibration results, all sides must be reachable. From a4c35b1555948a31ce0ac5d15a61617ced31a2d3 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 1 Apr 2025 23:40:22 -0500 Subject: [PATCH 180/787] =?UTF-8?q?=F0=9F=9A=B8=20Disable=20MIN=5FCHAMBER?= =?UTF-8?q?=5FPOWER?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/Configuration.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 08ef067328..69cae47ee1 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -880,9 +880,9 @@ #define MAX_CHAMBER_POWER 255 // limits duty cycle to chamber heater; 255=full current #if ENABLED(PIDTEMPCHAMBER) - #define MIN_CHAMBER_POWER 0 // Min power to improve PID stability. (0..MAX_CHAMBER_POWER) - // Get the power from the temperature report ('M105' => C@:nnn) and try P*2-20 to P*2-10. - //#define PID_CHAMBER_DEBUG // Print Chamber PID debug data to the serial port. Use 'M303 D' to enable/disable. + //#define MIN_CHAMBER_POWER 0 // Min power to improve PID stability. (0..MAX_CHAMBER_POWER) + // Get the power from the temperature report ('M105' => C@:nnn) and try P*2-20 to P*2-10. + //#define PID_CHAMBER_DEBUG // Print Chamber PID debug data to the serial port. Use 'M303 D' to enable/disable. // Lasko "MyHeat Personal Heater" (200w) modified with a Fotek SSR-10DA to control only the heating element // and placed inside the small Creality printer enclosure tent. From c6dad4d1aaea5756b0931e4f3b66590a2a5437f6 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Thu, 3 Apr 2025 00:29:22 +0000 Subject: [PATCH 181/787] [cron] Bump distribution date (2025-04-03) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 7ca68426b9..594f3546b6 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-04-02" +//#define STRING_DISTRIBUTION_DATE "2025-04-03" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index ac704f4af4..adb9112bfe 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-04-02" + #define STRING_DISTRIBUTION_DATE "2025-04-03" #endif /** From c080518b125303bea33caa21075c1fbfae192fa8 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Fri, 4 Apr 2025 21:58:49 -0500 Subject: [PATCH 182/787] =?UTF-8?q?=F0=9F=8E=A8=20DGUS/MKS=20cosmetic=20fi?= =?UTF-8?q?xes,=20most?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/core/macros.h | 7 +- Marlin/src/gcode/control/M605.cpp | 2 +- Marlin/src/lcd/extui/dgus/DGUSDisplay.cpp | 34 +- Marlin/src/lcd/extui/dgus/DGUSDisplay.h | 17 +- .../src/lcd/extui/dgus/DGUSScreenHandler.cpp | 50 +- Marlin/src/lcd/extui/dgus/DGUSScreenHandler.h | 8 +- .../lcd/extui/dgus/DGUSScreenHandlerBase.h | 16 +- Marlin/src/lcd/extui/dgus/dgus_extui.cpp | 8 +- .../lcd/extui/dgus/fysetc/DGUSDisplayDef.cpp | 6 +- .../lcd/extui/dgus/fysetc/DGUSDisplayDef.h | 2 +- .../extui/dgus/fysetc/DGUSScreenHandler.cpp | 22 +- .../lcd/extui/dgus/hiprecy/DGUSDisplayDef.cpp | 6 +- .../lcd/extui/dgus/hiprecy/DGUSDisplayDef.h | 2 +- .../extui/dgus/hiprecy/DGUSScreenHandler.cpp | 20 +- .../src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp | 24 +- .../src/lcd/extui/dgus/mks/DGUSDisplayDef.h | 385 +++-- .../lcd/extui/dgus/mks/DGUSScreenHandler.cpp | 1281 ++++++++--------- .../lcd/extui/dgus/mks/DGUSScreenHandler.h | 8 +- .../lcd/extui/dgus/origin/DGUSDisplayDef.cpp | 2 +- .../lcd/extui/dgus/origin/DGUSDisplayDef.h | 2 +- .../extui/dgus/origin/DGUSScreenHandler.cpp | 22 +- .../dgus_e3s1pro/DGUSSDCardHandler_Basic.cpp | 6 +- .../extui/dgus_e3s1pro/DGUSScreenHandler.cpp | 2 +- Marlin/src/lcd/menu/menu_configuration.cpp | 2 +- Marlin/src/module/endstops.h | 2 +- Marlin/src/pins/samd/pins_MINITRONICS20.h | 2 +- buildroot/tests/FYSETC_F6 | 7 + 27 files changed, 941 insertions(+), 1004 deletions(-) diff --git a/Marlin/src/core/macros.h b/Marlin/src/core/macros.h index 344ab04e74..c75d684566 100644 --- a/Marlin/src/core/macros.h +++ b/Marlin/src/core/macros.h @@ -658,11 +658,8 @@ #define IF_ELSE(TF) _IF_ELSE(_BOOL(TF)) #define _IF_ELSE(TF) _CAT(_IF_, TF) -#define _IF_1(V...) V _IF_1_ELSE -#define _IF_0(...) _IF_0_ELSE - -#define _IF_1_ELSE(...) -#define _IF_0_ELSE(V...) V +#define _IF_1(V...) V OMIT +#define _IF_0(...) EMIT #define HAS_ARGS(V...) _BOOL(FIRST(_END_OF_ARGUMENTS_ V)()) #define _END_OF_ARGUMENTS_() 0 diff --git a/Marlin/src/gcode/control/M605.cpp b/Marlin/src/gcode/control/M605.cpp index 167cdae4a9..56d7594b08 100644 --- a/Marlin/src/gcode/control/M605.cpp +++ b/Marlin/src/gcode/control/M605.cpp @@ -115,7 +115,7 @@ else if (!parser.seen('W')) // if no S or W parameter, the DXC mode gets reset to the user's default dual_x_carriage_mode = DEFAULT_DUAL_X_CARRIAGE_MODE; - #ifdef DEBUG_DXC_MODE + #if ENABLED(DEBUG_DXC_MODE) if (parser.seen('W')) { DEBUG_ECHO_START(); diff --git a/Marlin/src/lcd/extui/dgus/DGUSDisplay.cpp b/Marlin/src/lcd/extui/dgus/DGUSDisplay.cpp index 074dad96c2..94ea71817e 100644 --- a/Marlin/src/lcd/extui/dgus/DGUSDisplay.cpp +++ b/Marlin/src/lcd/extui/dgus/DGUSDisplay.cpp @@ -46,7 +46,7 @@ DGUSDisplay dgus; -#ifdef DEBUG_DGUS_COMM +#if ENABLED(DEBUG_DGUS_COMM) #define DEBUGLCDCOMM_ECHOPGM DEBUG_ECHOPGM #else #define DEBUGLCDCOMM_ECHOPGM(...) NOOP @@ -76,7 +76,22 @@ void DGUSDisplay::initDisplay() { requestScreen(TERN(SHOW_BOOTSCREEN, DGUS_SCREEN_BOOT, DGUS_SCREEN_MAIN)); } -void DGUSDisplay::writeVariable(uint16_t adr, const void *values, uint8_t valueslen, bool isstr) { +void DGUSDisplay::writeVariable_P(uint16_t adr, const void *values, uint8_t valueslen, bool isstr/*=false*/) { + const char* myvalues = static_cast(values); + bool strend = !myvalues; + writeHeader(adr, DGUS_CMD_WRITEVAR, valueslen); + while (valueslen--) { + char x; + if (!strend) x = pgm_read_byte(myvalues++); + if ((isstr && !x) || strend) { + strend = true; + x = ' '; + } + LCD_SERIAL.write(x); + } +} + +void DGUSDisplay::writeVariable(uint16_t adr, const void *values, uint8_t valueslen, bool isstr/*=false*/) { const char* myvalues = static_cast(values); bool strend = !myvalues; writeHeader(adr, DGUS_CMD_WRITEVAR, valueslen); @@ -120,21 +135,6 @@ void DGUSDisplay::writeVariable(uint16_t adr, long value) { writeVariable(adr, static_cast(&tmp), sizeof(long)); } -void DGUSDisplay::writeVariablePGM(uint16_t adr, const void *values, uint8_t valueslen, bool isstr) { - const char* myvalues = static_cast(values); - bool strend = !myvalues; - writeHeader(adr, DGUS_CMD_WRITEVAR, valueslen); - while (valueslen--) { - char x; - if (!strend) x = pgm_read_byte(myvalues++); - if ((isstr && !x) || strend) { - strend = true; - x = ' '; - } - LCD_SERIAL.write(x); - } -} - void DGUSDisplay::processRx() { #if ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS) diff --git a/Marlin/src/lcd/extui/dgus/DGUSDisplay.h b/Marlin/src/lcd/extui/dgus/DGUSDisplay.h index 816360d3f3..6329d8fb23 100644 --- a/Marlin/src/lcd/extui/dgus/DGUSDisplay.h +++ b/Marlin/src/lcd/extui/dgus/DGUSDisplay.h @@ -60,15 +60,28 @@ public: static void initDisplay(); // Variable access. + static void writeVariable_P(uint16_t adr, const void *values, uint8_t valueslen, bool isstr=false); static void writeVariable(uint16_t adr, const void *values, uint8_t valueslen, bool isstr=false); - static void writeVariablePGM(uint16_t adr, const void *values, uint8_t valueslen, bool isstr=false); static void writeVariable(uint16_t adr, int16_t value); static void writeVariable(uint16_t adr, uint16_t value); static void writeVariable(uint16_t adr, uint8_t value); static void writeVariable(uint16_t adr, int8_t value); static void writeVariable(uint16_t adr, long value); - // Utility functions for bridging ui_api and dbus + static void writeStringVar_P(uint16_t adr, PGM_P const pstr, uint8_t vallen=32) { + writeVariable_P(adr, (const void *)pstr, vallen, true); + } + static void writeStringVar(uint16_t adr, const char * const cstr, uint8_t vallen=32) { + writeVariable(adr, (const void *)cstr, vallen, true); + } + static void writeStringVar(uint16_t adr, const uint16_t * const zhstr, uint8_t vallen=16) { + writeVariable(adr, (const void *)zhstr, vallen, true); + } + static void writeVariable(uint16_t adr, FSTR_P const fstr, uint8_t vallen=32) { + writeStringVar_P(adr, FTOP(fstr), vallen); + } + + // Utility functions for bridging ui_api and dgus template static void setVariable(DGUS_VP_Variable &var) { writeVariable(var.VP, (WireType)Getter(selector)); diff --git a/Marlin/src/lcd/extui/dgus/DGUSScreenHandler.cpp b/Marlin/src/lcd/extui/dgus/DGUSScreenHandler.cpp index 00876f10e1..f85fc9beac 100644 --- a/Marlin/src/lcd/extui/dgus/DGUSScreenHandler.cpp +++ b/Marlin/src/lcd/extui/dgus/DGUSScreenHandler.cpp @@ -101,7 +101,7 @@ void DGUSScreenHandler::setStatusMessage(const char *msg) { } } -void DGUSScreenHandler::setstatusmessagePGM(PGM_P const msg) { +void DGUSScreenHandler::setStatusMessage_P(PGM_P const msg) { DGUS_VP_Variable ramcopy; if (populate_VPVar(VP_M117, &ramcopy)) { ramcopy.memadr = (void*) msg; @@ -164,10 +164,11 @@ void DGUSScreenHandler::sendStringToDisplay(DGUS_VP_Variable &var) { // overwrite the remainings with spaces.// var.size has the display buffer size! void DGUSScreenHandler::sendStringToDisplayPGM(DGUS_VP_Variable &var) { char *tmp = (char*) var.memadr; - dgus.writeVariablePGM(var.VP, tmp, var.size, true); + dgus.writeVariable_P(var.VP, tmp, var.size, true); } #if HAS_PID_HEATING + void DGUSScreenHandler::sendTemperaturePID(DGUS_VP_Variable &var) { float value = *(float *)var.memadr; value /= 10; @@ -200,7 +201,8 @@ void DGUSScreenHandler::sendStringToDisplayPGM(DGUS_VP_Variable &var) { tmp[1] = endian.lb[0]; dgus.writeVariable(var.VP, tmp, 2); } -#endif + +#endif // HAS_PID_HEATING #if ENABLED(PRINTCOUNTER) @@ -221,7 +223,7 @@ void DGUSScreenHandler::sendStringToDisplayPGM(DGUS_VP_Variable &var) { dgus.writeVariable(VP_PrintsTotal, buf, var.size, true); } -#endif +#endif // PRINTCOUNTER // Send fan status value to the display. #if HAS_FAN @@ -249,8 +251,7 @@ void DGUSScreenHandler::sendHeaterStatusToDisplay(DGUS_VP_Variable &var) { void DGUSScreenHandler::sendWaitingStatusToDisplay(DGUS_VP_Variable &var) { // In FYSETC UI design there are 10 statuses to loop - static uint16_t period = 0; - static uint16_t index = 0; + static uint16_t period = 0, index = 0; if (period++ > DGUS_UI_WAITING_STATUS_PERIOD) { dgus.writeVariable(var.VP, index); if (++index >= DGUS_UI_WAITING_STATUS) index = 0; @@ -270,9 +271,9 @@ void DGUSScreenHandler::sendHeaterStatusToDisplay(DGUS_VP_Variable &var) { return; } - // if we are printing, we jump to two screens after the requested one. - // This should host e.g a print pause / print abort / print resume dialog. - // This concept allows to recycle this hook for other file + // If we are printing we jump to two screens after the requested one. + // This should host, e.g., a print pause / print abort / print resume dialog. + // This concept allows to recycle this hook for other files. if (ExtUI::isPrintingFromMedia() && !card.flag.abort_sd_printing) { gotoScreen(DGUS_SCREEN_SDPRINTMANIPULATION); return; @@ -324,7 +325,7 @@ void DGUSScreenHandler::sendHeaterStatusToDisplay(DGUS_VP_Variable &var) { void DGUSScreenHandler::sdCardError() { DGUSScreenHandler::sdCardRemoved(); - sendInfoScreen(F("NOTICE"), nullptr, F("SD card error"), nullptr, true, true, true, true); + sendInfoScreen(F("NOTICE"), nullptr, F("SD card error"), nullptr); setupConfirmAction(nullptr); gotoScreen(DGUS_SCREEN_POPUP); } @@ -432,9 +433,9 @@ void DGUSScreenHandler::handleManualExtrude(DGUS_VP_Variable &var, void *val_ptr switch (var.VP) { #if HAS_HOTEND case VP_MOVE_E0: target_extruder = ExtUI::extruder_t::E0; break; - #if HAS_MULTI_EXTRUDER - case VP_MOVE_E1: target_extruder = ExtUI::extruder_t::E1; break; - #endif + #endif + #if HAS_MULTI_EXTRUDER + case VP_MOVE_E1: target_extruder = ExtUI::extruder_t::E1; break; #endif default: return; } @@ -491,12 +492,12 @@ void DGUSScreenHandler::handleSettings(DGUS_VP_Variable &var, void *val_ptr) { ExtUI::extruder_t extruder; switch (var.VP) { default: return; - #if HAS_EXTRUDERS - case VP_E0_STEP_PER_MM: extruder = ExtUI::extruder_t::E0; break; - #if HAS_MULTI_EXTRUDER - case VP_E1_STEP_PER_MM: extruder = ExtUI::extruder_t::E1; break; - #endif - #endif + #if HAS_EXTRUDERS + case VP_E0_STEP_PER_MM: extruder = ExtUI::extruder_t::E0; break; + #endif + #if HAS_MULTI_EXTRUDER + case VP_E1_STEP_PER_MM: extruder = ExtUI::extruder_t::E1; break; + #endif } ExtUI::setAxisSteps_per_mm(value, extruder); skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel @@ -506,21 +507,17 @@ void DGUSScreenHandler::handleSettings(DGUS_VP_Variable &var, void *val_ptr) { #if HAS_PID_HEATING void DGUSScreenHandler::handlePIDAutotune(DGUS_VP_Variable &var, void *val_ptr) { - char buf[32] = {0}; - switch (var.VP) { default: break; #if ENABLED(PIDTEMP) #if HAS_HOTEND case VP_PID_AUTOTUNE_E0: // Autotune Extruder 0 - sprintf_P(buf, PSTR("M303 E%d C5 S210 U1"), ExtUI::extruder_t::E0); - queue.enqueue_one_now(buf); + queue.enqueue_one_now(F("M303 E0 C5 S210 U1")); break; #endif #if HAS_MULTI_HOTEND case VP_PID_AUTOTUNE_E1: - sprintf_P(buf, PSTR("M303 E%d C5 S210 U1"), ExtUI::extruder_t::E1); - queue.enqueue_one_now(buf); + queue.enqueue_one_now(F("M303 E1 C5 S210 U1")); break; #endif #endif @@ -536,6 +533,7 @@ void DGUSScreenHandler::handleSettings(DGUS_VP_Variable &var, void *val_ptr) { gotoScreen(DGUS_SCREEN_WAITING); #endif } + #endif // HAS_PID_HEATING #if HAS_BED_PROBE @@ -607,7 +605,7 @@ void DGUSScreenHandler::handleHeaterControl(DGUS_VP_Variable &var, void *val_ptr uint16_t value = BE16_P(val_ptr); if (value) { queue.inject(F("M1000")); - dgus.writeVariable(VP_SD_Print_Filename, filelist.filename(), 32, true); + dgus.writeStringVar(VP_SD_Print_Filename, filelist.filename()); gotoScreen(PLR_SCREEN_RECOVER); } else { diff --git a/Marlin/src/lcd/extui/dgus/DGUSScreenHandler.h b/Marlin/src/lcd/extui/dgus/DGUSScreenHandler.h index cb403dbdad..d8d66b764c 100644 --- a/Marlin/src/lcd/extui/dgus/DGUSScreenHandler.h +++ b/Marlin/src/lcd/extui/dgus/DGUSScreenHandler.h @@ -32,10 +32,10 @@ #if ENABLED(DGUS_FILAMENT_LOADUNLOAD) typedef struct { - ExtUI::extruder_t extruder; // which extruder to operate - uint8_t action; // load or unload - bool heated; // heating done ? - float purge_length; // the length to extrude before unload, prevent filament jam + uint8_t extruder; // Which extruder index to operate + uint8_t action; // Load or unload + bool heated; // Heating done? + float purge_length; // The length to extrude before unload, prevent filament jam } filament_data_t; extern filament_data_t filament_data; diff --git a/Marlin/src/lcd/extui/dgus/DGUSScreenHandlerBase.h b/Marlin/src/lcd/extui/dgus/DGUSScreenHandlerBase.h index 8ee0fa68c8..ceaeb7cd7f 100644 --- a/Marlin/src/lcd/extui/dgus/DGUSScreenHandlerBase.h +++ b/Marlin/src/lcd/extui/dgus/DGUSScreenHandlerBase.h @@ -37,21 +37,21 @@ public: // Send all 4 strings that are displayed on the infoscreen, confirmation screen and kill screen // The bools specifying whether the strings are in RAM or FLASH. - static void sendInfoScreen_P(PGM_P const line1, PGM_P const line2, PGM_P const line3, PGM_P const line4, bool l1inflash, bool l2inflash, bool l3inflash, bool liinflash); - static void sendInfoScreen(FSTR_P const line1, FSTR_P const line2, PGM_P const line3, PGM_P const line4, bool l1inflash, bool l2inflash, bool l3inflash, bool liinflash) { - sendInfoScreen_P(FTOP(line1), FTOP(line2), line3, line4, l1inflash, l2inflash, l3inflash, liinflash); + static void sendInfoScreen_P(PGM_P const line1, PGM_P const line2, PGM_P const line3, PGM_P const line4, bool l1inflash, bool l2inflash, bool l3inflash, bool l4inflash); + static void sendInfoScreen(FSTR_P const line1, FSTR_P const line2, PGM_P const line3, PGM_P const line4, bool l1inflash, bool l2inflash, bool l3inflash, bool l4inflash) { + sendInfoScreen_P(FTOP(line1), FTOP(line2), line3, line4, l1inflash, l2inflash, l3inflash, l4inflash); } - static void sendInfoScreen(FSTR_P const line1, FSTR_P const line2, FSTR_P const line3, FSTR_P const line4, bool l1inflash, bool l2inflash, bool l3inflash, bool liinflash) { - sendInfoScreen_P(FTOP(line1), FTOP(line2), FTOP(line3), FTOP(line4), l1inflash, l2inflash, l3inflash, liinflash); + static void sendInfoScreen(FSTR_P const line1, FSTR_P const line2, FSTR_P const line3, FSTR_P const line4) { + sendInfoScreen_P(FTOP(line1), FTOP(line2), FTOP(line3), FTOP(line4), true, true, true, true); } - static void handleUserConfirmationPopUp(uint16_t confirmVP, PGM_P const line1, PGM_P const line2, PGM_P const line3, PGM_P const line4, bool l1inflash, bool l2inflash, bool l3inflash, bool liinflash); + static void handleUserConfirmationPopUp(uint16_t confirmVP, PGM_P const line1, PGM_P const line2, PGM_P const line3, PGM_P const line4, bool l1inflash, bool l2inflash, bool l3inflash, bool l4inflash); // "M117" Message -- msg is a RAM ptr. static void setStatusMessage(const char *msg); // The same for messages from Flash - static void setstatusmessagePGM(PGM_P const msg); - static void setStatusMessage(FSTR_P const fmsg) { setstatusmessagePGM(FTOP(fmsg)); } + static void setStatusMessage_P(PGM_P const msg); + static void setStatusMessage(FSTR_P const fmsg) { setStatusMessage_P(FTOP(fmsg)); } // Callback for VP "Display wants to change screen on idle printer" static void screenChangeHookIfIdle(DGUS_VP_Variable &var, void *val_ptr); // Callback for VP "Screen has been changed" diff --git a/Marlin/src/lcd/extui/dgus/dgus_extui.cpp b/Marlin/src/lcd/extui/dgus/dgus_extui.cpp index adc78caf07..e68eed16fd 100644 --- a/Marlin/src/lcd/extui/dgus/dgus_extui.cpp +++ b/Marlin/src/lcd/extui/dgus/dgus_extui.cpp @@ -43,7 +43,7 @@ namespace ExtUI { void onIdle() { screen.loop(); } void onPrinterKilled(FSTR_P const error, FSTR_P const) { - screen.sendInfoScreen(GET_TEXT_F(MSG_HALTED), error, FPSTR(NUL_STR), GET_TEXT_F(MSG_PLEASE_RESET), true, true, true, true); + screen.sendInfoScreen(GET_TEXT_F(MSG_HALTED), error, FPSTR(NUL_STR), GET_TEXT_F(MSG_PLEASE_RESET)); screen.gotoScreen(DGUS_SCREEN_KILL); while (!screen.loop()); // Wait while anything is left to be sent } @@ -75,13 +75,11 @@ namespace ExtUI { } // For fancy LCDs include an icon ID, message, and translated button title - void onUserConfirmRequired(const int icon, const char * const cstr, FSTR_P const fBtn) { + void onUserConfirmRequired(const int, const char * const cstr, FSTR_P const) { onUserConfirmRequired(cstr); - UNUSED(icon); UNUSED(fBtn); } - void onUserConfirmRequired(const int icon, FSTR_P const fstr, FSTR_P const fBtn) { + void onUserConfirmRequired(const int, FSTR_P const fstr, FSTR_P const) { onUserConfirmRequired(fstr); - UNUSED(icon); UNUSED(fBtn); } #if ENABLED(ADVANCED_PAUSE_FEATURE) diff --git a/Marlin/src/lcd/extui/dgus/fysetc/DGUSDisplayDef.cpp b/Marlin/src/lcd/extui/dgus/fysetc/DGUSDisplayDef.cpp index 575e56103e..24e472be05 100644 --- a/Marlin/src/lcd/extui/dgus/fysetc/DGUSDisplayDef.cpp +++ b/Marlin/src/lcd/extui/dgus/fysetc/DGUSDisplayDef.cpp @@ -340,7 +340,7 @@ const struct DGUS_VP_Variable ListOfVP[] PROGMEM = { VPHELPER(VP_MOVE_Z, nullptr, screen.handleManualMove, nullptr), VPHELPER(VP_HOME_ALL, nullptr, screen.handleManualMove, nullptr), #endif - VPHELPER(VP_MOTOR_LOCK_UNLOK, nullptr, screen.handleMotorLockUnlock, nullptr), + VPHELPER(VP_MOTOR_LOCK_UNLOCK, nullptr, screen.handleMotorLockUnlock, nullptr), #if ENABLED(POWER_LOSS_RECOVERY) VPHELPER(VP_POWER_LOSS_RECOVERY, nullptr, screen.handlePowerLossRecovery, nullptr), #endif @@ -361,7 +361,7 @@ const struct DGUS_VP_Variable ListOfVP[] PROGMEM = { #if HAS_HOTEND VPHELPER(VP_T_E0_Is, &thermalManager.temp_hotend[0].celsius, nullptr, screen.sendFloatAsLongValueToDisplay<0>), VPHELPER(VP_T_E0_Set, &thermalManager.temp_hotend[0].target, screen.handleTemperatureChanged, screen.sendWordValueToDisplay), - VPHELPER(VP_Flowrate_E0, &planner.flow_percentage[ExtUI::extruder_t::E0], screen.handleFlowRateChanged, screen.sendWordValueToDisplay), + VPHELPER(VP_Flowrate_E0, &planner.flow_percentage[0], screen.handleFlowRateChanged, screen.sendWordValueToDisplay), VPHELPER(VP_EPos, &destination.e, nullptr, screen.sendFloatAsLongValueToDisplay<2>), VPHELPER(VP_MOVE_E0, nullptr, screen.handleManualExtrude, nullptr), VPHELPER(VP_E0_CONTROL, &thermalManager.temp_hotend[0].target, screen.handleHeaterControl, nullptr), @@ -382,7 +382,7 @@ const struct DGUS_VP_Variable ListOfVP[] PROGMEM = { #if HAS_MULTI_HOTEND VPHELPER(VP_T_E1_Is, &thermalManager.temp_hotend[1].celsius, nullptr, screen.sendFloatAsLongValueToDisplay<0>), VPHELPER(VP_T_E1_Set, &thermalManager.temp_hotend[1].target, screen.handleTemperatureChanged, screen.sendWordValueToDisplay), - VPHELPER(VP_Flowrate_E1, &planner.flow_percentage[ExtUI::extruder_t::E1], screen.handleFlowRateChanged, screen.sendWordValueToDisplay), // ERROR: Flow is per-extruder, not per-hotend + VPHELPER(VP_Flowrate_E1, &planner.flow_percentage[1], screen.handleFlowRateChanged, screen.sendWordValueToDisplay), // ERROR: Flow is per-extruder, not per-hotend VPHELPER(VP_MOVE_E1, nullptr, screen.handleManualExtrude, nullptr), VPHELPER(VP_E1_CONTROL, &thermalManager.temp_hotend[1].target, screen.handleHeaterControl, nullptr), VPHELPER(VP_E1_STATUS, &thermalManager.temp_hotend[1].target, nullptr, screen.sendHeaterStatusToDisplay), diff --git a/Marlin/src/lcd/extui/dgus/fysetc/DGUSDisplayDef.h b/Marlin/src/lcd/extui/dgus/fysetc/DGUSDisplayDef.h index d8dc81b566..3bac9cf2c6 100644 --- a/Marlin/src/lcd/extui/dgus/fysetc/DGUSDisplayDef.h +++ b/Marlin/src/lcd/extui/dgus/fysetc/DGUSDisplayDef.h @@ -116,7 +116,7 @@ constexpr uint16_t VP_MOVE_E1 = 0x2112; //constexpr uint16_t VP_MOVE_E4 = 0x2118; //constexpr uint16_t VP_MOVE_E5 = 0x211A; constexpr uint16_t VP_HOME_ALL = 0x2120; -constexpr uint16_t VP_MOTOR_LOCK_UNLOK = 0x2130; +constexpr uint16_t VP_MOTOR_LOCK_UNLOCK = 0x2130; // Power loss recovery constexpr uint16_t VP_POWER_LOSS_RECOVERY = 0x2180; diff --git a/Marlin/src/lcd/extui/dgus/fysetc/DGUSScreenHandler.cpp b/Marlin/src/lcd/extui/dgus/fysetc/DGUSScreenHandler.cpp index 8c26066b28..be0e60a8df 100644 --- a/Marlin/src/lcd/extui/dgus/fysetc/DGUSScreenHandler.cpp +++ b/Marlin/src/lcd/extui/dgus/fysetc/DGUSScreenHandler.cpp @@ -141,7 +141,7 @@ void DGUSScreenHandler::screenChangeHook(DGUS_VP_Variable &var, void *val_ptr) { updateNewScreen(target); - #ifdef DEBUG_DGUSLCD + #if ENABLED(DEBUG_DGUSLCD) if (!findScreenVPMapList(target)) DEBUG_ECHOLNPGM("WARNING: No screen Mapping found for ", target); #endif } @@ -288,7 +288,9 @@ void DGUSScreenHandler::handleManualMove(DGUS_VP_Variable &var, void *val_ptr) { #endif break; case 1: // Load ABS - TERN_(PREHEAT_2_TEMP_HOTEND, e_temp = PREHEAT_2_TEMP_HOTEND); + #ifdef PREHEAT_2_TEMP_HOTEND + e_temp = PREHEAT_2_TEMP_HOTEND; + #endif break; case 2: // Load PET #ifdef PREHEAT_3_TEMP_HOTEND @@ -308,9 +310,9 @@ void DGUSScreenHandler::handleManualMove(DGUS_VP_Variable &var, void *val_ptr) { if (filament_data.action == 0) { // Go back to utility screen #if HAS_HOTEND - thermalManager.setTargetHotend(e_temp, ExtUI::extruder_t::E0); + thermalManager.setTargetHotend(e_temp, 0); #if HAS_MULTI_HOTEND - thermalManager.setTargetHotend(e_temp, ExtUI::extruder_t::E1); + thermalManager.setTargetHotend(e_temp, 1); #endif #endif gotoScreen(DGUS_SCREEN_UTILITY); @@ -320,13 +322,13 @@ void DGUSScreenHandler::handleManualMove(DGUS_VP_Variable &var, void *val_ptr) { default: return; #if HAS_HOTEND case VP_E0_FILAMENT_LOAD_UNLOAD: - filament_data.extruder = ExtUI::extruder_t::E0; + filament_data.extruder = 0; thermalManager.setTargetHotend(e_temp, filament_data.extruder); break; #endif #if HAS_MULTI_HOTEND case VP_E1_FILAMENT_LOAD_UNLOAD: - filament_data.extruder = ExtUI::extruder_t::E1; + filament_data.extruder = 1; thermalManager.setTargetHotend(e_temp, filament_data.extruder); break; #endif @@ -348,7 +350,7 @@ void DGUSScreenHandler::handleManualMove(DGUS_VP_Variable &var, void *val_ptr) { //gotoScreen(DGUS_SCREEN_FILAMENT_LOADING); filament_data.heated = true; } - movevalue = ExtUI::getAxisPosition_mm(filament_data.extruder) + movevalue; + movevalue = ExtUI::getAxisPosition_mm(filament_data.extruder ? ExtUI::extruder_t::E1 : ExtUI::extruder_t::E0) + movevalue; } else { // unload filament if (!filament_data.heated) { @@ -357,14 +359,14 @@ void DGUSScreenHandler::handleManualMove(DGUS_VP_Variable &var, void *val_ptr) { } // Before unloading extrude to prevent jamming if (filament_data.purge_length >= 0) { - movevalue = ExtUI::getAxisPosition_mm(filament_data.extruder) + movevalue; + movevalue = ExtUI::getAxisPosition_mm(filament_data.extruder ? ExtUI::extruder_t::E1 : ExtUI::extruder_t::E0) + movevalue; filament_data.purge_length -= movevalue; } else { - movevalue = ExtUI::getAxisPosition_mm(filament_data.extruder) - movevalue; + movevalue = ExtUI::getAxisPosition_mm(filament_data.extruder ? ExtUI::extruder_t::E1 : ExtUI::extruder_t::E0) - movevalue; } } - ExtUI::setAxisPosition_mm(movevalue, filament_data.extruder); + ExtUI::setAxisPosition_mm(movevalue, filament_data.extruder ? ExtUI::extruder_t::E1 : ExtUI::extruder_t::E0); } } #endif // DGUS_FILAMENT_LOADUNLOAD diff --git a/Marlin/src/lcd/extui/dgus/hiprecy/DGUSDisplayDef.cpp b/Marlin/src/lcd/extui/dgus/hiprecy/DGUSDisplayDef.cpp index 338f6a319c..79e0ccf942 100644 --- a/Marlin/src/lcd/extui/dgus/hiprecy/DGUSDisplayDef.cpp +++ b/Marlin/src/lcd/extui/dgus/hiprecy/DGUSDisplayDef.cpp @@ -338,7 +338,7 @@ const struct DGUS_VP_Variable ListOfVP[] PROGMEM = { VPHELPER(VP_MOVE_Z, nullptr, screen.handleManualMove, nullptr), VPHELPER(VP_HOME_ALL, nullptr, screen.handleManualMove, nullptr), #endif - VPHELPER(VP_MOTOR_LOCK_UNLOK, nullptr, screen.handleMotorLockUnlock, nullptr), + VPHELPER(VP_MOTOR_LOCK_UNLOCK, nullptr, screen.handleMotorLockUnlock, nullptr), #if ENABLED(POWER_LOSS_RECOVERY) VPHELPER(VP_POWER_LOSS_RECOVERY, nullptr, screen.handlePowerLossRecovery, nullptr), #endif @@ -358,7 +358,7 @@ const struct DGUS_VP_Variable ListOfVP[] PROGMEM = { #if HAS_HOTEND VPHELPER(VP_T_E0_Is, &thermalManager.temp_hotend[0].celsius, nullptr, screen.sendFloatAsLongValueToDisplay<0>), VPHELPER(VP_T_E0_Set, &thermalManager.temp_hotend[0].target, screen.handleTemperatureChanged, screen.sendWordValueToDisplay), - VPHELPER(VP_Flowrate_E0, &planner.flow_percentage[ExtUI::extruder_t::E0], screen.handleFlowRateChanged, screen.sendWordValueToDisplay), + VPHELPER(VP_Flowrate_E0, &planner.flow_percentage[0], screen.handleFlowRateChanged, screen.sendWordValueToDisplay), VPHELPER(VP_EPos, &destination.e, nullptr, screen.sendFloatAsLongValueToDisplay<2>), VPHELPER(VP_MOVE_E0, nullptr, screen.handleManualExtrude, nullptr), VPHELPER(VP_E0_CONTROL, &thermalManager.temp_hotend[0].target, screen.handleHeaterControl, nullptr), @@ -379,7 +379,7 @@ const struct DGUS_VP_Variable ListOfVP[] PROGMEM = { #if HAS_MULTI_HOTEND VPHELPER(VP_T_E1_Is, &thermalManager.temp_hotend[1].celsius, nullptr, screen.sendFloatAsLongValueToDisplay<0>), VPHELPER(VP_T_E1_Set, &thermalManager.temp_hotend[1].target, screen.handleTemperatureChanged, screen.sendWordValueToDisplay), - VPHELPER(VP_Flowrate_E1, nullptr, screen.handleFlowRateChanged, screen.sendWordValueToDisplay), + VPHELPER(VP_Flowrate_E1, &planner.flow_percentage[1], screen.handleFlowRateChanged, screen.sendWordValueToDisplay), VPHELPER(VP_MOVE_E1, nullptr, screen.handleManualExtrude, nullptr), VPHELPER(VP_E1_CONTROL, &thermalManager.temp_hotend[1].target, screen.handleHeaterControl, nullptr), VPHELPER(VP_E1_STATUS, &thermalManager.temp_hotend[1].target, nullptr, screen.sendHeaterStatusToDisplay), diff --git a/Marlin/src/lcd/extui/dgus/hiprecy/DGUSDisplayDef.h b/Marlin/src/lcd/extui/dgus/hiprecy/DGUSDisplayDef.h index 3019b6651e..a5e0d327a4 100644 --- a/Marlin/src/lcd/extui/dgus/hiprecy/DGUSDisplayDef.h +++ b/Marlin/src/lcd/extui/dgus/hiprecy/DGUSDisplayDef.h @@ -116,7 +116,7 @@ constexpr uint16_t VP_MOVE_E1 = 0x2112; //constexpr uint16_t VP_MOVE_E4 = 0x2118; //constexpr uint16_t VP_MOVE_E5 = 0x211A; constexpr uint16_t VP_HOME_ALL = 0x2120; -constexpr uint16_t VP_MOTOR_LOCK_UNLOK = 0x2130; +constexpr uint16_t VP_MOTOR_LOCK_UNLOCK = 0x2130; // Power loss recovery constexpr uint16_t VP_POWER_LOSS_RECOVERY = 0x2180; diff --git a/Marlin/src/lcd/extui/dgus/hiprecy/DGUSScreenHandler.cpp b/Marlin/src/lcd/extui/dgus/hiprecy/DGUSScreenHandler.cpp index f817453f1b..297c71f8a9 100644 --- a/Marlin/src/lcd/extui/dgus/hiprecy/DGUSScreenHandler.cpp +++ b/Marlin/src/lcd/extui/dgus/hiprecy/DGUSScreenHandler.cpp @@ -143,7 +143,7 @@ void DGUSScreenHandler::screenChangeHook(DGUS_VP_Variable &var, void *val_ptr) { updateNewScreen(target); - #ifdef DEBUG_DGUSLCD + #if ENABLED(DEBUG_DGUSLCD) if (!findScreenVPMapList(target)) DEBUG_ECHOLNPGM("WARNING: No screen Mapping found for ", target); #endif } @@ -290,7 +290,9 @@ void DGUSScreenHandler::handleManualMove(DGUS_VP_Variable &var, void *val_ptr) { #endif break; case 1: // Load ABS - TERN_(PREHEAT_2_TEMP_HOTEND, e_temp = PREHEAT_2_TEMP_HOTEND); + #ifdef PREHEAT_2_TEMP_HOTEND + e_temp = PREHEAT_2_TEMP_HOTEND; + #endif break; case 2: // Load PET #ifdef PREHEAT_3_TEMP_HOTEND @@ -310,9 +312,9 @@ void DGUSScreenHandler::handleManualMove(DGUS_VP_Variable &var, void *val_ptr) { if (filament_data.action == 0) { // Go back to utility screen #if HAS_HOTEND - thermalManager.setTargetHotend(e_temp, ExtUI::extruder_t::E0); + thermalManager.setTargetHotend(e_temp, 0); #if HAS_MULTI_HOTEND - thermalManager.setTargetHotend(e_temp, ExtUI::extruder_t::E1); + thermalManager.setTargetHotend(e_temp, 1); #endif #endif gotoScreen(DGUS_SCREEN_UTILITY); @@ -322,13 +324,13 @@ void DGUSScreenHandler::handleManualMove(DGUS_VP_Variable &var, void *val_ptr) { default: return; #if HAS_HOTEND case VP_E0_FILAMENT_LOAD_UNLOAD: - filament_data.extruder = ExtUI::extruder_t::E0; + filament_data.extruder = 0; thermalManager.setTargetHotend(e_temp, filament_data.extruder); break; #endif #if HAS_MULTI_HOTEND case VP_E1_FILAMENT_LOAD_UNLOAD: - filament_data.extruder = ExtUI::extruder_t::E1; + filament_data.extruder = 1; thermalManager.setTargetHotend(e_temp, filament_data.extruder); break; #endif @@ -350,7 +352,7 @@ void DGUSScreenHandler::handleManualMove(DGUS_VP_Variable &var, void *val_ptr) { //gotoScreen(DGUS_SCREEN_FILAMENT_LOADING); filament_data.heated = true; } - movevalue = ExtUI::getAxisPosition_mm(filament_data.extruder) + movevalue; + movevalue = ExtUI::getAxisPosition_mm(filament_data.extruder ? ExtUI::extruder_t::E1 : ExtUI::extruder_t::E0) + movevalue; } else { // unload filament if (!filament_data.heated) { @@ -359,11 +361,11 @@ void DGUSScreenHandler::handleManualMove(DGUS_VP_Variable &var, void *val_ptr) { } // Before unloading extrude to prevent jamming if (filament_data.purge_length >= 0) { - movevalue = ExtUI::getAxisPosition_mm(filament_data.extruder) + movevalue; + movevalue = ExtUI::getAxisPosition_mm(filament_data.extruder ? ExtUI::extruder_t::E1 : ExtUI::extruder_t::E0) + movevalue; filament_data.purge_length -= movevalue; } else { - movevalue = ExtUI::getAxisPosition_mm(filament_data.extruder) - movevalue; + movevalue = ExtUI::getAxisPosition_mm(filament_data.extruder ? ExtUI::extruder_t::E1 : ExtUI::extruder_t::E0) - movevalue; } } ExtUI::setAxisPosition_mm(movevalue, filament_data.extruder); diff --git a/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp b/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp index 08eff9d41e..7288b03b18 100644 --- a/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp +++ b/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp @@ -180,7 +180,7 @@ const uint16_t MKSList_Tool[] PROGMEM = { 0x0000 }; -const uint16_t MKSList_EXTRUE[] PROGMEM = { +const uint16_t MKSList_EXTRUDE[] PROGMEM = { // E Temp REPEAT(EXTRUDERS, MKSLIST_E_ITEM) // HB Temp @@ -265,7 +265,7 @@ const uint16_t MKSList_TempOnly[] PROGMEM = { 0x0000 }; -const uint16_t MKSList_Pluse[] PROGMEM = { +const uint16_t MKSList_Pulse[] PROGMEM = { // E Temp REPEAT(EXTRUDERS, MKSLIST_E_ITEM) // HB Temp @@ -273,7 +273,7 @@ const uint16_t MKSList_Pluse[] PROGMEM = { // FAN VP_Fan0_Percentage, - // Pluse + // Steps/mm VP_X_STEP_PER_MM, VP_Y_STEP_PER_MM, VP_Z_STEP_PER_MM, @@ -291,7 +291,7 @@ const uint16_t MKSList_MaxSpeed[] PROGMEM = { // FAN VP_Fan0_Percentage, - // Pluse + // Max Speed VP_X_MAX_SPEED, VP_Y_MAX_SPEED, VP_Z_MAX_SPEED, @@ -463,16 +463,16 @@ const struct VPMapping VPMap[] PROGMEM = { { MKSLCD_SCREEN_HOME, MKSList_Home }, // Home, Page 1 { MKSLCD_SCREEN_SETTING, MKSList_Setting }, // Setting, Page 2 { MKSLCD_SCREEM_TOOL, MKSList_Tool }, // Page 3 - { MKSLCD_SCREEN_EXTRUDE_P1, MKSList_EXTRUE }, // Page 4 - { MKSLCD_SCREEN_EXTRUDE_P2, MKSList_EXTRUE }, // Page 11 - { MKSLCD_PAUSE_SETTING_EX, MKSList_EXTRUE }, // Page 57 - { MKSLCD_PAUSE_SETTING_EX2, MKSList_EXTRUE }, // Page 61 + { MKSLCD_SCREEN_EXTRUDE_P1, MKSList_EXTRUDE }, // Page 4 + { MKSLCD_SCREEN_EXTRUDE_P2, MKSList_EXTRUDE }, // Page 11 + { MKSLCD_PAUSE_SETTING_EX, MKSList_EXTRUDE }, // Page 57 + { MKSLCD_PAUSE_SETTING_EX2, MKSList_EXTRUDE }, // Page 61 { MKSLCD_SCREEN_LEVEL, MKSList_LEVEL }, // Page 5 { MKSLCD_SCREEN_MOVE, MKSList_MOVE }, // Page 6 { MKSLCD_SCREEN_PRINT, MKSList_Print }, // Page 7 { MKSLCD_SCREEN_PAUSE, MKSList_Print }, // Page 26 { MKSLCD_SCREEN_CHOOSE_FILE, MKSList_SD_File }, // Page 15 - { MKSLCD_SCREEN_MOTOR_PLUSE, MKSList_Pluse }, // Page 51 + { MKSLCD_SCREEN_MOTOR_PULSE, MKSList_Pulse }, // Page 51 { MKSLCD_SCREEN_MOTOR_SPEED, MKSList_MaxSpeed }, // Page 55 { MKSLCD_SCREEN_MOTOR_ACC_MAX, MKSList_MaxAcc }, // Page 53 { MKSLCD_SCREEN_LEVEL_DATA, MKSList_Level_Point }, // Page 48 @@ -522,7 +522,7 @@ const struct DGUS_VP_Variable ListOfVP[] PROGMEM = { VPHELPER(VP_MOVE_DISTANCE, &manualMoveStep, screen.getManualMovestep, nullptr), - VPHELPER(VP_MOTOR_LOCK_UNLOK, nullptr, screen.handleManualMove, nullptr), + VPHELPER(VP_MOTOR_LOCK_UNLOCK, nullptr, screen.handleManualMove, nullptr), VPHELPER(VP_LEVEL_POINT, nullptr, screen.manualAssistLeveling, nullptr), #if ENABLED(POWER_LOSS_RECOVERY) @@ -545,7 +545,7 @@ const struct DGUS_VP_Variable ListOfVP[] PROGMEM = { #if HAS_HOTEND VPHELPER(VP_T_E0_Is, &thermalManager.temp_hotend[0].celsius, nullptr, screen.sendFloatAsLongValueToDisplay<0>), VPHELPER(VP_T_E0_Set, &thermalManager.temp_hotend[0].target, screen.handleTemperatureChanged, screen.sendWordValueToDisplay), - VPHELPER(VP_Flowrate_E0, &planner.flow_percentage[ExtUI::extruder_t::E0], screen.handleFlowRateChanged, screen.sendWordValueToDisplay), + VPHELPER(VP_Flowrate_E0, &planner.flow_percentage[0], screen.handleFlowRateChanged, screen.sendWordValueToDisplay), VPHELPER(VP_EPos, &destination.e, nullptr, screen.sendFloatAsLongValueToDisplay<2>), VPHELPER(VP_MOVE_E0, nullptr, screen.handleManualExtrude, nullptr), VPHELPER(VP_E0_CONTROL, &thermalManager.temp_hotend[0].target, screen.handleHeaterControl, nullptr), @@ -570,7 +570,7 @@ const struct DGUS_VP_Variable ListOfVP[] PROGMEM = { #if HAS_MULTI_HOTEND VPHELPER(VP_T_E1_Is, &thermalManager.temp_hotend[1].celsius, nullptr, screen.sendFloatAsLongValueToDisplay<0>), VPHELPER(VP_T_E1_Set, &thermalManager.temp_hotend[1].target, screen.handleTemperatureChanged, screen.sendWordValueToDisplay), - VPHELPER(VP_Flowrate_E1, &planner.flow_percentage[ExtUI::extruder_t::E1], screen.handleFlowRateChanged, screen.sendWordValueToDisplay), + VPHELPER(VP_Flowrate_E1, &planner.flow_percentage[1], screen.handleFlowRateChanged, screen.sendWordValueToDisplay), VPHELPER(VP_MOVE_E1, nullptr, screen.handleManualExtrude, nullptr), VPHELPER(VP_E1_CONTROL, &thermalManager.temp_hotend[1].target, screen.handleHeaterControl, nullptr), VPHELPER(VP_E1_STATUS, &thermalManager.temp_hotend[1].target, nullptr, screen.sendHeaterStatusToDisplay), diff --git a/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.h b/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.h index 95bee17229..a0b95aa14a 100644 --- a/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.h +++ b/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.h @@ -53,25 +53,9 @@ extern xyz_int_t tmc_step; extern uint16_t lcd_default_light; -#if X_HAS_STEALTHCHOP - extern uint16_t tmc_x_current; -#endif -#if Y_HAS_STEALTHCHOP - extern uint16_t tmc_y_current; -#endif -#if Z_HAS_STEALTHCHOP - extern uint16_t tmc_z_current; -#endif -#if E0_HAS_STEALTHCHOP - extern uint16_t tmc_e0_current; -#endif -#if E1_HAS_STEALTHCHOP - extern uint16_t tmc_e1_current; -#endif - typedef enum { EX_HEATING, - EX_HEAT_STARUS, + EX_HEAT_STATUS, EX_CHANGING, EX_CHANGE_STATUS, EX_NONE, @@ -80,7 +64,7 @@ typedef enum { typedef struct { //uint8_t ex_change_flag:1; //uint8_t ex_heat_flag:1; - uint8_t ex_load_unload_flag:1; //0:unload 1:load + uint8_t ex_load_unload_flag:1; // 0:unload 1:load EX_STATUS_DEF ex_status; uint32_t ex_tick_start; uint32_t ex_tick_end; @@ -121,118 +105,118 @@ extern NOZZLE_PARK_DEF nozzle_park_mks; enum DGUS_ScreenID : uint8_t { #if ENABLED(USE_MKS_GREEN_UI) - DGUS_SCREEN_BOOT = 33, - DGUS_SCREEN_MAIN = 60, - DGUS_SCREEN_STATUS = 60, - DGUS_SCREEN_STATUS2 = 60, - DGUS_SCREEN_PREHEAT = 18, - DGUS_SCREEN_POWER_LOSS = 100, - DGUS_SCREEN_MANUALMOVE = 192, - DGUS_SCREEN_UTILITY = 120, - DGUS_SCREEN_FILAMENT_UNLOADING = 158, - DGUS_SCREEN_SDFILELIST = 15, - DGUS_SCREEN_SDPRINTMANIPULATION = 15, - DGUS_SCREEN_SDPRINTTUNE = 17, + DGUS_SCREEN_BOOT = 33, + DGUS_SCREEN_MAIN = 60, + DGUS_SCREEN_STATUS = 60, + DGUS_SCREEN_STATUS2 = 60, + DGUS_SCREEN_PREHEAT = 18, + DGUS_SCREEN_POWER_LOSS = 100, + DGUS_SCREEN_MANUALMOVE = 192, + DGUS_SCREEN_UTILITY = 120, + DGUS_SCREEN_FILAMENT_UNLOADING = 158, + DGUS_SCREEN_SDFILELIST = 15, + DGUS_SCREEN_SDPRINTMANIPULATION = 15, + DGUS_SCREEN_SDPRINTTUNE = 17, - MKSLCD_SCREEN_BOOT = 33, - MKSLCD_SCREEN_HOME = 60, // MKS main page - MKSLCD_SCREEN_SETTING = 62, // MKS Setting page / no wifi whit - MKSLCD_SCREEM_TOOL = 64, // MKS Tool page - MKSLCD_SCREEN_EXTRUDE_P1 = 75, - MKSLCD_SCREEN_EXTRUDE_P2 = 77, - MKSLCD_SCREEN_LEVEL = 73, - MKSLCD_AUTO_LEVEL = 81, - MKSLCD_SCREEN_MOVE = 66, - MKSLCD_SCREEN_PRINT = 68, - MKSLCD_SCREEN_PAUSE = 70, - MKSLCD_SCREEN_CHOOSE_FILE = 87, - MKSLCD_SCREEN_NO_CHOOSE_FILE = 88, - MKSLCD_SCREEN_Config = 101, - MKSLCD_SCREEN_Config_MOTOR = 103, - MKSLCD_SCREEN_MOTOR_PLUSE = 104, - MKSLCD_SCREEN_MOTOR_SPEED = 102, - MKSLCD_SCREEN_MOTOR_ACC_MAX = 105, - MKSLCD_SCREEN_PRINT_CONFIG = 72, - MKSLCD_SCREEN_LEVEL_DATA = 106, - MKSLCD_PrintPause_SET = 107, - MKSLCD_FILAMENT_DATA = 50, - MKSLCD_ABOUT = 83, - MKSLCD_PID = 108, - MKSLCD_PAUSE_SETTING_MOVE = 98, - MKSLCD_PAUSE_SETTING_EX = 96, - MKSLCD_PAUSE_SETTING_EX2 = 97, - MKSLCD_SCREEN_PRINT_CONFIRM = 94, - MKSLCD_SCREEN_EX_CONFIG = 112, - MKSLCD_SCREEN_EEP_Config = 89, - MKSLCD_SCREEN_PrintDone = 92, - MKSLCD_SCREEN_TMC_Config = 111, - MKSLCD_Screen_Offset_Config = 109, - MKSLCD_Screen_PMove = 98, - MKSLCD_Screen_Baby = 79, + MKSLCD_SCREEN_BOOT = 33, + MKSLCD_SCREEN_HOME = 60, // MKS main page + MKSLCD_SCREEN_SETTING = 62, // MKS Setting page / no wifi whit + MKSLCD_SCREEM_TOOL = 64, // MKS Tool page + MKSLCD_SCREEN_EXTRUDE_P1 = 75, + MKSLCD_SCREEN_EXTRUDE_P2 = 77, + MKSLCD_SCREEN_LEVEL = 73, + MKSLCD_AUTO_LEVEL = 81, + MKSLCD_SCREEN_MOVE = 66, + MKSLCD_SCREEN_PRINT = 68, + MKSLCD_SCREEN_PAUSE = 70, + MKSLCD_SCREEN_CHOOSE_FILE = 87, + MKSLCD_SCREEN_NO_CHOOSE_FILE = 88, + MKSLCD_SCREEN_Config = 101, + MKSLCD_SCREEN_Config_MOTOR = 103, + MKSLCD_SCREEN_MOTOR_PULSE = 104, + MKSLCD_SCREEN_MOTOR_SPEED = 102, + MKSLCD_SCREEN_MOTOR_ACC_MAX = 105, + MKSLCD_SCREEN_PRINT_CONFIG = 72, + MKSLCD_SCREEN_LEVEL_DATA = 106, + MKSLCD_PrintPause_SET = 107, + MKSLCD_FILAMENT_DATA = 50, + MKSLCD_ABOUT = 83, + MKSLCD_PID = 108, + MKSLCD_PAUSE_SETTING_MOVE = 98, + MKSLCD_PAUSE_SETTING_EX = 96, + MKSLCD_PAUSE_SETTING_EX2 = 97, + MKSLCD_SCREEN_PRINT_CONFIRM = 94, + MKSLCD_SCREEN_EX_CONFIG = 112, + MKSLCD_SCREEN_EEP_Config = 89, + MKSLCD_SCREEN_PrintDone = 92, + MKSLCD_SCREEN_TMC_Config = 111, + MKSLCD_Screen_Offset_Config = 109, + MKSLCD_Screen_PMove = 98, + MKSLCD_Screen_Baby = 79, #else - DGUS_SCREEN_BOOT = 120, - DGUS_SCREEN_MAIN = 1, + DGUS_SCREEN_BOOT = 120, + DGUS_SCREEN_MAIN = 1, - DGUS_SCREEN_STATUS = 1, - DGUS_SCREEN_STATUS2 = 1, - DGUS_SCREEN_PREHEAT = 18, - DGUS_SCREEN_POWER_LOSS = 100, - DGUS_SCREEN_MANUALMOVE = 192, - DGUS_SCREEN_UTILITY = 120, - DGUS_SCREEN_FILAMENT_UNLOADING = 158, - DGUS_SCREEN_SDFILELIST = 15, - DGUS_SCREEN_SDPRINTMANIPULATION = 15, - DGUS_SCREEN_SDPRINTTUNE = 17, + DGUS_SCREEN_STATUS = 1, + DGUS_SCREEN_STATUS2 = 1, + DGUS_SCREEN_PREHEAT = 18, + DGUS_SCREEN_POWER_LOSS = 100, + DGUS_SCREEN_MANUALMOVE = 192, + DGUS_SCREEN_UTILITY = 120, + DGUS_SCREEN_FILAMENT_UNLOADING = 158, + DGUS_SCREEN_SDFILELIST = 15, + DGUS_SCREEN_SDPRINTMANIPULATION = 15, + DGUS_SCREEN_SDPRINTTUNE = 17, - MKSLCD_SCREEN_BOOT = 0, - MKSLCD_SCREEN_HOME = 1, // MKS main page - MKSLCD_SCREEN_SETTING = 2, // MKS Setting page / no wifi whit - MKSLCD_SCREEM_TOOL = 3, // MKS Tool page - MKSLCD_SCREEN_EXTRUDE_P1 = 4, - MKSLCD_SCREEN_EXTRUDE_P2 = 11, - MKSLCD_SCREEN_LEVEL = 5, - MKSLCD_AUTO_LEVEL = 73, - MKSLCD_SCREEN_LEVEL_PRESS = 9, - MKSLCD_SCREEN_MOVE = 6, - MKSLCD_SCREEN_PRINT = 7, - MKSLCD_SCREEN_PRINT_PRESS = 13, - MKSLCD_SCREEN_PAUSE = 26, - MKSLCD_SCREEN_PAUSE_PRESS = 26, - MKSLCD_SCREEN_CHOOSE_FILE = 15, - MKSLCD_SCREEN_NO_CHOOSE_FILE = 17, - MKSLCD_SCREEN_Config = 46, - MKSLCD_SCREEN_Config_MOTOR = 47, - MKSLCD_SCREEN_MOTOR_PLUSE = 51, - MKSLCD_SCREEN_MOTOR_SPEED = 55, - MKSLCD_SCREEN_MOTOR_ACC_MAX = 53, - MKSLCD_SCREEN_PRINT_CONFIG = 60, - MKSLCD_SCREEN_LEVEL_DATA = 48, - MKSLCD_PrintPause_SET = 49, - MKSLCD_FILAMENT_DATA = 50, - MKSLCD_ABOUT = 36, - MKSLCD_PID = 56, - MKSLCD_PAUSE_SETTING_MOVE = 58, - MKSLCD_PAUSE_SETTING_EX = 57, - MKSLCD_PAUSE_SETTING_EX2 = 61, - MKSLCD_SCREEN_NO_FILE = 42, - MKSLCD_SCREEN_PRINT_CONFIRM = 43, - MKSLCD_SCREEN_EX_CONFIG = 65, - MKSLCD_SCREEN_EEP_Config = 20, - MKSLCD_SCREEN_PrintDone = 25, - MKSLCD_SCREEN_TMC_Config = 70, - MKSLCD_Screen_Offset_Config = 30, - MKSLCD_Screen_PMove = 64, - MKSLCD_Screen_Baby = 71, + MKSLCD_SCREEN_BOOT = 0, + MKSLCD_SCREEN_HOME = 1, // MKS main page + MKSLCD_SCREEN_SETTING = 2, // MKS Setting page / no wifi whit + MKSLCD_SCREEM_TOOL = 3, // MKS Tool page + MKSLCD_SCREEN_EXTRUDE_P1 = 4, + MKSLCD_SCREEN_EXTRUDE_P2 = 11, + MKSLCD_SCREEN_LEVEL = 5, + MKSLCD_AUTO_LEVEL = 73, + MKSLCD_SCREEN_LEVEL_PRESS = 9, + MKSLCD_SCREEN_MOVE = 6, + MKSLCD_SCREEN_PRINT = 7, + MKSLCD_SCREEN_PRINT_PRESS = 13, + MKSLCD_SCREEN_PAUSE = 26, + MKSLCD_SCREEN_PAUSE_PRESS = 26, + MKSLCD_SCREEN_CHOOSE_FILE = 15, + MKSLCD_SCREEN_NO_CHOOSE_FILE = 17, + MKSLCD_SCREEN_Config = 46, + MKSLCD_SCREEN_Config_MOTOR = 47, + MKSLCD_SCREEN_MOTOR_PULSE = 51, + MKSLCD_SCREEN_MOTOR_SPEED = 55, + MKSLCD_SCREEN_MOTOR_ACC_MAX = 53, + MKSLCD_SCREEN_PRINT_CONFIG = 60, + MKSLCD_SCREEN_LEVEL_DATA = 48, + MKSLCD_PrintPause_SET = 49, + MKSLCD_FILAMENT_DATA = 50, + MKSLCD_ABOUT = 36, + MKSLCD_PID = 56, + MKSLCD_PAUSE_SETTING_MOVE = 58, + MKSLCD_PAUSE_SETTING_EX = 57, + MKSLCD_PAUSE_SETTING_EX2 = 61, + MKSLCD_SCREEN_NO_FILE = 42, + MKSLCD_SCREEN_PRINT_CONFIRM = 43, + MKSLCD_SCREEN_EX_CONFIG = 65, + MKSLCD_SCREEN_EEP_Config = 20, + MKSLCD_SCREEN_PrintDone = 25, + MKSLCD_SCREEN_TMC_Config = 70, + MKSLCD_Screen_Offset_Config = 30, + MKSLCD_Screen_PMove = 64, + MKSLCD_Screen_Baby = 71, #endif - DGUS_SCREEN_CONFIRM = 240, - DGUS_SCREEN_KILL = 250, //!< Kill Screen. Must always be 250 (to be able to display "Error wrong LCD Version") - DGUS_SCREEN_WAITING = 251, - DGUS_SCREEN_POPUP = 252, //!< special target, popup screen will also return this code to say "return to previous screen" - DGUS_SCREEN_UNUSED = 255 + DGUS_SCREEN_CONFIRM = 240, + DGUS_SCREEN_KILL = 250, //!< Kill Screen. Must always be 250 (to be able to display "Error wrong LCD Version") + DGUS_SCREEN_WAITING = 251, + DGUS_SCREEN_POPUP = 252, //!< special target, popup screen will also return this code to say "return to previous screen" + DGUS_SCREEN_UNUSED = 255 }; // Place for status messages. @@ -290,7 +274,7 @@ constexpr uint16_t SP_T_Bed_Set = 0x5040; constexpr uint8_t VP_MSGSTR4_LEN = 0x20; constexpr uint16_t VP_MARLIN_VERSION = 0x1A00; - constexpr uint8_t VP_MARLIN_VERSION_LEN = 16; // there is more space on the display, if needed. + constexpr uint8_t VP_MARLIN_VERSION_LEN = 16; // there is more space on the display, if needed. constexpr uint16_t VP_SCREENCHANGE_ASK = 0x1500; constexpr uint16_t VP_SCREENCHANGE = 0x1501; // Key-Return button to new menu pressed. Data contains target screen in low byte and info in high byte. @@ -347,8 +331,9 @@ constexpr uint16_t SP_T_Bed_Set = 0x5040; constexpr uint16_t VP_MOVE_E5 = 0x231A; constexpr uint16_t VP_MOVE_E6 = 0x231C; constexpr uint16_t VP_MOVE_E7 = 0x231E; + constexpr uint16_t VP_HOME_ALL = 0x2320; - constexpr uint16_t VP_MOTOR_LOCK_UNLOK = 0x2330; + constexpr uint16_t VP_MOTOR_LOCK_UNLOCK = 0x2330; constexpr uint16_t VP_MOVE_DISTANCE = 0x2334; constexpr uint16_t VP_X_HOME = 0x2336; constexpr uint16_t VP_Y_HOME = 0x2338; @@ -383,7 +368,7 @@ constexpr uint16_t SP_T_Bed_Set = 0x5040; constexpr uint16_t VP_E0_FILAMENT_LOAD_UNLOAD = 0x2500; constexpr uint16_t VP_E1_FILAMENT_LOAD_UNLOAD = 0x2504; constexpr uint16_t VP_LOAD_Filament = 0x2508; - // constexpr uint16_t VP_LOAD_UNLOAD_Cancle = 0x250A; + //constexpr uint16_t VP_LOAD_UNLOAD_Cancel = 0x250A; constexpr uint16_t VP_UNLOAD_Filament = 0x250B; constexpr uint16_t VP_Filament_distance = 0x2600; constexpr uint16_t VP_Filament_speed = 0x2604; @@ -467,10 +452,10 @@ constexpr uint16_t SP_T_Bed_Set = 0x5040; constexpr uint16_t VP_SD_Print_Filename = 0x32C0; // X Y Z Point - constexpr uint16_t VP_XPos = 0x3300; // 4 Byte Fixed point number; format xxx.yy - constexpr uint16_t VP_YPos = 0x3302; // 4 Byte Fixed point number; format xxx.yy - constexpr uint16_t VP_ZPos = 0x3304; // 4 Byte Fixed point number; format xxx.yy - constexpr uint16_t VP_EPos = 0x3306; // 4 Byte Fixed point number; format xxx.yy + constexpr uint16_t VP_XPos = 0x3300; // 4 Byte Fixed point number; format xxx.yy + constexpr uint16_t VP_YPos = 0x3302; // 4 Byte Fixed point number; format xxx.yy + constexpr uint16_t VP_ZPos = 0x3304; // 4 Byte Fixed point number; format xxx.yy + constexpr uint16_t VP_EPos = 0x3306; // 4 Byte Fixed point number; format xxx.yy // Print constexpr uint16_t VP_PrintProgress_Percentage = 0x3330; // 2 Byte Integer (0..100) @@ -481,16 +466,16 @@ constexpr uint16_t SP_T_Bed_Set = 0x5040; constexpr uint16_t VP_PrintsTotal = 0x3380; constexpr uint16_t VP_PrintsTotal_LEN = 16; - constexpr uint16_t VP_File_Pictutr0 = 0x3400; - constexpr uint16_t VP_File_Pictutr1 = 0x3402; - constexpr uint16_t VP_File_Pictutr2 = 0x3404; - constexpr uint16_t VP_File_Pictutr3 = 0x3406; - constexpr uint16_t VP_File_Pictutr4 = 0x3408; - constexpr uint16_t VP_File_Pictutr5 = 0x340A; - constexpr uint16_t VP_File_Pictutr6 = 0x340C; - constexpr uint16_t VP_File_Pictutr7 = 0x340E; - constexpr uint16_t VP_File_Pictutr8 = 0x3410; - constexpr uint16_t VP_File_Pictutr9 = 0x3412; + constexpr uint16_t VP_File_Picture0 = 0x3400; + constexpr uint16_t VP_File_Picture1 = 0x3402; + constexpr uint16_t VP_File_Picture2 = 0x3404; + constexpr uint16_t VP_File_Picture3 = 0x3406; + constexpr uint16_t VP_File_Picture4 = 0x3408; + constexpr uint16_t VP_File_Picture5 = 0x340A; + constexpr uint16_t VP_File_Picture6 = 0x340C; + constexpr uint16_t VP_File_Picture7 = 0x340E; + constexpr uint16_t VP_File_Picture8 = 0x3410; + constexpr uint16_t VP_File_Picture9 = 0x3412; constexpr uint16_t VP_BED_STATUS = 0x341C; @@ -512,101 +497,103 @@ constexpr uint16_t SP_T_Bed_Set = 0x5040; constexpr uint16_t VP_PrintTime_S = 0x3504; // PIDs - constexpr uint16_t VP_E0_PID_P = 0x3700; // at the moment , uint16_t , 0~1638.4 - constexpr uint16_t VP_E0_PID_I = 0x3702; - constexpr uint16_t VP_E0_PID_D = 0x3704; - constexpr uint16_t VP_E1_PID_P = 0x3706; // at the moment , uint16_t , 0~1638.4 - constexpr uint16_t VP_E1_PID_I = 0x3708; - constexpr uint16_t VP_E1_PID_D = 0x370A; - constexpr uint16_t VP_BED_PID_P = 0x3710; - constexpr uint16_t VP_BED_PID_I = 0x3712; - constexpr uint16_t VP_BED_PID_D = 0x3714; + constexpr uint16_t VP_E0_PID_P = 0x3700; // at the moment , uint16_t , 0~1638.4 + constexpr uint16_t VP_E0_PID_I = 0x3702; + constexpr uint16_t VP_E0_PID_D = 0x3704; + constexpr uint16_t VP_E1_PID_P = 0x3706; // at the moment , uint16_t , 0~1638.4 + constexpr uint16_t VP_E1_PID_I = 0x3708; + constexpr uint16_t VP_E1_PID_D = 0x370A; + constexpr uint16_t VP_BED_PID_P = 0x3710; + constexpr uint16_t VP_BED_PID_I = 0x3712; + constexpr uint16_t VP_BED_PID_D = 0x3714; - constexpr uint16_t VP_EEPROM_CTRL = 0x3720; + constexpr uint16_t VP_EEPROM_CTRL = 0x3720; - constexpr uint16_t VP_OFFSET_X = 0x3724; - constexpr uint16_t VP_OFFSET_Y = 0x3728; - constexpr uint16_t VP_OFFSET_Z = 0x372B; + constexpr uint16_t VP_OFFSET_X = 0x3724; + constexpr uint16_t VP_OFFSET_Y = 0x3728; + constexpr uint16_t VP_OFFSET_Z = 0x372B; // PID autotune - constexpr uint16_t VP_PID_AUTOTUNE_E0 = 0x3800; - constexpr uint16_t VP_PID_AUTOTUNE_E1 = 0x3802; - constexpr uint16_t VP_PID_AUTOTUNE_E2 = 0x3804; - constexpr uint16_t VP_PID_AUTOTUNE_E3 = 0x3806; - constexpr uint16_t VP_PID_AUTOTUNE_E4 = 0x3808; - constexpr uint16_t VP_PID_AUTOTUNE_E5 = 0x380A; - constexpr uint16_t VP_PID_AUTOTUNE_BED = 0x380C; + constexpr uint16_t VP_PID_AUTOTUNE_E0 = 0x3800; + constexpr uint16_t VP_PID_AUTOTUNE_E1 = 0x3802; + constexpr uint16_t VP_PID_AUTOTUNE_E2 = 0x3804; + constexpr uint16_t VP_PID_AUTOTUNE_E3 = 0x3806; + constexpr uint16_t VP_PID_AUTOTUNE_E4 = 0x3808; + constexpr uint16_t VP_PID_AUTOTUNE_E5 = 0x380A; + constexpr uint16_t VP_PID_AUTOTUNE_BED = 0x380C; + // Calibrate Z - constexpr uint16_t VP_Z_CALIBRATE = 0x3810; + constexpr uint16_t VP_Z_CALIBRATE = 0x3810; - constexpr uint16_t VP_AutoTurnOffSw = 0x3812; - constexpr uint16_t VP_LCD_BLK = 0x3814; + constexpr uint16_t VP_AutoTurnOffSw = 0x3812; + constexpr uint16_t VP_LCD_BLK = 0x3814; - constexpr uint16_t VP_X_PARK_POS = 0x3900; - constexpr uint16_t VP_Y_PARK_POS = 0x3902; - constexpr uint16_t VP_Z_PARK_POS = 0x3904; + constexpr uint16_t VP_X_PARK_POS = 0x3900; + constexpr uint16_t VP_Y_PARK_POS = 0x3902; + constexpr uint16_t VP_Z_PARK_POS = 0x3904; /* -------------------------------0x4000-0x4FFF------------------------------- */ // Heater Control Buttons , triged between "cool down" and "heat PLA" state - constexpr uint16_t VP_E0_CONTROL = 0x4010; - constexpr uint16_t VP_E1_CONTROL = 0x4012; + constexpr uint16_t VP_E0_CONTROL = 0x4010; + constexpr uint16_t VP_E1_CONTROL = 0x4012; //constexpr uint16_t VP_E2_CONTROL = 0x2214; //constexpr uint16_t VP_E3_CONTROL = 0x2216; //constexpr uint16_t VP_E4_CONTROL = 0x2218; //constexpr uint16_t VP_E5_CONTROL = 0x221A; - constexpr uint16_t VP_BED_CONTROL = 0x401C; + constexpr uint16_t VP_BED_CONTROL = 0x401C; // Preheat - constexpr uint16_t VP_E0_BED_PREHEAT = 0x4020; - constexpr uint16_t VP_E1_BED_PREHEAT = 0x4022; + constexpr uint16_t VP_E0_BED_PREHEAT = 0x4020; + constexpr uint16_t VP_E1_BED_PREHEAT = 0x4022; //constexpr uint16_t VP_E2_BED_PREHEAT = 0x4024; //constexpr uint16_t VP_E3_BED_PREHEAT = 0x4026; //constexpr uint16_t VP_E4_BED_PREHEAT = 0x4028; //constexpr uint16_t VP_E5_BED_PREHEAT = 0x402A; // Filament load and unload - // constexpr uint16_t VP_E0_FILAMENT_LOAD_UNLOAD = 0x4030; - // constexpr uint16_t VP_E1_FILAMENT_LOAD_UNLOAD = 0x4032; + //constexpr uint16_t VP_E0_FILAMENT_LOAD_UNLOAD = 0x4030; + //constexpr uint16_t VP_E1_FILAMENT_LOAD_UNLOAD = 0x4032; // Settings store , reset // Level data - constexpr uint16_t VP_Level_Point_One_X = 0x4100; - constexpr uint16_t VP_Level_Point_One_Y = 0x4102; - constexpr uint16_t VP_Level_Point_Two_X = 0x4104; - constexpr uint16_t VP_Level_Point_Two_Y = 0x4106; - constexpr uint16_t VP_Level_Point_Three_X = 0x4108; - constexpr uint16_t VP_Level_Point_Three_Y = 0x410A; - constexpr uint16_t VP_Level_Point_Four_X = 0x410C; - constexpr uint16_t VP_Level_Point_Four_Y = 0x410E; - constexpr uint16_t VP_Level_Point_Five_X = 0x4110; - constexpr uint16_t VP_Level_Point_Five_Y = 0x4112; + constexpr uint16_t VP_Level_Point_One_X = 0x4100; + constexpr uint16_t VP_Level_Point_One_Y = 0x4102; + constexpr uint16_t VP_Level_Point_Two_X = 0x4104; + constexpr uint16_t VP_Level_Point_Two_Y = 0x4106; + constexpr uint16_t VP_Level_Point_Three_X = 0x4108; + constexpr uint16_t VP_Level_Point_Three_Y = 0x410A; + constexpr uint16_t VP_Level_Point_Four_X = 0x410C; + constexpr uint16_t VP_Level_Point_Four_Y = 0x410E; + constexpr uint16_t VP_Level_Point_Five_X = 0x4110; + constexpr uint16_t VP_Level_Point_Five_Y = 0x4112; /* H43 Version */ - constexpr uint16_t VP_MKS_H43_VERSION = 0x4A00; // MKS H43 V1.0.0 - constexpr uint16_t VP_MKS_H43_VERSION_LEN = 16; - constexpr uint16_t VP_MKS_H43_UpdataVERSION = 0x4A10; // MKS H43 V1.0.0 - constexpr uint16_t VP_MKS_H43_UpdataVERSION_LEN = 16; + constexpr uint16_t VP_MKS_H43_VERSION = 0x4A00; // MKS H43 V1.0.0 + constexpr uint16_t VP_MKS_H43_VERSION_LEN = 16; + constexpr uint16_t VP_MKS_H43_UpdataVERSION = 0x4A10; // MKS H43 V1.0.0 + constexpr uint16_t VP_MKS_H43_UpdataVERSION_LEN = 16; /* -------------------------------0x5000-0xFFFF------------------------------- */ constexpr uint16_t VP_HOME_Dis = 0x5000; constexpr uint16_t VP_Setting_Dis = 0x5010; constexpr uint16_t VP_Tool_Dis = 0x5020; constexpr uint16_t VP_Printing_Dis = 0x5030; + constexpr uint16_t VP_Print_Dis = 0x5250; constexpr uint16_t VP_Language_Dis = 0x5080; constexpr uint16_t VP_LossPoint_Dis = 0x5090; constexpr uint16_t VP_PrintPauseConfig_Dis = 0x5120; - constexpr uint16_t VP_MotorPluse_Dis = 0x5140; + constexpr uint16_t VP_MotorPulse_Dis = 0x5140; constexpr uint16_t VP_MotorMaxSpeed_Dis = 0x5150; constexpr uint16_t VP_MotorMaxAcc_Dis = 0x5160; - constexpr uint16_t VP_X_Pluse_Dis = 0x5170; - constexpr uint16_t VP_Y_Pluse_Dis = 0x5180; - constexpr uint16_t VP_Z_Pluse_Dis = 0x5190; - constexpr uint16_t VP_E0_Pluse_Dis = 0x51A0; - constexpr uint16_t VP_E1_Pluse_Dis = 0x51B0; + constexpr uint16_t VP_X_Pulse_Dis = 0x5170; + constexpr uint16_t VP_Y_Pulse_Dis = 0x5180; + constexpr uint16_t VP_Z_Pulse_Dis = 0x5190; + constexpr uint16_t VP_E0_Pulse_Dis = 0x51A0; + constexpr uint16_t VP_E1_Pulse_Dis = 0x51B0; constexpr uint16_t VP_X_Max_Speed_Dis = 0x5280; constexpr uint16_t VP_Y_Max_Speed_Dis = 0x5290; @@ -614,11 +601,11 @@ constexpr uint16_t SP_T_Bed_Set = 0x5040; constexpr uint16_t VP_E0_Max_Speed_Dis = 0x52B0; constexpr uint16_t VP_E1_Max_Speed_Dis = 0x52C0; - constexpr uint16_t VP_X_Max_Acc_Speed_Dis = 0x51E0; - constexpr uint16_t VP_Y_Max_Acc_Speed_Dis = 0x51F0; - constexpr uint16_t VP_Z_Max_Acc_Speed_Dis = 0x5200; - constexpr uint16_t VP_E0_Max_Acc_Speed_Dis = 0x5210; - constexpr uint16_t VP_E1_Max_Acc_Speed_Dis = 0x5220; + constexpr uint16_t VP_X_Max_Acc_Dis = 0x51E0; + constexpr uint16_t VP_Y_Max_Acc_Dis = 0x51F0; + constexpr uint16_t VP_Z_Max_Acc_Dis = 0x5200; + constexpr uint16_t VP_E0_Max_Acc_Dis = 0x5210; + constexpr uint16_t VP_E1_Max_Acc_Dis = 0x5220; constexpr uint16_t VP_PrintTime_Dis = 0x5470; constexpr uint16_t VP_E0_Temp_Dis = 0x5310; @@ -672,8 +659,8 @@ constexpr uint16_t SP_T_Bed_Set = 0x5040; constexpr uint16_t VP_Length_Dis = 0x5B00; - constexpr uint16_t VP_PrintConfrim_Info_Dis = 0x5B90; - constexpr uint16_t VP_StopPrintConfrim_Info_Dis = 0x5B80; + constexpr uint16_t VP_PrintConfirm_Info_Dis = 0x5B90; + constexpr uint16_t VP_StopPrintConfirm_Info_Dis = 0x5B80; constexpr uint16_t VP_Point_One_Dis = 0x5BA0; constexpr uint16_t VP_Point_Two_Dis = 0x5BB0; @@ -681,8 +668,6 @@ constexpr uint16_t SP_T_Bed_Set = 0x5040; constexpr uint16_t VP_Point_Four_Dis = 0x5BD0; constexpr uint16_t VP_Point_Five_Dis = 0x5BE0; - constexpr uint16_t VP_Print_Dis = 0x5250; - constexpr uint16_t VP_About_Dis = 0x5A00; constexpr uint16_t VP_Config_Dis = 0x5A10; constexpr uint16_t VP_Filament_Dis = 0x5A20; diff --git a/Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.cpp b/Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.cpp index 1761451da1..0ac704ed3d 100644 --- a/Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.cpp +++ b/Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.cpp @@ -60,17 +60,17 @@ MKS_Language mks_language_index; // Initialized by settings.load #if 0 void DGUSScreenHandlerMKS::sendinfoscreen_ch(const uint16_t *line1, const uint16_t *line2, const uint16_t *line3, const uint16_t *line4) { - dgus.writeVariable(VP_MSGSTR1, line1, 32, true); - dgus.writeVariable(VP_MSGSTR2, line2, 32, true); - dgus.writeVariable(VP_MSGSTR3, line3, 32, true); - dgus.writeVariable(VP_MSGSTR4, line4, 32, true); + dgus.writeStringVar(VP_MSGSTR1, line1, 32); + dgus.writeStringVar(VP_MSGSTR2, line2, 32); + dgus.writeStringVar(VP_MSGSTR3, line3, 32); + dgus.writeStringVar(VP_MSGSTR4, line4, 32); } void DGUSScreenHandlerMKS::sendinfoscreen_en(PGM_P const line1, PGM_P const line2, PGM_P const line3, PGM_P const line4) { - dgus.writeVariable(VP_MSGSTR1, line1, 32, true); - dgus.writeVariable(VP_MSGSTR2, line2, 32, true); - dgus.writeVariable(VP_MSGSTR3, line3, 32, true); - dgus.writeVariable(VP_MSGSTR4, line4, 32, true); + dgus.writeStringVar(VP_MSGSTR1, line1); + dgus.writeStringVar(VP_MSGSTR2, line2); + dgus.writeStringVar(VP_MSGSTR3, line3); + dgus.writeStringVar(VP_MSGSTR4, line4); } void DGUSScreenHandlerMKS::sendInfoScreen(const void *line1, const void *line2, const void *line3, const void *line4, uint16_t language) { @@ -85,14 +85,14 @@ void DGUSScreenHandlerMKS::sendInfoScreen(const void *line1, const void *line2, void DGUSScreenHandlerMKS::sendFanToDisplay(DGUS_VP_Variable &var) { if (var.memadr) { uint16_t tmp = *(uint8_t *) var.memadr; // +1 -> avoid rounding issues for the display. - // tmp = map(tmp, 0, 255, 0, 100); + //tmp = map(constrain(tmp, 0, 255), 0, 255, 0, 100); dgus.writeVariable(var.VP, tmp); } } void DGUSScreenHandlerMKS::sendBabyStepToDisplay(DGUS_VP_Variable &var) { float value = current_position.z; - value *= cpow(10, 2); + value *= 100; //cpow(10, 2); dgus.writeVariable(VP_SD_Print_Baby, (uint16_t)value); } @@ -113,17 +113,20 @@ void DGUSScreenHandlerMKS::setUint8(DGUS_VP_Variable &var, void *val_ptr) { void DGUSScreenHandlerMKS::sendGbkToDisplay(DGUS_VP_Variable &var) { uint16_t *tmp = (uint16_t*) var.memadr; - dgus.writeVariable(var.VP, tmp, var.size, true); + dgus.writeStringVar(var.VP, tmp, var.size); } void DGUSScreenHandlerMKS::sendStringToDisplay_Language(DGUS_VP_Variable &var) { - if (mks_language_index == MKS_English) { - char *tmp = (char*) var.memadr; - dgus.writeVariable(var.VP, tmp, var.size, true); - } - else if (mks_language_index == MKS_SimpleChinese) { - uint16_t *tmp = (uint16_t *)var.memadr; - dgus.writeVariable(var.VP, tmp, var.size, true); + switch (mks_language_index) { + default: + case MKS_English: { + char *tmp = (char*) var.memadr; + dgus.writeStringVar(var.VP, tmp, var.size); + } break; + case MKS_SimpleChinese: { + uint16_t *tmp = (uint16_t *)var.memadr; + dgus.writeStringVar(var.VP, tmp, var.size); + } break; } } @@ -168,7 +171,7 @@ void DGUSScreenHandlerMKS::sendTMCStepValue(DGUS_VP_Variable &var) { #if ENABLED(DGUS_PRINT_FILENAME) // Send print filename - dgus.writeVariable(VP_SD_Print_Filename, filelist.filename(), VP_SD_FileName_LEN, true); + dgus.writeStringVar(VP_SD_Print_Filename, filelist.filename(), VP_SD_FileName_LEN); #endif // Setup Confirmation screen @@ -212,7 +215,6 @@ void DGUSScreenHandlerMKS::sendTMCStepValue(DGUS_VP_Variable &var) { nozzle_park_mks.print_pause_start_flag = 1; nozzle_park_mks.blstatus = true; ExtUI::pausePrint(); - //ExtUI::mks_pausePrint(); } break; @@ -235,7 +237,7 @@ void DGUSScreenHandlerMKS::sendTMCStepValue(DGUS_VP_Variable &var) { } sendStringToDisplay(var); - dgus.writeVariable(VP_File_Pictutr0 + target_line * 2, dir_icon_val); + dgus.writeVariable(VP_File_Picture0 + target_line * 2, dir_icon_val); } void DGUSScreenHandler::sdCardInserted() { @@ -248,8 +250,8 @@ void DGUSScreenHandlerMKS::sendTMCStepValue(DGUS_VP_Variable &var) { void DGUSScreenHandler::sdCardRemoved() { if (current_screenID == DGUS_SCREEN_SDFILELIST - || (current_screenID == DGUS_SCREEN_CONFIRM && (confirmVP == VP_SD_AbortPrintConfirmed || confirmVP == VP_SD_FileSelectConfirm)) - || current_screenID == DGUS_SCREEN_SDPRINTMANIPULATION + || (current_screenID == DGUS_SCREEN_CONFIRM && (confirmVP == VP_SD_AbortPrintConfirmed || confirmVP == VP_SD_FileSelectConfirm)) + || current_screenID == DGUS_SCREEN_SDPRINTMANIPULATION ) filelist.refresh(); } @@ -261,12 +263,13 @@ void DGUSScreenHandlerMKS::sendTMCStepValue(DGUS_VP_Variable &var) { gotoScreen(MKSLCD_SCREEN_PrintDone); } -#else +#else // !HAS_MEDIA + void DGUSScreenHandlerMKS::printReturn(DGUS_VP_Variable& var, void *val_ptr) { - const uint16_t value = BE16_P(val_ptr); - if (value == 0x0F) gotoScreen(DGUS_SCREEN_MAIN); + if (BE16_P(val_ptr) == 0x0F) gotoScreen(DGUS_SCREEN_MAIN); } -#endif // HAS_MEDIA + +#endif void DGUSScreenHandler::screenChangeHook(DGUS_VP_Variable &var, void *val_ptr) { uint8_t *tmp = (uint8_t*)val_ptr; @@ -276,10 +279,9 @@ void DGUSScreenHandler::screenChangeHook(DGUS_VP_Variable &var, void *val_ptr) { // meaning "return to previous screen" DGUS_ScreenID target = (DGUS_ScreenID)tmp[1]; - // when the dgus had reboot, it will enter the DGUS_SCREEN_MAIN page, - // so user can change any page to use this function, an it will check - // if robin nano is printing. when it is, dgus will enter the printing - // page to continue print; + // When the DGUS reboots it enters the DGUS_SCREEN_MAIN page so the user + // can change any page to use this function and it will check whether a print + // job is active. If so DGUS will go to the printing page to continue the job. // //if (printJobOngoing() || printingIsPaused()) { // if (target == MKSLCD_PAUSE_SETTING_MOVE || target == MKSLCD_PAUSE_SETTING_EX @@ -288,7 +290,7 @@ void DGUSScreenHandler::screenChangeHook(DGUS_VP_Variable &var, void *val_ptr) { // } // else // gotoScreen(MKSLCD_SCREEN_PRINT); - // return; + // return; //} if (target == DGUS_SCREEN_POPUP) { @@ -302,7 +304,7 @@ void DGUSScreenHandler::screenChangeHook(DGUS_VP_Variable &var, void *val_ptr) { updateNewScreen(target); - #ifdef DEBUG_DGUSLCD + #if ENABLED(DEBUG_DGUSLCD) if (!findScreenVPMapList(target)) DEBUG_ECHOLNPGM("WARNING: No screen Mapping found for ", target); #endif } @@ -323,10 +325,7 @@ void DGUSScreenHandlerMKS::zOffsetConfirm(DGUS_VP_Variable &var, void *val_ptr) void DGUSScreenHandlerMKS::getTurnOffCtrl(DGUS_VP_Variable &var, void *val_ptr) { const uint16_t value = BE16_P(val_ptr); - switch (value) { - case 0 ... 1: DGUSAutoTurnOff = (bool)value; break; - default: break; - } + if (value < 2) DGUSAutoTurnOff = (bool)value; } void DGUSScreenHandlerMKS::getMinExtrudeTemp(DGUS_VP_Variable &var, void *val_ptr) { @@ -337,14 +336,13 @@ void DGUSScreenHandlerMKS::getMinExtrudeTemp(DGUS_VP_Variable &var, void *val_pt } void DGUSScreenHandlerMKS::getZoffsetDistance(DGUS_VP_Variable &var, void *val_ptr) { - const uint16_t value = BE16_P(val_ptr); float val_distance = 0; - switch (value) { - case 0: val_distance = 0.01; break; - case 1: val_distance = 0.1; break; - case 2: val_distance = 0.5; break; - case 3: val_distance = 1; break; - default: val_distance = 0.01; break; + switch (BE16_P(val_ptr)) { + default: + case 0: val_distance = 0.01f; break; + case 1: val_distance = 0.10f; break; + case 2: val_distance = 0.50f; break; + case 3: val_distance = 1.00f; break; } ZOffset_distance = val_distance; } @@ -354,11 +352,10 @@ void DGUSScreenHandlerMKS::getManualMovestep(DGUS_VP_Variable &var, void *val_pt } void DGUSScreenHandlerMKS::eepromControl(DGUS_VP_Variable &var, void *val_ptr) { - const uint16_t eep_flag = BE16_P(val_ptr); - switch (eep_flag) { + switch (BE16_P(val_ptr)) { case 0: settings.save(); - settings.load(); // load eeprom data to check the data is right + //settings.load(); // Load EEPROM to validate the data gotoScreen(MKSLCD_SCREEN_EEP_Config); break; @@ -366,56 +363,39 @@ void DGUSScreenHandlerMKS::eepromControl(DGUS_VP_Variable &var, void *val_ptr) { settings.reset(); gotoScreen(MKSLCD_SCREEN_EEP_Config); break; - - default: break; } } void DGUSScreenHandlerMKS::zOffsetSelect(DGUS_VP_Variable &var, void *val_ptr) { - const uint16_t z = BE16_P(val_ptr); - switch (z) { - case 0: Z_distance = 0.01; break; - case 1: Z_distance = 0.1; break; - case 2: Z_distance = 0.5; break; - default: Z_distance = 1; break; + switch (BE16_P(val_ptr)) { + case 0: Z_distance = 0.01f; break; + case 1: Z_distance = 0.10f; break; + case 2: Z_distance = 0.50f; break; + case 3: + default: Z_distance = 1.00f; break; } } void DGUSScreenHandlerMKS::getOffsetValue(DGUS_VP_Variable &var, void *val_ptr) { - #if HAS_BED_PROBE - const int32_t value = BE32_P(val_ptr); - const float Offset = value / 100.0f; - + const float offset = BE32_P(val_ptr) / 100.0f; switch (var.VP) { default: break; - case VP_OFFSET_X: probe.offset.x = Offset; break; - case VP_OFFSET_Y: probe.offset.y = Offset; break; - case VP_OFFSET_Z: probe.offset.z = Offset; break; + case VP_OFFSET_X: probe.offset.x = offset; break; + case VP_OFFSET_Y: probe.offset.y = offset; break; + case VP_OFFSET_Z: probe.offset.z = offset; break; } settings.save(); #endif } void DGUSScreenHandlerMKS::languageChange(DGUS_VP_Variable &var, void *val_ptr) { - const uint16_t lag_flag = BE16_P(val_ptr); - switch (lag_flag) { - case MKS_SimpleChinese: - languageDisplay(MKS_SimpleChinese); - mks_language_index = MKS_SimpleChinese; - dgus.writeVariable(VP_LANGUAGE_CHANGE1, (uint8_t)MKS_Language_Choose); - dgus.writeVariable(VP_LANGUAGE_CHANGE2, (uint8_t)MKS_Language_NoChoose); - settings.save(); - break; - case MKS_English: - languageDisplay(MKS_English); - mks_language_index = MKS_English; - dgus.writeVariable(VP_LANGUAGE_CHANGE1, (uint8_t)MKS_Language_NoChoose); - dgus.writeVariable(VP_LANGUAGE_CHANGE2, (uint8_t)MKS_Language_Choose); - settings.save(); - break; - default: break; - } + const MKS_Language lang = (MKS_Language)BE16_P(val_ptr); + if (lang != MKS_SimpleChinese && lang != MKS_English) return; + mks_language_index = lang; + updateDisplayLanguage(); + languagePInit(); + settings.save(); } #if ENABLED(MESH_BED_LEVELING) @@ -426,8 +406,8 @@ void DGUSScreenHandlerMKS::levelControl(DGUS_VP_Variable &var, void *val_ptr) { #if ENABLED(MESH_BED_LEVELING) auto cs = getCurrentScreen(); #endif - const uint16_t lev_but = BE16_P(val_ptr); - switch (lev_but) { + + switch (BE16_P(val_ptr)) { case 0: #if ENABLED(AUTO_BED_LEVELING_BILINEAR) @@ -442,22 +422,27 @@ void DGUSScreenHandlerMKS::levelControl(DGUS_VP_Variable &var, void *val_ptr) { mesh_point_count = GRID_MAX_POINTS; - if (mks_language_index == MKS_English) { - const char level_buf_en[] = "Start Level"; - dgus.writeVariable(VP_AutoLevel_1_Dis, level_buf_en, 32, true); - } - else if (mks_language_index == MKS_SimpleChinese) { - const uint16_t level_buf_ch[] = {0xAABF, 0xBCCA, 0xF7B5, 0xBDC6, 0x2000}; - dgus.writeVariable(VP_AutoLevel_1_Dis, level_buf_ch, 32, true); + switch (mks_language_index) { + default: + case MKS_English: { + const char level_buf_en[] = "Start Leveling"; + dgus.writeStringVar(VP_AutoLevel_1_Dis, level_buf_en); + } break; + case MKS_SimpleChinese: { + const uint16_t level_buf_ch[] = { 0xAABF, 0xBCCA, 0xF7B5, 0xBDC6, 0x2000 }; + dgus.writeStringVar(VP_AutoLevel_1_Dis, level_buf_ch); + } break; } cs = getCurrentScreen(); if (cs != MKSLCD_AUTO_LEVEL) gotoScreen(MKSLCD_AUTO_LEVEL); + #else gotoScreen(MKSLCD_SCREEN_LEVEL); #endif + break; case 1: @@ -470,26 +455,23 @@ void DGUSScreenHandlerMKS::levelControl(DGUS_VP_Variable &var, void *val_ptr) { } void DGUSScreenHandlerMKS::meshLevelDistanceConfig(DGUS_VP_Variable &var, void *val_ptr) { - const uint16_t mesh_dist = BE16_P(val_ptr); - switch (mesh_dist) { - case 0: mesh_adj_distance = 0.01; break; - case 1: mesh_adj_distance = 0.1; break; - case 2: mesh_adj_distance = 1; break; - default: mesh_adj_distance = 0.1; break; + switch (BE16_P(val_ptr)) { + case 0: mesh_adj_distance = 0.01f; break; + case 1: mesh_adj_distance = 0.10f; break; + case 2: mesh_adj_distance = 1.00f; break; + default: mesh_adj_distance = 0.10f; break; } } void DGUSScreenHandlerMKS::meshLevel(DGUS_VP_Variable &var, void *val_ptr) { #if ENABLED(MESH_BED_LEVELING) - const uint16_t mesh_val = BE16_P(val_ptr); - // static uint8_t a_first_level = 1; char cmd_buf[30]; float offset = mesh_adj_distance; int16_t integer, Deci, Deci2; if (!queue.ring_buffer.empty()) return; - switch (mesh_val) { + switch (BE16_P(val_ptr)) { case 0: offset = mesh_adj_distance; integer = offset; // get int @@ -502,7 +484,6 @@ void DGUSScreenHandlerMKS::meshLevel(DGUS_VP_Variable &var, void *val_ptr) { snprintf_P(cmd_buf, 30, PSTR("G1 Z%d.%d%d"), integer, Deci, Deci2); queue.enqueue_one_now(cmd_buf); queue.enqueue_now(F("G90")); - //soft_endstop._enabled = true; break; case 1: @@ -521,42 +502,49 @@ void DGUSScreenHandlerMKS::meshLevel(DGUS_VP_Variable &var, void *val_ptr) { case 2: if (mesh_point_count == GRID_MAX_POINTS) { // The first point - - queue.enqueue_now(F("G28")); - queue.enqueue_now(F("G29S1")); + queue.enqueue_now(F("G28\nG29S1")); mesh_point_count--; - if (mks_language_index == MKS_English) { - const char level_buf_en1[] = "Next Point"; - dgus.writeVariable(VP_AutoLevel_1_Dis, level_buf_en1, 32, true); - } - else if (mks_language_index == MKS_SimpleChinese) { - const uint16_t level_buf_ch1[] = {0xC2CF, 0xBBD2, 0xE3B5, 0x2000}; - dgus.writeVariable(VP_AutoLevel_1_Dis, level_buf_ch1, 32, true); + switch (mks_language_index) { + default: + case MKS_English: { + const char level_buf_en1[] = "Next Point"; + dgus.writeStringVar(VP_AutoLevel_1_Dis, level_buf_en1); + } break; + case MKS_SimpleChinese: { + const uint16_t level_buf_ch1[] = { 0xC2CF, 0xBBD2, 0xE3B5, 0x2000 }; + dgus.writeStringVar(VP_AutoLevel_1_Dis, level_buf_ch1); + } break; } } - else if (mesh_point_count > 1) { // 倒数第二个点 + else if (mesh_point_count > 1) { queue.enqueue_now(F("G29S2")); mesh_point_count--; - if (mks_language_index == MKS_English) { - const char level_buf_en2[] = "Next Point"; - dgus.writeVariable(VP_AutoLevel_1_Dis, level_buf_en2, 32, true); - } - else if (mks_language_index == MKS_SimpleChinese) { - const uint16_t level_buf_ch2[] = {0xC2CF, 0xBBD2, 0xE3B5, 0x2000}; - dgus.writeVariable(VP_AutoLevel_1_Dis, level_buf_ch2, 32, true); + switch (mks_language_index) { + default: + case MKS_English: { + const char level_buf_en2[] = "Next Point"; + dgus.writeStringVar(VP_AutoLevel_1_Dis, level_buf_en2); + } break; + case MKS_SimpleChinese: { + const uint16_t level_buf_ch2[] = { 0xC2CF, 0xBBD2, 0xE3B5, 0x2000 }; + dgus.writeStringVar(VP_AutoLevel_1_Dis, level_buf_ch2); + } break; } } else if (mesh_point_count == 1) { queue.enqueue_now(F("G29S2")); mesh_point_count--; - if (mks_language_index == MKS_English) { - const char level_buf_en2[] = "Leveling Done"; - dgus.writeVariable(VP_AutoLevel_1_Dis, level_buf_en2, 32, true); - } - else if (mks_language_index == MKS_SimpleChinese) { - const uint16_t level_buf_ch2[] = {0xF7B5, 0xBDC6, 0xEACD, 0xC9B3, 0x2000}; - dgus.writeVariable(VP_AutoLevel_1_Dis, level_buf_ch2, 32, true); + switch (mks_language_index) { + default: + case MKS_English: { + const char level_buf_en2[] = "Leveling Done"; + dgus.writeStringVar(VP_AutoLevel_1_Dis, level_buf_en2); + } break; + case MKS_SimpleChinese: { + const uint16_t level_buf_ch2[] = { 0xF7B5, 0xBDC6, 0xEACD, 0xC9B3, 0x2000 }; + dgus.writeStringVar(VP_AutoLevel_1_Dis, level_buf_ch2); + } break; } settings.save(); } @@ -568,8 +556,7 @@ void DGUSScreenHandlerMKS::meshLevel(DGUS_VP_Variable &var, void *val_ptr) { } break; - default: - break; + default: break; } #endif // MESH_BED_LEVELING } @@ -579,8 +566,7 @@ void DGUSScreenHandlerMKS::sdFileBack(DGUS_VP_Variable&, void*) { } void DGUSScreenHandlerMKS::lcdBLKAdjust(DGUS_VP_Variable &var, void *val_ptr) { - const uint16_t lcd_val = BE16_P(val_ptr); - lcd_default_light = constrain(lcd_val, 10, 100); + lcd_default_light = constrain(BE16_P(val_ptr), 10, 100); const uint16_t lcd_data[2] = { lcd_default_light, lcd_default_light }; dgus.writeVariable(0x0082, &lcd_data, 5, true); @@ -646,30 +632,24 @@ void DGUSScreenHandlerMKS::tmcChangeConfig(DGUS_VP_Variable &var, void *val_ptr) switch (var.VP) { case VP_TMC_X_STEP: - #if USE_SENSORLESS - #if X_HAS_STEALTHCHOP - stepperX.homing_threshold(mks_min(tmc_val, 255)); - settings.save(); - //tmc_step.x = stepperX.homing_threshold(); - #endif + #if USE_SENSORLESS && X_HAS_STEALTHCHOP + stepperX.homing_threshold(mks_min(tmc_val, 255)); + settings.save(); + //tmc_step.x = stepperX.homing_threshold(); #endif break; case VP_TMC_Y_STEP: - #if USE_SENSORLESS - #if Y_HAS_STEALTHCHOP - stepperY.homing_threshold(mks_min(tmc_val, 255)); - settings.save(); - //tmc_step.y = stepperY.homing_threshold(); - #endif + #if USE_SENSORLESS && Y_HAS_STEALTHCHOP + stepperY.homing_threshold(mks_min(tmc_val, 255)); + settings.save(); + //tmc_step.y = stepperY.homing_threshold(); #endif break; case VP_TMC_Z_STEP: - #if USE_SENSORLESS - #if Z_HAS_STEALTHCHOP - stepperZ.homing_threshold(mks_min(tmc_val, 255)); - settings.save(); - //tmc_step.z = stepperZ.homing_threshold(); - #endif + #if USE_SENSORLESS && Z_HAS_STEALTHCHOP + stepperZ.homing_threshold(mks_min(tmc_val, 255)); + settings.save(); + //tmc_step.z = stepperZ.homing_threshold(); #endif break; case VP_TMC_X_Current: @@ -691,7 +671,7 @@ void DGUSScreenHandlerMKS::tmcChangeConfig(DGUS_VP_Variable &var, void *val_ptr) #endif break; case VP_TMC_Y1_Current: - #if X2_IS_TRINAMIC + #if Y2_IS_TRINAMIC stepperY2.rms_current(tmc_val); settings.save(); #endif @@ -721,8 +701,7 @@ void DGUSScreenHandlerMKS::tmcChangeConfig(DGUS_VP_Variable &var, void *val_ptr) #endif break; - default: - break; + default: break; } #if USE_SENSORLESS TERN_(X_HAS_STEALTHCHOP, tmc_step.x = stepperX.homing_threshold()); @@ -749,55 +728,38 @@ void DGUSScreenHandler::handleManualMove(DGUS_VP_Variable &var, void *val_ptr) { default: return; #if HAS_X_AXIS case VP_MOVE_X: - axiscode = 'X'; - if (!ExtUI::canMove(ExtUI::axis_t::X)) goto cannotmove; + if (!ExtUI::canMove(ExtUI::axis_t::X)) return; + axiscode = 'X'; speed = manual_feedrate_mm_m.x; break; #endif #if HAS_Y_AXIS case VP_MOVE_Y: - axiscode = 'Y'; - speed = manual_feedrate_mm_m.y; - if (!ExtUI::canMove(ExtUI::axis_t::Y)) goto cannotmove; + if (!ExtUI::canMove(ExtUI::axis_t::Y)) return; + axiscode = 'Y'; speed = manual_feedrate_mm_m.y; break; #endif #if HAS_Z_AXIS case VP_MOVE_Z: - axiscode = 'Z'; - speed = manual_feedrate_mm_m.z; - if (!ExtUI::canMove(ExtUI::axis_t::Z)) goto cannotmove; + if (!ExtUI::canMove(ExtUI::axis_t::Z)) return; + axiscode = 'Z'; speed = manual_feedrate_mm_m.z; break; #endif - case VP_MOTOR_LOCK_UNLOK: - movevalue = 5; - break; + case VP_MOTOR_LOCK_UNLOCK: movevalue = 5; break; - case VP_HOME_ALL: // only used for homing - axiscode = '\0'; - movevalue = 0; // ignore value sent from display, this VP is _ONLY_ for homing. - break; + // Ignore value sent from display, this VP is _ONLY_ for homing. + case VP_HOME_ALL: axiscode = '\0'; movevalue = 0; break; #if HAS_X_AXIS - case VP_X_HOME: - axiscode = 'X'; - movevalue = 0; - break; + case VP_X_HOME: axiscode = 'X'; movevalue = 0; break; #endif - #if HAS_Y_AXIS - case VP_Y_HOME: - axiscode = 'Y'; - movevalue = 0; - break; + case VP_Y_HOME: axiscode = 'Y'; movevalue = 0; break; #endif - #if HAS_Z_AXIS - case VP_Z_HOME: - axiscode = 'Z'; - movevalue = 0; - break; + case VP_Z_HOME: axiscode = 'Z'; movevalue = 0; break; #endif } @@ -810,70 +772,55 @@ void DGUSScreenHandler::handleManualMove(DGUS_VP_Variable &var, void *val_ptr) { } if (!movevalue) { - // char buf[6] = "G28 X"; - // buf[4] = axiscode; - - char buf[6]; - sprintf(buf, "G28 %c", axiscode); - queue.enqueue_one_now(buf); + queue.enqueue_one_now(TS(F("G28"), axiscode)); forceCompleteUpdate(); return; } - else if (movevalue == 5) { - char buf[6]; - snprintf_P(buf,6,PSTR("M84 %c"), axiscode); - queue.enqueue_one_now(buf); + + if (movevalue == 5) { + queue.enqueue_one_now(TS(F("M84"), axiscode)); forceCompleteUpdate(); return; } - else { - // movement - const bool old_relative_mode = relative_mode; - if (!relative_mode) queue.enqueue_now(F("G91")); - char buf[32]; // G1 X9999.99 F12345 - //const uint16_t backup_speed = MMS_TO_MMM(feedrate_mm_s); - char sign[] = "\0"; - int16_t value = movevalue / 100; - if (movevalue < 0) { value = -value; sign[0] = '-'; } - const int16_t fraction = ABS(movevalue) % 100; - snprintf_P(buf, 32, PSTR("G0 %c%s%d.%02d F%d"), axiscode, sign, value, fraction, speed); - queue.enqueue_one_now(buf); - //if (backup_speed != speed) { - // snprintf_P(buf, 32, PSTR("G0 F%d"), backup_speed); - // queue.enqueue_one_now(buf); - //} + // Movement + const bool old_relative_mode = relative_mode; + if (!relative_mode) queue.enqueue_now(F("G91")); + char buf[32]; // G1 X9999.99 F12345 + //const uint16_t backup_speed = MMS_TO_MMM(feedrate_mm_s); + char sign[] = "\0"; + int16_t value = movevalue / 100; + if (movevalue < 0) { value = -value; sign[0] = '-'; } + const int16_t fraction = ABS(movevalue) % 100; + snprintf_P(buf, 32, PSTR("G0 %c%s%d.%02d F%d"), axiscode, sign, value, fraction, speed); + queue.enqueue_one_now(buf); - //while (!enqueue_and_echo_command(buf)) idle(); + //if (backup_speed != speed) { + // snprintf_P(buf, 32, PSTR("G0 F%d"), backup_speed); + // queue.enqueue_one_now(buf); + //} - if (!old_relative_mode) queue.enqueue_now(F("G90")); - } + //while (!enqueue_and_echo_command(buf)) idle(); + + if (!old_relative_mode) queue.enqueue_now(F("G90")); forceCompleteUpdate(); - - cannotmove: - return; } void DGUSScreenHandlerMKS::getParkPos(DGUS_VP_Variable &var, void *val_ptr) { const int16_t pos = BE16_P(val_ptr); - switch (var.VP) { case VP_X_PARK_POS: mks_park_pos.x = pos; break; case VP_Y_PARK_POS: mks_park_pos.y = pos; break; case VP_Z_PARK_POS: mks_park_pos.z = pos; break; - default: break; } - skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel + skipVP = var.VP; // Don't overwrite value the next update time as the display might autoincrement in parallel } void DGUSScreenHandlerMKS::handleChangeLevelPoint(DGUS_VP_Variable &var, void *val_ptr) { - const int16_t raw = BE16_P(val_ptr); - - *(int16_t*)var.memadr = raw; - + *(int16_t*)var.memadr = BE16_P(val_ptr); settings.save(); - skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel + skipVP = var.VP; // Don't overwrite value the next update time as the display might autoincrement in parallel } #if ENABLED(EDITABLE_STEPS_PER_UNIT) @@ -910,7 +857,7 @@ void DGUSScreenHandlerMKS::handleChangeLevelPoint(DGUS_VP_Variable &var, void *v } ExtUI::setAxisSteps_per_mm(value, extruder); settings.save(); - skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel + skipVP = var.VP; // Don't overwrite value the next update time as the display might autoincrement in parallel } #endif // EDITABLE_STEPS_PER_UNIT @@ -938,16 +885,16 @@ void DGUSScreenHandlerMKS::handleExtruderMaxSpeedChange(DGUS_VP_Variable &var, v ExtUI::extruder_t extruder; switch (var.VP) { default: return; - #if HAS_HOTEND - case VP_E0_MAX_SPEED: extruder = ExtUI::extruder_t::E0; break; - #endif - #if HAS_MULTI_HOTEND - #endif - case VP_E1_MAX_SPEED: extruder = ExtUI::extruder_t::E1; break; + #if HAS_HOTEND + case VP_E0_MAX_SPEED: extruder = ExtUI::extruder_t::E0; break; + #endif + #if HAS_MULTI_HOTEND + case VP_E1_MAX_SPEED: extruder = ExtUI::extruder_t::E1; break; + #endif } ExtUI::setAxisMaxFeedrate_mm_s(value, extruder); settings.save(); - skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel + skipVP = var.VP; // Don't overwrite value the next update time as the display might autoincrement in parallel } void DGUSScreenHandlerMKS::handleMaxAccChange(DGUS_VP_Variable &var, void *val_ptr) { @@ -981,74 +928,71 @@ void DGUSScreenHandlerMKS::handleExtruderAccChange(DGUS_VP_Variable &var, void * } ExtUI::setAxisMaxAcceleration_mm_s2(value, extruder); settings.save(); - skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel + skipVP = var.VP; // Don't overwrite value the next update time as the display might autoincrement in parallel } void DGUSScreenHandlerMKS::handleTravelAccChange(DGUS_VP_Variable &var, void *val_ptr) { - uint16_t travel = BE16_P(val_ptr); - planner.settings.travel_acceleration = (float)travel; - skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel + planner.settings.travel_acceleration = (float)BE16_P(val_ptr); + skipVP = var.VP; // Don't overwrite value the next update time as the display might autoincrement in parallel } void DGUSScreenHandlerMKS::handleFeedRateMinChange(DGUS_VP_Variable &var, void *val_ptr) { - uint16_t t = BE16_P(val_ptr); - planner.settings.min_feedrate_mm_s = (float)t; - skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel + planner.settings.min_feedrate_mm_s = (float)BE16_P(val_ptr); + skipVP = var.VP; // Don't overwrite value the next update time as the display might autoincrement in parallel } void DGUSScreenHandlerMKS::handleMin_T_F(DGUS_VP_Variable &var, void *val_ptr) { - uint16_t t_f = BE16_P(val_ptr); - planner.settings.min_travel_feedrate_mm_s = (float)t_f; - skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel + planner.settings.min_travel_feedrate_mm_s = (float)BE16_P(val_ptr); + skipVP = var.VP; // Don't overwrite value the next update time as the display might autoincrement in parallel } void DGUSScreenHandlerMKS::handleAccChange(DGUS_VP_Variable &var, void *val_ptr) { - uint16_t acc = BE16_P(val_ptr); - planner.settings.acceleration = (float)acc; - skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel + planner.settings.acceleration = (float)BE16_P(val_ptr); + skipVP = var.VP; // Don't overwrite value the next update time as the display might autoincrement in parallel } #if ENABLED(PREVENT_COLD_EXTRUSION) void DGUSScreenHandlerMKS::handleGetExMinTemp(DGUS_VP_Variable &var, void *val_ptr) { - const uint16_t ex_min_temp = BE16_P(val_ptr); - thermalManager.extrude_min_temp = ex_min_temp; - skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel + thermalManager.extrude_min_temp = BE16_P(val_ptr); + skipVP = var.VP; // Don't overwrite value the next update time as the display might autoincrement in parallel } #endif #if HAS_PID_HEATING + void DGUSScreenHandler::handleTemperaturePIDChanged(DGUS_VP_Variable &var, void *val_ptr) { - const uint16_t rawvalue = BE16_P(val_ptr); - const float value = float(rawvalue); + const float value = (float)BE16_P(val_ptr); float newvalue = 0; switch (var.VP) { default: return; - #if HAS_HOTEND - case VP_E0_PID_P: newvalue = value; break; - case VP_E0_PID_I: newvalue = scalePID_i(value); break; - case VP_E0_PID_D: newvalue = scalePID_d(value); break; - #endif - #if HAS_MULTI_HOTEND - case VP_E1_PID_P: newvalue = value; break; - case VP_E1_PID_I: newvalue = scalePID_i(value); break; - case VP_E1_PID_D: newvalue = scalePID_d(value); break; - #endif - #if HAS_HEATED_BED - case VP_BED_PID_P: newvalue = value; break; - case VP_BED_PID_I: newvalue = scalePID_i(value); break; - case VP_BED_PID_D: newvalue = scalePID_d(value); break; - #endif + #if HAS_HOTEND + case VP_E0_PID_P: newvalue = value; break; + case VP_E0_PID_I: newvalue = scalePID_i(value); break; + case VP_E0_PID_D: newvalue = scalePID_d(value); break; + #endif + #if HAS_MULTI_HOTEND + case VP_E1_PID_P: newvalue = value; break; + case VP_E1_PID_I: newvalue = scalePID_i(value); break; + case VP_E1_PID_D: newvalue = scalePID_d(value); break; + #endif + #if HAS_HEATED_BED + case VP_BED_PID_P: newvalue = value; break; + case VP_BED_PID_I: newvalue = scalePID_i(value); break; + case VP_BED_PID_D: newvalue = scalePID_d(value); break; + #endif } *(float *)var.memadr = newvalue; settings.save(); - skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel + skipVP = var.VP; // Don't overwrite value the next update time as the display might autoincrement in parallel } + #endif // HAS_PID_HEATING #if ENABLED(BABYSTEPPING) + void DGUSScreenHandler::handleLiveAdjustZ(DGUS_VP_Variable &var, void *val_ptr) { const float step = ZOffset_distance; @@ -1088,22 +1032,17 @@ void DGUSScreenHandlerMKS::handleAccChange(DGUS_VP_Variable &var, void *val_ptr) } forceCompleteUpdate(); } + #endif // BABYSTEPPING void DGUSScreenHandlerMKS::getManualFilament(DGUS_VP_Variable &var, void *val_ptr) { - const uint16_t len = BE16_P(val_ptr); - const float value = (float)len; - - distanceFilament = value; - - skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel + distanceFilament = (float)BE16_P(val_ptr); + skipVP = var.VP; // Don't overwrite value the next update time as the display might autoincrement in parallel } void DGUSScreenHandlerMKS::getManualFilamentSpeed(DGUS_VP_Variable &var, void *val_ptr) { - const uint16_t len = BE16_P(val_ptr); - filamentSpeed_mm_s = len; - - skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel + filamentSpeed_mm_s = BE16_P(val_ptr); + skipVP = var.VP; // Don't overwrite value the next update time as the display might autoincrement in parallel } void DGUSScreenHandlerMKS::filamentLoadUnload(DGUS_VP_Variable &var, void *val_ptr, const int filamentDir) { @@ -1146,7 +1085,7 @@ void DGUSScreenHandlerMKS::filamentLoadUnload(DGUS_VP_Variable &var, void *val_p #if ALL(HAS_HOTEND, PREVENT_COLD_EXTRUSION) if (hotend_too_cold) { if (thermalManager.targetTooColdToExtrude(hotend_too_cold - 1)) thermalManager.setTargetHotend(thermalManager.extrude_min_temp, hotend_too_cold - 1); - sendInfoScreen(F("NOTICE"), nullptr, F("Please wait."), F("Nozzle heating!"), true, true, true, true); + sendInfoScreen(F("NOTICE"), nullptr, F("Please wait."), F("Nozzle heating!")); setupConfirmAction(nullptr); gotoScreen(DGUS_SCREEN_POPUP); } @@ -1154,11 +1093,11 @@ void DGUSScreenHandlerMKS::filamentLoadUnload(DGUS_VP_Variable &var, void *val_p if (swap_tool) { char buf[30]; - snprintf_P(buf, 30 + snprintf_P(buf, 30, #if ANY(HAS_MULTI_HOTEND, SINGLENOZZLE) - , PSTR("M1002T%cE%dF%d"), char('0' + swap_tool - 1) + PSTR("M1002T%cE%dF%d"), char('0' + swap_tool - 1) #else - , PSTR("M1002E%dF%d") + PSTR("M1002E%dF%d") #endif , (int)distanceFilament * filamentDir, filamentSpeed_mm_s * 60 ); @@ -1181,11 +1120,13 @@ void GcodeSuite::M1002() { const uint8_t old_axis_relative = axis_relative; set_e_relative(); // M83 + { char buf[20]; snprintf_P(buf, 20, PSTR("G1E%dF%d"), parser.intval('E'), parser.intval('F')); process_subcommands_now(buf); } + axis_relative = old_axis_relative; } @@ -1200,7 +1141,6 @@ void DGUSScreenHandlerMKS::filamentUnload(DGUS_VP_Variable &var, void *val_ptr) #if ENABLED(DGUS_FILAMENT_LOADUNLOAD) void DGUSScreenHandler::handleFilamentOption(DGUS_VP_Variable &var, void *val_ptr) { - uint8_t e_temp = 0; filament_data.heated = false; uint16_t preheat_option = BE16_P(val_ptr); if (preheat_option >= 10) { // Unload filament type @@ -1213,6 +1153,7 @@ void DGUSScreenHandlerMKS::filamentUnload(DGUS_VP_Variable &var, void *val_ptr) else // Cancel filament operation filament_data.action = 0; + uint8_t e_temp = 0; switch (preheat_option) { case 0: // Load PLA #ifdef PREHEAT_1_TEMP_HOTEND @@ -1220,7 +1161,9 @@ void DGUSScreenHandlerMKS::filamentUnload(DGUS_VP_Variable &var, void *val_ptr) #endif break; case 1: // Load ABS - TERN_(PREHEAT_2_TEMP_HOTEND, e_temp = PREHEAT_2_TEMP_HOTEND); + #ifdef PREHEAT_2_TEMP_HOTEND + e_temp = PREHEAT_2_TEMP_HOTEND; + #endif break; case 2: // Load PET #ifdef PREHEAT_3_TEMP_HOTEND @@ -1234,35 +1177,31 @@ void DGUSScreenHandlerMKS::filamentUnload(DGUS_VP_Variable &var, void *val_ptr) break; case 9: // Cool down default: - e_temp = 0; - break; + e_temp = 0; break; } if (filament_data.action == 0) { // Go back to utility screen - #if HAS_HOTEND - thermalManager.setTargetHotend(e_temp, ExtUI::extruder_t::E0); - #endif - #if HAS_MULTI_HOTEND - thermalManager.setTargetHotend(e_temp, ExtUI::extruder_t::E1); - #endif + TERN_(HAS_EXTRUDERS, thermalManager.setTargetHotend(e_temp, 0)); + TERN_(HAS_MULTI_EXTRUDER, thermalManager.setTargetHotend(e_temp, 1)); gotoScreen(DGUS_SCREEN_UTILITY); + return; } - else { // Go to the preheat screen to show the heating progress - switch (var.VP) { - default: return; - #if HAS_HOTEND - case VP_E0_FILAMENT_LOAD_UNLOAD: - filament_data.extruder = ExtUI::extruder_t::E0; - thermalManager.setTargetHotend(e_temp, filament_data.extruder); - break; - #endif - #if HAS_MULTI_HOTEND - case VP_E1_FILAMENT_LOAD_UNLOAD: - filament_data.extruder = ExtUI::extruder_t::E1; - thermalManager.setTargetHotend(e_temp, filament_data.extruder); - break; - #endif - } + + // Go to the preheat screen to show the heating progress + switch (var.VP) { + default: return; + #if HAS_EXTRUDERS + case VP_E0_FILAMENT_LOAD_UNLOAD: + filament_data.extruder = 0; + thermalManager.setTargetHotend(e_temp, filament_data.extruder); + break; + #endif + #if HAS_MULTI_EXTRUDER + case VP_E1_FILAMENT_LOAD_UNLOAD: + filament_data.extruder = 1; + thermalManager.setTargetHotend(e_temp, filament_data.extruder); + break; + #endif } } @@ -1278,7 +1217,7 @@ void DGUSScreenHandlerMKS::filamentUnload(DGUS_VP_Variable &var, void *val_ptr) if (!filament_data.heated) { filament_data.heated = true; } - movevalue = ExtUI::getAxisPosition_mm(filament_data.extruder) + movevalue; + movevalue = ExtUI::getAxisPosition_mm(filament_data.extruder ? ExtUI::extruder_t::E1 : ExtUI::extruder_t::E0) + movevalue; } else { // unload filament if (!filament_data.heated) { @@ -1287,14 +1226,14 @@ void DGUSScreenHandlerMKS::filamentUnload(DGUS_VP_Variable &var, void *val_ptr) } // Before unloading extrude to prevent jamming if (filament_data.purge_length >= 0) { - movevalue = ExtUI::getAxisPosition_mm(filament_data.extruder) + movevalue; + movevalue = ExtUI::getAxisPosition_mm(filament_data.extruder ? ExtUI::extruder_t::E1 : ExtUI::extruder_t::E0) + movevalue; filament_data.purge_length -= movevalue; } else { - movevalue = ExtUI::getAxisPosition_mm(filament_data.extruder) - movevalue; + movevalue = ExtUI::getAxisPosition_mm(filament_data.extruder ? ExtUI::extruder_t::E1 : ExtUI::extruder_t::E0) - movevalue; } } - ExtUI::setAxisPosition_mm(movevalue, filament_data.extruder); + ExtUI::setAxisPosition_mm(movevalue, filament_data.extruder ? ExtUI::extruder_t::E1 : ExtUI::extruder_t::E0); } } @@ -1315,11 +1254,12 @@ bool DGUSScreenHandlerMKS::loop() { if (language_times != 0) { languagePInit(); - languageDisplay(mks_language_index); + updateDisplayLanguage(); language_times--; } #if ENABLED(SHOW_BOOTSCREEN) + static bool booted = false; if (!booted && ELAPSED(ms, TERN(USE_MKS_GREEN_UI, 1000, BOOTSCREEN_TIMEOUT))) { booted = true; @@ -1347,24 +1287,15 @@ bool DGUSScreenHandlerMKS::loop() { #if ENABLED(DGUS_MKS_RUNOUT_SENSOR) if (booted && printingIsActive()) runoutIdle(); #endif + #endif // SHOW_BOOTSCREEN return isScreenComplete(); } void DGUSScreenHandlerMKS::languagePInit() { - switch (mks_language_index) { - case MKS_SimpleChinese: - dgus.writeVariable(VP_LANGUAGE_CHANGE1, (uint8_t)MKS_Language_Choose); - dgus.writeVariable(VP_LANGUAGE_CHANGE2, (uint8_t)MKS_Language_NoChoose); - break; - case MKS_English: - dgus.writeVariable(VP_LANGUAGE_CHANGE1, (uint8_t)MKS_Language_NoChoose); - dgus.writeVariable(VP_LANGUAGE_CHANGE2, (uint8_t)MKS_Language_Choose); - break; - default: - break; - } + dgus.writeVariable(VP_LANGUAGE_CHANGE1, (uint8_t)(mks_language_index == MKS_English ? MKS_Language_NoChoose : MKS_Language_Choose)); + dgus.writeVariable(VP_LANGUAGE_CHANGE2, (uint8_t)(mks_language_index == MKS_English ? MKS_Language_Choose : MKS_Language_NoChoose)); } void DGUSScreenHandlerMKS::extrudeLoadInit() { @@ -1397,542 +1328,544 @@ void DGUSScreenHandlerMKS::runoutIdle() { queue.inject(F("M25")); gotoScreen(MKSLCD_SCREEN_PAUSE); - sendInfoScreen(F("NOTICE"), nullptr, F("Please change filament!"), nullptr, true, true, true, true); + sendInfoScreen(F("NOTICE"), nullptr, F("Please change filament!"), nullptr); //setupConfirmAction(nullptr); gotoScreen(DGUS_SCREEN_POPUP); break; case UNRUNOUT_STATUS: - if (FILAMENT_IS_OUT()) - runout_mks.runout_status = RUNOUT_STATUS; + if (FILAMENT_IS_OUT()) runout_mks.runout_status = RUNOUT_STATUS; break; case RUNOUT_BEGIN_STATUS: - if (!FILAMENT_IS_OUT()) - runout_mks.runout_status = RUNOUT_WAITING_STATUS; + if (!FILAMENT_IS_OUT()) runout_mks.runout_status = RUNOUT_WAITING_STATUS; break; case RUNOUT_WAITING_STATUS: - if (FILAMENT_IS_OUT()) - runout_mks.runout_status = RUNOUT_BEGIN_STATUS; + if (FILAMENT_IS_OUT()) runout_mks.runout_status = RUNOUT_BEGIN_STATUS; break; default: break; } - #endif + #endif // DGUS_MKS_RUNOUT_SENSOR } -void DGUSScreenHandlerMKS::languageDisplay(uint8_t var) { - if (var == MKS_English) { - const char home_buf_en[] = "Home"; - dgus.writeVariable(VP_HOME_Dis, home_buf_en, 32, true); +void DGUSScreenHandlerMKS::updateDisplayLanguage() { + switch (mks_language_index) { + case MKS_English : { + const char home_buf_en[] = "Home"; + dgus.writeStringVar(VP_HOME_Dis, home_buf_en); - const char setting_buf_en[] = "Setting"; - dgus.writeVariable(VP_Setting_Dis, setting_buf_en, 32, true); + const char setting_buf_en[] = "Settings"; + dgus.writeStringVar(VP_Setting_Dis, setting_buf_en); - const char Tool_buf_en[] = "Tool"; - dgus.writeVariable(VP_Tool_Dis, Tool_buf_en, 32, true); + const char Tool_buf_en[] = "Tools"; + dgus.writeStringVar(VP_Tool_Dis, Tool_buf_en); - const char Print_buf_en[] = "Print"; - dgus.writeVariable(VP_Print_Dis, Print_buf_en, 32, true); + const char Print_buf_en[] = "Print"; + dgus.writeStringVar(VP_Print_Dis, Print_buf_en); - const char Language_buf_en[] = "Language"; - dgus.writeVariable(VP_Language_Dis, Language_buf_en, 32, true); + const char Language_buf_en[] = "Language"; + dgus.writeStringVar(VP_Language_Dis, Language_buf_en); - const char About_buf_en[] = "About"; - dgus.writeVariable(VP_About_Dis, About_buf_en, 32, true); + const char About_buf_en[] = "About"; + dgus.writeStringVar(VP_About_Dis, About_buf_en); - const char Config_buf_en[] = "Config"; - dgus.writeVariable(VP_Config_Dis, Config_buf_en, 32, true); + const char Config_buf_en[] = "Config"; + dgus.writeStringVar(VP_Config_Dis, Config_buf_en); - const char MotorConfig_buf_en[] = "MotorConfig"; - dgus.writeVariable(VP_MotorConfig_Dis, MotorConfig_buf_en, 32, true); + const char MotorConfig_buf_en[] = "Motion Config"; + dgus.writeStringVar(VP_MotorConfig_Dis, MotorConfig_buf_en); - const char LevelConfig_buf_en[] = "LevelConfig"; - dgus.writeVariable(VP_LevelConfig_Dis, LevelConfig_buf_en, 32, true); + const char LevelConfig_buf_en[] = "Level Config"; + dgus.writeStringVar(VP_LevelConfig_Dis, LevelConfig_buf_en); - const char TemperatureConfig_buf_en[] = "Temperature"; - dgus.writeVariable(VP_TemperatureConfig_Dis, TemperatureConfig_buf_en, 32, true); + const char TemperatureConfig_buf_en[] = "Temperature"; + dgus.writeStringVar(VP_TemperatureConfig_Dis, TemperatureConfig_buf_en); - const char Advance_buf_en[] = "Advance"; - dgus.writeVariable(VP_Advance_Dis, Advance_buf_en, 32, true); + const char Advance_buf_en[] = "Advanced"; + dgus.writeStringVar(VP_Advance_Dis, Advance_buf_en); - const char Filament_buf_en[] = "Extrude"; - dgus.writeVariable(VP_Filament_Dis, Filament_buf_en, 32, true); + const char Filament_buf_en[] = "Extrude"; + dgus.writeStringVar(VP_Filament_Dis, Filament_buf_en); - const char Move_buf_en[] = "Move"; - dgus.writeVariable(VP_Move_Dis, Move_buf_en, 32, true); + const char Move_buf_en[] = "Move"; + dgus.writeStringVar(VP_Move_Dis, Move_buf_en); - #if ENABLED(AUTO_BED_LEVELING_BILINEAR) - const char Level_buf_en[] = "AutoLevel"; - dgus.writeVariable(VP_Level_Dis, Level_buf_en, 32, true); - #elif ENABLED(MESH_BED_LEVELING) - const char Level_buf_en[] = "MeshLevel"; - dgus.writeVariable(VP_Level_Dis, Level_buf_en, 32, true); - #else - const char Level_buf_en[] = "Level"; - dgus.writeVariable(VP_Level_Dis, Level_buf_en, 32, true); - #endif + const char Level_buf_en[] = + #if ENABLED(AUTO_BED_LEVELING_BILINEAR) + "Auto" + #elif ENABLED(MESH_BED_LEVELING) + "Mesh" + #endif + "Level" + ; + dgus.writeStringVar(VP_Level_Dis, Level_buf_en); - const char MotorPluse_buf_en[] = "MotorPluse"; - dgus.writeVariable(VP_MotorPluse_Dis, MotorPluse_buf_en, 32, true); + const char MotorPulse_buf_en[] = "MotorPulse"; + dgus.writeStringVar(VP_MotorPulse_Dis, MotorPulse_buf_en); - const char MotorMaxSpeed_buf_en[] = "MotorMaxSpeed"; - dgus.writeVariable(VP_MotorMaxSpeed_Dis, MotorMaxSpeed_buf_en, 32, true); + const char MotorMaxSpeed_buf_en[] = "MotorMaxSpeed"; + dgus.writeStringVar(VP_MotorMaxSpeed_Dis, MotorMaxSpeed_buf_en); - const char MotorMaxAcc_buf_en[] = "MotorAcc"; - dgus.writeVariable(VP_MotorMaxAcc_Dis, MotorMaxAcc_buf_en, 32, true); + const char MotorMaxAcc_buf_en[] = "MotorAcc"; + dgus.writeStringVar(VP_MotorMaxAcc_Dis, MotorMaxAcc_buf_en); - const char TravelAcc_buf_en[] = "TravelAcc"; - dgus.writeVariable(VP_TravelAcc_Dis, TravelAcc_buf_en, 32, true); + const char TravelAcc_buf_en[] = "Travel Acc."; + dgus.writeStringVar(VP_TravelAcc_Dis, TravelAcc_buf_en); - const char FeedRateMin_buf_en[] = "FeedRateMin"; - dgus.writeVariable(VP_FeedRateMin_Dis, FeedRateMin_buf_en, 32, true); + const char FeedRateMin_buf_en[] = "Min FeedRate"; + dgus.writeStringVar(VP_FeedRateMin_Dis, FeedRateMin_buf_en); - const char TravelFeeRateMin_buf_en[] = "TravelFeedRateMin"; - dgus.writeVariable(VP_TravelFeeRateMin_Dis, TravelFeeRateMin_buf_en, 32, true); + const char TravelFeeRateMin_buf_en[] = "Travel Min FeedRate"; + dgus.writeStringVar(VP_TravelFeeRateMin_Dis, TravelFeeRateMin_buf_en); - const char Acc_buf_en[] = "Acc"; - dgus.writeVariable(VP_ACC_Dis, Acc_buf_en, 32, true); + const char Acc_buf_en[] = "Acceleration"; + dgus.writeStringVar(VP_ACC_Dis, Acc_buf_en); - const char Point_One_buf_en[] = "Point_First"; - dgus.writeVariable(VP_Point_One_Dis, Point_One_buf_en, 32, true); + const char Point_One_buf_en[] = "Point 1"; + dgus.writeStringVar(VP_Point_One_Dis, Point_One_buf_en); - const char Point_Two_buf_en[] = "Point_Second"; - dgus.writeVariable(VP_Point_Two_Dis, Point_Two_buf_en, 32, true); + const char Point_Two_buf_en[] = "Point 2"; + dgus.writeStringVar(VP_Point_Two_Dis, Point_Two_buf_en); - const char Point_Three_buf_en[] = "Point_Third"; - dgus.writeVariable(VP_Point_Three_Dis, Point_Three_buf_en, 32, true); + const char Point_Three_buf_en[] = "Point 3"; + dgus.writeStringVar(VP_Point_Three_Dis, Point_Three_buf_en); - const char Point_Four_buf_en[] = "Point_Fourth"; - dgus.writeVariable(VP_Point_Four_Dis, Point_Four_buf_en, 32, true); + const char Point_Four_buf_en[] = "Point 4"; + dgus.writeStringVar(VP_Point_Four_Dis, Point_Four_buf_en); - const char Point_Five_buf_en[] = "Point_Fifth"; - dgus.writeVariable(VP_Point_Five_Dis, Point_Five_buf_en, 32, true); + const char Point_Five_buf_en[] = "Point 5"; + dgus.writeStringVar(VP_Point_Five_Dis, Point_Five_buf_en); - const char Extrusion_buf_en[] = "Extrusion"; - dgus.writeVariable(VP_Extrusion_Dis, Extrusion_buf_en, 32, true); + const char Extrusion_buf_en[] = "Extrusion"; + dgus.writeStringVar(VP_Extrusion_Dis, Extrusion_buf_en); - const char HeatBed_buf_en[] = "HeatBed"; - dgus.writeVariable(VP_HeatBed_Dis, HeatBed_buf_en, 32, true); + const char HeatBed_buf_en[] = "HeatBed"; + dgus.writeStringVar(VP_HeatBed_Dis, HeatBed_buf_en); - const char FactoryDefaults_buf_en[] = "FactoryDefaults"; - dgus.writeVariable(VP_FactoryDefaults_Dis, FactoryDefaults_buf_en, 32, true); + const char FactoryDefaults_buf_en[] = "Factory Defaults"; + dgus.writeStringVar(VP_FactoryDefaults_Dis, FactoryDefaults_buf_en); - const char StoreSetting_buf_en[] = "StoreSetting"; - dgus.writeVariable(VP_StoreSetting_Dis, StoreSetting_buf_en, 32, true); + const char StoreSetting_buf_en[] = "Store Setting"; + dgus.writeStringVar(VP_StoreSetting_Dis, StoreSetting_buf_en); - const char PrintPauseConfig_buf_en[] = "PrintPauseConfig"; - dgus.writeVariable(VP_PrintPauseConfig_Dis, PrintPauseConfig_buf_en, 32, true); + const char PrintPauseConfig_buf_en[] = "PrintPause Config"; + dgus.writeStringVar(VP_PrintPauseConfig_Dis, PrintPauseConfig_buf_en); - const char X_Pluse_buf_en[] = "X_Pluse"; - dgus.writeVariable(VP_X_Pluse_Dis, X_Pluse_buf_en, 32, true); + const char X_Pulse_buf_en[] = "X_Pulse"; + dgus.writeStringVar(VP_X_Pulse_Dis, X_Pulse_buf_en); - const char Y_Pluse_buf_en[] = "Y_Pluse"; - dgus.writeVariable(VP_Y_Pluse_Dis, Y_Pluse_buf_en, 32, true); + const char Y_Pulse_buf_en[] = "Y_Pulse"; + dgus.writeStringVar(VP_Y_Pulse_Dis, Y_Pulse_buf_en); - const char Z_Pluse_buf_en[] = "Z_Pluse"; - dgus.writeVariable(VP_Z_Pluse_Dis, Z_Pluse_buf_en, 32, true); + const char Z_Pulse_buf_en[] = "Z_Pulse"; + dgus.writeStringVar(VP_Z_Pulse_Dis, Z_Pulse_buf_en); - const char E0_Pluse_buf_en[] = "E0_Pluse"; - dgus.writeVariable(VP_E0_Pluse_Dis, E0_Pluse_buf_en, 32, true); + const char E0_Pulse_buf_en[] = "E0_Pulse"; + dgus.writeStringVar(VP_E0_Pulse_Dis, E0_Pulse_buf_en); - const char E1_Pluse_buf_en[] = "E1_Pluse"; - dgus.writeVariable(VP_E1_Pluse_Dis, E1_Pluse_buf_en, 32, true); + const char E1_Pulse_buf_en[] = "E1_Pulse"; + dgus.writeStringVar(VP_E1_Pulse_Dis, E1_Pulse_buf_en); - const char X_Max_Speed_buf_en[] = "X_Max_Speed"; - dgus.writeVariable(VP_X_Max_Speed_Dis, X_Max_Speed_buf_en, 32, true); + const char X_Max_Speed_buf_en[] = "X Max Speed"; + dgus.writeStringVar(VP_X_Max_Speed_Dis, X_Max_Speed_buf_en); - const char Y_Max_Speed_buf_en[] = "Y_Max_Speed"; - dgus.writeVariable(VP_Y_Max_Speed_Dis, Y_Max_Speed_buf_en, 32, true); + const char Y_Max_Speed_buf_en[] = "Y Max Speed"; + dgus.writeStringVar(VP_Y_Max_Speed_Dis, Y_Max_Speed_buf_en); - const char Z_Max_Speed_buf_en[] = "Z_Max_Speed"; - dgus.writeVariable(VP_Z_Max_Speed_Dis, Z_Max_Speed_buf_en, 32, true); + const char Z_Max_Speed_buf_en[] = "Z Max Speed"; + dgus.writeStringVar(VP_Z_Max_Speed_Dis, Z_Max_Speed_buf_en); - const char E0_Max_Speed_buf_en[] = "E0_Max_Speed"; - dgus.writeVariable(VP_E0_Max_Speed_Dis, E0_Max_Speed_buf_en, 32, true); + const char E0_Max_Speed_buf_en[] = "E0 Max Speed"; + dgus.writeStringVar(VP_E0_Max_Speed_Dis, E0_Max_Speed_buf_en); - const char E1_Max_Speed_buf_en[] = "E1_Max_Speed"; - dgus.writeVariable(VP_E1_Max_Speed_Dis, E1_Max_Speed_buf_en, 32, true); + const char E1_Max_Speed_buf_en[] = "E1 Max Speed"; + dgus.writeStringVar(VP_E1_Max_Speed_Dis, E1_Max_Speed_buf_en); - const char X_Max_Acc_Speed_buf_en[] = "X_Max_Acc_Speed"; - dgus.writeVariable(VP_X_Max_Acc_Speed_Dis, X_Max_Acc_Speed_buf_en, 32, true); + const char X_Max_Acc_Speed_buf_en[] = "X Max Acc"; + dgus.writeStringVar(VP_X_Max_Acc_Dis, X_Max_Acc_Speed_buf_en); - const char Y_Max_Acc_Speed_buf_en[] = "Y_Max_Acc_Speed"; - dgus.writeVariable(VP_Y_Max_Acc_Speed_Dis, Y_Max_Acc_Speed_buf_en, 32, true); + const char Y_Max_Acc_Speed_buf_en[] = "Y Max Acc"; + dgus.writeStringVar(VP_Y_Max_Acc_Dis, Y_Max_Acc_Speed_buf_en); - const char Z_Max_Acc_Speed_buf_en[] = "Z_Max_Acc_Speed"; - dgus.writeVariable(VP_Z_Max_Acc_Speed_Dis, Z_Max_Acc_Speed_buf_en, 32, true); + const char Z_Max_Acc_Speed_buf_en[] = "Z Max Acc"; + dgus.writeStringVar(VP_Z_Max_Acc_Dis, Z_Max_Acc_Speed_buf_en); - const char E0_Max_Acc_Speed_buf_en[] = "E0_Max_Acc_Speed"; - dgus.writeVariable(VP_E0_Max_Acc_Speed_Dis, E0_Max_Acc_Speed_buf_en, 32, true); + const char E0_Max_Acc_Speed_buf_en[] = "E0 Max Acc"; + dgus.writeStringVar(VP_E0_Max_Acc_Dis, E0_Max_Acc_Speed_buf_en); - const char E1_Max_Acc_Speed_buf_en[] = "E1_Max_Acc_Speed"; - dgus.writeVariable(VP_E1_Max_Acc_Speed_Dis, E1_Max_Acc_Speed_buf_en, 32, true); + const char E1_Max_Acc_Speed_buf_en[] = "E1 Max Acc"; + dgus.writeStringVar(VP_E1_Max_Acc_Dis, E1_Max_Acc_Speed_buf_en); - const char X_PARK_POS_buf_en[] = "X_PARK_POS"; - dgus.writeVariable(VP_X_PARK_POS_Dis, X_PARK_POS_buf_en, 32, true); + const char X_PARK_POS_buf_en[] = "X Park Pos"; + dgus.writeStringVar(VP_X_PARK_POS_Dis, X_PARK_POS_buf_en); - const char Y_PARK_POS_buf_en[] = "Y_PARK_POS"; - dgus.writeVariable(VP_Y_PARK_POS_Dis, Y_PARK_POS_buf_en, 32, true); + const char Y_PARK_POS_buf_en[] = "Y Park Pos"; + dgus.writeStringVar(VP_Y_PARK_POS_Dis, Y_PARK_POS_buf_en); - const char Z_PARK_POS_buf_en[] = "Z_PARK_POS"; - dgus.writeVariable(VP_Z_PARK_POS_Dis, Z_PARK_POS_buf_en, 32, true); + const char Z_PARK_POS_buf_en[] = "Z Park Pos"; + dgus.writeStringVar(VP_Z_PARK_POS_Dis, Z_PARK_POS_buf_en); - const char Length_buf_en[] = "Length"; - dgus.writeVariable(VP_Length_Dis, Length_buf_en, 32, true); + const char Length_buf_en[] = "Length"; + dgus.writeStringVar(VP_Length_Dis, Length_buf_en); - const char Speed_buf_en[] = "Speed"; - dgus.writeVariable(VP_Speed_Dis, Speed_buf_en, 32, true); + const char Speed_buf_en[] = "Speed"; + dgus.writeStringVar(VP_Speed_Dis, Speed_buf_en); - const char InOut_buf_en[] = "InOut"; - dgus.writeVariable(VP_InOut_Dis, InOut_buf_en, 32, true); + const char InOut_buf_en[] = "In/Out"; + dgus.writeStringVar(VP_InOut_Dis, InOut_buf_en); - const char PrintTimet_buf_en[] = "PrintTime"; - dgus.writeVariable(VP_PrintTime_Dis, PrintTimet_buf_en, 32, true); + const char PrintTimet_buf_en[] = "Print Time"; + dgus.writeStringVar(VP_PrintTime_Dis, PrintTimet_buf_en); - const char E0_Temp_buf_en[] = "E0_Temp"; - dgus.writeVariable(VP_E0_Temp_Dis, E0_Temp_buf_en, 32, true); + const char E0_Temp_buf_en[] = "E0 Temp"; + dgus.writeStringVar(VP_E0_Temp_Dis, E0_Temp_buf_en); - const char E1_Temp_buf_en[] = "E1_Temp"; - dgus.writeVariable(VP_E1_Temp_Dis, E1_Temp_buf_en, 32, true); + const char E1_Temp_buf_en[] = "E1 Temp"; + dgus.writeStringVar(VP_E1_Temp_Dis, E1_Temp_buf_en); - const char HB_Temp_buf_en[] = "HB_Temp"; - dgus.writeVariable(VP_HB_Temp_Dis, HB_Temp_buf_en, 32, true); + const char HB_Temp_buf_en[] = "HB Temp"; + dgus.writeStringVar(VP_HB_Temp_Dis, HB_Temp_buf_en); - const char Feedrate_buf_en[] = "Feedrate"; - dgus.writeVariable(VP_Feedrate_Dis, Feedrate_buf_en, 32, true); + const char Feedrate_buf_en[] = "Feedrate"; + dgus.writeStringVar(VP_Feedrate_Dis, Feedrate_buf_en); - const char PrintAcc_buf_en[] = "PrintSpeed"; - dgus.writeVariable(VP_PrintAcc_Dis, PrintAcc_buf_en, 32, true); + const char PrintAcc_buf_en[] = "Print Speed"; + dgus.writeStringVar(VP_PrintAcc_Dis, PrintAcc_buf_en); - const char FAN_Speed_buf_en[] = "FAN_Speed"; - dgus.writeVariable(VP_Fan_Speed_Dis, FAN_Speed_buf_en, 32, true); + const char FAN_Speed_buf_en[] = "FAN Speed"; + dgus.writeStringVar(VP_Fan_Speed_Dis, FAN_Speed_buf_en); - const char Printing_buf_en[] = "Printing"; - dgus.writeVariable(VP_Printing_Dis, Printing_buf_en, 32, true); + const char Printing_buf_en[] = "Printing"; + dgus.writeStringVar(VP_Printing_Dis, Printing_buf_en); - const char Info_EEPROM_1_buf_en[] = "Store setting?"; - dgus.writeVariable(VP_Info_EEPROM_1_Dis, Info_EEPROM_1_buf_en, 32, true); + const char Info_EEPROM_1_buf_en[] = "Store Settings?"; + dgus.writeStringVar(VP_Info_EEPROM_1_Dis, Info_EEPROM_1_buf_en); - const char Info_EEPROM_2_buf_en[] = "Revert setting?"; - dgus.writeVariable(VP_Info_EEPROM_2_Dis, Info_EEPROM_2_buf_en, 32, true); + const char Info_EEPROM_2_buf_en[] = "Revert Settings?"; + dgus.writeStringVar(VP_Info_EEPROM_2_Dis, Info_EEPROM_2_buf_en); - const char Info_PrintFinish_1_buf_en[] = "Print Done"; - dgus.writeVariable(VP_Info_PrintFinish_1_Dis, Info_PrintFinish_1_buf_en, 32, true); + const char Info_PrintFinish_1_buf_en[] = "Print Done"; + dgus.writeStringVar(VP_Info_PrintFinish_1_Dis, Info_PrintFinish_1_buf_en); - const char TMC_X_Step_buf_en[] = "X_SenSitivity"; - dgus.writeVariable(VP_TMC_X_Step_Dis, TMC_X_Step_buf_en, 32, true); + const char TMC_X_Step_buf_en[] = "X Sensitivity"; + dgus.writeStringVar(VP_TMC_X_Step_Dis, TMC_X_Step_buf_en); - const char TMC_Y_Step_buf_en[] = "Y_SenSitivity"; - dgus.writeVariable(VP_TMC_Y_Step_Dis, TMC_Y_Step_buf_en, 32, true); + const char TMC_Y_Step_buf_en[] = "Y Sensitivity"; + dgus.writeStringVar(VP_TMC_Y_Step_Dis, TMC_Y_Step_buf_en); - const char TMC_Z_Step_buf_en[] = "Z_SenSitivity"; - dgus.writeVariable(VP_TMC_Z_Step_Dis, TMC_Z_Step_buf_en, 32, true); + const char TMC_Z_Step_buf_en[] = "Z Sensitivity"; + dgus.writeStringVar(VP_TMC_Z_Step_Dis, TMC_Z_Step_buf_en); - const char TMC_X_Current_buf_en[] = "X_Current"; - dgus.writeVariable(VP_TMC_X_Current_Dis, TMC_X_Current_buf_en, 32, true); + const char TMC_X_Current_buf_en[] = "X Current"; + dgus.writeStringVar(VP_TMC_X_Current_Dis, TMC_X_Current_buf_en); - const char TMC_Y_Current_buf_en[] = "Y_Current"; - dgus.writeVariable(VP_TMC_Y_Current_Dis, TMC_Y_Current_buf_en, 32, true); + const char TMC_Y_Current_buf_en[] = "Y Current"; + dgus.writeStringVar(VP_TMC_Y_Current_Dis, TMC_Y_Current_buf_en); - const char TMC_Z_Current_buf_en[] = "Z_Current"; - dgus.writeVariable(VP_TMC_Z_Current_Dis, TMC_Z_Current_buf_en, 32, true); + const char TMC_Z_Current_buf_en[] = "Z Current"; + dgus.writeStringVar(VP_TMC_Z_Current_Dis, TMC_Z_Current_buf_en); - const char TMC_E0_Current_buf_en[] = "E0_Current"; - dgus.writeVariable(VP_TMC_E0_Current_Dis, TMC_E0_Current_buf_en, 32, true); + const char TMC_E0_Current_buf_en[] = "E0 Current"; + dgus.writeStringVar(VP_TMC_E0_Current_Dis, TMC_E0_Current_buf_en); - const char TMC_X1_Current_buf_en[] = "X1_Current"; - dgus.writeVariable(VP_TMC_X1_Current_Dis, TMC_X1_Current_buf_en, 32, true); + const char TMC_X1_Current_buf_en[] = "X2 Current"; + dgus.writeStringVar(VP_TMC_X1_Current_Dis, TMC_X1_Current_buf_en); - const char TMC_Y1_Current_buf_en[] = "Y1_Current"; - dgus.writeVariable(VP_TMC_Y1_Current_Dis, TMC_Y1_Current_buf_en, 32, true); + const char TMC_Y1_Current_buf_en[] = "Y2 Current"; + dgus.writeStringVar(VP_TMC_Y1_Current_Dis, TMC_Y1_Current_buf_en); - const char TMC_Z1_Current_buf_en[] = "Z1_Current"; - dgus.writeVariable(VP_TMC_Z1_Current_Dis, TMC_Z1_Current_buf_en, 32, true); + const char TMC_Z1_Current_buf_en[] = "Z2 Current"; + dgus.writeStringVar(VP_TMC_Z1_Current_Dis, TMC_Z1_Current_buf_en); - const char TMC_E1_Current_buf_en[] = "E1_Current"; - dgus.writeVariable(VP_TMC_E1_Current_Dis, TMC_E1_Current_buf_en, 32, true); + const char TMC_E1_Current_buf_en[] = "E1 Current"; + dgus.writeStringVar(VP_TMC_E1_Current_Dis, TMC_E1_Current_buf_en); - const char Min_Ex_Temp_buf_en[] = "Min_Ex_Temp"; - dgus.writeVariable(VP_Min_Ex_Temp_Dis, Min_Ex_Temp_buf_en, 32, true); + const char Min_Ex_Temp_buf_en[] = "Min Extrude Temp"; + dgus.writeStringVar(VP_Min_Ex_Temp_Dis, Min_Ex_Temp_buf_en); - const char AutoLEVEL_INFO1_buf_en[] = "Please Press Button!"; - dgus.writeVariable(VP_AutoLEVEL_INFO1, AutoLEVEL_INFO1_buf_en, 32, true); + const char AutoLEVEL_INFO1_buf_en[] = "Please Press Button!"; + dgus.writeStringVar(VP_AutoLEVEL_INFO1, AutoLEVEL_INFO1_buf_en); - const char EX_TEMP_INFO2_buf_en[] = "Please wait a monent"; - dgus.writeVariable(VP_EX_TEMP_INFO2_Dis, EX_TEMP_INFO2_buf_en, 32, true); + const char EX_TEMP_INFO2_buf_en[] = "Please wait a moment"; + dgus.writeStringVar(VP_EX_TEMP_INFO2_Dis, EX_TEMP_INFO2_buf_en); - const char EX_TEMP_INFO3_buf_en[] = "Cancle"; - dgus.writeVariable(VP_EX_TEMP_INFO3_Dis, EX_TEMP_INFO3_buf_en, 32, true); + const char EX_TEMP_INFO3_buf_en[] = "Cancel"; + dgus.writeStringVar(VP_EX_TEMP_INFO3_Dis, EX_TEMP_INFO3_buf_en); - const char PrintConfrim_Info_buf_en[] = "Start Print?"; - dgus.writeVariable(VP_PrintConfrim_Info_Dis, PrintConfrim_Info_buf_en, 32, true); + const char PrintConfirm_Info_buf_en[] = "Start Print?"; + dgus.writeStringVar(VP_PrintConfirm_Info_Dis, PrintConfirm_Info_buf_en); - const char StopPrintConfrim_Info_buf_en[] = "Stop Print?"; - dgus.writeVariable(VP_StopPrintConfrim_Info_Dis, StopPrintConfrim_Info_buf_en, 32, true); + const char StopPrintConfirm_Info_buf_en[] = "Stop Print?"; + dgus.writeStringVar(VP_StopPrintConfirm_Info_Dis, StopPrintConfirm_Info_buf_en); - const char Printting_buf_en[] = "Printing"; - dgus.writeVariable(VP_Printting_Dis, Printting_buf_en, 32, true); + const char Printting_buf_en[] = "Printing"; + dgus.writeStringVar(VP_Printting_Dis, Printting_buf_en); - const char LCD_BLK_buf_en[] = "Backlight"; - dgus.writeVariable(VP_LCD_BLK_Dis, LCD_BLK_buf_en, 32, true); - } - else if (var == MKS_SimpleChinese) { - uint16_t home_buf_ch[] = { 0xF7D6, 0xB3D2 }; - dgus.writeVariable(VP_HOME_Dis, home_buf_ch, 4, true); + const char LCD_BLK_buf_en[] = "Backlight"; + dgus.writeStringVar(VP_LCD_BLK_Dis, LCD_BLK_buf_en); - const uint16_t Setting_Dis[] = { 0xE8C9, 0xC3D6, 0x2000, 0x2000, 0x2000 }; - dgus.writeVariable(VP_Setting_Dis, Setting_Dis, 7, true); + } break; // MKS_English - const uint16_t Tool_Dis[] = { 0xA4B9, 0xDFBE }; - dgus.writeVariable(VP_Tool_Dis, Tool_Dis, 4, true); + case MKS_SimpleChinese: { + uint16_t home_buf_ch[] = { 0xF7D6, 0xB3D2 }; + dgus.writeStringVar(VP_HOME_Dis, home_buf_ch, 4); - const uint16_t Print_buf_ch[] = { 0xF2B4, 0xA1D3, 0x2000 }; - dgus.writeVariable(VP_Print_Dis, Print_buf_ch, 6, true); + const uint16_t Setting_Dis[] = { 0xE8C9, 0xC3D6, 0x2000, 0x2000, 0x2000 }; + dgus.writeStringVar(VP_Setting_Dis, Setting_Dis, 7); - const uint16_t Language_buf_ch[] = { 0xEFD3, 0xD4D1, 0x2000, 0x2000 }; - dgus.writeVariable(VP_Language_Dis, Language_buf_ch, 8, true); + const uint16_t Tool_Dis[] = { 0xA4B9, 0xDFBE }; + dgus.writeStringVar(VP_Tool_Dis, Tool_Dis, 4); - const uint16_t About_buf_ch[] = { 0xD8B9, 0xDAD3, 0x2000 }; - dgus.writeVariable(VP_About_Dis, About_buf_ch, 6, true); + const uint16_t Print_buf_ch[] = { 0xF2B4, 0xA1D3, 0x2000 }; + dgus.writeStringVar(VP_Print_Dis, Print_buf_ch, 6); - const uint16_t Config_buf_ch[] = { 0xE4C5, 0xC3D6, 0x2000 }; - dgus.writeVariable(VP_Config_Dis, Config_buf_ch, 6, true); + const uint16_t Language_buf_ch[] = { 0xEFD3, 0xD4D1, 0x2000, 0x2000 }; + dgus.writeStringVar(VP_Language_Dis, Language_buf_ch, 8); - const uint16_t MotorConfig_buf_ch[] = { 0xE7B5, 0xFABB, 0xE4C5, 0xC3D6, 0x2000 }; - dgus.writeVariable(VP_MotorConfig_Dis, MotorConfig_buf_ch, 12, true); + const uint16_t About_buf_ch[] = { 0xD8B9, 0xDAD3, 0x2000 }; + dgus.writeStringVar(VP_About_Dis, About_buf_ch, 6); - const uint16_t LevelConfig_buf_ch[] = { 0xD6CA, 0xAFB6, 0xF7B5, 0xBDC6, 0xE8C9, 0xC3D6, 0x2000 }; - dgus.writeVariable(VP_LevelConfig_Dis, LevelConfig_buf_ch, 32, true); + const uint16_t Config_buf_ch[] = { 0xE4C5, 0xC3D6, 0x2000 }; + dgus.writeStringVar(VP_Config_Dis, Config_buf_ch, 6); - const uint16_t TemperatureConfig_buf_ch[] = { 0xC2CE, 0xC8B6, 0x2000 }; - dgus.writeVariable(VP_TemperatureConfig_Dis, TemperatureConfig_buf_ch, 11, true); + const uint16_t MotorConfig_buf_ch[] = { 0xE7B5, 0xFABB, 0xE4C5, 0xC3D6, 0x2000 }; + dgus.writeStringVar(VP_MotorConfig_Dis, MotorConfig_buf_ch, 12); - const uint16_t Advance_buf_ch[] = { 0xDFB8, 0xB6BC, 0xE8C9, 0xC3D6, 0x2000 }; - dgus.writeVariable(VP_Advance_Dis, Advance_buf_ch, 16, true); + const uint16_t LevelConfig_buf_ch[] = { 0xD6CA, 0xAFB6, 0xF7B5, 0xBDC6, 0xE8C9, 0xC3D6, 0x2000 }; + dgus.writeStringVar(VP_LevelConfig_Dis, LevelConfig_buf_ch, 32); - const uint16_t Filament_buf_ch[] = { 0xB7BC, 0xF6B3, 0x2000 }; - dgus.writeVariable(VP_Filament_Dis, Filament_buf_ch, 8, true); + const uint16_t TemperatureConfig_buf_ch[] = { 0xC2CE, 0xC8B6, 0x2000 }; + dgus.writeStringVar(VP_TemperatureConfig_Dis, TemperatureConfig_buf_ch, 11); - const uint16_t Move_buf_ch[] = { 0xC6D2, 0xAFB6, 0x2000 }; - dgus.writeVariable(VP_Move_Dis, Move_buf_ch, 4, true); + const uint16_t Advance_buf_ch[] = { 0xDFB8, 0xB6BC, 0xE8C9, 0xC3D6, 0x2000 }; + dgus.writeStringVar(VP_Advance_Dis, Advance_buf_ch, 32); - #if ENABLED(AUTO_BED_LEVELING_BILINEAR) - const uint16_t Level_buf_ch[] = { 0xD4D7, 0xAFB6, 0xF7B5, 0xBDC6, 0x2000 }; - dgus.writeVariable(VP_Level_Dis, Level_buf_ch, 32, true); - #elif ENABLED(MESH_BED_LEVELING) - const uint16_t Level_buf_ch[] = { 0xF8CD, 0xF1B8, 0xF7B5, 0xBDC6, 0x2000 }; - dgus.writeVariable(VP_Level_Dis, Level_buf_ch, 32, true); - #else - const uint16_t Level_buf_ch[] = { 0xD6CA, 0xAFB6, 0xF7B5, 0xBDC6, 0x2000 }; - dgus.writeVariable(VP_Level_Dis, Level_buf_ch, 32, true); - #endif + const uint16_t Filament_buf_ch[] = { 0xB7BC, 0xF6B3, 0x2000 }; + dgus.writeStringVar(VP_Filament_Dis, Filament_buf_ch, 8); - const uint16_t MotorPluse_buf_ch[] = { 0xF6C2, 0xE5B3, 0x2000 }; - dgus.writeVariable(VP_MotorPluse_Dis, MotorPluse_buf_ch, 16, true); + const uint16_t Move_buf_ch[] = { 0xC6D2, 0xAFB6, 0x2000 }; + dgus.writeStringVar(VP_Move_Dis, Move_buf_ch, 4); - const uint16_t MotorMaxSpeed_buf_ch[] = { 0xEED7, 0xF3B4, 0xD9CB, 0xC8B6, 0x2000 }; - dgus.writeVariable(VP_MotorMaxSpeed_Dis, MotorMaxSpeed_buf_ch, 16, true); + const uint16_t Level_buf_ch[] = { + #if ENABLED(AUTO_BED_LEVELING_BILINEAR) + 0xD4D7, 0xAFB6 + #elif ENABLED(MESH_BED_LEVELING) + 0xF8CD, 0xF1B8 + #else + 0xD6CA, 0xAFB6 + #endif + , 0xF7B5, 0xBDC6, 0x2000 + }; + dgus.writeStringVar(VP_Level_Dis, Level_buf_ch, 32); - const uint16_t MotorMaxAcc_buf_ch[] = { 0xEED7, 0xF3B4, 0xD3BC, 0xD9CB, 0xC8B6, 0x2000 }; - dgus.writeVariable(VP_MotorMaxAcc_Dis, MotorMaxAcc_buf_ch, 16, true); + const uint16_t MotorPulse_buf_ch[] = { 0xF6C2, 0xE5B3, 0x2000 }; + dgus.writeStringVar(VP_MotorPulse_Dis, MotorPulse_buf_ch); - const uint16_t TravelAcc_buf_ch[] = { 0xD5BF, 0xD0D0, 0xD3BC, 0xD9CB, 0xC8B6, 0x2000 }; - dgus.writeVariable(VP_TravelAcc_Dis, TravelAcc_buf_ch, 16, true); + const uint16_t MotorMaxSpeed_buf_ch[] = { 0xEED7, 0xF3B4, 0xD9CB, 0xC8B6, 0x2000 }; + dgus.writeStringVar(VP_MotorMaxSpeed_Dis, MotorMaxSpeed_buf_ch); - const uint16_t FeedRateMin_buf_ch[] = { 0xEED7, 0xA1D0, 0xD9CB, 0xC8B6, 0x2000 }; - dgus.writeVariable(VP_FeedRateMin_Dis, FeedRateMin_buf_ch, 12, true); + const uint16_t MotorMaxAcc_buf_ch[] = { 0xEED7, 0xF3B4, 0xD3BC, 0xD9CB, 0xC8B6, 0x2000 }; + dgus.writeStringVar(VP_MotorMaxAcc_Dis, MotorMaxAcc_buf_ch); - const uint16_t TravelFeeRateMin_buf_ch[] = { 0xD5BF, 0xD0D0, 0xEED7, 0xA1D0, 0xD9CB, 0xC8B6, 0x2000 }; - dgus.writeVariable(VP_TravelFeeRateMin_Dis, TravelFeeRateMin_buf_ch, 24, true); + const uint16_t TravelAcc_buf_ch[] = { 0xD5BF, 0xD0D0, 0xD3BC, 0xD9CB, 0xC8B6, 0x2000 }; + dgus.writeStringVar(VP_TravelAcc_Dis, TravelAcc_buf_ch); - const uint16_t Acc_buf_ch[] = { 0xD3BC, 0xD9CB, 0xC8B6, 0x2000 }; - dgus.writeVariable(VP_ACC_Dis, Acc_buf_ch, 16, true); + const uint16_t FeedRateMin_buf_ch[] = { 0xEED7, 0xA1D0, 0xD9CB, 0xC8B6, 0x2000 }; + dgus.writeStringVar(VP_FeedRateMin_Dis, FeedRateMin_buf_ch, 12); - const uint16_t Point_One_buf_ch[] = { 0xDAB5, 0xBBD2, 0xE3B5, 0x2000 }; - dgus.writeVariable(VP_Point_One_Dis, Point_One_buf_ch, 12, true); + const uint16_t TravelFeeRateMin_buf_ch[] = { 0xD5BF, 0xD0D0, 0xEED7, 0xA1D0, 0xD9CB, 0xC8B6, 0x2000 }; + dgus.writeStringVar(VP_TravelFeeRateMin_Dis, TravelFeeRateMin_buf_ch, 24); - const uint16_t Point_Two_buf_ch[] = { 0xDAB5, 0xFEB6, 0xE3B5, 0x2000 }; - dgus.writeVariable(VP_Point_Two_Dis, Point_Two_buf_ch, 12, true); + const uint16_t Acc_buf_ch[] = { 0xD3BC, 0xD9CB, 0xC8B6, 0x2000 }; + dgus.writeStringVar(VP_ACC_Dis, Acc_buf_ch); - const uint16_t Point_Three_buf_ch[] = { 0xDAB5, 0xFDC8, 0xE3B5, 0x2000 }; - dgus.writeVariable(VP_Point_Three_Dis, Point_Three_buf_ch, 12, true); + const uint16_t Point_One_buf_ch[] = { 0xDAB5, 0xBBD2, 0xE3B5, 0x2000 }; + dgus.writeStringVar(VP_Point_One_Dis, Point_One_buf_ch, 12); - const uint16_t Point_Four_buf_ch[] = { 0xDAB5, 0xC4CB, 0xE3B5, 0x2000 }; - dgus.writeVariable(VP_Point_Four_Dis, Point_Four_buf_ch, 12, true); + const uint16_t Point_Two_buf_ch[] = { 0xDAB5, 0xFEB6, 0xE3B5, 0x2000 }; + dgus.writeStringVar(VP_Point_Two_Dis, Point_Two_buf_ch, 12); - const uint16_t Point_Five_buf_ch[] = { 0xDAB5, 0xE5CE, 0xE3B5, 0x2000 }; - dgus.writeVariable(VP_Point_Five_Dis, Point_Five_buf_ch, 12, true); + const uint16_t Point_Three_buf_ch[] = { 0xDAB5, 0xFDC8, 0xE3B5, 0x2000 }; + dgus.writeStringVar(VP_Point_Three_Dis, Point_Three_buf_ch, 12); - const uint16_t Extrusion_buf_ch[] = { 0xB7BC, 0xF6B3, 0xB7CD, 0x2000 }; - dgus.writeVariable(VP_Extrusion_Dis, Extrusion_buf_ch, 12, true); + const uint16_t Point_Four_buf_ch[] = { 0xDAB5, 0xC4CB, 0xE3B5, 0x2000 }; + dgus.writeStringVar(VP_Point_Four_Dis, Point_Four_buf_ch, 12); - const uint16_t HeatBed_buf_ch[] = { 0xC8C8, 0xB2B4, 0x2000 }; - dgus.writeVariable(VP_HeatBed_Dis, HeatBed_buf_ch, 12, true); + const uint16_t Point_Five_buf_ch[] = { 0xDAB5, 0xE5CE, 0xE3B5, 0x2000 }; + dgus.writeStringVar(VP_Point_Five_Dis, Point_Five_buf_ch, 12); - const uint16_t FactoryDefaults_buf_ch[] = { 0xD6BB, 0xB4B8, 0xF6B3, 0xA7B3, 0xE8C9, 0xC3D6, 0x2000 }; - dgus.writeVariable(VP_FactoryDefaults_Dis, FactoryDefaults_buf_ch, 16, true); + const uint16_t Extrusion_buf_ch[] = { 0xB7BC, 0xF6B3, 0xB7CD, 0x2000 }; + dgus.writeStringVar(VP_Extrusion_Dis, Extrusion_buf_ch, 12); - const uint16_t StoreSetting_buf_ch[] = { 0xA3B1, 0xE6B4, 0xE8C9, 0xC3D6, 0x2000 }; - dgus.writeVariable(VP_StoreSetting_Dis, StoreSetting_buf_ch, 16, true); + const uint16_t HeatBed_buf_ch[] = { 0xC8C8, 0xB2B4, 0x2000 }; + dgus.writeStringVar(VP_HeatBed_Dis, HeatBed_buf_ch, 12); - const uint16_t PrintPauseConfig_buf_ch[] = { 0xDDD4, 0xA3CD, 0xBBCE, 0xC3D6, 0x2000 }; - dgus.writeVariable(VP_PrintPauseConfig_Dis, PrintPauseConfig_buf_ch, 32, true); + const uint16_t FactoryDefaults_buf_ch[] = { 0xD6BB, 0xB4B8, 0xF6B3, 0xA7B3, 0xE8C9, 0xC3D6, 0x2000 }; + dgus.writeStringVar(VP_FactoryDefaults_Dis, FactoryDefaults_buf_ch); - const uint16_t X_Pluse_buf_ch[] = { 0x2058, 0xE1D6, 0xF6C2, 0xE5B3, 0x2000 }; - dgus.writeVariable(VP_X_Pluse_Dis, X_Pluse_buf_ch, 16, true); + const uint16_t StoreSetting_buf_ch[] = { 0xA3B1, 0xE6B4, 0xE8C9, 0xC3D6, 0x2000 }; + dgus.writeStringVar(VP_StoreSetting_Dis, StoreSetting_buf_ch); - const uint16_t Y_Pluse_buf_ch[] = { 0x2059, 0xE1D6, 0xF6C2, 0xE5B3, 0x2000 }; - dgus.writeVariable(VP_Y_Pluse_Dis, Y_Pluse_buf_ch, 16, true); + const uint16_t PrintPauseConfig_buf_ch[] = { 0xDDD4, 0xA3CD, 0xBBCE, 0xC3D6, 0x2000 }; + dgus.writeStringVar(VP_PrintPauseConfig_Dis, PrintPauseConfig_buf_ch, 32); - const uint16_t Z_Pluse_buf_ch[] = { 0x205A, 0xE1D6, 0xF6C2, 0xE5B3, 0x2000 }; - dgus.writeVariable(VP_Z_Pluse_Dis, Z_Pluse_buf_ch, 16, true); + const uint16_t X_Pulse_buf_ch[] = { 0x2058, 0xE1D6, 0xF6C2, 0xE5B3, 0x2000 }; + dgus.writeStringVar(VP_X_Pulse_Dis, X_Pulse_buf_ch); - const uint16_t E0_Pluse_buf_ch[] = { 0x3045, 0xE1D6, 0xF6C2, 0xE5B3, 0x2000 }; - dgus.writeVariable(VP_E0_Pluse_Dis, E0_Pluse_buf_ch, 16, true); + const uint16_t Y_Pulse_buf_ch[] = { 0x2059, 0xE1D6, 0xF6C2, 0xE5B3, 0x2000 }; + dgus.writeStringVar(VP_Y_Pulse_Dis, Y_Pulse_buf_ch); - const uint16_t E1_Pluse_buf_ch[] = { 0x3145, 0xE1D6, 0xF6C2, 0xE5B3, 0x2000 }; - dgus.writeVariable(VP_E1_Pluse_Dis, E1_Pluse_buf_ch, 16, true); + const uint16_t Z_Pulse_buf_ch[] = { 0x205A, 0xE1D6, 0xF6C2, 0xE5B3, 0x2000 }; + dgus.writeStringVar(VP_Z_Pulse_Dis, Z_Pulse_buf_ch); - const uint16_t X_Max_Speed_buf_ch[] = { 0x2058, 0xEED7, 0xF3B4, 0xD9CB, 0xC8B6, 0x2000 }; - dgus.writeVariable(VP_X_Max_Speed_Dis, X_Max_Speed_buf_ch, 16, true); + const uint16_t E0_Pulse_buf_ch[] = { 0x3045, 0xE1D6, 0xF6C2, 0xE5B3, 0x2000 }; + dgus.writeStringVar(VP_E0_Pulse_Dis, E0_Pulse_buf_ch); - const uint16_t Y_Max_Speed_buf_ch[] = { 0x2059, 0xEED7, 0xF3B4, 0xD9CB, 0xC8B6, 0x2000 }; - dgus.writeVariable(VP_Y_Max_Speed_Dis, Y_Max_Speed_buf_ch, 16, true); + const uint16_t E1_Pulse_buf_ch[] = { 0x3145, 0xE1D6, 0xF6C2, 0xE5B3, 0x2000 }; + dgus.writeStringVar(VP_E1_Pulse_Dis, E1_Pulse_buf_ch); - const uint16_t Z_Max_Speed_buf_ch[] = { 0x205A, 0xEED7, 0xF3B4, 0xD9CB, 0xC8B6, 0x2000 }; - dgus.writeVariable(VP_Z_Max_Speed_Dis, Z_Max_Speed_buf_ch, 16, true); + const uint16_t X_Max_Speed_buf_ch[] = { 0x2058, 0xEED7, 0xF3B4, 0xD9CB, 0xC8B6, 0x2000 }; + dgus.writeStringVar(VP_X_Max_Speed_Dis, X_Max_Speed_buf_ch); - const uint16_t E0_Max_Speed_buf_ch[] = { 0x3045, 0xEED7, 0xF3B4, 0xD9CB, 0xC8B6, 0x2000 }; - dgus.writeVariable(VP_E0_Max_Speed_Dis, E0_Max_Speed_buf_ch, 16, true); + const uint16_t Y_Max_Speed_buf_ch[] = { 0x2059, 0xEED7, 0xF3B4, 0xD9CB, 0xC8B6, 0x2000 }; + dgus.writeStringVar(VP_Y_Max_Speed_Dis, Y_Max_Speed_buf_ch); - const uint16_t E1_Max_Speed_buf_ch[] = { 0x3145, 0xEED7, 0xF3B4, 0xD9CB, 0xC8B6, 0x2000 }; - dgus.writeVariable(VP_E1_Max_Speed_Dis, E1_Max_Speed_buf_ch, 16, true); + const uint16_t Z_Max_Speed_buf_ch[] = { 0x205A, 0xEED7, 0xF3B4, 0xD9CB, 0xC8B6, 0x2000 }; + dgus.writeStringVar(VP_Z_Max_Speed_Dis, Z_Max_Speed_buf_ch); - const uint16_t X_Max_Acc_Speed_buf_ch[] = { 0x2058, 0xEED7, 0xF3B4, 0xD3BC, 0xD9CB, 0xC8B6, 0x2000 }; - dgus.writeVariable(VP_X_Max_Acc_Speed_Dis, X_Max_Acc_Speed_buf_ch, 16, true); + const uint16_t E0_Max_Speed_buf_ch[] = { 0x3045, 0xEED7, 0xF3B4, 0xD9CB, 0xC8B6, 0x2000 }; + dgus.writeStringVar(VP_E0_Max_Speed_Dis, E0_Max_Speed_buf_ch); - const uint16_t Y_Max_Acc_Speed_buf_ch[] = { 0x2059, 0xEED7, 0xF3B4, 0xD3BC, 0xD9CB, 0xC8B6, 0x2000 }; - dgus.writeVariable(VP_Y_Max_Acc_Speed_Dis, Y_Max_Acc_Speed_buf_ch, 16, true); + const uint16_t E1_Max_Speed_buf_ch[] = { 0x3145, 0xEED7, 0xF3B4, 0xD9CB, 0xC8B6, 0x2000 }; + dgus.writeStringVar(VP_E1_Max_Speed_Dis, E1_Max_Speed_buf_ch); - const uint16_t Z_Max_Acc_Speed_buf_ch[] = { 0x205A, 0xEED7, 0xF3B4, 0xD3BC, 0xD9CB, 0xC8B6, 0x2000 }; - dgus.writeVariable(VP_Z_Max_Acc_Speed_Dis, Z_Max_Acc_Speed_buf_ch, 16, true); + const uint16_t X_Max_Acc_Speed_buf_ch[] = { 0x2058, 0xEED7, 0xF3B4, 0xD3BC, 0xD9CB, 0xC8B6, 0x2000 }; + dgus.writeStringVar(VP_X_Max_Acc_Dis, X_Max_Acc_Speed_buf_ch); - const uint16_t E0_Max_Acc_Speed_buf_ch[] = { 0x3045, 0xEED7, 0xF3B4, 0xD3BC, 0xD9CB, 0xC8B6, 0x2000 }; - dgus.writeVariable(VP_E0_Max_Acc_Speed_Dis, E0_Max_Acc_Speed_buf_ch, 16, true); + const uint16_t Y_Max_Acc_Speed_buf_ch[] = { 0x2059, 0xEED7, 0xF3B4, 0xD3BC, 0xD9CB, 0xC8B6, 0x2000 }; + dgus.writeStringVar(VP_Y_Max_Acc_Dis, Y_Max_Acc_Speed_buf_ch); - const uint16_t E1_Max_Acc_Speed_buf_ch[] = { 0x3145, 0xEED7, 0xF3B4, 0xD3BC, 0xD9CB, 0xC8B6, 0x2000 }; - dgus.writeVariable(VP_E1_Max_Acc_Speed_Dis, E1_Max_Acc_Speed_buf_ch, 16, true); + const uint16_t Z_Max_Acc_Speed_buf_ch[] = { 0x205A, 0xEED7, 0xF3B4, 0xD3BC, 0xD9CB, 0xC8B6, 0x2000 }; + dgus.writeStringVar(VP_Z_Max_Acc_Dis, Z_Max_Acc_Speed_buf_ch); - const uint16_t X_PARK_POS_buf_ch[] = { 0x2058, 0xDDD4, 0xA3CD, 0xBBCE, 0xC3D6, 0x2000 }; - dgus.writeVariable(VP_X_PARK_POS_Dis, X_PARK_POS_buf_ch, 16, true); + const uint16_t E0_Max_Acc_Speed_buf_ch[] = { 0x3045, 0xEED7, 0xF3B4, 0xD3BC, 0xD9CB, 0xC8B6, 0x2000 }; + dgus.writeStringVar(VP_E0_Max_Acc_Dis, E0_Max_Acc_Speed_buf_ch); - const uint16_t Y_PARK_POS_buf_ch[] = { 0x2059, 0xDDD4, 0xA3CD, 0xBBCE, 0xC3D6, 0x2000 }; - dgus.writeVariable(VP_Y_PARK_POS_Dis, Y_PARK_POS_buf_ch, 16, true); + const uint16_t E1_Max_Acc_Speed_buf_ch[] = { 0x3145, 0xEED7, 0xF3B4, 0xD3BC, 0xD9CB, 0xC8B6, 0x2000 }; + dgus.writeStringVar(VP_E1_Max_Acc_Dis, E1_Max_Acc_Speed_buf_ch); - const uint16_t Z_PARK_POS_buf_ch[] = { 0x205A, 0xDDD4, 0xA3CD, 0xBBCE, 0xC3D6, 0x2000 }; - dgus.writeVariable(VP_Z_PARK_POS_Dis, Z_PARK_POS_buf_ch, 16, true); + const uint16_t X_PARK_POS_buf_ch[] = { 0x2058, 0xDDD4, 0xA3CD, 0xBBCE, 0xC3D6, 0x2000 }; + dgus.writeStringVar(VP_X_PARK_POS_Dis, X_PARK_POS_buf_ch); - const uint16_t Length_buf_ch[] = { 0xBDB2, 0xA4B3, 0x2000 }; - dgus.writeVariable(VP_Length_Dis, Length_buf_ch, 8, true); + const uint16_t Y_PARK_POS_buf_ch[] = { 0x2059, 0xDDD4, 0xA3CD, 0xBBCE, 0xC3D6, 0x2000 }; + dgus.writeStringVar(VP_Y_PARK_POS_Dis, Y_PARK_POS_buf_ch); - const uint16_t Speed_buf_ch[] = { 0xD9CB, 0xC8B6, 0x2000 }; - dgus.writeVariable(VP_Speed_Dis, Speed_buf_ch, 8, true); + const uint16_t Z_PARK_POS_buf_ch[] = { 0x205A, 0xDDD4, 0xA3CD, 0xBBCE, 0xC3D6, 0x2000 }; + dgus.writeStringVar(VP_Z_PARK_POS_Dis, Z_PARK_POS_buf_ch); - const uint16_t InOut_buf_ch[] = { 0xF8BD, 0xF6B3, 0x2000 }; - dgus.writeVariable(VP_InOut_Dis, InOut_buf_ch, 8, true); + const uint16_t Length_buf_ch[] = { 0xBDB2, 0xA4B3, 0x2000 }; + dgus.writeStringVar(VP_Length_Dis, Length_buf_ch, 8); - const uint16_t PrintTimet_buf_en[] = { 0xF2B4, 0xA1D3, 0xB1CA, 0xE4BC, 0x2000 }; - dgus.writeVariable(VP_PrintTime_Dis, PrintTimet_buf_en, 16, true); + const uint16_t Speed_buf_ch[] = { 0xD9CB, 0xC8B6, 0x2000 }; + dgus.writeStringVar(VP_Speed_Dis, Speed_buf_ch, 8); - const uint16_t E0_Temp_buf_ch[] = { 0x3045, 0xC2CE, 0xC8B6, 0x2000 }; - dgus.writeVariable(VP_E0_Temp_Dis, E0_Temp_buf_ch, 16, true); + const uint16_t InOut_buf_ch[] = { 0xF8BD, 0xF6B3, 0x2000 }; + dgus.writeStringVar(VP_InOut_Dis, InOut_buf_ch, 8); - const uint16_t E1_Temp_buf_ch[] = { 0x3145, 0xC2CE, 0xC8B6, 0x2000 }; - dgus.writeVariable(VP_E1_Temp_Dis, E1_Temp_buf_ch, 16, true); + const uint16_t PrintTimet_buf_ch[] = { 0xF2B4, 0xA1D3, 0xB1CA, 0xE4BC, 0x2000 }; + dgus.writeStringVar(VP_PrintTime_Dis, PrintTimet_buf_ch); - const uint16_t HB_Temp_buf_ch[] = { 0xC8C8, 0xB2B4, 0xC2CE, 0xC8B6, 0x2000 }; - dgus.writeVariable(VP_HB_Temp_Dis, HB_Temp_buf_ch, 16, true); + const uint16_t E0_Temp_buf_ch[] = { 0x3045, 0xC2CE, 0xC8B6, 0x2000 }; + dgus.writeStringVar(VP_E0_Temp_Dis, E0_Temp_buf_ch); - const uint16_t Feedrate_buf_ch[] = { 0xB7BC, 0xF6B3, 0xD9CB, 0xC8B6, 0x2000 }; - dgus.writeVariable(VP_Feedrate_Dis, Feedrate_buf_ch, 16, true); + const uint16_t E1_Temp_buf_ch[] = { 0x3145, 0xC2CE, 0xC8B6, 0x2000 }; + dgus.writeStringVar(VP_E1_Temp_Dis, E1_Temp_buf_ch); - const uint16_t PrintAcc_buf_ch[] = { 0xF2B4, 0xA1D3, 0xD9CB, 0xC8B6, 0x2000 }; - dgus.writeVariable(VP_PrintAcc_Dis, PrintAcc_buf_ch, 16, true); + const uint16_t HB_Temp_buf_ch[] = { 0xC8C8, 0xB2B4, 0xC2CE, 0xC8B6, 0x2000 }; + dgus.writeStringVar(VP_HB_Temp_Dis, HB_Temp_buf_ch); - const uint16_t FAN_Speed_buf_ch[] = { 0xE7B7, 0xC8C9, 0xD9CB, 0xC8B6, 0x2000 }; - dgus.writeVariable(VP_Fan_Speed_Dis, FAN_Speed_buf_ch, 16, true); + const uint16_t Feedrate_buf_ch[] = { 0xB7BC, 0xF6B3, 0xD9CB, 0xC8B6, 0x2000 }; + dgus.writeStringVar(VP_Feedrate_Dis, Feedrate_buf_ch); - const uint16_t Printing_buf_ch[] = { 0xF2B4, 0xA1D3, 0xD0D6, 0x2000 }; - dgus.writeVariable(VP_Printing_Dis, Printing_buf_ch, 16, true); + const uint16_t PrintAcc_buf_ch[] = { 0xF2B4, 0xA1D3, 0xD9CB, 0xC8B6, 0x2000 }; + dgus.writeStringVar(VP_PrintAcc_Dis, PrintAcc_buf_ch); - const uint16_t Info_EEPROM_1_buf_ch[] = { 0xC7CA, 0xF1B7, 0xA3B1, 0xE6B4, 0xE8C9, 0xC3D6, 0xBFA3, 0x2000 }; - dgus.writeVariable(VP_Info_EEPROM_1_Dis, Info_EEPROM_1_buf_ch, 32, true); + const uint16_t FAN_Speed_buf_ch[] = { 0xE7B7, 0xC8C9, 0xD9CB, 0xC8B6, 0x2000 }; + dgus.writeStringVar(VP_Fan_Speed_Dis, FAN_Speed_buf_ch); - const uint16_t Info_EEPROM_2_buf_ch[] = { 0xC7CA, 0xF1B7, 0xD6BB, 0xB4B8, 0xF6B3, 0xA7B3, 0xE8C9, 0xC3D6, 0xBFA3, 0x2000 }; - dgus.writeVariable(VP_Info_EEPROM_2_Dis, Info_EEPROM_2_buf_ch, 32, true); + const uint16_t Printing_buf_ch[] = { 0xF2B4, 0xA1D3, 0xD0D6, 0x2000 }; + dgus.writeStringVar(VP_Printing_Dis, Printing_buf_ch); - const uint16_t TMC_X_Step_buf_ch[] = { 0x2058, 0xE9C1, 0xF4C3, 0xC8B6, 0x2000 }; - dgus.writeVariable(VP_TMC_X_Step_Dis, TMC_X_Step_buf_ch, 16, true); + const uint16_t Info_EEPROM_1_buf_ch[] = { 0xC7CA, 0xF1B7, 0xA3B1, 0xE6B4, 0xE8C9, 0xC3D6, 0xBFA3, 0x2000 }; + dgus.writeStringVar(VP_Info_EEPROM_1_Dis, Info_EEPROM_1_buf_ch, 32); - const uint16_t TMC_Y_Step_buf_ch[] = { 0x2059, 0xE9C1, 0xF4C3, 0xC8B6, 0x2000 }; - dgus.writeVariable(VP_TMC_Y_Step_Dis, TMC_Y_Step_buf_ch, 16, true); + const uint16_t Info_EEPROM_2_buf_ch[] = { 0xC7CA, 0xF1B7, 0xD6BB, 0xB4B8, 0xF6B3, 0xA7B3, 0xE8C9, 0xC3D6, 0xBFA3, 0x2000 }; + dgus.writeStringVar(VP_Info_EEPROM_2_Dis, Info_EEPROM_2_buf_ch, 32); - const uint16_t TMC_Z_Step_buf_ch[] = { 0x205A, 0xE9C1, 0xF4C3, 0xC8B6, 0x2000 }; - dgus.writeVariable(VP_TMC_Z_Step_Dis, TMC_Z_Step_buf_ch, 16, true); + const uint16_t TMC_X_Step_buf_ch[] = { 0x2058, 0xE9C1, 0xF4C3, 0xC8B6, 0x2000 }; + dgus.writeStringVar(VP_TMC_X_Step_Dis, TMC_X_Step_buf_ch); - const uint16_t Info_PrintFinish_1_buf_ch[] = { 0xF2B4, 0xA1D3, 0xEACD, 0xC9B3, 0x2000 }; - dgus.writeVariable(VP_Info_PrintFinish_1_Dis, Info_PrintFinish_1_buf_ch, 32, true); + const uint16_t TMC_Y_Step_buf_ch[] = { 0x2059, 0xE9C1, 0xF4C3, 0xC8B6, 0x2000 }; + dgus.writeStringVar(VP_TMC_Y_Step_Dis, TMC_Y_Step_buf_ch); - const uint16_t TMC_X_Current_buf_ch[] = { 0x2058, 0xE1D6, 0xE7B5, 0xF7C1, 0x2000 }; - dgus.writeVariable(VP_TMC_X_Current_Dis, TMC_X_Current_buf_ch, 16, true); + const uint16_t TMC_Z_Step_buf_ch[] = { 0x205A, 0xE9C1, 0xF4C3, 0xC8B6, 0x2000 }; + dgus.writeStringVar(VP_TMC_Z_Step_Dis, TMC_Z_Step_buf_ch); - const uint16_t TMC_Y_Current_buf_ch[] = { 0x2059, 0xE1D6, 0xE7B5, 0xF7C1, 0x2000 }; - dgus.writeVariable(VP_TMC_Y_Current_Dis, TMC_Y_Current_buf_ch, 16, true); + const uint16_t Info_PrintFinish_1_buf_ch[] = { 0xF2B4, 0xA1D3, 0xEACD, 0xC9B3, 0x2000 }; + dgus.writeStringVar(VP_Info_PrintFinish_1_Dis, Info_PrintFinish_1_buf_ch, 32); - const uint16_t TMC_Z_Current_buf_ch[] = { 0x205A, 0xE1D6, 0xE7B5, 0xF7C1, 0x2000 }; - dgus.writeVariable(VP_TMC_Z_Current_Dis, TMC_Z_Current_buf_ch, 16, true); + const uint16_t TMC_X_Current_buf_ch[] = { 0x2058, 0xE1D6, 0xE7B5, 0xF7C1, 0x2000 }; + dgus.writeStringVar(VP_TMC_X_Current_Dis, TMC_X_Current_buf_ch); - const uint16_t TMC_E0_Current_buf_ch[] = { 0x3045, 0xE1D6, 0xE7B5, 0xF7C1, 0x2000 }; - dgus.writeVariable(VP_TMC_E0_Current_Dis, TMC_E0_Current_buf_ch, 16, true); + const uint16_t TMC_Y_Current_buf_ch[] = { 0x2059, 0xE1D6, 0xE7B5, 0xF7C1, 0x2000 }; + dgus.writeStringVar(VP_TMC_Y_Current_Dis, TMC_Y_Current_buf_ch); - const uint16_t TMC_X1_Current_buf_ch[] = { 0x3158, 0xE1D6, 0xE7B5, 0xF7C1, 0x2000 }; - dgus.writeVariable(VP_TMC_X1_Current_Dis, TMC_X1_Current_buf_ch, 16, true); + const uint16_t TMC_Z_Current_buf_ch[] = { 0x205A, 0xE1D6, 0xE7B5, 0xF7C1, 0x2000 }; + dgus.writeStringVar(VP_TMC_Z_Current_Dis, TMC_Z_Current_buf_ch); - const uint16_t TMC_Y1_Current_buf_ch[] = { 0x3159, 0xE1D6, 0xE7B5, 0xF7C1, 0x2000 }; - dgus.writeVariable(VP_TMC_Y1_Current_Dis, TMC_Y1_Current_buf_ch, 16, true); + const uint16_t TMC_E0_Current_buf_ch[] = { 0x3045, 0xE1D6, 0xE7B5, 0xF7C1, 0x2000 }; + dgus.writeStringVar(VP_TMC_E0_Current_Dis, TMC_E0_Current_buf_ch); - const uint16_t TMC_Z1_Current_buf_ch[] = { 0x315A, 0xE1D6, 0xE7B5, 0xF7C1, 0x2000 }; - dgus.writeVariable(VP_TMC_Z1_Current_Dis, TMC_Z1_Current_buf_ch, 16, true); + const uint16_t TMC_X1_Current_buf_ch[] = { 0x3158, 0xE1D6, 0xE7B5, 0xF7C1, 0x2000 }; + dgus.writeStringVar(VP_TMC_X1_Current_Dis, TMC_X1_Current_buf_ch); - const uint16_t TMC_E1_Current_buf_ch[] = { 0x3145, 0xE1D6, 0xE7B5, 0xF7C1, 0x2000 }; - dgus.writeVariable(VP_TMC_E1_Current_Dis, TMC_E1_Current_buf_ch, 16, true); + const uint16_t TMC_Y1_Current_buf_ch[] = { 0x3159, 0xE1D6, 0xE7B5, 0xF7C1, 0x2000 }; + dgus.writeStringVar(VP_TMC_Y1_Current_Dis, TMC_Y1_Current_buf_ch); - const uint16_t Min_Ex_Temp_buf_ch[] = { 0xEED7, 0xA1D0, 0xB7BC, 0xF6B3, 0xC2CE, 0xC8B6, 0x2000 }; - dgus.writeVariable(VP_Min_Ex_Temp_Dis, Min_Ex_Temp_buf_ch, 32, true); + const uint16_t TMC_Z1_Current_buf_ch[] = { 0x315A, 0xE1D6, 0xE7B5, 0xF7C1, 0x2000 }; + dgus.writeStringVar(VP_TMC_Z1_Current_Dis, TMC_Z1_Current_buf_ch); - const uint16_t AutoLEVEL_INFO1_buf_ch[] = { 0xEBC7, 0xB4B0, 0xC2CF, 0xB4B0, 0xA5C5, 0x2000 }; - dgus.writeVariable(VP_AutoLEVEL_INFO1, AutoLEVEL_INFO1_buf_ch, 32, true); + const uint16_t TMC_E1_Current_buf_ch[] = { 0x3145, 0xE1D6, 0xE7B5, 0xF7C1, 0x2000 }; + dgus.writeStringVar(VP_TMC_E1_Current_Dis, TMC_E1_Current_buf_ch); - const uint16_t EX_TEMP_INFO2_buf_ch[] = { 0xEBC7, 0xD4C9, 0xC8B5, 0x2000 }; - dgus.writeVariable(VP_EX_TEMP_INFO2_Dis, EX_TEMP_INFO2_buf_ch, 32, true); + const uint16_t Min_Ex_Temp_buf_ch[] = { 0xEED7, 0xA1D0, 0xB7BC, 0xF6B3, 0xC2CE, 0xC8B6, 0x2000 }; + dgus.writeStringVar(VP_Min_Ex_Temp_Dis, Min_Ex_Temp_buf_ch, 32); - const uint16_t EX_TEMP_INFO3_buf_ch[] = { 0xA1C8, 0xFBCF, 0xD3BC, 0xC8C8, 0x2000 }; - dgus.writeVariable(VP_EX_TEMP_INFO3_Dis, EX_TEMP_INFO3_buf_ch, 32, true); + const uint16_t AutoLEVEL_INFO1_buf_ch[] = { 0xEBC7, 0xB4B0, 0xC2CF, 0xB4B0, 0xA5C5, 0x2000 }; + dgus.writeStringVar(VP_AutoLEVEL_INFO1, AutoLEVEL_INFO1_buf_ch, 32); - const uint16_t PrintConfrim_Info_buf_ch[] = { 0xC7CA, 0xF1B7, 0xAABF, 0xBCCA, 0xF2B4, 0xA1D3, 0x2000 }; - dgus.writeVariable(VP_PrintConfrim_Info_Dis, PrintConfrim_Info_buf_ch, 32, true); + const uint16_t EX_TEMP_INFO2_buf_ch[] = { 0xEBC7, 0xD4C9, 0xC8B5, 0x2000 }; + dgus.writeStringVar(VP_EX_TEMP_INFO2_Dis, EX_TEMP_INFO2_buf_ch, 32); - const uint16_t StopPrintConfrim_Info_buf_ch[] = { 0xC7CA, 0xF1B7, 0xA3CD, 0xB9D6, 0xF2B4, 0xA1D3, 0x2000 }; - dgus.writeVariable(VP_StopPrintConfrim_Info_Dis, StopPrintConfrim_Info_buf_ch, 32, true); + const uint16_t EX_TEMP_INFO3_buf_ch[] = { 0xA1C8, 0xFBCF, 0xD3BC, 0xC8C8, 0x2000 }; + dgus.writeStringVar(VP_EX_TEMP_INFO3_Dis, EX_TEMP_INFO3_buf_ch, 32); - const uint16_t Printting_buf_ch[] = { 0xF2B4, 0xA1D3, 0xD0D6, 0x2000 }; - dgus.writeVariable(VP_Printting_Dis, Printting_buf_ch, 32, true); + const uint16_t PrintConfirm_Info_buf_ch[] = { 0xC7CA, 0xF1B7, 0xAABF, 0xBCCA, 0xF2B4, 0xA1D3, 0x2000 }; + dgus.writeStringVar(VP_PrintConfirm_Info_Dis, PrintConfirm_Info_buf_ch, 32); - const uint16_t LCD_BLK_buf_ch[] = { 0xB3B1, 0xE2B9, 0xE8C9, 0xC3D6, 0x2000 }; - dgus.writeVariable(VP_LCD_BLK_Dis, LCD_BLK_buf_ch, 32, true); - } + const uint16_t StopPrintConfirm_Info_buf_ch[] = { 0xC7CA, 0xF1B7, 0xA3CD, 0xB9D6, 0xF2B4, 0xA1D3, 0x2000 }; + dgus.writeStringVar(VP_StopPrintConfirm_Info_Dis, StopPrintConfirm_Info_buf_ch, 32); + + const uint16_t Printting_buf_ch[] = { 0xF2B4, 0xA1D3, 0xD0D6, 0x2000 }; + dgus.writeStringVar(VP_Printting_Dis, Printting_buf_ch, 32); + + const uint16_t LCD_BLK_buf_ch[] = { 0xB3B1, 0xE2B9, 0xE8C9, 0xC3D6, 0x2000 }; + dgus.writeStringVar(VP_LCD_BLK_Dis, LCD_BLK_buf_ch, 32); + + } break; // MKS_SimpleChinese + } // switch } #endif // DGUS_LCD_UI_MKS diff --git a/Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.h b/Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.h index 2a026f751e..7bcb7c0a02 100644 --- a/Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.h +++ b/Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.h @@ -25,6 +25,9 @@ enum DGUS_ScreenID : uint8_t; +enum MKS_Choose : uint8_t { MKS_Language_Choose, MKS_Language_NoChoose }; +enum MKS_Language : uint8_t { MKS_SimpleChinese, MKS_English }; + class DGUSScreenHandlerMKS : public DGUSScreenHandler { public: DGUSScreenHandlerMKS() = default; @@ -53,7 +56,7 @@ public: #if ENABLED(PREVENT_COLD_EXTRUSION) static void handleGetExMinTemp(DGUS_VP_Variable &var, void *val_ptr); #endif - static void languageDisplay(uint8_t var); + static void updateDisplayLanguage(); static void tmcChangeConfig(DGUS_VP_Variable &var, void *val_ptr); static void getTurnOffCtrl(DGUS_VP_Variable &var, void *val_ptr); static void languagePInit(); @@ -105,9 +108,6 @@ public: static bool loop(); }; -enum MKS_Choose : uint8_t { MKS_Language_Choose, MKS_Language_NoChoose }; -enum MKS_Language : uint8_t { MKS_SimpleChinese, MKS_English }; - extern MKS_Language mks_language_index; extern bool DGUSAutoTurnOff; diff --git a/Marlin/src/lcd/extui/dgus/origin/DGUSDisplayDef.cpp b/Marlin/src/lcd/extui/dgus/origin/DGUSDisplayDef.cpp index 4875020f55..ac408e8d9c 100644 --- a/Marlin/src/lcd/extui/dgus/origin/DGUSDisplayDef.cpp +++ b/Marlin/src/lcd/extui/dgus/origin/DGUSDisplayDef.cpp @@ -150,7 +150,7 @@ const struct DGUS_VP_Variable ListOfVP[] PROGMEM = { VPHELPER(VP_HOME_ALL, nullptr, screen.handleManualMove, nullptr), #endif - VPHELPER(VP_MOTOR_LOCK_UNLOK, nullptr, screen.handleMotorLockUnlock, nullptr), + VPHELPER(VP_MOTOR_LOCK_UNLOCK, nullptr, screen.handleMotorLockUnlock, nullptr), #if ENABLED(POWER_LOSS_RECOVERY) VPHELPER(VP_POWER_LOSS_RECOVERY, nullptr, screen.handlePowerLossRecovery, nullptr), #endif diff --git a/Marlin/src/lcd/extui/dgus/origin/DGUSDisplayDef.h b/Marlin/src/lcd/extui/dgus/origin/DGUSDisplayDef.h index 136b90e641..d34b90b45f 100644 --- a/Marlin/src/lcd/extui/dgus/origin/DGUSDisplayDef.h +++ b/Marlin/src/lcd/extui/dgus/origin/DGUSDisplayDef.h @@ -111,7 +111,7 @@ constexpr uint16_t VP_MOVE_E1 = 0x2112; //constexpr uint16_t VP_MOVE_E4 = 0x2118; //constexpr uint16_t VP_MOVE_E5 = 0x211A; constexpr uint16_t VP_HOME_ALL = 0x2120; -constexpr uint16_t VP_MOTOR_LOCK_UNLOK = 0x2130; +constexpr uint16_t VP_MOTOR_LOCK_UNLOCK = 0x2130; // Power loss recovery constexpr uint16_t VP_POWER_LOSS_RECOVERY = 0x2180; diff --git a/Marlin/src/lcd/extui/dgus/origin/DGUSScreenHandler.cpp b/Marlin/src/lcd/extui/dgus/origin/DGUSScreenHandler.cpp index 943d8c50a5..0afc8a25ad 100644 --- a/Marlin/src/lcd/extui/dgus/origin/DGUSScreenHandler.cpp +++ b/Marlin/src/lcd/extui/dgus/origin/DGUSScreenHandler.cpp @@ -143,7 +143,7 @@ void DGUSScreenHandler::screenChangeHook(DGUS_VP_Variable &var, void *val_ptr) { updateNewScreen(target); - #ifdef DEBUG_DGUSLCD + #if ENABLED(DEBUG_DGUSLCD) if (!findScreenVPMapList(target)) DEBUG_ECHOLNPGM("WARNING: No screen Mapping found for ", target); #endif } @@ -290,7 +290,9 @@ void DGUSScreenHandler::handleManualMove(DGUS_VP_Variable &var, void *val_ptr) { #endif break; case 1: // Load ABS - TERN_(PREHEAT_2_TEMP_HOTEND, e_temp = PREHEAT_2_TEMP_HOTEND); + #ifdef PREHEAT_2_TEMP_HOTEND + e_temp = PREHEAT_2_TEMP_HOTEND; + #endif break; case 2: // Load PET #ifdef PREHEAT_3_TEMP_HOTEND @@ -310,9 +312,9 @@ void DGUSScreenHandler::handleManualMove(DGUS_VP_Variable &var, void *val_ptr) { if (filament_data.action == 0) { // Go back to utility screen #if HAS_HOTEND - thermalManager.setTargetHotend(e_temp, ExtUI::extruder_t::E0); + thermalManager.setTargetHotend(e_temp, 0); #if HAS_MULTI_HOTEND - thermalManager.setTargetHotend(e_temp, ExtUI::extruder_t::E1); + thermalManager.setTargetHotend(e_temp, 1); #endif #endif gotoScreen(DGUS_SCREEN_UTILITY); @@ -322,13 +324,13 @@ void DGUSScreenHandler::handleManualMove(DGUS_VP_Variable &var, void *val_ptr) { default: return; #if HAS_HOTEND case VP_E0_FILAMENT_LOAD_UNLOAD: - filament_data.extruder = ExtUI::extruder_t::E0; + filament_data.extruder = 0; thermalManager.setTargetHotend(e_temp, filament_data.extruder); break; #endif #if HAS_MULTI_HOTEND case VP_E1_FILAMENT_LOAD_UNLOAD: - filament_data.extruder = ExtUI::extruder_t::E1; + filament_data.extruder = 1; thermalManager.setTargetHotend(e_temp, filament_data.extruder); break; #endif @@ -350,7 +352,7 @@ void DGUSScreenHandler::handleManualMove(DGUS_VP_Variable &var, void *val_ptr) { //gotoScreen(DGUS_SCREEN_FILAMENT_LOADING); filament_data.heated = true; } - movevalue = ExtUI::getAxisPosition_mm(filament_data.extruder) + movevalue; + movevalue = ExtUI::getAxisPosition_mm(filament_data.extruder ? ExtUI::extruder_t::E1 : ExtUI::extruder_t::E0) + movevalue; } else { // unload filament if (!filament_data.heated) { @@ -359,14 +361,14 @@ void DGUSScreenHandler::handleManualMove(DGUS_VP_Variable &var, void *val_ptr) { } // Before unloading extrude to prevent jamming if (filament_data.purge_length >= 0) { - movevalue = ExtUI::getAxisPosition_mm(filament_data.extruder) + movevalue; + movevalue = ExtUI::getAxisPosition_mm(filament_data.extruder ? ExtUI::extruder_t::E1 : ExtUI::extruder_t::E0) + movevalue; filament_data.purge_length -= movevalue; } else { - movevalue = ExtUI::getAxisPosition_mm(filament_data.extruder) - movevalue; + movevalue = ExtUI::getAxisPosition_mm(filament_data.extruder ? ExtUI::extruder_t::E1 : ExtUI::extruder_t::E0) - movevalue; } } - ExtUI::setAxisPosition_mm(movevalue, filament_data.extruder); + ExtUI::setAxisPosition_mm(movevalue, filament_data.extruder ? ExtUI::extruder_t::E1 : ExtUI::extruder_t::E0); } } #endif // DGUS_FILAMENT_LOADUNLOAD diff --git a/Marlin/src/lcd/extui/dgus_e3s1pro/DGUSSDCardHandler_Basic.cpp b/Marlin/src/lcd/extui/dgus_e3s1pro/DGUSSDCardHandler_Basic.cpp index 85c7b660a7..4cb0cdf89b 100644 --- a/Marlin/src/lcd/extui/dgus_e3s1pro/DGUSSDCardHandler_Basic.cpp +++ b/Marlin/src/lcd/extui/dgus_e3s1pro/DGUSSDCardHandler_Basic.cpp @@ -52,7 +52,7 @@ void DGUS_SDCardHandler::Reset() { currentSeekPos++; } - #ifdef DEBUG_DGUSLCD + #if ENABLED(DEBUG_DGUSLCD) DEBUG_ECHOPGM("Reset() :", fileCount); DEBUG_CHAR('/'); DEBUG_ECHOLN(currentSeekPos); @@ -71,7 +71,7 @@ void DGUS_SDCardHandler::onPageLoad(DGUS_SDCardHandler::page_t page) { uint16_t currentSeekPos = 0; uint16_t entriesCount = fileList.count(); - #ifdef DEBUG_DGUSLCD + #if ENABLED(DEBUG_DGUSLCD) DEBUG_ECHOLNPGM("onPageLoad(): seek page ", pageIndex); #endif while (currentFilePos < pageIndex * DGUS_E3S1PRO_BASIC_SDCARD_FILES_PER_PAGE @@ -83,7 +83,7 @@ void DGUS_SDCardHandler::onPageLoad(DGUS_SDCardHandler::page_t page) { currentFilePos++; } - #ifdef DEBUG_DGUSLCD + #if ENABLED(DEBUG_DGUSLCD) DEBUG_ECHOPGM("onPageLoad() :", currentFilePos); DEBUG_CHAR('/'); DEBUG_ECHOLN(currentSeekPos - 1); diff --git a/Marlin/src/lcd/extui/dgus_e3s1pro/DGUSScreenHandler.cpp b/Marlin/src/lcd/extui/dgus_e3s1pro/DGUSScreenHandler.cpp index c88412fe2c..938663f9b3 100644 --- a/Marlin/src/lcd/extui/dgus_e3s1pro/DGUSScreenHandler.cpp +++ b/Marlin/src/lcd/extui/dgus_e3s1pro/DGUSScreenHandler.cpp @@ -208,7 +208,7 @@ void DGUSScreenHandler::userConfirmation() { if (confirm_return_screen >= DGUS_ScreenID::FILE1 && confirm_return_screen <= DGUS_ScreenID::FILE4) dgus_sdcard_handler.onPageLoad(DGUS_SCREEN_TO_PAGE(confirm_return_screen)); - #ifdef DEBUG_DGUSLCD + #if ENABLED(DEBUG_DGUSLCD) DEBUG_ECHOLNPGM("trig confirmed, ret:", (uint16_t)confirm_return_screen); #endif diff --git a/Marlin/src/lcd/menu/menu_configuration.cpp b/Marlin/src/lcd/menu/menu_configuration.cpp index c581bab4e3..259a81fb0e 100644 --- a/Marlin/src/lcd/menu/menu_configuration.cpp +++ b/Marlin/src/lcd/menu/menu_configuration.cpp @@ -112,7 +112,7 @@ void menu_advanced_settings(); #else #define S1_SPACE(I) #endif - #define STOP_ITEM(A,I,M,L) TERN(HAS_##A##I##_##M##_STATE, _STOP_ITEM, _IF_1_ELSE)(STRINGIFY(A) STRINGIFY(I) S1_SPACE(I) " " L, A##I##_##M) + #define STOP_ITEM(A,I,M,L) TERN(HAS_##A##I##_##M##_STATE, _STOP_ITEM, OMIT)(STRINGIFY(A) STRINGIFY(I) S1_SPACE(I) " " L, A##I##_##M) #define STOP_MINMAX(A,I) STOP_ITEM(A,I,MIN,"Min") STOP_ITEM(A,I,MAX,"Max") #define FIL_ITEM(N) PSTRING_ITEM_N_P(N-1, MSG_FILAMENT_EN, FILAMENT_IS_OUT(N) ? PSTR("out") : PSTR("PRESENT"), SS_FULL); diff --git a/Marlin/src/module/endstops.h b/Marlin/src/module/endstops.h index 10ae915beb..1ef217b64a 100644 --- a/Marlin/src/module/endstops.h +++ b/Marlin/src/module/endstops.h @@ -32,7 +32,7 @@ #define ES_ENUM(A,M) _ES_ENUM(A,M) #define _ES_ITEM(N) , N -#define ES_ITEM(K,N) TERN(K,_ES_ITEM,_IF_1_ELSE)(N) +#define ES_ITEM(K,N) TERN(K,_ES_ITEM,OMIT)(N) #define _ESN_ITEM(K,A,M) ES_ITEM(K,ES_ENUM(A,M)) #define ES_MINMAX(A) ES_ITEM(HAS_##A##_MIN_STATE, ES_ENUM(A,MIN)) ES_ITEM(HAS_##A##_MAX_STATE, ES_ENUM(A,MAX)) diff --git a/Marlin/src/pins/samd/pins_MINITRONICS20.h b/Marlin/src/pins/samd/pins_MINITRONICS20.h index 83206e3bc6..0f61aea713 100644 --- a/Marlin/src/pins/samd/pins_MINITRONICS20.h +++ b/Marlin/src/pins/samd/pins_MINITRONICS20.h @@ -128,7 +128,7 @@ #endif // Verify that drivers match the hardware -#if (HAS_X_AXIS && !AXIS_DRIVER_TYPE_X(DRV8825)) || (HAS_Y_AXIS && !AXIS_DRIVER_TYPE_Y(DRV8825)) || (HAS_Z_AXIS && !AXIS_DRIVER_TYPE_Z(DRV8825)) || (HAS_EXTRUDER && !AXIS_DRIVER_TYPE_E0(DRV8825)) +#if (HAS_X_AXIS && !AXIS_DRIVER_TYPE_X(DRV8825)) || (HAS_Y_AXIS && !AXIS_DRIVER_TYPE_Y(DRV8825)) || (HAS_Z_AXIS && !AXIS_DRIVER_TYPE_Z(DRV8825)) || (HAS_EXTRUDERS && !AXIS_DRIVER_TYPE_E0(DRV8825)) #error "Minitronics v2.0 has hard-wired DRV8825 drivers. Comment out this line to continue." #endif diff --git a/buildroot/tests/FYSETC_F6 b/buildroot/tests/FYSETC_F6 index 6dd7bb60fa..4c647d57d4 100755 --- a/buildroot/tests/FYSETC_F6 +++ b/buildroot/tests/FYSETC_F6 @@ -13,6 +13,13 @@ restore_configs opt_set MOTHERBOARD BOARD_FYSETC_F6_13 LCD_SERIAL_PORT 1 DGUS_LCD_UI FYSETC exec_test $1 $2 "DGUS (FYSETC)" "$3" +# +# Test DGUS_LCD_UI MKS +# +restore_configs +opt_set MOTHERBOARD BOARD_FYSETC_F6_13 LCD_SERIAL_PORT 1 DGUS_LCD_UI MKS +exec_test $1 $2 "DGUS (MKS)" "$3" + # # Test DGUS_LCD_UI RELOADED # From 7a257ef3e1f229aabf857e93661b68d197635b61 Mon Sep 17 00:00:00 2001 From: schnurly <93942607+schnurly@users.noreply.github.com> Date: Sat, 5 Apr 2025 05:27:50 +0200 Subject: [PATCH 183/787] =?UTF-8?q?=F0=9F=9A=B8=20Fix=20MKS=20UI=20print?= =?UTF-8?q?=20done=20state=20(#27730)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/lcd/extui/mks_ui/draw_dialog.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Marlin/src/lcd/extui/mks_ui/draw_dialog.cpp b/Marlin/src/lcd/extui/mks_ui/draw_dialog.cpp index 4b2474a8e6..8713bf8909 100644 --- a/Marlin/src/lcd/extui/mks_ui/draw_dialog.cpp +++ b/Marlin/src/lcd/extui/mks_ui/draw_dialog.cpp @@ -123,6 +123,7 @@ static void btn_ok_event_cb(lv_obj_t *btn, lv_event_t event) { #endif } else if (DIALOG_IS(TYPE_FINISH_PRINT)) { + uiCfg.print_state = IDLE; clear_cur_ui(); lv_draw_ready_print(); } From c5de0c69e584ad1b22e5ee2e99b0459f6fc98135 Mon Sep 17 00:00:00 2001 From: narno2202 <130909513+narno2202@users.noreply.github.com> Date: Sat, 5 Apr 2025 06:17:30 +0200 Subject: [PATCH 184/787] =?UTF-8?q?=F0=9F=9A=B8=20Refactor=20MKS=20H43=20L?= =?UTF-8?q?CD=20(#27776)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Scott Lahteine --- .../src/lcd/extui/dgus/DGUSScreenHandler.cpp | 6 +- Marlin/src/lcd/extui/dgus/dgus_extui.cpp | 13 +- .../src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp | 201 +++----- .../src/lcd/extui/dgus/mks/DGUSDisplayDef.h | 128 ++--- .../lcd/extui/dgus/mks/DGUSScreenHandler.cpp | 475 +++++++----------- .../lcd/extui/dgus/mks/DGUSScreenHandler.h | 13 +- 6 files changed, 314 insertions(+), 522 deletions(-) diff --git a/Marlin/src/lcd/extui/dgus/DGUSScreenHandler.cpp b/Marlin/src/lcd/extui/dgus/DGUSScreenHandler.cpp index f85fc9beac..e40aab0bff 100644 --- a/Marlin/src/lcd/extui/dgus/DGUSScreenHandler.cpp +++ b/Marlin/src/lcd/extui/dgus/DGUSScreenHandler.cpp @@ -325,7 +325,11 @@ void DGUSScreenHandler::sendHeaterStatusToDisplay(DGUS_VP_Variable &var) { void DGUSScreenHandler::sdCardError() { DGUSScreenHandler::sdCardRemoved(); - sendInfoScreen(F("NOTICE"), nullptr, F("SD card error"), nullptr); + #if DGUS_LCD_UI_MKS + screen.sendInfoScreenMKS(F("NOTICE"), nullptr, F("SD card error"), nullptr, mks_language_index); + #else + sendInfoScreen(F("NOTICE"), nullptr, F("SD card error"), nullptr, true, true, true, true); + #endif setupConfirmAction(nullptr); gotoScreen(DGUS_SCREEN_POPUP); } diff --git a/Marlin/src/lcd/extui/dgus/dgus_extui.cpp b/Marlin/src/lcd/extui/dgus/dgus_extui.cpp index e68eed16fd..3706ca449c 100644 --- a/Marlin/src/lcd/extui/dgus/dgus_extui.cpp +++ b/Marlin/src/lcd/extui/dgus/dgus_extui.cpp @@ -43,7 +43,12 @@ namespace ExtUI { void onIdle() { screen.loop(); } void onPrinterKilled(FSTR_P const error, FSTR_P const) { - screen.sendInfoScreen(GET_TEXT_F(MSG_HALTED), error, FPSTR(NUL_STR), GET_TEXT_F(MSG_PLEASE_RESET)); + #if DGUS_LCD_UI_MKS + screen.sendInfoScreenMKS(GET_TEXT_F(MSG_HALTED), error, nullptr, GET_TEXT_F(MSG_PLEASE_RESET), mks_language_index); + #else + screen.sendInfoScreen(GET_TEXT_F(MSG_HALTED), error, FPSTR(NUL_STR), GET_TEXT_F(MSG_PLEASE_RESET)); + #endif + screen.gotoScreen(DGUS_SCREEN_KILL); while (!screen.loop()); // Wait while anything is left to be sent } @@ -64,7 +69,11 @@ namespace ExtUI { void onUserConfirmRequired(const char * const msg) { if (msg) { - screen.sendInfoScreen(F("Please confirm."), nullptr, msg, nullptr, true, true, false, true); + #if DGUS_LCD_UI_MKS + screen.sendInfoScreenMKS(F("Please confirm."), nullptr, msg, nullptr, mks_language_index); + #else + screen.sendInfoScreen(F("Please confirm."), nullptr, msg, nullptr, true, false, false, false); + #endif screen.setupConfirmAction(setUserConfirmed); screen.gotoScreen(DGUS_SCREEN_POPUP); } diff --git a/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp b/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp index 7288b03b18..4a67f78b8c 100644 --- a/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp +++ b/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp @@ -103,7 +103,7 @@ void MKS_resume_print_move() { float z_offset_add = 0; -xyz_int_t tmc_step; // = { 0, 0, 0 } +xyz_int_t tmc_stall_sens; // = { 0, 0, 0 } uint16_t lcd_default_light = 50; @@ -117,7 +117,10 @@ const uint16_t VPList_Boot[] PROGMEM = { }; #define MKSLIST_E_ITEM(N) VP_T_E##N##_Is, VP_T_E##N##_Set, +#define INFO_BAR REPEAT(EXTRUDERS, MKSLIST_E_ITEM) VP_T_Bed_Is, VP_T_Bed_Set, VP_Fan0_Percentage, +// Not defined in firmware 1.30 or 1.31 +/* const uint16_t VPList_Main[] PROGMEM = { // VP_M117, for completeness, but it cannot be auto-uploaded. #if HAS_HOTEND @@ -140,53 +143,31 @@ const uint16_t VPList_Main[] PROGMEM = { #endif 0x0000 }; +*/ const uint16_t MKSList_Home[] PROGMEM = { - // E Temp - REPEAT(EXTRUDERS, MKSLIST_E_ITEM) - // HB Temp - VP_T_Bed_Is, VP_T_Bed_Set, - // FAN - VP_Fan0_Percentage, - // Language - // VP_HOME_Dis, + INFO_BAR 0x0000 }; const uint16_t MKSList_Setting[] PROGMEM = { - // E Temp - REPEAT(EXTRUDERS, MKSLIST_E_ITEM) - // HB Temp - VP_T_Bed_Is, VP_T_Bed_Set, - // FAN - VP_Fan0_Percentage, - // Language - VP_Setting_Dis, + INFO_BAR + 0x0000 }; const uint16_t MKSList_Tool[] PROGMEM = { - // E Temp - REPEAT(EXTRUDERS, MKSLIST_E_ITEM) - // HB Temp - VP_T_Bed_Is, VP_T_Bed_Set, - // FAN - VP_Fan0_Percentage, - // Language - VP_Tool_Dis, - // LCD BLK + INFO_BAR + + // LCD BackLight VP_LCD_BLK, + 0x0000 }; const uint16_t MKSList_EXTRUDE[] PROGMEM = { - // E Temp - REPEAT(EXTRUDERS, MKSLIST_E_ITEM) - // HB Temp - VP_T_Bed_Is, VP_T_Bed_Set, - // FAN - VP_Fan0_Percentage, + INFO_BAR VP_Filament_distance, VP_Filament_speed, @@ -195,34 +176,19 @@ const uint16_t MKSList_EXTRUDE[] PROGMEM = { }; const uint16_t MKSList_LEVEL[] PROGMEM = { - // E Temp - REPEAT(EXTRUDERS, MKSLIST_E_ITEM) - // HB Temp - VP_T_Bed_Is, VP_T_Bed_Set, - // FAN - VP_Fan0_Percentage, + INFO_BAR 0x0000 }; const uint16_t MKSList_MOVE[] PROGMEM = { - // E Temp - REPEAT(EXTRUDERS, MKSLIST_E_ITEM) - // HB Temp - VP_T_Bed_Is, VP_T_Bed_Set, - // FAN - VP_Fan0_Percentage, + INFO_BAR 0x0000 }; const uint16_t MKSList_Print[] PROGMEM = { - // E Temp - REPEAT(EXTRUDERS, MKSLIST_E_ITEM) - // HB Temp - VP_T_Bed_Is, VP_T_Bed_Set, - // FAN - VP_Fan0_Percentage, + INFO_BAR // Print Percent VP_PrintProgress_Percentage, @@ -254,24 +220,13 @@ const uint16_t MKSList_SD_File[] PROGMEM = { }; const uint16_t MKSList_TempOnly[] PROGMEM = { - // E Temp - REPEAT(EXTRUDERS, MKSLIST_E_ITEM) - // HB Temp - VP_T_Bed_Is, VP_T_Bed_Set, - // FAN - VP_Fan0_Percentage, - // LCD BLK - VP_LCD_BLK, + INFO_BAR + 0x0000 }; -const uint16_t MKSList_Pulse[] PROGMEM = { - // E Temp - REPEAT(EXTRUDERS, MKSLIST_E_ITEM) - // HB Temp - VP_T_Bed_Is, VP_T_Bed_Set, - // FAN - VP_Fan0_Percentage, +const uint16_t MKSList_Steps_mm[] PROGMEM = { + INFO_BAR // Steps/mm VP_X_STEP_PER_MM, @@ -284,12 +239,7 @@ const uint16_t MKSList_Pulse[] PROGMEM = { }; const uint16_t MKSList_MaxSpeed[] PROGMEM = { - // E Temp - REPEAT(EXTRUDERS, MKSLIST_E_ITEM) - // HB Temp - VP_T_Bed_Is, VP_T_Bed_Set, - // FAN - VP_Fan0_Percentage, + INFO_BAR // Max Speed VP_X_MAX_SPEED, @@ -302,31 +252,20 @@ const uint16_t MKSList_MaxSpeed[] PROGMEM = { }; const uint16_t MKSList_MaxAcc[] PROGMEM = { - // E Temp - REPEAT(EXTRUDERS, MKSLIST_E_ITEM) - // HB Temp - VP_T_Bed_Is, VP_T_Bed_Set, - // FAN - VP_Fan0_Percentage, + INFO_BAR - // ACC - VP_ACC_SPEED, - VP_X_ACC_MAX_SPEED, - VP_Y_ACC_MAX_SPEED, - VP_Z_ACC_MAX_SPEED, - VP_E0_ACC_MAX_SPEED, - VP_E1_ACC_MAX_SPEED, + // Acceleration + VP_X_MAX_ACC, + VP_Y_MAX_ACC, + VP_Z_MAX_ACC, + VP_E0_MAX_ACC, + VP_E1_MAX_ACC, 0x0000 }; const uint16_t MKSList_PID[] PROGMEM = { - // E Temp - REPEAT(EXTRUDERS, MKSLIST_E_ITEM) - // HB Temp - VP_T_Bed_Is, VP_T_Bed_Set, - // FAN - VP_Fan0_Percentage, + INFO_BAR // PID VP_E0_PID_P, @@ -337,12 +276,7 @@ const uint16_t MKSList_PID[] PROGMEM = { }; const uint16_t MKSList_Level_Point[] PROGMEM = { - // E Temp - REPEAT(EXTRUDERS, MKSLIST_E_ITEM) - // HB Temp - VP_T_Bed_Is, VP_T_Bed_Set, - // FAN - VP_Fan0_Percentage, + INFO_BAR // Level Point VP_Level_Point_One_X, @@ -372,10 +306,7 @@ const uint16_t MKSList_Level_PrintConfig[] PROGMEM = { }; const uint16_t MKSList_PrintPauseConfig[] PROGMEM = { - // E Temp - REPEAT(EXTRUDERS, MKSLIST_E_ITEM) - // HB Temp - VP_T_Bed_Is, VP_T_Bed_Set, + INFO_BAR VP_X_PARK_POS, VP_Y_PARK_POS, @@ -384,11 +315,8 @@ const uint16_t MKSList_PrintPauseConfig[] PROGMEM = { 0x0000 }; -const uint16_t MKSList_MotoConfig[] PROGMEM = { - // E Temp - REPEAT(EXTRUDERS, MKSLIST_E_ITEM) - // HB Temp - VP_T_Bed_Is, VP_T_Bed_Set, +const uint16_t MKSList_MotionConfig[] PROGMEM = { + INFO_BAR VP_TRAVEL_SPEED, VP_FEEDRATE_MIN_SPEED, @@ -398,24 +326,18 @@ const uint16_t MKSList_MotoConfig[] PROGMEM = { }; const uint16_t MKSList_EX_Config[] PROGMEM = { - // E Temp - REPEAT(EXTRUDERS, MKSLIST_E_ITEM) - // HB Temp - VP_T_Bed_Is, VP_T_Bed_Set, + INFO_BAR VP_MIN_EX_T,VP_Min_EX_T_E, + 0x0000 }; const uint16_t MKSTMC_Config[] PROGMEM = { - // E Temp - REPEAT(EXTRUDERS, MKSLIST_E_ITEM) - // HB Temp - VP_T_Bed_Is, VP_T_Bed_Set, - VP_MIN_EX_T, + INFO_BAR - VP_TMC_X_STEP, - VP_TMC_Y_STEP, - VP_TMC_Z_STEP, + VP_TMC_X_SENS, + VP_TMC_Y_SENS, + VP_TMC_Z_SENS, VP_TMC_X1_Current, VP_TMC_Y1_Current, VP_TMC_X_Current, @@ -431,20 +353,23 @@ const uint16_t MKSTMC_Config[] PROGMEM = { const uint16_t MKSAuto_Level[] PROGMEM = { VP_MESH_LEVEL_POINT_DIS, VP_ZPos, + 0x0000 }; const uint16_t MKSOffset_Config[] PROGMEM = { - // E Temp - REPEAT(EXTRUDERS, MKSLIST_E_ITEM) + INFO_BAR + VP_OFFSET_X, VP_OFFSET_Y, VP_OFFSET_Z, + 0x0000 }; const uint16_t MKSBabyStep[] PROGMEM = { VP_ZOffset_DE_DIS, + 0x0000 }; @@ -472,14 +397,14 @@ const struct VPMapping VPMap[] PROGMEM = { { MKSLCD_SCREEN_PRINT, MKSList_Print }, // Page 7 { MKSLCD_SCREEN_PAUSE, MKSList_Print }, // Page 26 { MKSLCD_SCREEN_CHOOSE_FILE, MKSList_SD_File }, // Page 15 - { MKSLCD_SCREEN_MOTOR_PULSE, MKSList_Pulse }, // Page 51 - { MKSLCD_SCREEN_MOTOR_SPEED, MKSList_MaxSpeed }, // Page 55 - { MKSLCD_SCREEN_MOTOR_ACC_MAX, MKSList_MaxAcc }, // Page 53 + { MKSLCD_SCREEN_STEPS_MM, MKSList_Steps_mm }, // Page 51 + { MKSLCD_SCREEN_AXIS_SPEED, MKSList_MaxSpeed }, // Page 55 + { MKSLCD_SCREEN_AXIS_ACC_MAX, MKSList_MaxAcc }, // Page 53 { MKSLCD_SCREEN_LEVEL_DATA, MKSList_Level_Point }, // Page 48 { MKSLCD_PrintPause_SET, MKSList_PrintPauseConfig }, // Page 49 - { MKSLCD_FILAMENT_DATA, MKSList_SD_File }, // Page 50 + //{ MKSLCD_FILAMENT_DATA, MKSList_SD_File }, // Page 50 { MKSLCD_SCREEN_Config, MKSList_TempOnly }, // Page 46 - { MKSLCD_SCREEN_Config_MOTOR, MKSList_MotoConfig }, // Page 47 + { MKSLCD_SCREEN_Config_MOTOR, MKSList_MotionConfig }, // Page 47 { MKSLCD_PID, MKSList_PID }, // Page 56 { MKSLCD_ABOUT, MKSList_About }, // Page 36 { MKSLCD_SCREEN_PRINT_CONFIG, MKSList_Level_PrintConfig }, // Page 60 @@ -495,7 +420,7 @@ const struct VPMapping VPMap[] PROGMEM = { }; const char MarlinVersion[] PROGMEM = SHORT_BUILD_VERSION; -const char H43Version[] PROGMEM = "MKS H43_V1.30"; +const char H43Version[] PROGMEM = "MKS H43_V1.31"; const char Updata_Time[] PROGMEM = STRING_DISTRIBUTION_DATE; const struct DGUS_VP_Variable ListOfVP[] PROGMEM = { @@ -664,27 +589,27 @@ const struct DGUS_VP_Variable ListOfVP[] PROGMEM = { VPHELPER(VP_Z_MAX_SPEED, &planner.settings.max_feedrate_mm_s[Z_AXIS], screen.handleMaxSpeedChange, screen.sendFloatAsIntValueToDisplay<0>), #if HAS_HOTEND - VPHELPER(VP_E0_MAX_SPEED, &planner.settings.max_feedrate_mm_s[E_AXIS_N(0)], screen.handleExtruderMaxSpeedChange, screen.sendFloatAsIntValueToDisplay<0>), + VPHELPER(VP_E0_MAX_SPEED, &planner.settings.max_feedrate_mm_s[E_AXIS_N(0)], screen.handleMaxSpeedChange, screen.sendFloatAsIntValueToDisplay<0>), #if HAS_MULTI_HOTEND - VPHELPER(VP_E1_MAX_SPEED, &planner.settings.max_feedrate_mm_s[E_AXIS_N(1)], screen.handleExtruderMaxSpeedChange, screen.sendFloatAsIntValueToDisplay<0>), + VPHELPER(VP_E1_MAX_SPEED, &planner.settings.max_feedrate_mm_s[E_AXIS_N(1)], screen.handleMaxSpeedChange, screen.sendFloatAsIntValueToDisplay<0>), #endif #endif - VPHELPER(VP_X_ACC_MAX_SPEED, (uint16_t *)&planner.settings.max_acceleration_mm_per_s2[X_AXIS], screen.handleMaxAccChange, screen.sendWordValueToDisplay), - VPHELPER(VP_Y_ACC_MAX_SPEED, (uint16_t *)&planner.settings.max_acceleration_mm_per_s2[Y_AXIS], screen.handleMaxAccChange, screen.sendWordValueToDisplay), - VPHELPER(VP_Z_ACC_MAX_SPEED, (uint16_t *)&planner.settings.max_acceleration_mm_per_s2[Z_AXIS], screen.handleMaxAccChange, screen.sendWordValueToDisplay), + VPHELPER(VP_X_MAX_ACC, (uint16_t *)&planner.settings.max_acceleration_mm_per_s2[X_AXIS], screen.handleMaxAccChange, screen.sendWordValueToDisplay), + VPHELPER(VP_Y_MAX_ACC, (uint16_t *)&planner.settings.max_acceleration_mm_per_s2[Y_AXIS], screen.handleMaxAccChange, screen.sendWordValueToDisplay), + VPHELPER(VP_Z_MAX_ACC, (uint16_t *)&planner.settings.max_acceleration_mm_per_s2[Z_AXIS], screen.handleMaxAccChange, screen.sendWordValueToDisplay), #if HAS_HOTEND - VPHELPER(VP_E0_ACC_MAX_SPEED, (uint16_t *)&planner.settings.max_acceleration_mm_per_s2[E_AXIS_N(0)], screen.handleExtruderAccChange, screen.sendWordValueToDisplay), + VPHELPER(VP_E0_MAX_ACC, (uint16_t *)&planner.settings.max_acceleration_mm_per_s2[E_AXIS_N(0)], screen.handleMaxAccChange, screen.sendWordValueToDisplay), #if HAS_MULTI_HOTEND - VPHELPER(VP_E1_ACC_MAX_SPEED, (uint16_t *)&planner.settings.max_acceleration_mm_per_s2[E_AXIS_N(1)], screen.handleExtruderAccChange, screen.sendWordValueToDisplay), + VPHELPER(VP_E1_MAX_ACC, (uint16_t *)&planner.settings.max_acceleration_mm_per_s2[E_AXIS_N(1)], screen.handleMaxAccChange, screen.sendWordValueToDisplay), #endif #endif VPHELPER(VP_TRAVEL_SPEED, (uint16_t *)&planner.settings.travel_acceleration, screen.handleTravelAccChange, screen.sendFloatAsIntValueToDisplay<0>), VPHELPER(VP_FEEDRATE_MIN_SPEED, (uint16_t *)&planner.settings.min_feedrate_mm_s, screen.handleFeedRateMinChange, screen.sendFloatAsIntValueToDisplay<0>), VPHELPER(VP_T_F_SPEED, (uint16_t *)&planner.settings.min_travel_feedrate_mm_s, screen.handleMin_T_F, screen.sendFloatAsIntValueToDisplay<0>), - VPHELPER(VP_ACC_SPEED, (uint16_t *)&planner.settings.acceleration, screen.handleAccChange, screen.sendWordValueToDisplay), + //VPHELPER(VP_DEFAULT_ACC, (uint16_t *)&planner.settings.acceleration, screen.handleAccChange, screen.sendWordValueToDisplay), VPHELPER(VP_X_PARK_POS, &mks_park_pos.x, screen.getParkPos, screen.sendWordValueToDisplay), VPHELPER(VP_Y_PARK_POS, &mks_park_pos.y, screen.getParkPos, screen.sendWordValueToDisplay), @@ -696,13 +621,13 @@ const struct DGUS_VP_Variable ListOfVP[] PROGMEM = { #if ENABLED(SENSORLESS_HOMING) // TMC SENSORLESS Setting #if X_HAS_STEALTHCHOP - VPHELPER(VP_TMC_X_STEP, &tmc_step.x, screen.tmcChangeConfig, screen.sendTMCStepValue), + VPHELPER(VP_TMC_X_SENS, &tmc_stall_sens.x, screen.tmcChangeConfig, screen.sendTMCSensValue), #endif #if Y_HAS_STEALTHCHOP - VPHELPER(VP_TMC_Y_STEP, &tmc_step.y, screen.tmcChangeConfig, screen.sendTMCStepValue), + VPHELPER(VP_TMC_Y_SENS, &tmc_stall_sens.y, screen.tmcChangeConfig, screen.sendTMCSensValue), #endif #if Z_HAS_STEALTHCHOP - VPHELPER(VP_TMC_Z_STEP, &tmc_step.z, screen.tmcChangeConfig, screen.sendTMCStepValue), + VPHELPER(VP_TMC_Z_SENS, &tmc_stall_sens.z, screen.tmcChangeConfig, screen.sendTMCSensValue), #endif #endif @@ -753,9 +678,9 @@ const struct DGUS_VP_Variable ListOfVP[] PROGMEM = { #if ENABLED(EDITABLE_STEPS_PER_UNIT) #if HAS_HOTEND - VPHELPER(VP_E0_STEP_PER_MM, &planner.settings.axis_steps_per_mm[E_AXIS_N(0)], screen.handleStepPerMMExtruderChanged, screen.sendFloatAsIntValueToDisplay<0>), + VPHELPER(VP_E0_STEP_PER_MM, &planner.settings.axis_steps_per_mm[E_AXIS_N(0)], screen.handleStepPerMMChanged, screen.sendFloatAsIntValueToDisplay<0>), #if HAS_MULTI_HOTEND - VPHELPER(VP_E1_STEP_PER_MM, &planner.settings.axis_steps_per_mm[E_AXIS_N(1)], screen.handleStepPerMMExtruderChanged, screen.sendFloatAsIntValueToDisplay<0>), + VPHELPER(VP_E1_STEP_PER_MM, &planner.settings.axis_steps_per_mm[E_AXIS_N(1)], screen.handleStepPerMMChanged, screen.sendFloatAsIntValueToDisplay<0>), #endif #endif #endif diff --git a/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.h b/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.h index a0b95aa14a..a0e5b5d731 100644 --- a/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.h +++ b/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.h @@ -49,7 +49,7 @@ void MKS_resume_print_move(); extern float z_offset_add; -extern xyz_int_t tmc_step; +extern xyz_int_t tmc_stall_sens; extern uint16_t lcd_default_light; @@ -130,16 +130,16 @@ enum DGUS_ScreenID : uint8_t { MKSLCD_SCREEN_PRINT = 68, MKSLCD_SCREEN_PAUSE = 70, MKSLCD_SCREEN_CHOOSE_FILE = 87, - MKSLCD_SCREEN_NO_CHOOSE_FILE = 88, + //MKSLCD_SCREEN_NO_CHOOSE_FILE = 88, // Missing in 1.31 firmware MKSLCD_SCREEN_Config = 101, MKSLCD_SCREEN_Config_MOTOR = 103, - MKSLCD_SCREEN_MOTOR_PULSE = 104, - MKSLCD_SCREEN_MOTOR_SPEED = 102, - MKSLCD_SCREEN_MOTOR_ACC_MAX = 105, + MKSLCD_SCREEN_STEPS_MM = 104, + MKSLCD_SCREEN_AXIS_SPEED = 102, + MKSLCD_SCREEN_AXIS_ACC_MAX = 105, MKSLCD_SCREEN_PRINT_CONFIG = 72, MKSLCD_SCREEN_LEVEL_DATA = 106, MKSLCD_PrintPause_SET = 107, - MKSLCD_FILAMENT_DATA = 50, + //MKSLCD_FILAMENT_DATA = 50, // Missing in 1.31 firmware MKSLCD_ABOUT = 83, MKSLCD_PID = 108, MKSLCD_PAUSE_SETTING_MOVE = 98, @@ -185,16 +185,16 @@ enum DGUS_ScreenID : uint8_t { MKSLCD_SCREEN_PAUSE = 26, MKSLCD_SCREEN_PAUSE_PRESS = 26, MKSLCD_SCREEN_CHOOSE_FILE = 15, - MKSLCD_SCREEN_NO_CHOOSE_FILE = 17, + //MKSLCD_SCREEN_NO_CHOOSE_FILE = 17, // Missing in 1.30 firmware MKSLCD_SCREEN_Config = 46, MKSLCD_SCREEN_Config_MOTOR = 47, - MKSLCD_SCREEN_MOTOR_PULSE = 51, + MKSLCD_SCREEN_STEPS_MM = 51, MKSLCD_SCREEN_MOTOR_SPEED = 55, MKSLCD_SCREEN_MOTOR_ACC_MAX = 53, MKSLCD_SCREEN_PRINT_CONFIG = 60, MKSLCD_SCREEN_LEVEL_DATA = 48, MKSLCD_PrintPause_SET = 49, - MKSLCD_FILAMENT_DATA = 50, + //MKSLCD_FILAMENT_DATA = 50, // Missing in 1.31 firmware MKSLCD_ABOUT = 36, MKSLCD_PID = 56, MKSLCD_PAUSE_SETTING_MOVE = 58, @@ -214,7 +214,7 @@ enum DGUS_ScreenID : uint8_t { DGUS_SCREEN_CONFIRM = 240, DGUS_SCREEN_KILL = 250, //!< Kill Screen. Must always be 250 (to be able to display "Error wrong LCD Version") - DGUS_SCREEN_WAITING = 251, + DGUS_SCREEN_WAITING = 252, // Missing in 1.30 and 1.31 firmware, workaround DGUS_SCREEN_POPUP = 252, //!< special target, popup screen will also return this code to say "return to previous screen" DGUS_SCREEN_UNUSED = 255 }; @@ -226,23 +226,8 @@ constexpr uint8_t VP_M117_LEN = 0x20; // Heater status constexpr uint16_t VP_E0_STATUS = 0x3410; constexpr uint16_t VP_E1_STATUS = 0x3412; -//constexpr uint16_t VP_E2_STATUS = 0x3414; -//constexpr uint16_t VP_E3_STATUS = 0x3416; -//constexpr uint16_t VP_E4_STATUS = 0x3418; -//constexpr uint16_t VP_E5_STATUS = 0x341A; constexpr uint16_t VP_MOVE_OPTION = 0x3500; -// // PIDs -// constexpr uint16_t VP_E0_PID_P = 0x3700; // at the moment , uint16_t , 0~1638.4 -// constexpr uint16_t VP_E0_PID_I = 0x3702; -// constexpr uint16_t VP_E0_PID_D = 0x3704; -// constexpr uint16_t VP_E1_PID_P = 0x3706; // at the moment , uint16_t , 0~1638.4 -// constexpr uint16_t VP_E1_PID_I = 0x3708; -// constexpr uint16_t VP_E1_PID_D = 0x370A; -// constexpr uint16_t VP_BED_PID_P = 0x3710; -// constexpr uint16_t VP_BED_PID_I = 0x3712; -// constexpr uint16_t VP_BED_PID_D = 0x3714; - // Waiting screen status constexpr uint16_t VP_WAITING_STATUS = 0x3800; @@ -288,22 +273,11 @@ constexpr uint16_t SP_T_Bed_Set = 0x5040; constexpr uint16_t VP_POWER_LOSS_RECOVERY = 0x1680; /* -------------------------------0x2000-0x2FFF------------------------------- */ // Temperatures. + // Only E0 and E1 are present in H43 firmware constexpr uint16_t VP_T_E0_Is = 0x2000; // 4 Byte Integer constexpr uint16_t VP_T_E0_Set = 0x2004; // 2 Byte Integer constexpr uint16_t VP_T_E1_Is = 0x2008; // 4 Byte Integer constexpr uint16_t VP_T_E1_Set = 0x200B; // 2 Byte Integer - constexpr uint16_t VP_T_E2_Is = 0x2010; // 4 Byte Integer - constexpr uint16_t VP_T_E2_Set = 0x2014; // 2 Byte Integer - constexpr uint16_t VP_T_E3_Is = 0x2018; // 4 Byte Integer - constexpr uint16_t VP_T_E3_Set = 0x201B; // 2 Byte Integer - constexpr uint16_t VP_T_E4_Is = 0x2020; // 4 Byte Integer - constexpr uint16_t VP_T_E4_Set = 0x2024; // 2 Byte Integer - constexpr uint16_t VP_T_E5_Is = 0x2028; // 4 Byte Integer - constexpr uint16_t VP_T_E5_Set = 0x202B; // 2 Byte Integer - constexpr uint16_t VP_T_E6_Is = 0x2030; // 4 Byte Integer - constexpr uint16_t VP_T_E6_Set = 0x2034; // 2 Byte Integer - constexpr uint16_t VP_T_E7_Is = 0x2038; // 4 Byte Integer - constexpr uint16_t VP_T_E7_Set = 0x203B; // 2 Byte Integer constexpr uint16_t VP_T_Bed_Is = 0x2040; // 4 Byte Integer constexpr uint16_t VP_T_Bed_Set = 0x2044; // 2 Byte Integer @@ -312,12 +286,6 @@ constexpr uint16_t SP_T_Bed_Set = 0x5040; constexpr uint16_t VP_Flowrate_E0 = 0x2200; // 2 Byte Integer constexpr uint16_t VP_Flowrate_E1 = 0x2202; // 2 Byte Integer - constexpr uint16_t VP_Flowrate_E2 = 0x2204; - constexpr uint16_t VP_Flowrate_E3 = 0x2206; - constexpr uint16_t VP_Flowrate_E4 = 0x2208; - constexpr uint16_t VP_Flowrate_E5 = 0x220A; - constexpr uint16_t VP_Flowrate_E6 = 0x220C; - constexpr uint16_t VP_Flowrate_E7 = 0x220E; // Move constexpr uint16_t VP_MOVE_X = 0x2300; @@ -325,12 +293,6 @@ constexpr uint16_t SP_T_Bed_Set = 0x5040; constexpr uint16_t VP_MOVE_Z = 0x2304; constexpr uint16_t VP_MOVE_E0 = 0x2310; constexpr uint16_t VP_MOVE_E1 = 0x2312; - constexpr uint16_t VP_MOVE_E2 = 0x2314; - constexpr uint16_t VP_MOVE_E3 = 0x2316; - constexpr uint16_t VP_MOVE_E4 = 0x2318; - constexpr uint16_t VP_MOVE_E5 = 0x231A; - constexpr uint16_t VP_MOVE_E6 = 0x231C; - constexpr uint16_t VP_MOVE_E7 = 0x231E; constexpr uint16_t VP_HOME_ALL = 0x2320; constexpr uint16_t VP_MOTOR_LOCK_UNLOCK = 0x2330; @@ -350,9 +312,6 @@ constexpr uint16_t SP_T_Bed_Set = 0x5040; constexpr uint16_t VP_LANGUAGE_CHANGE = 0x2380; constexpr uint16_t VP_LANGUAGE_CHANGE1 = 0x2382; constexpr uint16_t VP_LANGUAGE_CHANGE2 = 0x2384; - constexpr uint16_t VP_LANGUAGE_CHANGE3 = 0x2386; - constexpr uint16_t VP_LANGUAGE_CHANGE4 = 0x2388; - constexpr uint16_t VP_LANGUAGE_CHANGE5 = 0x238A; // LEVEL constexpr uint16_t VP_LEVEL_POINT = 0x2400; @@ -396,12 +355,6 @@ constexpr uint16_t SP_T_Bed_Set = 0x5040; constexpr uint16_t VP_Z_STEP_PER_MM = 0x2908; constexpr uint16_t VP_E0_STEP_PER_MM = 0x2910; constexpr uint16_t VP_E1_STEP_PER_MM = 0x2912; - constexpr uint16_t VP_E2_STEP_PER_MM = 0x2914; - constexpr uint16_t VP_E3_STEP_PER_MM = 0x2916; - constexpr uint16_t VP_E4_STEP_PER_MM = 0x2918; - constexpr uint16_t VP_E5_STEP_PER_MM = 0x291A; - constexpr uint16_t VP_E6_STEP_PER_MM = 0x291C; - constexpr uint16_t VP_E7_STEP_PER_MM = 0x291E; constexpr uint16_t VP_X_MAX_SPEED = 0x2A00; constexpr uint16_t VP_Y_MAX_SPEED = 0x2A04; @@ -409,16 +362,16 @@ constexpr uint16_t SP_T_Bed_Set = 0x5040; constexpr uint16_t VP_E0_MAX_SPEED = 0x2A0C; constexpr uint16_t VP_E1_MAX_SPEED = 0x2A10; - constexpr uint16_t VP_X_ACC_MAX_SPEED = 0x2A28; - constexpr uint16_t VP_Y_ACC_MAX_SPEED = 0x2A2C; - constexpr uint16_t VP_Z_ACC_MAX_SPEED = 0x2A30; - constexpr uint16_t VP_E0_ACC_MAX_SPEED = 0x2A34; - constexpr uint16_t VP_E1_ACC_MAX_SPEED = 0x2A38; + constexpr uint16_t VP_X_MAX_ACC = 0x2A28; + constexpr uint16_t VP_Y_MAX_ACC = 0x2A2C; + constexpr uint16_t VP_Z_MAX_ACC = 0x2A30; + constexpr uint16_t VP_E0_MAX_ACC = 0x2A34; + constexpr uint16_t VP_E1_MAX_ACC = 0x2A38; constexpr uint16_t VP_TRAVEL_SPEED = 0x2A3C; constexpr uint16_t VP_FEEDRATE_MIN_SPEED = 0x2A40; constexpr uint16_t VP_T_F_SPEED = 0x2A44; - constexpr uint16_t VP_ACC_SPEED = 0x2A48; + constexpr uint16_t VP_DEFAULT_ACC = 0x2A48; /* -------------------------------0x3000-0x3FFF------------------------------- */ // Buttons on the SD-Card File listing. @@ -479,9 +432,9 @@ constexpr uint16_t SP_T_Bed_Set = 0x5040; constexpr uint16_t VP_BED_STATUS = 0x341C; - constexpr uint16_t VP_TMC_X_STEP = 0x3430; - constexpr uint16_t VP_TMC_Y_STEP = 0x3432; - constexpr uint16_t VP_TMC_Z_STEP = 0x3434; + constexpr uint16_t VP_TMC_X_SENS = 0x3430; + constexpr uint16_t VP_TMC_Y_SENS = 0x3432; + constexpr uint16_t VP_TMC_Z_SENS = 0x3434; constexpr uint16_t VP_TMC_X1_Current = 0x3436; constexpr uint16_t VP_TMC_Y1_Current = 0x3438; @@ -516,10 +469,6 @@ constexpr uint16_t SP_T_Bed_Set = 0x5040; // PID autotune constexpr uint16_t VP_PID_AUTOTUNE_E0 = 0x3800; constexpr uint16_t VP_PID_AUTOTUNE_E1 = 0x3802; - constexpr uint16_t VP_PID_AUTOTUNE_E2 = 0x3804; - constexpr uint16_t VP_PID_AUTOTUNE_E3 = 0x3806; - constexpr uint16_t VP_PID_AUTOTUNE_E4 = 0x3808; - constexpr uint16_t VP_PID_AUTOTUNE_E5 = 0x380A; constexpr uint16_t VP_PID_AUTOTUNE_BED = 0x380C; // Calibrate Z @@ -536,19 +485,11 @@ constexpr uint16_t SP_T_Bed_Set = 0x5040; // Heater Control Buttons , triged between "cool down" and "heat PLA" state constexpr uint16_t VP_E0_CONTROL = 0x4010; constexpr uint16_t VP_E1_CONTROL = 0x4012; - //constexpr uint16_t VP_E2_CONTROL = 0x2214; - //constexpr uint16_t VP_E3_CONTROL = 0x2216; - //constexpr uint16_t VP_E4_CONTROL = 0x2218; - //constexpr uint16_t VP_E5_CONTROL = 0x221A; constexpr uint16_t VP_BED_CONTROL = 0x401C; // Preheat constexpr uint16_t VP_E0_BED_PREHEAT = 0x4020; constexpr uint16_t VP_E1_BED_PREHEAT = 0x4022; - //constexpr uint16_t VP_E2_BED_PREHEAT = 0x4024; - //constexpr uint16_t VP_E3_BED_PREHEAT = 0x4026; - //constexpr uint16_t VP_E4_BED_PREHEAT = 0x4028; - //constexpr uint16_t VP_E5_BED_PREHEAT = 0x402A; // Filament load and unload //constexpr uint16_t VP_E0_FILAMENT_LOAD_UNLOAD = 0x4030; @@ -578,22 +519,21 @@ constexpr uint16_t SP_T_Bed_Set = 0x5040; constexpr uint16_t VP_HOME_Dis = 0x5000; constexpr uint16_t VP_Setting_Dis = 0x5010; constexpr uint16_t VP_Tool_Dis = 0x5020; - constexpr uint16_t VP_Printing_Dis = 0x5030; constexpr uint16_t VP_Print_Dis = 0x5250; constexpr uint16_t VP_Language_Dis = 0x5080; constexpr uint16_t VP_LossPoint_Dis = 0x5090; constexpr uint16_t VP_PrintPauseConfig_Dis = 0x5120; - constexpr uint16_t VP_MotorPulse_Dis = 0x5140; - constexpr uint16_t VP_MotorMaxSpeed_Dis = 0x5150; - constexpr uint16_t VP_MotorMaxAcc_Dis = 0x5160; + constexpr uint16_t VP_AxisRes_Dis = 0x5140; + constexpr uint16_t VP_AxisMaxSpeed_Dis = 0x5150; + constexpr uint16_t VP_AxisMaxAcc_Dis = 0x5160; - constexpr uint16_t VP_X_Pulse_Dis = 0x5170; - constexpr uint16_t VP_Y_Pulse_Dis = 0x5180; - constexpr uint16_t VP_Z_Pulse_Dis = 0x5190; - constexpr uint16_t VP_E0_Pulse_Dis = 0x51A0; - constexpr uint16_t VP_E1_Pulse_Dis = 0x51B0; + constexpr uint16_t VP_X_Steps_mm_Dis = 0x5170; + constexpr uint16_t VP_Y_Steps_mm_Dis = 0x5180; + constexpr uint16_t VP_Z_Steps_mm_Dis = 0x5190; + constexpr uint16_t VP_E0_Steps_mm_Dis = 0x51A0; + constexpr uint16_t VP_E1_Steps_mm_Dis = 0x51B0; constexpr uint16_t VP_X_Max_Speed_Dis = 0x5280; constexpr uint16_t VP_Y_Max_Speed_Dis = 0x5290; @@ -629,7 +569,7 @@ constexpr uint16_t SP_T_Bed_Set = 0x5040; constexpr uint16_t VP_Extrusion_Dis = 0x5230; constexpr uint16_t VP_HeatBed_Dis = 0x5240; - constexpr uint16_t VP_Printting_Dis = 0x5430; + constexpr uint16_t VP_Printing_Dis = 0x5430; constexpr uint16_t VP_FactoryDefaults_Dis = 0x54C0; constexpr uint16_t VP_StoreSetting_Dis = 0x54B0; constexpr uint16_t VP_Info_EEPROM_2_Dis = 0x54D0; @@ -637,9 +577,9 @@ constexpr uint16_t SP_T_Bed_Set = 0x5040; constexpr uint16_t VP_AutoLevel_1_Dis = 0x55F0; - constexpr uint16_t VP_TMC_X_Step_Dis = 0x5530; - constexpr uint16_t VP_TMC_Y_Step_Dis = 0x5540; - constexpr uint16_t VP_TMC_Z_Step_Dis = 0x5550; + constexpr uint16_t VP_TMC_X_SENS_Dis = 0x5530; + constexpr uint16_t VP_TMC_Y_SENS_Dis = 0x5540; + constexpr uint16_t VP_TMC_Z_SENS_Dis = 0x5550; constexpr uint16_t VP_TMC_X1_Current_Dis = 0x5560; constexpr uint16_t VP_TMC_Y1_Current_Dis = 0x5570; constexpr uint16_t VP_TMC_X_Current_Dis = 0x5580; @@ -653,6 +593,9 @@ constexpr uint16_t SP_T_Bed_Set = 0x5040; constexpr uint16_t VP_EX_TEMP_INFO1_Dis = 0x5610; constexpr uint16_t VP_EX_TEMP_INFO2_Dis = 0x5620; constexpr uint16_t VP_EX_TEMP_INFO3_Dis = 0x5630; + constexpr uint16_t VP_X_Offset_Dis = 0x5660; + constexpr uint16_t VP_Y_Offset_Dis = 0x5670; + constexpr uint16_t VP_Z_Offset_Dis = 0x5680; constexpr uint16_t VP_LCD_BLK_Dis = 0x56A0; constexpr uint16_t VP_Info_PrintFinish_1_Dis = 0x5C00; constexpr uint16_t VP_Info_PrintFinish_2_Dis = 0x5C10; @@ -678,6 +621,7 @@ constexpr uint16_t SP_T_Bed_Set = 0x5040; constexpr uint16_t VP_MotorConfig_Dis = 0x5100; constexpr uint16_t VP_LevelConfig_Dis = 0x5110; + constexpr uint16_t VP_Probe_Offset_Dis = 0x5650; constexpr uint16_t VP_Advance_Dis = 0x5130; constexpr uint16_t VP_TemperatureConfig_Dis = 0x5390; diff --git a/Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.cpp b/Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.cpp index 0ac704ed3d..b24c6d5e2e 100644 --- a/Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.cpp +++ b/Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.cpp @@ -58,29 +58,33 @@ bool DGUSAutoTurnOff = false; MKS_Language mks_language_index; // Initialized by settings.load -#if 0 -void DGUSScreenHandlerMKS::sendinfoscreen_ch(const uint16_t *line1, const uint16_t *line2, const uint16_t *line3, const uint16_t *line4) { - dgus.writeStringVar(VP_MSGSTR1, line1, 32); - dgus.writeStringVar(VP_MSGSTR2, line2, 32); - dgus.writeStringVar(VP_MSGSTR3, line3, 32); - dgus.writeStringVar(VP_MSGSTR4, line4, 32); -} - -void DGUSScreenHandlerMKS::sendinfoscreen_en(PGM_P const line1, PGM_P const line2, PGM_P const line3, PGM_P const line4) { +void DGUSScreenHandlerMKS::sendInfoScreen(const uint16_t *line1, const uint16_t *line2, const uint16_t *line3, const uint16_t *line4) { dgus.writeStringVar(VP_MSGSTR1, line1); dgus.writeStringVar(VP_MSGSTR2, line2); dgus.writeStringVar(VP_MSGSTR3, line3); dgus.writeStringVar(VP_MSGSTR4, line4); } -void DGUSScreenHandlerMKS::sendInfoScreen(const void *line1, const void *line2, const void *line3, const void *line4, uint16_t language) { - if (language == MKS_English) - DGUSScreenHandlerMKS::sendinfoscreen_en((char *)line1, (char *)line2, (char *)line3, (char *)line4); - else if (language == MKS_SimpleChinese) - DGUSScreenHandlerMKS::sendinfoscreen_ch((uint16_t *)line1, (uint16_t *)line2, (uint16_t *)line3, (uint16_t *)line4); +void DGUSScreenHandlerMKS::sendInfoScreen(const char *line1, const char *line2, const char *line3, const char *line4) { + dgus.writeStringVar(VP_MSGSTR1, line1); + dgus.writeStringVar(VP_MSGSTR2, line2); + dgus.writeStringVar(VP_MSGSTR3, line3); + dgus.writeStringVar(VP_MSGSTR4, line4); } -#endif +void DGUSScreenHandlerMKS::sendInfoScreen_P(PGM_P const line1, PGM_P const line2, PGM_P const line3, PGM_P const line4) { + dgus.writeStringVar_P(VP_MSGSTR1, line1); + dgus.writeStringVar_P(VP_MSGSTR2, line2); + dgus.writeStringVar_P(VP_MSGSTR3, line3); + dgus.writeStringVar_P(VP_MSGSTR4, line4); +} + +void DGUSScreenHandlerMKS::sendInfoScreenMKS(const void *line1, const void *line2, const void *line3, const void *line4, const MKS_Language language) { + if (language == MKS_English) + DGUSScreenHandlerMKS::sendInfoScreen_P((char *)line1, (char *)line2, (char *)line3, (char *)line4); + else if (language == MKS_SimpleChinese) + DGUSScreenHandlerMKS::sendInfoScreen((uint16_t *)line1, (uint16_t *)line2, (uint16_t *)line3, (uint16_t *)line4); +} void DGUSScreenHandlerMKS::sendFanToDisplay(DGUS_VP_Variable &var) { if (var.memadr) { @@ -130,18 +134,18 @@ void DGUSScreenHandlerMKS::sendStringToDisplay_Language(DGUS_VP_Variable &var) { } } -void DGUSScreenHandlerMKS::sendTMCStepValue(DGUS_VP_Variable &var) { +void DGUSScreenHandlerMKS::sendTMCSensValue(DGUS_VP_Variable &var) { #if ENABLED(SENSORLESS_HOMING) #if X_HAS_STEALTHCHOP - tmc_step.x = stepperX.homing_threshold(); + tmc_stall_sens.x = stepperX.homing_threshold(); dgus.writeVariable(var.VP, *(int16_t*)var.memadr); #endif #if Y_HAS_STEALTHCHOP - tmc_step.y = stepperY.homing_threshold(); + tmc_stall_sens.y = stepperY.homing_threshold(); dgus.writeVariable(var.VP, *(int16_t*)var.memadr); #endif #if Z_HAS_STEALTHCHOP - tmc_step.z = stepperZ.homing_threshold(); + tmc_stall_sens.z = stepperZ.homing_threshold(); dgus.writeVariable(var.VP, *(int16_t*)var.memadr); #endif #endif @@ -475,10 +479,8 @@ void DGUSScreenHandlerMKS::meshLevel(DGUS_VP_Variable &var, void *val_ptr) { case 0: offset = mesh_adj_distance; integer = offset; // get int - Deci = (offset * 10); - Deci = Deci % 10; - Deci2 = offset * 100; - Deci2 = Deci2 % 10; + Deci = (offset * 10) % 10; + Deci2 = (offset * 100) % 10; soft_endstop._enabled = false; queue.enqueue_now(F("G91")); snprintf_P(cmd_buf, 30, PSTR("G1 Z%d.%d%d"), integer, Deci, Deci2); @@ -489,10 +491,8 @@ void DGUSScreenHandlerMKS::meshLevel(DGUS_VP_Variable &var, void *val_ptr) { case 1: offset = mesh_adj_distance; integer = offset; // get int - Deci = (offset * 10); - Deci = Deci % 10; - Deci2 = offset * 100; - Deci2 = Deci2 % 10; + Deci = (offset * 10) % 10; + Deci2 = (offset * 100) % 10; soft_endstop._enabled = false; queue.enqueue_now(F("G91")); snprintf_P(cmd_buf, 30, PSTR("G1 Z-%d.%d%d"), integer, Deci, Deci2); @@ -617,98 +617,90 @@ void DGUSScreenHandlerMKS::manualAssistLeveling(DGUS_VP_Variable &var, void *val break; } - if (WITHIN(point_val, 0x0002, 0x0005)) { - //queue.enqueue_now(F("G28Z")); + if (WITHIN(point_val, 0x0002, 0x0005)) queue.enqueue_now(F("G1Z-10")); - } } -#define mks_min(a, b) ((a) < (b)) ? (a) : (b) -#define mks_max(a, b) ((a) > (b)) ? (a) : (b) -void DGUSScreenHandlerMKS::tmcChangeConfig(DGUS_VP_Variable &var, void *val_ptr) { - #if ANY(HAS_TRINAMIC_CONFIG, HAS_STEALTHCHOP) +#if ANY(HAS_TRINAMIC_CONFIG, HAS_STEALTHCHOP) + + void DGUSScreenHandlerMKS::tmcChangeConfig(DGUS_VP_Variable &var, void *val_ptr) { const uint16_t tmc_val = BE16_P(val_ptr); - #endif + switch (var.VP) { + case VP_TMC_X_SENS: + #if USE_SENSORLESS && X_HAS_STEALTHCHOP + stepperX.homing_threshold(_MIN(tmc_val, 255)); + settings.save(); + tmc_stall_sens.x = stepperX.homing_threshold(); + #endif + break; + case VP_TMC_Y_SENS: + #if USE_SENSORLESS && Y_HAS_STEALTHCHOP + stepperY.homing_threshold(_MIN(tmc_val, 255)); + settings.save(); + tmc_stall_sens.y = stepperY.homing_threshold(); + #endif + break; + case VP_TMC_Z_SENS: + #if USE_SENSORLESS && Z_HAS_STEALTHCHOP + stepperZ.homing_threshold(_MIN(tmc_val, 255)); + settings.save(); + tmc_stall_sens.z = stepperZ.homing_threshold(); + #endif + break; + case VP_TMC_X_Current: + #if X_IS_TRINAMIC + stepperX.rms_current(tmc_val); + settings.save(); + #endif + break; + case VP_TMC_X1_Current: + #if X2_IS_TRINAMIC + stepperX2.rms_current(tmc_val); + settings.save(); + #endif + break; + case VP_TMC_Y_Current: + #if Y_IS_TRINAMIC + stepperY.rms_current(tmc_val); + settings.save(); + #endif + break; + case VP_TMC_Y1_Current: + #if Y2_IS_TRINAMIC + stepperY2.rms_current(tmc_val); + settings.save(); + #endif + break; + case VP_TMC_Z_Current: + #if Z_IS_TRINAMIC + stepperZ.rms_current(tmc_val); + settings.save(); + #endif + break; + case VP_TMC_Z1_Current: + #if Z2_IS_TRINAMIC + stepperZ2.rms_current(tmc_val); + settings.save(); + #endif + break; + case VP_TMC_E0_Current: + #if E0_IS_TRINAMIC + stepperE0.rms_current(tmc_val); + settings.save(); + #endif + break; + case VP_TMC_E1_Current: + #if E1_IS_TRINAMIC + stepperE1.rms_current(tmc_val); + settings.save(); + #endif + break; - switch (var.VP) { - case VP_TMC_X_STEP: - #if USE_SENSORLESS && X_HAS_STEALTHCHOP - stepperX.homing_threshold(mks_min(tmc_val, 255)); - settings.save(); - //tmc_step.x = stepperX.homing_threshold(); - #endif - break; - case VP_TMC_Y_STEP: - #if USE_SENSORLESS && Y_HAS_STEALTHCHOP - stepperY.homing_threshold(mks_min(tmc_val, 255)); - settings.save(); - //tmc_step.y = stepperY.homing_threshold(); - #endif - break; - case VP_TMC_Z_STEP: - #if USE_SENSORLESS && Z_HAS_STEALTHCHOP - stepperZ.homing_threshold(mks_min(tmc_val, 255)); - settings.save(); - //tmc_step.z = stepperZ.homing_threshold(); - #endif - break; - case VP_TMC_X_Current: - #if X_IS_TRINAMIC - stepperX.rms_current(tmc_val); - settings.save(); - #endif - break; - case VP_TMC_X1_Current: - #if X2_IS_TRINAMIC - stepperX2.rms_current(tmc_val); - settings.save(); - #endif - break; - case VP_TMC_Y_Current: - #if Y_IS_TRINAMIC - stepperY.rms_current(tmc_val); - settings.save(); - #endif - break; - case VP_TMC_Y1_Current: - #if Y2_IS_TRINAMIC - stepperY2.rms_current(tmc_val); - settings.save(); - #endif - break; - case VP_TMC_Z_Current: - #if Z_IS_TRINAMIC - stepperZ.rms_current(tmc_val); - settings.save(); - #endif - break; - case VP_TMC_Z1_Current: - #if Z2_IS_TRINAMIC - stepperZ2.rms_current(tmc_val); - settings.save(); - #endif - break; - case VP_TMC_E0_Current: - #if E0_IS_TRINAMIC - stepperE0.rms_current(tmc_val); - settings.save(); - #endif - break; - case VP_TMC_E1_Current: - #if E1_IS_TRINAMIC - stepperE1.rms_current(tmc_val); - settings.save(); - #endif - break; - - default: break; + default: break; + } } - #if USE_SENSORLESS - TERN_(X_HAS_STEALTHCHOP, tmc_step.x = stepperX.homing_threshold()); - TERN_(Y_HAS_STEALTHCHOP, tmc_step.y = stepperY.homing_threshold()); - TERN_(Z_HAS_STEALTHCHOP, tmc_step.z = stepperZ.homing_threshold()); - #endif -} + +#endif // HAS_TRINAMIC_CONFIG || HAS_STEALTHCHOP void DGUSScreenHandler::handleManualMove(DGUS_VP_Variable &var, void *val_ptr) { int16_t movevalue = BE16_P(val_ptr); @@ -721,11 +713,10 @@ void DGUSScreenHandler::handleManualMove(DGUS_VP_Variable &var, void *val_ptr) { if (!print_job_timer.isPaused() && !queue.ring_buffer.empty()) return; - char axiscode; - uint16_t speed = manual_feedrate_mm_m.x; // Default feedrate for manual moves + char axiscode = '\0'; + uint16_t speed = 0; switch (var.VP) { // switch X Y Z or Home - default: return; #if HAS_X_AXIS case VP_MOVE_X: if (!ExtUI::canMove(ExtUI::axis_t::X)) return; @@ -763,13 +754,8 @@ void DGUSScreenHandler::handleManualMove(DGUS_VP_Variable &var, void *val_ptr) { #endif } - if (movevalue != 0 && movevalue != 5) { // get move distance - switch (movevalue) { - case 0x0001: movevalue = manualMoveStep; break; - case 0x0002: movevalue = -manualMoveStep; break; - default: movevalue = 0; break; - } - } + if WITHIN(movevalue, 1, 4) // get move distance + movevalue == 1 ? movevalue = manualMoveStep : movevalue = -manualMoveStep; if (!movevalue) { queue.enqueue_one_now(TS(F("G28"), axiscode)); @@ -786,8 +772,10 @@ void DGUSScreenHandler::handleManualMove(DGUS_VP_Variable &var, void *val_ptr) { // Movement const bool old_relative_mode = relative_mode; if (!relative_mode) queue.enqueue_now(F("G91")); + + // TODO: Use MString / TS() ... + char buf[32]; // G1 X9999.99 F12345 - //const uint16_t backup_speed = MMS_TO_MMM(feedrate_mm_s); char sign[] = "\0"; int16_t value = movevalue / 100; if (movevalue < 0) { value = -value; sign[0] = '-'; } @@ -795,13 +783,6 @@ void DGUSScreenHandler::handleManualMove(DGUS_VP_Variable &var, void *val_ptr) { snprintf_P(buf, 32, PSTR("G0 %c%s%d.%02d F%d"), axiscode, sign, value, fraction, speed); queue.enqueue_one_now(buf); - //if (backup_speed != speed) { - // snprintf_P(buf, 32, PSTR("G0 F%d"), backup_speed); - // queue.enqueue_one_now(buf); - //} - - //while (!enqueue_and_echo_command(buf)) idle(); - if (!old_relative_mode) queue.enqueue_now(F("G90")); forceCompleteUpdate(); @@ -826,36 +807,18 @@ void DGUSScreenHandlerMKS::handleChangeLevelPoint(DGUS_VP_Variable &var, void *v #if ENABLED(EDITABLE_STEPS_PER_UNIT) void DGUSScreenHandlerMKS::handleStepPerMMChanged(DGUS_VP_Variable &var, void *val_ptr) { - const uint16_t raw = BE16_P(val_ptr); - const float value = (float)raw; - - ExtUI::axis_t axis; + const float value = (float)BE16_P(val_ptr); switch (var.VP) { - default: return; - case VP_X_STEP_PER_MM: axis = ExtUI::axis_t::X; break; - case VP_Y_STEP_PER_MM: axis = ExtUI::axis_t::Y; break; - case VP_Z_STEP_PER_MM: axis = ExtUI::axis_t::Z; break; - } - ExtUI::setAxisSteps_per_mm(value, axis); - settings.save(); - skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel - } - - void DGUSScreenHandlerMKS::handleStepPerMMExtruderChanged(DGUS_VP_Variable &var, void *val_ptr) { - const uint16_t raw = BE16_P(val_ptr); - const float value = (float)raw; - - ExtUI::extruder_t extruder; - switch (var.VP) { - default: return; + case VP_X_STEP_PER_MM: ExtUI::setAxisSteps_per_mm(value, ExtUI::axis_t::X); break; + case VP_Y_STEP_PER_MM: ExtUI::setAxisSteps_per_mm(value, ExtUI::axis_t::Y); break; + case VP_Z_STEP_PER_MM: ExtUI::setAxisSteps_per_mm(value, ExtUI::axis_t::Z); break; #if HAS_HOTEND - case VP_E0_STEP_PER_MM: extruder = ExtUI::extruder_t::E0; break; + case VP_E0_STEP_PER_MM: ExtUI::setAxisSteps_per_mm(value, ExtUI::extruder_t::E0); break; #endif #if HAS_MULTI_HOTEND - case VP_E1_STEP_PER_MM: extruder = ExtUI::extruder_t::E1; break; + case VP_E1_STEP_PER_MM: ExtUI::setAxisSteps_per_mm(value, ExtUI::extruder_t::E1); break; #endif } - ExtUI::setAxisSteps_per_mm(value, extruder); settings.save(); skipVP = var.VP; // Don't overwrite value the next update time as the display might autoincrement in parallel } @@ -863,70 +826,36 @@ void DGUSScreenHandlerMKS::handleChangeLevelPoint(DGUS_VP_Variable &var, void *v #endif // EDITABLE_STEPS_PER_UNIT void DGUSScreenHandlerMKS::handleMaxSpeedChange(DGUS_VP_Variable &var, void *val_ptr) { - const uint16_t raw = BE16_P(val_ptr); - const float value = (float)raw; - - ExtUI::axis_t axis; + const float value = (float)BE16_P(val_ptr); switch (var.VP) { - case VP_X_MAX_SPEED: axis = ExtUI::axis_t::X; break; - case VP_Y_MAX_SPEED: axis = ExtUI::axis_t::Y; break; - case VP_Z_MAX_SPEED: axis = ExtUI::axis_t::Z; break; - default: return; - } - ExtUI::setAxisMaxFeedrate_mm_s(value, axis); - settings.save(); - skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel -} - -void DGUSScreenHandlerMKS::handleExtruderMaxSpeedChange(DGUS_VP_Variable &var, void *val_ptr) { - const uint16_t raw = BE16_P(val_ptr); - const float value = (float)raw; - - ExtUI::extruder_t extruder; - switch (var.VP) { - default: return; + case VP_X_MAX_SPEED: ExtUI::setAxisMaxFeedrate_mm_s(value, ExtUI::axis_t::X); break; + case VP_Y_MAX_SPEED: ExtUI::setAxisMaxFeedrate_mm_s(value, ExtUI::axis_t::Y); break; + case VP_Z_MAX_SPEED: ExtUI::setAxisMaxFeedrate_mm_s(value, ExtUI::axis_t::Z); break; #if HAS_HOTEND - case VP_E0_MAX_SPEED: extruder = ExtUI::extruder_t::E0; break; + case VP_E0_MAX_SPEED: ExtUI::setAxisMaxFeedrate_mm_s(value, ExtUI::extruder_t::E0); break; #endif #if HAS_MULTI_HOTEND - case VP_E1_MAX_SPEED: extruder = ExtUI::extruder_t::E1; break; + case VP_E1_MAX_SPEED: ExtUI::setAxisMaxFeedrate_mm_s(value, ExtUI::extruder_t::E1); break; #endif } - ExtUI::setAxisMaxFeedrate_mm_s(value, extruder); settings.save(); skipVP = var.VP; // Don't overwrite value the next update time as the display might autoincrement in parallel } void DGUSScreenHandlerMKS::handleMaxAccChange(DGUS_VP_Variable &var, void *val_ptr) { - const uint16_t raw = BE16_P(val_ptr); - const float value = (float)raw; - - ExtUI::axis_t axis; - switch (var.VP) { - default: return; - case VP_X_ACC_MAX_SPEED: axis = ExtUI::axis_t::X; break; - case VP_Y_ACC_MAX_SPEED: axis = ExtUI::axis_t::Y; break; - case VP_Z_ACC_MAX_SPEED: axis = ExtUI::axis_t::Z; break; - } - ExtUI::setAxisMaxAcceleration_mm_s2(value, axis); - settings.save(); - skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel -} - -void DGUSScreenHandlerMKS::handleExtruderAccChange(DGUS_VP_Variable &var, void *val_ptr) { - uint16_t raw = BE16_P(val_ptr); - float value = (float)raw; - ExtUI::extruder_t extruder; + const float value = (float)BE16_P(val_ptr); switch (var.VP) { default: return; + case VP_X_MAX_ACC: ExtUI::setAxisMaxAcceleration_mm_s2(value, ExtUI::axis_t::X); break; + case VP_Y_MAX_ACC: ExtUI::setAxisMaxAcceleration_mm_s2(value, ExtUI::axis_t::Y); break; + case VP_Z_MAX_ACC: ExtUI::setAxisMaxAcceleration_mm_s2(value, ExtUI::axis_t::Z); break; #if HAS_HOTEND - case VP_E0_ACC_MAX_SPEED: extruder = ExtUI::extruder_t::E0; settings.load(); break; + case VP_E0_MAX_ACC: ExtUI::setAxisMaxAcceleration_mm_s2(value, ExtUI::extruder_t::E0); break; #endif #if HAS_MULTI_HOTEND - case VP_E1_ACC_MAX_SPEED: extruder = ExtUI::extruder_t::E1; settings.load(); break; + case VP_E1_MAX_ACC: ExtUI::setAxisMaxAcceleration_mm_s2(value, ExtUI::extruder_t::E1); break; #endif } - ExtUI::setAxisMaxAcceleration_mm_s2(value, extruder); settings.save(); skipVP = var.VP; // Don't overwrite value the next update time as the display might autoincrement in parallel } @@ -994,37 +923,14 @@ void DGUSScreenHandlerMKS::handleAccChange(DGUS_VP_Variable &var, void *val_ptr) #if ENABLED(BABYSTEPPING) void DGUSScreenHandler::handleLiveAdjustZ(DGUS_VP_Variable &var, void *val_ptr) { - const float step = ZOffset_distance; - - const uint16_t flag = BE16_P(val_ptr); - switch (flag) { + switch (BE16_P(val_ptr)) { case 0: - if (step == 0.01) - queue.inject(F("M290 Z-0.01")); - else if (step == 0.1) - queue.inject(F("M290 Z-0.1")); - else if (step == 0.5) - queue.inject(F("M290 Z-0.5")); - else if (step == 1) - queue.inject(F("M290 Z-1")); - else - queue.inject(F("M290 Z-0.01")); - + queue.inject(TS(F("M290 Z"), -ZOffset_distance)); z_offset_add -= ZOffset_distance; break; case 1: - if (step == 0.01) - queue.inject(F("M290 Z0.01")); - else if (step == 0.1) - queue.inject(F("M290 Z0.1")); - else if (step == 0.5) - queue.inject(F("M290 Z0.5")); - else if (step == 1) - queue.inject(F("M290 Z1")); - else - queue.inject(F("M290 Z-0.01")); - + queue.inject(TS(F("M290 Z"), ZOffset_distance)); z_offset_add += ZOffset_distance; break; @@ -1084,15 +990,16 @@ void DGUSScreenHandlerMKS::filamentLoadUnload(DGUS_VP_Variable &var, void *val_p #if ALL(HAS_HOTEND, PREVENT_COLD_EXTRUSION) if (hotend_too_cold) { - if (thermalManager.targetTooColdToExtrude(hotend_too_cold - 1)) thermalManager.setTargetHotend(thermalManager.extrude_min_temp, hotend_too_cold - 1); - sendInfoScreen(F("NOTICE"), nullptr, F("Please wait."), F("Nozzle heating!")); + if (thermalManager.targetTooColdToExtrude(hotend_too_cold - 1)) + thermalManager.setTargetHotend(thermalManager.extrude_min_temp, hotend_too_cold - 1); + sendInfoScreenMKS(F("NOTICE"), nullptr, F("Please wait."), F("Nozzle heating!"), MKS_English); setupConfirmAction(nullptr); gotoScreen(DGUS_SCREEN_POPUP); } #endif if (swap_tool) { - char buf[30]; + char buf[30]; // TODO: Use MString / TS() snprintf_P(buf, 30, #if ANY(HAS_MULTI_HOTEND, SINGLENOZZLE) PSTR("M1002T%cE%dF%d"), char('0' + swap_tool - 1) @@ -1112,7 +1019,7 @@ void DGUSScreenHandlerMKS::filamentLoadUnload(DGUS_VP_Variable &var, void *val_p void GcodeSuite::M1002() { #if ANY(HAS_MULTI_HOTEND, SINGLENOZZLE) { - char buf[3]; + char buf[3]; // TODO: Use MString / TS() sprintf_P(buf, PSTR("T%c"), char('0' + parser.intval('T'))); process_subcommands_now(buf); } @@ -1122,7 +1029,7 @@ void GcodeSuite::M1002() { set_e_relative(); // M83 { - char buf[20]; + char buf[20]; // TODO: Use MString / TS() snprintf_P(buf, 20, PSTR("G1E%dF%d"), parser.intval('E'), parser.intval('F')); process_subcommands_now(buf); } @@ -1264,9 +1171,9 @@ bool DGUSScreenHandlerMKS::loop() { if (!booted && ELAPSED(ms, TERN(USE_MKS_GREEN_UI, 1000, BOOTSCREEN_TIMEOUT))) { booted = true; #if USE_SENSORLESS - TERN_(X_HAS_STEALTHCHOP, tmc_step.x = stepperX.homing_threshold()); - TERN_(Y_HAS_STEALTHCHOP, tmc_step.y = stepperY.homing_threshold()); - TERN_(Z_HAS_STEALTHCHOP, tmc_step.z = stepperZ.homing_threshold()); + TERN_(X_HAS_STEALTHCHOP, tmc_stall_sens.x = stepperX.homing_threshold()); + TERN_(Y_HAS_STEALTHCHOP, tmc_stall_sens.y = stepperY.homing_threshold()); + TERN_(Z_HAS_STEALTHCHOP, tmc_stall_sens.z = stepperZ.homing_threshold()); #endif #if ENABLED(PREVENT_COLD_EXTRUSION) @@ -1328,7 +1235,7 @@ void DGUSScreenHandlerMKS::runoutIdle() { queue.inject(F("M25")); gotoScreen(MKSLCD_SCREEN_PAUSE); - sendInfoScreen(F("NOTICE"), nullptr, F("Please change filament!"), nullptr); + sendInfoScreenMKS(F("NOTICE"), nullptr, F("Please change filament!"), nullptr, MKS_English); //setupConfirmAction(nullptr); gotoScreen(DGUS_SCREEN_POPUP); break; @@ -1383,6 +1290,9 @@ void DGUSScreenHandlerMKS::updateDisplayLanguage() { const char TemperatureConfig_buf_en[] = "Temperature"; dgus.writeStringVar(VP_TemperatureConfig_Dis, TemperatureConfig_buf_en); + const char Probe_Offset_buf_en[] = "Probe Offset"; + dgus.writeStringVar(VP_Probe_Offset_Dis, Probe_Offset_buf_en); + const char Advance_buf_en[] = "Advanced"; dgus.writeStringVar(VP_Advance_Dis, Advance_buf_en); @@ -1402,14 +1312,14 @@ void DGUSScreenHandlerMKS::updateDisplayLanguage() { ; dgus.writeStringVar(VP_Level_Dis, Level_buf_en); - const char MotorPulse_buf_en[] = "MotorPulse"; - dgus.writeStringVar(VP_MotorPulse_Dis, MotorPulse_buf_en); + const char AxisRes_buf_en[] = "Axis Resolution"; + dgus.writeStringVar(VP_AxisRes_Dis, AxisRes_buf_en); - const char MotorMaxSpeed_buf_en[] = "MotorMaxSpeed"; - dgus.writeStringVar(VP_MotorMaxSpeed_Dis, MotorMaxSpeed_buf_en); + const char AxisMaxSpeed_buf_en[] = "Axis Max Speed"; + dgus.writeStringVar(VP_AxisMaxSpeed_Dis, AxisMaxSpeed_buf_en); - const char MotorMaxAcc_buf_en[] = "MotorAcc"; - dgus.writeStringVar(VP_MotorMaxAcc_Dis, MotorMaxAcc_buf_en); + const char AxisMaxAcc_buf_en[] = "Axis Max Acc."; + dgus.writeStringVar(VP_AxisMaxAcc_Dis, AxisMaxAcc_buf_en); const char TravelAcc_buf_en[] = "Travel Acc."; dgus.writeStringVar(VP_TravelAcc_Dis, TravelAcc_buf_en); @@ -1447,26 +1357,26 @@ void DGUSScreenHandlerMKS::updateDisplayLanguage() { const char FactoryDefaults_buf_en[] = "Factory Defaults"; dgus.writeStringVar(VP_FactoryDefaults_Dis, FactoryDefaults_buf_en); - const char StoreSetting_buf_en[] = "Store Setting"; + const char StoreSetting_buf_en[] = "Store Settings"; dgus.writeStringVar(VP_StoreSetting_Dis, StoreSetting_buf_en); const char PrintPauseConfig_buf_en[] = "PrintPause Config"; dgus.writeStringVar(VP_PrintPauseConfig_Dis, PrintPauseConfig_buf_en); - const char X_Pulse_buf_en[] = "X_Pulse"; - dgus.writeStringVar(VP_X_Pulse_Dis, X_Pulse_buf_en); + const char X_Steps_mm_buf_en[] = "X steps/mm"; + dgus.writeStringVar(VP_X_Steps_mm_Dis, X_Steps_mm_buf_en); - const char Y_Pulse_buf_en[] = "Y_Pulse"; - dgus.writeStringVar(VP_Y_Pulse_Dis, Y_Pulse_buf_en); + const char Y_Steps_mm_buf_en[] = "Y steps/mm"; + dgus.writeStringVar(VP_Y_Steps_mm_Dis, Y_Steps_mm_buf_en); - const char Z_Pulse_buf_en[] = "Z_Pulse"; - dgus.writeStringVar(VP_Z_Pulse_Dis, Z_Pulse_buf_en); + const char Z_Steps_mm_buf_en[] = "Z steps/mm"; + dgus.writeStringVar(VP_Z_Steps_mm_Dis, Z_Steps_mm_buf_en); - const char E0_Pulse_buf_en[] = "E0_Pulse"; - dgus.writeStringVar(VP_E0_Pulse_Dis, E0_Pulse_buf_en); + const char E0_Steps_mm_buf_en[] = "E0 steps/mm"; + dgus.writeStringVar(VP_E0_Steps_mm_Dis, E0_Steps_mm_buf_en); - const char E1_Pulse_buf_en[] = "E1_Pulse"; - dgus.writeStringVar(VP_E1_Pulse_Dis, E1_Pulse_buf_en); + const char E1_Steps_mm_buf_en[] = "E1 steps/mm"; + dgus.writeStringVar(VP_E1_Steps_mm_Dis, E1_Steps_mm_buf_en); const char X_Max_Speed_buf_en[] = "X Max Speed"; dgus.writeStringVar(VP_X_Max_Speed_Dis, X_Max_Speed_buf_en); @@ -1550,13 +1460,13 @@ void DGUSScreenHandlerMKS::updateDisplayLanguage() { dgus.writeStringVar(VP_Info_PrintFinish_1_Dis, Info_PrintFinish_1_buf_en); const char TMC_X_Step_buf_en[] = "X Sensitivity"; - dgus.writeStringVar(VP_TMC_X_Step_Dis, TMC_X_Step_buf_en); + dgus.writeStringVar(VP_TMC_X_SENS_Dis, TMC_X_Step_buf_en); const char TMC_Y_Step_buf_en[] = "Y Sensitivity"; - dgus.writeStringVar(VP_TMC_Y_Step_Dis, TMC_Y_Step_buf_en); + dgus.writeStringVar(VP_TMC_Y_SENS_Dis, TMC_Y_Step_buf_en); const char TMC_Z_Step_buf_en[] = "Z Sensitivity"; - dgus.writeStringVar(VP_TMC_Z_Step_Dis, TMC_Z_Step_buf_en); + dgus.writeStringVar(VP_TMC_Z_SENS_Dis, TMC_Z_Step_buf_en); const char TMC_X_Current_buf_en[] = "X Current"; dgus.writeStringVar(VP_TMC_X_Current_Dis, TMC_X_Current_buf_en); @@ -1585,6 +1495,15 @@ void DGUSScreenHandlerMKS::updateDisplayLanguage() { const char Min_Ex_Temp_buf_en[] = "Min Extrude Temp"; dgus.writeStringVar(VP_Min_Ex_Temp_Dis, Min_Ex_Temp_buf_en); + const char X_Offset_buf_en[] = "X Offset"; + dgus.writeStringVar(VP_X_Offset_Dis, X_Offset_buf_en); + + const char Y_Offset_buf_en[] = "Y Offset"; + dgus.writeStringVar(VP_Y_Offset_Dis, Y_Offset_buf_en); + + const char Z_Offset_buf_en[] = "Z Offset"; + dgus.writeStringVar(VP_Z_Offset_Dis, Z_Offset_buf_en); + const char AutoLEVEL_INFO1_buf_en[] = "Please Press Button!"; dgus.writeStringVar(VP_AutoLEVEL_INFO1, AutoLEVEL_INFO1_buf_en); @@ -1600,9 +1519,6 @@ void DGUSScreenHandlerMKS::updateDisplayLanguage() { const char StopPrintConfirm_Info_buf_en[] = "Stop Print?"; dgus.writeStringVar(VP_StopPrintConfirm_Info_Dis, StopPrintConfirm_Info_buf_en); - const char Printting_buf_en[] = "Printing"; - dgus.writeStringVar(VP_Printting_Dis, Printting_buf_en); - const char LCD_BLK_buf_en[] = "Backlight"; dgus.writeStringVar(VP_LCD_BLK_Dis, LCD_BLK_buf_en); @@ -1660,14 +1576,14 @@ void DGUSScreenHandlerMKS::updateDisplayLanguage() { }; dgus.writeStringVar(VP_Level_Dis, Level_buf_ch, 32); - const uint16_t MotorPulse_buf_ch[] = { 0xF6C2, 0xE5B3, 0x2000 }; - dgus.writeStringVar(VP_MotorPulse_Dis, MotorPulse_buf_ch); + const uint16_t AxisRes_buf_ch[] = { 0xF6C2, 0xE5B3, 0x2000 }; + dgus.writeStringVar(VP_AxisRes_Dis, AxisRes_buf_ch); - const uint16_t MotorMaxSpeed_buf_ch[] = { 0xEED7, 0xF3B4, 0xD9CB, 0xC8B6, 0x2000 }; - dgus.writeStringVar(VP_MotorMaxSpeed_Dis, MotorMaxSpeed_buf_ch); + const uint16_t AxisMaxSpeed_buf_ch[] = { 0xEED7, 0xF3B4, 0xD9CB, 0xC8B6, 0x2000 }; + dgus.writeStringVar(VP_AxisMaxSpeed_Dis, AxisMaxSpeed_buf_ch); - const uint16_t MotorMaxAcc_buf_ch[] = { 0xEED7, 0xF3B4, 0xD3BC, 0xD9CB, 0xC8B6, 0x2000 }; - dgus.writeStringVar(VP_MotorMaxAcc_Dis, MotorMaxAcc_buf_ch); + const uint16_t AxisMaxAcc_buf_ch[] = { 0xEED7, 0xF3B4, 0xD3BC, 0xD9CB, 0xC8B6, 0x2000 }; + dgus.writeStringVar(VP_AxisMaxAcc_Dis, AxisMaxAcc_buf_ch); const uint16_t TravelAcc_buf_ch[] = { 0xD5BF, 0xD0D0, 0xD3BC, 0xD9CB, 0xC8B6, 0x2000 }; dgus.writeStringVar(VP_TravelAcc_Dis, TravelAcc_buf_ch); @@ -1711,20 +1627,20 @@ void DGUSScreenHandlerMKS::updateDisplayLanguage() { const uint16_t PrintPauseConfig_buf_ch[] = { 0xDDD4, 0xA3CD, 0xBBCE, 0xC3D6, 0x2000 }; dgus.writeStringVar(VP_PrintPauseConfig_Dis, PrintPauseConfig_buf_ch, 32); - const uint16_t X_Pulse_buf_ch[] = { 0x2058, 0xE1D6, 0xF6C2, 0xE5B3, 0x2000 }; - dgus.writeStringVar(VP_X_Pulse_Dis, X_Pulse_buf_ch); + const uint16_t X_Steps_mm_buf_ch[] = { 0x2058, 0xE1D6, 0xF6C2, 0xE5B3, 0x2000 }; + dgus.writeStringVar(VP_X_Steps_mm_Dis, X_Steps_mm_buf_ch); - const uint16_t Y_Pulse_buf_ch[] = { 0x2059, 0xE1D6, 0xF6C2, 0xE5B3, 0x2000 }; - dgus.writeStringVar(VP_Y_Pulse_Dis, Y_Pulse_buf_ch); + const uint16_t Y_Steps_mm_buf_ch[] = { 0x2059, 0xE1D6, 0xF6C2, 0xE5B3, 0x2000 }; + dgus.writeStringVar(VP_Y_Steps_mm_Dis, Y_Steps_mm_buf_ch); - const uint16_t Z_Pulse_buf_ch[] = { 0x205A, 0xE1D6, 0xF6C2, 0xE5B3, 0x2000 }; - dgus.writeStringVar(VP_Z_Pulse_Dis, Z_Pulse_buf_ch); + const uint16_t Z_Steps_mm_buf_ch[] = { 0x205A, 0xE1D6, 0xF6C2, 0xE5B3, 0x2000 }; + dgus.writeStringVar(VP_Z_Steps_mm_Dis, Z_Steps_mm_buf_ch); - const uint16_t E0_Pulse_buf_ch[] = { 0x3045, 0xE1D6, 0xF6C2, 0xE5B3, 0x2000 }; - dgus.writeStringVar(VP_E0_Pulse_Dis, E0_Pulse_buf_ch); + const uint16_t E0_Steps_mm_buf_ch[] = { 0x3045, 0xE1D6, 0xF6C2, 0xE5B3, 0x2000 }; + dgus.writeStringVar(VP_E0_Steps_mm_Dis, E0_Steps_mm_buf_ch); - const uint16_t E1_Pulse_buf_ch[] = { 0x3145, 0xE1D6, 0xF6C2, 0xE5B3, 0x2000 }; - dgus.writeStringVar(VP_E1_Pulse_Dis, E1_Pulse_buf_ch); + const uint16_t E1_Steps_mm_buf_ch[] = { 0x3145, 0xE1D6, 0xF6C2, 0xE5B3, 0x2000 }; + dgus.writeStringVar(VP_E1_Steps_mm_Dis, E1_Steps_mm_buf_ch); const uint16_t X_Max_Speed_buf_ch[] = { 0x2058, 0xEED7, 0xF3B4, 0xD9CB, 0xC8B6, 0x2000 }; dgus.writeStringVar(VP_X_Max_Speed_Dis, X_Max_Speed_buf_ch); @@ -1805,13 +1721,13 @@ void DGUSScreenHandlerMKS::updateDisplayLanguage() { dgus.writeStringVar(VP_Info_EEPROM_2_Dis, Info_EEPROM_2_buf_ch, 32); const uint16_t TMC_X_Step_buf_ch[] = { 0x2058, 0xE9C1, 0xF4C3, 0xC8B6, 0x2000 }; - dgus.writeStringVar(VP_TMC_X_Step_Dis, TMC_X_Step_buf_ch); + dgus.writeStringVar(VP_TMC_X_SENS_Dis, TMC_X_Step_buf_ch); const uint16_t TMC_Y_Step_buf_ch[] = { 0x2059, 0xE9C1, 0xF4C3, 0xC8B6, 0x2000 }; - dgus.writeStringVar(VP_TMC_Y_Step_Dis, TMC_Y_Step_buf_ch); + dgus.writeStringVar(VP_TMC_Y_SENS_Dis, TMC_Y_Step_buf_ch); const uint16_t TMC_Z_Step_buf_ch[] = { 0x205A, 0xE9C1, 0xF4C3, 0xC8B6, 0x2000 }; - dgus.writeStringVar(VP_TMC_Z_Step_Dis, TMC_Z_Step_buf_ch); + dgus.writeStringVar(VP_TMC_Z_SENS_Dis, TMC_Z_Step_buf_ch); const uint16_t Info_PrintFinish_1_buf_ch[] = { 0xF2B4, 0xA1D3, 0xEACD, 0xC9B3, 0x2000 }; dgus.writeStringVar(VP_Info_PrintFinish_1_Dis, Info_PrintFinish_1_buf_ch, 32); @@ -1858,9 +1774,6 @@ void DGUSScreenHandlerMKS::updateDisplayLanguage() { const uint16_t StopPrintConfirm_Info_buf_ch[] = { 0xC7CA, 0xF1B7, 0xA3CD, 0xB9D6, 0xF2B4, 0xA1D3, 0x2000 }; dgus.writeStringVar(VP_StopPrintConfirm_Info_Dis, StopPrintConfirm_Info_buf_ch, 32); - const uint16_t Printting_buf_ch[] = { 0xF2B4, 0xA1D3, 0xD0D6, 0x2000 }; - dgus.writeStringVar(VP_Printting_Dis, Printting_buf_ch, 32); - const uint16_t LCD_BLK_buf_ch[] = { 0xB3B1, 0xE2B9, 0xE8C9, 0xC3D6, 0x2000 }; dgus.writeStringVar(VP_LCD_BLK_Dis, LCD_BLK_buf_ch, 32); diff --git a/Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.h b/Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.h index 7bcb7c0a02..58acb5fe60 100644 --- a/Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.h +++ b/Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.h @@ -32,11 +32,10 @@ class DGUSScreenHandlerMKS : public DGUSScreenHandler { public: DGUSScreenHandlerMKS() = default; - #if 0 - static void sendinfoscreen_ch(const uint16_t *line1, const uint16_t *line2, const uint16_t *line3, const uint16_t *line4); - static void sendinfoscreen_en(PGM_P const line1, PGM_P const line2, PGM_P const line3, PGM_P const line4); - static void sendInfoScreen(const void *line1, const void *line2, const void *line3, const void *line4, uint16_t language); - #endif + static void sendInfoScreen(const char *line1, const char *line2, const char *line3, const char *line4); + static void sendInfoScreen(const uint16_t *line1, const uint16_t *line2, const uint16_t *line3, const uint16_t *line4); + static void sendInfoScreen_P(PGM_P const line1, PGM_P const line2, PGM_P const line3, PGM_P const line4); + static void sendInfoScreenMKS(const void *line1, const void *line2, const void *line3, const void *line4, const MKS_Language language); static void screenBackChange(DGUS_VP_Variable &var, void *val_ptr); @@ -72,10 +71,8 @@ public: #endif static void handleMaxSpeedChange(DGUS_VP_Variable &var, void *val_ptr); - static void handleExtruderMaxSpeedChange(DGUS_VP_Variable &var, void *val_ptr); static void handleAccChange(DGUS_VP_Variable &var, void *val_ptr); static void handleMaxAccChange(DGUS_VP_Variable &var, void *val_ptr); - static void handleExtruderAccChange(DGUS_VP_Variable &var, void *val_ptr); static void handleChangeLevelPoint(DGUS_VP_Variable &var, void *val_ptr); static void handleTravelAccChange(DGUS_VP_Variable &var, void *val_ptr); static void handleFeedRateMinChange(DGUS_VP_Variable &var, void *val_ptr); @@ -101,7 +98,7 @@ public: static void sendFanToDisplay(DGUS_VP_Variable &var); static void sendGbkToDisplay(DGUS_VP_Variable &var); static void sendStringToDisplay_Language(DGUS_VP_Variable &var); - static void sendTMCStepValue(DGUS_VP_Variable &var); + static void sendTMCSensValue(DGUS_VP_Variable &var); static void setUint8(DGUS_VP_Variable &var, void *val_ptr); From 489727330bbe97fbedef6476ad57a39f961a4f05 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Sat, 5 Apr 2025 06:08:15 +0000 Subject: [PATCH 185/787] [cron] Bump distribution date (2025-04-05) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 594f3546b6..26d094f40a 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-04-03" +//#define STRING_DISTRIBUTION_DATE "2025-04-05" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index adb9112bfe..337bcc5850 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-04-03" + #define STRING_DISTRIBUTION_DATE "2025-04-05" #endif /** From 493c5eec21cd01c15f63bdfe1018eb7ce5e28ed7 Mon Sep 17 00:00:00 2001 From: Vovodroid Date: Sun, 6 Apr 2025 21:42:14 +0300 Subject: [PATCH 186/787] =?UTF-8?q?=F0=9F=9A=B8=20Report=20M48=20Max=20Del?= =?UTF-8?q?ta=20(#26286)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/gcode/calibrate/M48.cpp | 14 +++++++++++++- Marlin/src/lcd/language/language_en.h | 2 ++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/Marlin/src/gcode/calibrate/M48.cpp b/Marlin/src/gcode/calibrate/M48.cpp index 910395e561..981a1d9877 100644 --- a/Marlin/src/gcode/calibrate/M48.cpp +++ b/Marlin/src/gcode/calibrate/M48.cpp @@ -261,7 +261,19 @@ void GcodeSuite::M48() { #if HAS_STATUS_MESSAGE // Display M48 results in the status bar - ui.set_status_and_level(MString<30>(GET_TEXT_F(MSG_M48_DEVIATION), F(": "), w_float_t(sigma, 2, 6))); + if (MAX_MESSAGE_SIZE <= 20) { + // 12345678901234567890 + // Deviation: 0.123456 + ui.set_status_and_level(TS(GET_TEXT_F(MSG_M48_DEVIATION), F(": "), w_float_t(sigma, 2, 6))); + } else if (MAX_MESSAGE_SIZE <= 30) { + // 123456789012345678901234567890 + // Dev:0.12345, Max delta:0.12345 + ui.set_status_and_level(TS(GET_TEXT_F(MSG_M48_DEV), ':', w_float_t(sigma, 2, 5), F(", "), GET_TEXT(MSG_M48_MAX_DELTA), ':', w_float_t(_MAX(mean - min, max - mean), 2, 5))); + } else { + // 1234567890123456789012345678901234567890 + // Deviation: 1.23456, Max delta: 1.23456 + ui.set_status_and_level(TS(GET_TEXT_F(MSG_M48_DEVIATION), F(": "), w_float_t(sigma, 2, 6), F(", "), GET_TEXT(MSG_M48_MAX_DELTA), F(": "), w_float_t(_MAX(mean - min, max - mean), 2, 6))); + } #endif } diff --git a/Marlin/src/lcd/language/language_en.h b/Marlin/src/lcd/language/language_en.h index 571f85e8ce..54740c923e 100644 --- a/Marlin/src/lcd/language/language_en.h +++ b/Marlin/src/lcd/language/language_en.h @@ -222,7 +222,9 @@ namespace LanguageNarrow_en { LSTR MSG_M48_TEST = _UxGT("M48 Probe Test"); LSTR MSG_M48_POINT = _UxGT("M48 Point"); LSTR MSG_M48_OUT_OF_BOUNDS = _UxGT("Probe out of bounds"); + LSTR MSG_M48_DEV = _UxGT("Dev"); LSTR MSG_M48_DEVIATION = _UxGT("Deviation"); + LSTR MSG_M48_MAX_DELTA = _UxGT("Max delta"); LSTR MSG_IDEX_MENU = _UxGT("IDEX Mode"); LSTR MSG_OFFSETS_MENU = _UxGT("Tool Offsets"); LSTR MSG_IDEX_MODE_AUTOPARK = _UxGT("Auto-Park"); From bc85f5bebfdc3637f971d8dac2927940c7f83877 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sun, 6 Apr 2025 13:48:01 -0500 Subject: [PATCH 187/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Add?= =?UTF-8?q?=20Parser::has=5Fstring?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/gcode/config/M550.cpp | 2 +- Marlin/src/gcode/control/T.cpp | 2 +- Marlin/src/gcode/lcd/M117.cpp | 2 +- Marlin/src/gcode/parser.h | 2 ++ Marlin/src/gcode/stats/M75-M78.cpp | 2 +- Marlin/src/lcd/extui/ia_creality/ia_creality_rts.cpp | 2 +- 6 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Marlin/src/gcode/config/M550.cpp b/Marlin/src/gcode/config/M550.cpp index 6ff0c506de..88712786da 100644 --- a/Marlin/src/gcode/config/M550.cpp +++ b/Marlin/src/gcode/config/M550.cpp @@ -42,7 +42,7 @@ void GcodeSuite::M550() { machine_name = parser.value_string(); else if (TERN(GCODE_QUOTED_STRINGS, false, parser.seen('P'))) machine_name = parser.string_arg[0] == 'P' ? &parser.string_arg[1] : parser.string_arg; - else if (parser.string_arg && parser.string_arg[0]) + else if (parser.has_string()) machine_name = parser.string_arg; else did_set = false; diff --git a/Marlin/src/gcode/control/T.cpp b/Marlin/src/gcode/control/T.cpp index 9f6fb2bb00..ce6428950e 100644 --- a/Marlin/src/gcode/control/T.cpp +++ b/Marlin/src/gcode/control/T.cpp @@ -69,7 +69,7 @@ void GcodeSuite::T(const int8_t tool_index) { reset_stepper_timeout(); #if HAS_PRUSA_MMU3 - if (parser.string_arg) { + if (parser.has_string()) { mmu3.tool_change(parser.string_arg[0], uint8_t(tool_index)); // Special commands T?/Tx/Tc return; } diff --git a/Marlin/src/gcode/lcd/M117.cpp b/Marlin/src/gcode/lcd/M117.cpp index 57a26851fd..e8b9cc46f6 100644 --- a/Marlin/src/gcode/lcd/M117.cpp +++ b/Marlin/src/gcode/lcd/M117.cpp @@ -32,7 +32,7 @@ */ void GcodeSuite::M117() { - if (parser.string_arg && parser.string_arg[0]) + if (parser.has_string()) ui.set_status_no_expire(parser.string_arg); else ui.reset_status(); diff --git a/Marlin/src/gcode/parser.h b/Marlin/src/gcode/parser.h index 401548b309..e56a723087 100644 --- a/Marlin/src/gcode/parser.h +++ b/Marlin/src/gcode/parser.h @@ -97,6 +97,8 @@ public: FORCE_INLINE static void cancel_motion_mode() { motion_mode_codenum = -1; } #endif + FORCE_INLINE static bool has_string() { return string_arg && string_arg[0]; } + #if ENABLED(DEBUG_GCODE_PARSER) static void debug(); #endif diff --git a/Marlin/src/gcode/stats/M75-M78.cpp b/Marlin/src/gcode/stats/M75-M78.cpp index 03e76d531d..8ab94577ef 100644 --- a/Marlin/src/gcode/stats/M75-M78.cpp +++ b/Marlin/src/gcode/stats/M75-M78.cpp @@ -43,7 +43,7 @@ void GcodeSuite::M75() { startOrResumeJob(); // ... ExtUI::onPrintTimerStarted() #if ENABLED(DWIN_LCD_PROUI) // TODO: Remove if M75 is never used - if (!IS_SD_PRINTING()) dwinPrintHeader(parser.string_arg && parser.string_arg[0] ? parser.string_arg : GET_TEXT(MSG_HOST_START_PRINT)); + if (!IS_SD_PRINTING()) dwinPrintHeader(parser.has_string() ? parser.string_arg : GET_TEXT(MSG_HOST_START_PRINT)); #endif } diff --git a/Marlin/src/lcd/extui/ia_creality/ia_creality_rts.cpp b/Marlin/src/lcd/extui/ia_creality/ia_creality_rts.cpp index 660d7faed7..8fb672931d 100644 --- a/Marlin/src/lcd/extui/ia_creality/ia_creality_rts.cpp +++ b/Marlin/src/lcd/extui/ia_creality/ia_creality_rts.cpp @@ -100,7 +100,7 @@ void RTS::onStartup() { delay_ms(400); // Delay to allow screen to configure #if ENABLED(CONFIGURABLE_MACHINE_NAME) - const MString<32> ready(message_string, " Ready"); + const MString<32> ready(machine_name, " Ready"); onStatusChanged(ready); #else onStatusChanged(F(MACHINE_NAME " Ready")); From 9f0879785e0187863c6610f31b1311e5bbf6d899 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Mon, 7 Apr 2025 00:31:15 +0000 Subject: [PATCH 188/787] [cron] Bump distribution date (2025-04-07) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 26d094f40a..f5b31acafd 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-04-05" +//#define STRING_DISTRIBUTION_DATE "2025-04-07" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 337bcc5850..c49c7faeb6 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-04-05" + #define STRING_DISTRIBUTION_DATE "2025-04-07" #endif /** From d7b73542a168a27840d207f26255b42146d6adcb Mon Sep 17 00:00:00 2001 From: narno2202 <130909513+narno2202@users.noreply.github.com> Date: Mon, 7 Apr 2025 03:58:05 +0200 Subject: [PATCH 189/787] =?UTF-8?q?=F0=9F=9A=B8=20Refactor=20MKS=20H43=20L?= =?UTF-8?q?CD=20(2)=20(#27780)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Followup to #27776 --- Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.cpp b/Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.cpp index b24c6d5e2e..662430ab79 100644 --- a/Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.cpp +++ b/Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.cpp @@ -81,7 +81,7 @@ void DGUSScreenHandlerMKS::sendInfoScreen_P(PGM_P const line1, PGM_P const line2 void DGUSScreenHandlerMKS::sendInfoScreenMKS(const void *line1, const void *line2, const void *line3, const void *line4, const MKS_Language language) { if (language == MKS_English) - DGUSScreenHandlerMKS::sendInfoScreen_P((char *)line1, (char *)line2, (char *)line3, (char *)line4); + DGUSScreenHandlerMKS::sendInfoScreen((char *)line1, (char *)line2, (char *)line3, (char *)line4); else if (language == MKS_SimpleChinese) DGUSScreenHandlerMKS::sendInfoScreen((uint16_t *)line1, (uint16_t *)line2, (uint16_t *)line3, (uint16_t *)line4); } From 7bfecf659b9c02ca87201b32801ec8cac672e70e Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sun, 6 Apr 2025 21:09:40 -0500 Subject: [PATCH 190/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Mis?= =?UTF-8?q?c.=20dgus/mks=20comments?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/lcd/extui/dgus/DGUSDisplay.h | 10 +++++++--- Marlin/src/lcd/extui/dgus/DGUSScreenHandler.cpp | 4 ++-- Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.cpp | 2 +- Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.h | 7 ++++++- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/Marlin/src/lcd/extui/dgus/DGUSDisplay.h b/Marlin/src/lcd/extui/dgus/DGUSDisplay.h index 6329d8fb23..e54b916ec6 100644 --- a/Marlin/src/lcd/extui/dgus/DGUSDisplay.h +++ b/Marlin/src/lcd/extui/dgus/DGUSDisplay.h @@ -68,18 +68,22 @@ public: static void writeVariable(uint16_t adr, int8_t value); static void writeVariable(uint16_t adr, long value); + // Western PROGMEM string constant static void writeStringVar_P(uint16_t adr, PGM_P const pstr, uint8_t vallen=32) { writeVariable_P(adr, (const void *)pstr, vallen, true); } + // Western F-string constant + static void writeVariable(uint16_t adr, FSTR_P const fstr, uint8_t vallen=32) { + writeStringVar_P(adr, FTOP(fstr), vallen); + } + // Western string constant static void writeStringVar(uint16_t adr, const char * const cstr, uint8_t vallen=32) { writeVariable(adr, (const void *)cstr, vallen, true); } + // Chinese string constant static void writeStringVar(uint16_t adr, const uint16_t * const zhstr, uint8_t vallen=16) { writeVariable(adr, (const void *)zhstr, vallen, true); } - static void writeVariable(uint16_t adr, FSTR_P const fstr, uint8_t vallen=32) { - writeStringVar_P(adr, FTOP(fstr), vallen); - } // Utility functions for bridging ui_api and dgus template diff --git a/Marlin/src/lcd/extui/dgus/DGUSScreenHandler.cpp b/Marlin/src/lcd/extui/dgus/DGUSScreenHandler.cpp index e40aab0bff..38b3d93853 100644 --- a/Marlin/src/lcd/extui/dgus/DGUSScreenHandler.cpp +++ b/Marlin/src/lcd/extui/dgus/DGUSScreenHandler.cpp @@ -326,9 +326,9 @@ void DGUSScreenHandler::sendHeaterStatusToDisplay(DGUS_VP_Variable &var) { void DGUSScreenHandler::sdCardError() { DGUSScreenHandler::sdCardRemoved(); #if DGUS_LCD_UI_MKS - screen.sendInfoScreenMKS(F("NOTICE"), nullptr, F("SD card error"), nullptr, mks_language_index); + sendInfoScreenMKS(F("NOTICE"), nullptr, F("SD card error"), nullptr, mks_language_index); #else - sendInfoScreen(F("NOTICE"), nullptr, F("SD card error"), nullptr, true, true, true, true); + sendInfoScreen(F("NOTICE"), nullptr, F("SD card error"), nullptr); #endif setupConfirmAction(nullptr); gotoScreen(DGUS_SCREEN_POPUP); diff --git a/Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.cpp b/Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.cpp index 662430ab79..2a9ba87d68 100644 --- a/Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.cpp +++ b/Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.cpp @@ -1525,7 +1525,7 @@ void DGUSScreenHandlerMKS::updateDisplayLanguage() { } break; // MKS_English case MKS_SimpleChinese: { - uint16_t home_buf_ch[] = { 0xF7D6, 0xB3D2 }; + const uint16_t home_buf_ch[] = { 0xF7D6, 0xB3D2 }; dgus.writeStringVar(VP_HOME_Dis, home_buf_ch, 4); const uint16_t Setting_Dis[] = { 0xE8C9, 0xC3D6, 0x2000, 0x2000, 0x2000 }; diff --git a/Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.h b/Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.h index 58acb5fe60..01faed6896 100644 --- a/Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.h +++ b/Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.h @@ -32,9 +32,14 @@ class DGUSScreenHandlerMKS : public DGUSScreenHandler { public: DGUSScreenHandlerMKS() = default; + // Western / Chinese PROGMEM strings + static void sendInfoScreen_P(PGM_P const line1, PGM_P const line2, PGM_P const line3, PGM_P const line4); + + // Western / Chinese strings static void sendInfoScreen(const char *line1, const char *line2, const char *line3, const char *line4); static void sendInfoScreen(const uint16_t *line1, const uint16_t *line2, const uint16_t *line3, const uint16_t *line4); - static void sendInfoScreen_P(PGM_P const line1, PGM_P const line2, PGM_P const line3, PGM_P const line4); + + // Use the language parameter to choose Western / Chinese string method static void sendInfoScreenMKS(const void *line1, const void *line2, const void *line3, const void *line4, const MKS_Language language); static void screenBackChange(DGUS_VP_Variable &var, void *val_ptr); From 6984c7f30883737593aaf17ee9c8f7d3004704ae Mon Sep 17 00:00:00 2001 From: Andrey Samokhin <97097314+AndreySamokhin@users.noreply.github.com> Date: Mon, 7 Apr 2025 05:18:01 +0300 Subject: [PATCH 191/787] =?UTF-8?q?=F0=9F=94=A7=20Max=20Stepper=20Rate=20s?= =?UTF-8?q?anity-checks=20(#27764)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/inc/Conditionals-4-adv.h | 2 +- Marlin/src/inc/SanityCheck.h | 78 +++++++++++++++++++++++++++++ buildroot/tests/LPC1769 | 2 +- buildroot/tests/STM32H743VI_btt | 1 + 4 files changed, 81 insertions(+), 2 deletions(-) diff --git a/Marlin/src/inc/Conditionals-4-adv.h b/Marlin/src/inc/Conditionals-4-adv.h index eaa8aca5b0..653a754700 100644 --- a/Marlin/src/inc/Conditionals-4-adv.h +++ b/Marlin/src/inc/Conditionals-4-adv.h @@ -1296,7 +1296,7 @@ #define MAXIMUM_STEPPER_RATE 150000 #elif HAS_DRIVER(DRV8825) #define MAXIMUM_STEPPER_RATE 250000 - #elif HAS_DRIVER(A4988) + #elif HAS_DRIVER(A4988) || HAS_DRIVER(A5984) #define MAXIMUM_STEPPER_RATE 500000 #elif HAS_DRIVER(LV8729) #define MAXIMUM_STEPPER_RATE 1000000 diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index 1505b8b896..fa06bac9f5 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -3720,6 +3720,84 @@ static_assert(COUNT(sanity_arr_3) >= LOGICAL_AXES, "DEFAULT_MAX_ACCELERATION re static_assert(COUNT(sanity_arr_3) <= DISTINCT_AXES, "DEFAULT_MAX_ACCELERATION has too many elements." _EXTRA_NOTE); static_assert(_PLUS_TEST(3), "DEFAULT_MAX_ACCELERATION values must be positive."); +#if MAXIMUM_STEPPER_RATE + static_assert(TERN1(HAS_X_AXIS, sanity_arr_1[X_AXIS] * sanity_arr_2[X_AXIS] <= MAXIMUM_STEPPER_RATE), + "Slow down! DEFAULT_MAX_FEEDRATE[X] * DEFAULT_AXIS_STEPS_PER_UNIT[X] > MAXIMUM_STEPPER_RATE (" STRINGIFY(MAXIMUM_STEPPER_RATE) ")." + ); + static_assert(TERN1(HAS_Y_AXIS, sanity_arr_1[Y_AXIS] * sanity_arr_2[Y_AXIS] <= MAXIMUM_STEPPER_RATE), + "Slow down! DEFAULT_MAX_FEEDRATE[Y] * DEFAULT_AXIS_STEPS_PER_UNIT[Y] > MAXIMUM_STEPPER_RATE (" STRINGIFY(MAXIMUM_STEPPER_RATE) ")." + ); + static_assert(TERN1(HAS_Z_AXIS, sanity_arr_1[Z_AXIS] * sanity_arr_2[Z_AXIS] <= MAXIMUM_STEPPER_RATE), + "Slow down! DEFAULT_MAX_FEEDRATE[Z] * DEFAULT_AXIS_STEPS_PER_UNIT[Z] > MAXIMUM_STEPPER_RATE (" STRINGIFY(MAXIMUM_STEPPER_RATE) ")." + ); + static_assert(TERN1(HAS_I_AXIS, sanity_arr_1[I_AXIS] * sanity_arr_2[I_AXIS] <= MAXIMUM_STEPPER_RATE), + "Slow down! DEFAULT_MAX_FEEDRATE[I] * DEFAULT_AXIS_STEPS_PER_UNIT[I] > MAXIMUM_STEPPER_RATE (" STRINGIFY(MAXIMUM_STEPPER_RATE) ")." + ); + static_assert(TERN1(HAS_J_AXIS, sanity_arr_1[J_AXIS] * sanity_arr_2[J_AXIS] <= MAXIMUM_STEPPER_RATE), + "Slow down! DEFAULT_MAX_FEEDRATE[J] * DEFAULT_AXIS_STEPS_PER_UNIT[J] > MAXIMUM_STEPPER_RATE (" STRINGIFY(MAXIMUM_STEPPER_RATE) ")." + ); + static_assert(TERN1(HAS_K_AXIS, sanity_arr_1[K_AXIS] * sanity_arr_2[K_AXIS] <= MAXIMUM_STEPPER_RATE), + "Slow down! DEFAULT_MAX_FEEDRATE[K] * DEFAULT_AXIS_STEPS_PER_UNIT[K] > MAXIMUM_STEPPER_RATE (" STRINGIFY(MAXIMUM_STEPPER_RATE) ")." + ); + static_assert(TERN1(HAS_U_AXIS, sanity_arr_1[U_AXIS] * sanity_arr_2[U_AXIS] <= MAXIMUM_STEPPER_RATE), + "Slow down! DEFAULT_MAX_FEEDRATE[U] * DEFAULT_AXIS_STEPS_PER_UNIT[U] > MAXIMUM_STEPPER_RATE (" STRINGIFY(MAXIMUM_STEPPER_RATE) ")." + ); + static_assert(TERN1(HAS_V_AXIS, sanity_arr_1[V_AXIS] * sanity_arr_2[V_AXIS] <= MAXIMUM_STEPPER_RATE), + "Slow down! DEFAULT_MAX_FEEDRATE[V] * DEFAULT_AXIS_STEPS_PER_UNIT[V] > MAXIMUM_STEPPER_RATE (" STRINGIFY(MAXIMUM_STEPPER_RATE) ")." + ); + static_assert(TERN1(HAS_W_AXIS, sanity_arr_1[W_AXIS] * sanity_arr_2[W_AXIS] <= MAXIMUM_STEPPER_RATE), + "Slow down! DEFAULT_MAX_FEEDRATE[W] * DEFAULT_AXIS_STEPS_PER_UNIT[W] > MAXIMUM_STEPPER_RATE (" STRINGIFY(MAXIMUM_STEPPER_RATE) ")." + ); + #if ALL(HAS_EXTRUDERS, SANITY_CHECK_E_STEPPER_RATES) + #if DISABLED(DISTINCT_E_FACTORS) + static_assert(sanity_arr_1[E_AXIS] * sanity_arr_2[E_AXIS] <= MAXIMUM_STEPPER_RATE, + "Slow down! DEFAULT_MAX_FEEDRATE[E] * DEFAULT_AXIS_STEPS_PER_UNIT[E] > MAXIMUM_STEPPER_RATE (" STRINGIFY(MAXIMUM_STEPPER_RATE) ")." + ); + #else + #define _ELEM_E(A,N) _MIN(E_AXIS+N,COUNT(sanity_arr_##A)-1) + static_assert(sanity_arr_1[_ELEM_E(1,0)] * sanity_arr_2[_ELEM_E(2,0)] <= MAXIMUM_STEPPER_RATE, + "Slow down! DEFAULT_MAX_FEEDRATE[E0] * DEFAULT_AXIS_STEPS_PER_UNIT[E0] > MAXIMUM_STEPPER_RATE (" STRINGIFY(MAXIMUM_STEPPER_RATE) ")." + ); + #if HAS_MULTI_EXTRUDER + static_assert(sanity_arr_1[_ELEM_E(1,1)] * sanity_arr_2[_ELEM_E(2,1)] <= MAXIMUM_STEPPER_RATE, + "Slow down! DEFAULT_MAX_FEEDRATE[E1] * DEFAULT_AXIS_STEPS_PER_UNIT[E1] > MAXIMUM_STEPPER_RATE (" STRINGIFY(MAXIMUM_STEPPER_RATE) ")." + ); + #endif + #if EXTRUDERS > 2 + static_assert(sanity_arr_1[_ELEM_E(1,2)] * sanity_arr_2[_ELEM_E(2,2)] <= MAXIMUM_STEPPER_RATE, + "Slow down! DEFAULT_MAX_FEEDRATE[E2] * DEFAULT_AXIS_STEPS_PER_UNIT[E2] > MAXIMUM_STEPPER_RATE (" STRINGIFY(MAXIMUM_STEPPER_RATE) ")." + ); + #endif + #if EXTRUDERS > 3 + static_assert(sanity_arr_1[_ELEM_E(1,3)] * sanity_arr_2[_ELEM_E(2,3)] <= MAXIMUM_STEPPER_RATE, + "Slow down! DEFAULT_MAX_FEEDRATE[E3] * DEFAULT_AXIS_STEPS_PER_UNIT[E3] > MAXIMUM_STEPPER_RATE (" STRINGIFY(MAXIMUM_STEPPER_RATE) ")." + ); + #endif + #if EXTRUDERS > 4 + static_assert(sanity_arr_1[_ELEM_E(1,4)] * sanity_arr_2[_ELEM_E(2,4)] <= MAXIMUM_STEPPER_RATE, + "Slow down! DEFAULT_MAX_FEEDRATE[E4] * DEFAULT_AXIS_STEPS_PER_UNIT[E4] > MAXIMUM_STEPPER_RATE (" STRINGIFY(MAXIMUM_STEPPER_RATE) ")." + ); + #endif + #if EXTRUDERS > 5 + static_assert(sanity_arr_1[_ELEM_E(1,5)] * sanity_arr_2[_ELEM_E(2,5)] <= MAXIMUM_STEPPER_RATE, + "Slow down! DEFAULT_MAX_FEEDRATE[E5] * DEFAULT_AXIS_STEPS_PER_UNIT[E5] > MAXIMUM_STEPPER_RATE (" STRINGIFY(MAXIMUM_STEPPER_RATE) ")." + ); + #endif + #if EXTRUDERS > 6 + static_assert(sanity_arr_1[_ELEM_E(1,6)] * sanity_arr_2[_ELEM_E(2,6)] <= MAXIMUM_STEPPER_RATE, + "Slow down! DEFAULT_MAX_FEEDRATE[E6] * DEFAULT_AXIS_STEPS_PER_UNIT[E6] > MAXIMUM_STEPPER_RATE (" STRINGIFY(MAXIMUM_STEPPER_RATE) ")." + ); + #endif + #if EXTRUDERS > 7 + static_assert(sanity_arr_1[_ELEM_E(1,7)] * sanity_arr_2[_ELEM_E(2,7)] <= MAXIMUM_STEPPER_RATE, + "Slow down! DEFAULT_MAX_FEEDRATE[E7] * DEFAULT_AXIS_STEPS_PER_UNIT[E7] > MAXIMUM_STEPPER_RATE (" STRINGIFY(MAXIMUM_STEPPER_RATE) ")." + ); + #endif + #undef _ELEM_E + #endif + #endif // HAS_EXTRUDERS +#endif // MAXIMUM_STEPPER_RATE + #if NUM_AXES constexpr float sanity_arr_4[] = HOMING_FEEDRATE_MM_M; static_assert(COUNT(sanity_arr_4) == NUM_AXES, "HOMING_FEEDRATE_MM_M requires " _NUM_AXES_STR "elements (and no others)."); diff --git a/buildroot/tests/LPC1769 b/buildroot/tests/LPC1769 index a97790e988..f29bbb5656 100755 --- a/buildroot/tests/LPC1769 +++ b/buildroot/tests/LPC1769 @@ -46,7 +46,7 @@ opt_set MOTHERBOARD BOARD_COHESION3D_REMIX \ TEMP_SENSOR_0 1 \ X_DRIVER_TYPE TMC2130 Y_DRIVER_TYPE TMC2130 Z_DRIVER_TYPE TMC2130 I_DRIVER_TYPE TB6560 \ DEFAULT_AXIS_STEPS_PER_UNIT '{ 80, 80, 400, 500, 80 }' \ - DEFAULT_MAX_FEEDRATE '{ 300, 300, 5, 25, 300 }' \ + DEFAULT_MAX_FEEDRATE '{ 187, 187, 5, 25, 187 }' \ DEFAULT_MAX_ACCELERATION '{ 3000, 3000, 100, 10000, 3000 }' \ MANUAL_FEEDRATE '{ 50*60, 50*60, 4*60, 2*60, 50*60 }' \ AXIS_RELATIVE_MODES '{ false, false, false, false, false }' \ diff --git a/buildroot/tests/STM32H743VI_btt b/buildroot/tests/STM32H743VI_btt index e73a786ff4..7ca63aa53a 100755 --- a/buildroot/tests/STM32H743VI_btt +++ b/buildroot/tests/STM32H743VI_btt @@ -12,6 +12,7 @@ set -e # restore_configs use_example_configs "Creality/Ender-5 Plus/BigTreeTech SKR 3" +opt_set DEFAULT_MAX_FEEDRATE '{ 6250, 6250, 15, 5375 }' exec_test $1 $2 "Creality Ender-5 Plus with BigTreeTech SKR 3" "$3" From ed4afab00404d437cb3f76e41fc160ffad6417f0 Mon Sep 17 00:00:00 2001 From: narno2202 <130909513+narno2202@users.noreply.github.com> Date: Tue, 8 Apr 2025 00:38:11 +0200 Subject: [PATCH 192/787] =?UTF-8?q?=F0=9F=9A=B8=20Fix=20FT=20Motion=20Line?= =?UTF-8?q?ar=20Advance=20MarlinUI=20edit=20item=20(#27786)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/lcd/menu/menu_motion.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/src/lcd/menu/menu_motion.cpp b/Marlin/src/lcd/menu/menu_motion.cpp index 4717f4b221..f6f13e2a4e 100644 --- a/Marlin/src/lcd/menu/menu_motion.cpp +++ b/Marlin/src/lcd/menu/menu_motion.cpp @@ -503,7 +503,7 @@ void menu_move() { #if HAS_EXTRUDERS EDIT_ITEM(bool, MSG_LINEAR_ADVANCE, &c.linearAdvEna); if (c.linearAdvEna || ENABLED(FT_MOTION_NO_MENU_TOGGLE)) - EDIT_ITEM(float42_52, MSG_ADVANCE_K, &c.linearAdvK, 0, 10); + EDIT_ITEM(float62, MSG_ADVANCE_K, &c.linearAdvK, 0.0f, 1000.0f); #endif END_MENU(); From bdc0bd0eef1920ff850434eeb0954d8c5715001a Mon Sep 17 00:00:00 2001 From: Boyd Date: Mon, 7 Apr 2025 16:22:58 -0700 Subject: [PATCH 193/787] =?UTF-8?q?=E2=9C=A8=20Native=20GD32=20support=20f?= =?UTF-8?q?or=20Aquila=20v1.0.1=20(#27765)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci-build-tests.yml | 3 ++ Marlin/src/HAL/GD32_MFL/HAL.h | 4 +- Marlin/src/core/boards.h | 10 ++++- .../pins/gd32f1/pins_AQUILA_101_GD32_MFL.h | 37 +++++++++++++++++++ Marlin/src/pins/pins.h | 7 ++++ Marlin/src/pins/stm32f1/env_validate.h | 5 ++- buildroot/tests/GD32F103RC_aquila_mfl | 17 +++++++++ ini/gd32.ini | 27 ++++++++++++-- 8 files changed, 102 insertions(+), 8 deletions(-) create mode 100644 Marlin/src/pins/gd32f1/pins_AQUILA_101_GD32_MFL.h create mode 100755 buildroot/tests/GD32F103RC_aquila_mfl diff --git a/.github/workflows/ci-build-tests.yml b/.github/workflows/ci-build-tests.yml index 2fd316ec0f..58fd02eb5d 100644 --- a/.github/workflows/ci-build-tests.yml +++ b/.github/workflows/ci-build-tests.yml @@ -154,6 +154,9 @@ jobs: # GD32F3 - GD32F303RE_creality_mfl + # GD32F1 + - GD32F103RC_aquila_mfl + # LPC176x - Lengthy tests - LPC1768 - LPC1769 diff --git a/Marlin/src/HAL/GD32_MFL/HAL.h b/Marlin/src/HAL/GD32_MFL/HAL.h index a8a28cc7f3..fd3a10d72b 100644 --- a/Marlin/src/HAL/GD32_MFL/HAL.h +++ b/Marlin/src/HAL/GD32_MFL/HAL.h @@ -82,7 +82,9 @@ typedef libServo hal_servo_t; // Disable Marlin's software oversampling. // The MFL framework uses 16x hardware oversampling by default -#define HAL_ADC_FILTERED +#ifdef GD32F303RE + #define HAL_ADC_FILTERED +#endif #define GET_PIN_MAP_PIN(index) index #define GET_PIN_MAP_INDEX(pin) pin diff --git a/Marlin/src/core/boards.h b/Marlin/src/core/boards.h index 3d34e3717e..e7851d001a 100644 --- a/Marlin/src/core/boards.h +++ b/Marlin/src/core/boards.h @@ -549,14 +549,20 @@ // HC32 ARM Cortex-M4 // -#define BOARD_AQUILA_V101 7200 // Voxelab Aquila V1.0.0/V1.0.1/V1.0.2/V1.0.3 as found in the Voxelab Aquila X2 and C2 +#define BOARD_AQUILA_V101 7200 // Voxelab Aquila V1.0.0/1/2/3 (e.g., Aquila X2, C2). ... GD32 Variant Below! #define BOARD_CREALITY_ENDER2P_V24S4 7201 // Creality Ender 2 Pro v2.4.S4_170 (HC32f460kcta) +// +// GD32 ARM Cortex-M3 +// + +#define BOARD_AQUILA_V101_GD32_MFL 7300 // Voxelab Aquila V1.0.1 MFL (GD32F103RC) ... STM32/HC32 Variant Above! + // // GD32 ARM Cortex-M4 // -#define BOARD_CREALITY_V422_GD32_MFL 7300 // Creality V4.2.2 MFL (GD32F303RE) ... STM32 Variant Above! +#define BOARD_CREALITY_V422_GD32_MFL 7400 // Creality V4.2.2 MFL (GD32F303RE) ... STM32 Variant Above! // // Raspberry Pi diff --git a/Marlin/src/pins/gd32f1/pins_AQUILA_101_GD32_MFL.h b/Marlin/src/pins/gd32f1/pins_AQUILA_101_GD32_MFL.h new file mode 100644 index 0000000000..f3bc9378e9 --- /dev/null +++ b/Marlin/src/pins/gd32f1/pins_AQUILA_101_GD32_MFL.h @@ -0,0 +1,37 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +/** + * Aquila v1.0.1 GD32 MFL (GD32F103RC) board pin assignments + */ + +#define ALLOW_GD32F1 + +#ifndef BOARD_INFO_NAME + #define BOARD_INFO_NAME "Aquila v1.0.1 GD32 MFL" +#endif +#ifndef DEFAULT_MACHINE_NAME + #define DEFAULT_MACHINE_NAME "Aquila" +#endif + +#include "../stm32f1/pins_CREALITY_V4.h" diff --git a/Marlin/src/pins/pins.h b/Marlin/src/pins/pins.h index 2e0919062c..dcb8415de8 100644 --- a/Marlin/src/pins/pins.h +++ b/Marlin/src/pins/pins.h @@ -964,6 +964,13 @@ #elif MB(CREALITY_ENDER2P_V24S4) #include "hc32f4/pins_CREALITY_ENDER2P_V24S4.h" // HC32F460 env:HC32F460C_e2p24s4 +// +// GD32 ARM Cortex-M3 +// + +#elif MB(AQUILA_V101_GD32_MFL) + #include "gd32f1/pins_AQUILA_101_GD32_MFL.h" // GD32F103RC env:GD32F103RC_aquila_mfl + // // GD32 ARM Cortex-M4 // diff --git a/Marlin/src/pins/stm32f1/env_validate.h b/Marlin/src/pins/stm32f1/env_validate.h index 34b07723e7..e219e7cd51 100644 --- a/Marlin/src/pins/stm32f1/env_validate.h +++ b/Marlin/src/pins/stm32f1/env_validate.h @@ -23,16 +23,19 @@ #define ENV_VALIDATE_H #if NOT_TARGET(__STM32F1__, STM32F1) - #if NONE(ALLOW_STM32F4, ALLOW_GD32F3) + #if NONE(ALLOW_STM32F4, ALLOW_GD32F3, ALLOW_GD32F1) #error "Oops! Select an STM32F1 board in 'Tools > Board.'" #elif ENABLED(ALLOW_STM32F4) && NOT_TARGET(STM32F4) #error "Oops! Select an STM32F4 board in 'Tools > Board.'" #elif ENABLED(ALLOW_GD32F3) && NOT_TARGET(ARDUINO_ARCH_MFL) #error "Oops! Make sure you have a GD32F3 MFL environment selected." + #elif ENABLED(ALLOW_GD32F1) && NOT_TARGET(ARDUINO_ARCH_MFL) + #error "Oops! Make sure you have a GD32F1 MFL environment selected." #endif #endif #undef ALLOW_STM32F4 #undef ALLOW_GD32F3 +#undef ALLOW_GD32F1 #endif diff --git a/buildroot/tests/GD32F103RC_aquila_mfl b/buildroot/tests/GD32F103RC_aquila_mfl new file mode 100755 index 0000000000..ca7cd05936 --- /dev/null +++ b/buildroot/tests/GD32F103RC_aquila_mfl @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +# +# Build tests for GD32F103RC_aquila_mfl +# + +# exit on first failure +set -e + +restore_configs +opt_set MOTHERBOARD BOARD_AQUILA_V101_GD32_MFL SERIAL_PORT 0 +opt_enable EEPROM_SETTINGS SDSUPPORT EMERGENCY_PARSER FAN_SOFT_PWM PINS_DEBUGGING +opt_add NO_CREALITY_422_DRIVER_WARNING +opt_add NO_AUTO_ASSIGN_WARNING +exec_test $1 $2 "Aquila v1.0.1 MFL GD32 Default Configuration" "$3" + +# cleanup +restore_configs diff --git a/ini/gd32.ini b/ini/gd32.ini index 1286772786..e983f496ec 100644 --- a/ini/gd32.ini +++ b/ini/gd32.ini @@ -30,8 +30,8 @@ extra_scripts = ${common.extra_scripts} extends = gd32_base board = mfl_creality_422 board_build.offset = 0x7000 -board_build.rename = firmware-{time}.bin board_upload.offset_address = 0x08007000 +board_build.rename = firmware-{time}.bin build_flags = ${gd32_base.build_flags} -DMCU_GD32F303RE -DGD32F303RE @@ -40,7 +40,26 @@ build_flags = ${gd32_base.build_flags} -DTIMER_SERVO=4 -DTRANSFER_CLOCK_DIV=8 -fsingle-precision-constant -extra_scripts = ${gd32_base.extra_scripts} - buildroot/share/PlatformIO/scripts/offset_and_rename.py - +extra_scripts = ${gd32_base.extra_scripts} + buildroot/share/PlatformIO/scripts/offset_and_rename.py +monitor_speed = 115200 + +# +# Aquila v1.0.1 (GD32F103RC) +# +[env:GD32F103RC_aquila_mfl] +extends = gd32_base +board = mfl_aquila +board_build.offset = 0x7000 +board_upload.offset_address = 0x08007000 +board_build.rename = firmware-{time}.bin +build_flags = ${gd32_base.build_flags} + -DMCU_GD32F103RC + -DGD32F103RC + -DTIMER_TONE=2 + -DSS_TIMER=3 + -DTIMER_SERVO=4 + -DTRANSFER_CLOCK_DIV=8 +extra_scripts = ${gd32_base.extra_scripts} + buildroot/share/PlatformIO/scripts/offset_and_rename.py monitor_speed = 115200 From cbd79a5e870579cfcbf0cac3c4e6f85ce6940d30 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Mon, 7 Apr 2025 18:05:57 -0500 Subject: [PATCH 194/787] =?UTF-8?q?=E2=9C=85=20Tweak=20pip/PIO=20caching?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci-build-tests.yml | 13 +++++++++---- .github/workflows/ci-unit-tests.yml | 13 +++++++++---- .github/workflows/ci-validate-boards.yml | 4 ++-- .github/workflows/ci-validate-pins.yml | 4 ++-- 4 files changed, 22 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci-build-tests.yml b/.github/workflows/ci-build-tests.yml index 58fd02eb5d..f80417c0fe 100644 --- a/.github/workflows/ci-build-tests.yml +++ b/.github/workflows/ci-build-tests.yml @@ -170,15 +170,20 @@ jobs: uses: actions/cache@v4 with: path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + key: ${{ runner.os }}-pip-build-v1 restore-keys: | - ${{ runner.os }}-pip- + ${{ runner.os }}-pip-build- - name: Cache PlatformIO uses: actions/cache@v4 with: - path: ~/.platformio - key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }} + path: | + ~/.platformio + .pio/build + .pio/libdeps + key: ${{ runner.os }}-pio-build-v1 + restore-keys: | + ${{ runner.os }}-pio-build- - name: Select Python 3.9 uses: actions/setup-python@v5 diff --git a/.github/workflows/ci-unit-tests.yml b/.github/workflows/ci-unit-tests.yml index 9a311aabc6..30af812dff 100644 --- a/.github/workflows/ci-unit-tests.yml +++ b/.github/workflows/ci-unit-tests.yml @@ -46,15 +46,20 @@ jobs: uses: actions/cache@v4 with: path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + key: ${{ runner.os }}-pip-unit-v1 restore-keys: | - ${{ runner.os }}-pip- + ${{ runner.os }}-pip-unit- - name: Cache PlatformIO uses: actions/cache@v4 with: - path: ~/.platformio - key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }} + path: | + ~/.platformio + .pio/build + .pio/libdeps + key: ${{ runner.os }}-pio-tests-v1 + restore-keys: | + ${{ runner.os }}-pio-tests- - name: Select Python 3.9 uses: actions/setup-python@v5 diff --git a/.github/workflows/ci-validate-boards.yml b/.github/workflows/ci-validate-boards.yml index baa7b8b6e1..36f3a3522a 100644 --- a/.github/workflows/ci-validate-boards.yml +++ b/.github/workflows/ci-validate-boards.yml @@ -33,9 +33,9 @@ jobs: uses: actions/cache@v4 with: path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + key: ${{ runner.os }}-pip-boards-v1 restore-keys: | - ${{ runner.os }}-pip- + ${{ runner.os }}-pip-boards- - name: Select Python 3.9 uses: actions/setup-python@v5 diff --git a/.github/workflows/ci-validate-pins.yml b/.github/workflows/ci-validate-pins.yml index 695f8eff18..ae777427e7 100644 --- a/.github/workflows/ci-validate-pins.yml +++ b/.github/workflows/ci-validate-pins.yml @@ -36,9 +36,9 @@ jobs: uses: actions/cache@v4 with: path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + key: ${{ runner.os }}-pip-pins-v1 restore-keys: | - ${{ runner.os }}-pip- + ${{ runner.os }}-pip-pins- - name: Select Python 3.9 uses: actions/setup-python@v5 From db4990f2c4f36eb56323c262b42042ec8efb6ad9 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Tue, 8 Apr 2025 00:29:33 +0000 Subject: [PATCH 195/787] [cron] Bump distribution date (2025-04-08) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index f5b31acafd..d071d96c66 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-04-07" +//#define STRING_DISTRIBUTION_DATE "2025-04-08" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index c49c7faeb6..13b8eee07e 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-04-07" + #define STRING_DISTRIBUTION_DATE "2025-04-08" #endif /** From 6f5e6fd25b80aa994b2a887e0c20d3a67e3d2fb5 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Wed, 9 Apr 2025 18:41:12 -0500 Subject: [PATCH 196/787] =?UTF-8?q?=F0=9F=A9=B9=20TFT=5FBUFFER=5FSIZE=20?= =?UTF-8?q?=3D>=20=5FWORDS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Followup to #26011 --- Marlin/src/pins/rp2040/pins_RP2040.h | 2 +- .../pins/stm32f4/pins_BTT_SKR_V2_0_common.h | 2 +- .../src/pins/stm32f4/pins_MELLOW_FLY_E3_V2.h | 2 +- .../pins/stm32f4/pins_MKS_NEPTUNE_X_common.h | 39 +------------------ 4 files changed, 5 insertions(+), 40 deletions(-) diff --git a/Marlin/src/pins/rp2040/pins_RP2040.h b/Marlin/src/pins/rp2040/pins_RP2040.h index 48e37e4e1f..6a4e54f0bd 100644 --- a/Marlin/src/pins/rp2040/pins_RP2040.h +++ b/Marlin/src/pins/rp2040/pins_RP2040.h @@ -293,7 +293,7 @@ #define SPI_FLASH_SCK_PIN SD_SCK_PIN #endif - #define TFT_BUFFER_SIZE 0xFFFF + #define TFT_BUFFER_WORDS 0xFFFF #ifndef TFT_DRIVER #define TFT_DRIVER ST7796 #endif diff --git a/Marlin/src/pins/stm32f4/pins_BTT_SKR_V2_0_common.h b/Marlin/src/pins/stm32f4/pins_BTT_SKR_V2_0_common.h index 692b50be40..51b27efa39 100644 --- a/Marlin/src/pins/stm32f4/pins_BTT_SKR_V2_0_common.h +++ b/Marlin/src/pins/stm32f4/pins_BTT_SKR_V2_0_common.h @@ -483,7 +483,7 @@ #elif ENABLED(FYSETC_MINI_12864_2_1) #define NEOPIXEL_PIN EXP1_06_PIN #endif - #endif // !FYSETC_MINI_12864 + #endif // FYSETC_MINI_12864 #if IS_ULTIPANEL #define LCD_PINS_D5 EXP1_06_PIN diff --git a/Marlin/src/pins/stm32f4/pins_MELLOW_FLY_E3_V2.h b/Marlin/src/pins/stm32f4/pins_MELLOW_FLY_E3_V2.h index 3ae1432a14..4626176a99 100644 --- a/Marlin/src/pins/stm32f4/pins_MELLOW_FLY_E3_V2.h +++ b/Marlin/src/pins/stm32f4/pins_MELLOW_FLY_E3_V2.h @@ -472,7 +472,7 @@ #define LCD_READ_ID 0xD3 #define LCD_USE_DMA_SPI - #define TFT_BUFFER_SIZE 14400 + #define TFT_BUFFER_WORDS 14400 #endif diff --git a/Marlin/src/pins/stm32f4/pins_MKS_NEPTUNE_X_common.h b/Marlin/src/pins/stm32f4/pins_MKS_NEPTUNE_X_common.h index 7d1d7943cf..4e59f1c5dd 100644 --- a/Marlin/src/pins/stm32f4/pins_MKS_NEPTUNE_X_common.h +++ b/Marlin/src/pins/stm32f4/pins_MKS_NEPTUNE_X_common.h @@ -208,41 +208,6 @@ #define MKS_TEST_PS_ON_PIN PB2 // PW_OFF #endif -// -// TFT with FSMC interface -// -#if HAS_FSMC_TFT - /** - * Note: MKS Robin TFT screens use various TFT controllers. - * If the screen stays white, disable 'TFT_RESET_PIN' - * to let the bootloader init the screen. - */ - #define TFT_RESET_PIN PC6 // FSMC_RST - #define TFT_BACKLIGHT_PIN PD13 - - #define DOGLCD_MOSI -1 // Prevent auto-define by Conditionals_post.h - #define DOGLCD_SCK -1 - - #define TOUCH_CS_PIN PA7 // SPI2_NSS - #define TOUCH_SCK_PIN PB13 // SPI2_SCK - #define TOUCH_MISO_PIN PB14 // SPI2_MISO - #define TOUCH_MOSI_PIN PB15 // SPI2_MOSI - - #define LCD_USE_DMA_FSMC // Use DMA transfers to send data to the TFT - #define FSMC_CS_PIN PD7 - #define FSMC_RS_PIN PD11 - #define FSMC_DMA_DEV DMA2 - #define FSMC_DMA_CHANNEL DMA_CH5 - - #define TFT_CS_PIN FSMC_CS_PIN - #define TFT_RS_PIN FSMC_RS_PIN - - #define TOUCH_BUTTONS_HW_SPI - #define TOUCH_BUTTONS_HW_SPI_DEVICE 2 - - #define TFT_BUFFER_SIZE 14400 -#endif - // // Onboard SD card // @@ -305,5 +270,5 @@ #define TOUCH_BUTTONS_HW_SPI #define TOUCH_BUTTONS_HW_SPI_DEVICE 2 - #define TFT_BUFFER_SIZE 14400 -#endif + #define TFT_BUFFER_WORDS 14400 +#endif // HAS_FSMC_TFT From 47820cac8a20987508236cdc4de639502f500b2f Mon Sep 17 00:00:00 2001 From: Andrew <18502096+classicrocker883@users.noreply.github.com> Date: Wed, 9 Apr 2025 20:08:10 -0400 Subject: [PATCH 197/787] =?UTF-8?q?=F0=9F=8E=A8=20Whitespace=20cleanups=20?= =?UTF-8?q?(#27784)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/Makefile | 10 +- Marlin/src/HAL/AVR/pinsDebug_plus_70.h | 504 ++++++++--------- Marlin/src/HAL/DUE/HAL_SPI.cpp | 14 +- Marlin/src/HAL/RP2040/timers.h | 8 +- Marlin/src/HAL/STM32F1/HAL_N32.h | 16 +- Marlin/src/HAL/STM32F1/sdio.cpp | 2 +- Marlin/src/HAL/TEENSY31_32/fastio.h | 6 +- Marlin/src/HAL/TEENSY35_36/fastio.h | 6 +- Marlin/src/core/serial_base.h | 2 +- Marlin/src/core/types.h | 4 +- Marlin/src/feature/bedlevel/ubl/ubl.h | 2 +- Marlin/src/gcode/host/M360.cpp | 2 +- Marlin/src/inc/Conditionals-2-LCD.h | 2 +- Marlin/src/lcd/e3v2/jyersui/dwin.cpp | 4 +- Marlin/src/lcd/e3v2/proui/menus.cpp | 4 +- .../lcd/extui/anycubic_chiron/chiron_tft.cpp | 4 +- .../src/lcd/extui/anycubic_vyper/dgus_tft.cpp | 4 +- .../lcd/extui/dgus/fysetc/DGUSDisplayDef.cpp | 2 +- .../lcd/extui/dgus/fysetc/DGUSDisplayDef.h | 12 +- .../lcd/extui/dgus/hiprecy/DGUSDisplayDef.cpp | 2 +- .../lcd/extui/dgus/hiprecy/DGUSDisplayDef.h | 10 +- .../src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp | 12 +- .../src/lcd/extui/dgus/mks/DGUSDisplayDef.h | 12 +- .../lcd/extui/dgus/origin/DGUSDisplayDef.cpp | 2 +- .../lcd/extui/dgus/origin/DGUSDisplayDef.h | 10 +- .../ftdi_eve_lib/scripts/font2cpp.py | 2 +- Marlin/src/lcd/extui/mks_ui/tft_Language_en.h | 4 +- Marlin/src/lcd/extui/mks_ui/tft_Language_it.h | 4 +- Marlin/src/lcd/extui/mks_ui/tft_Language_ru.h | 4 +- Marlin/src/lcd/extui/ui_api.h | 4 +- Marlin/src/lcd/tft/ui_color_ui.cpp | 6 +- Marlin/src/module/scara.cpp | 4 +- Marlin/src/module/temperature.cpp | 4 +- Marlin/src/module/thermistor/thermistor_666.h | 2 +- Marlin/src/pins/sam/pins_ALLIGATOR_R2.h | 2 +- .../src/pins/samd/pins_BRICOLEMON_LITE_V1_0.h | 2 +- Marlin/src/pins/samd/pins_BRICOLEMON_V1_0.h | 2 +- .../usb_flashdrive/lib-uhs3/dyn_SWI/dyn_SWI.h | 2 +- buildroot/share/PlatformIO/scripts/exc.S | 2 +- .../variants/MARLIN_FLY_D5/ldscript.ld | 2 +- .../variants/MARLIN_FLY_D7/ldscript.ld | 2 +- .../MARLIN_MEGA_EXTENDED/pins_arduino.h | 516 +++++++++--------- .../marlin_maple_CHITU_F103/board.cpp | 128 ++--- .../variants/marlin_maple_MEEB_3DP/board.cpp | 6 +- .../scripts/createTemperatureLookupMarlin.py | 2 +- buildroot/tests/BTT_GTR_V1_0 | 2 +- docs/Cutter.md | 2 +- ini/hc32.ini | 12 +- 48 files changed, 686 insertions(+), 686 deletions(-) diff --git a/Marlin/Makefile b/Marlin/Makefile index 63b1029e1b..ce26bd3572 100644 --- a/Marlin/Makefile +++ b/Marlin/Makefile @@ -127,9 +127,9 @@ NEOPIXEL ?= 0 # on GCC versions: # https://www.avrfreaks.net/comment/1789106#comment-1789106 -CC_MAJ:=$(shell $(CC) -dM -E - < /dev/null | grep __GNUC__ | cut -f3 -d\ ) -CC_MIN:=$(shell $(CC) -dM -E - < /dev/null | grep __GNUC_MINOR__ | cut -f3 -d\ ) -CC_PATCHLEVEL:=$(shell $(CC) -dM -E - < /dev/null | grep __GNUC_PATCHLEVEL__ | cut -f3 -d\ ) +CC_MAJ:=$(shell $(CC) -dM -E - < /dev/null | grep __GNUC__ | cut -f3 -d' ' ) +CC_MIN:=$(shell $(CC) -dM -E - < /dev/null | grep __GNUC_MINOR__ | cut -f3 -d' ' ) +CC_PATCHLEVEL:=$(shell $(CC) -dM -E - < /dev/null | grep __GNUC_PATCHLEVEL__ | cut -f3 -d' ' ) CC_VER:=$(shell echo $$(( $(CC_MAJ) * 10000 + $(CC_MIN) * 100 + $(CC_PATCHLEVEL) ))) ifeq ($(shell test $(CC_VER) -lt 40901 && echo 1),1) $(warning This GCC version $(CC_VER) is likely broken. Enabling relocation workaround.) @@ -868,8 +868,8 @@ else ifeq ($(HARDWARE_VARIANT), archim) endif # Add all the source directories as include directories too -CINCS = ${addprefix -I ,${VPATH}} -CXXINCS = ${addprefix -I ,${VPATH}} +CINCS = ${addprefix -I, ${VPATH}} +CXXINCS = ${addprefix -I, ${VPATH}} # Silence warnings for library code (won't work for .h files, unfortunately) LIBWARN = -w -Wno-packed-bitfield-compat diff --git a/Marlin/src/HAL/AVR/pinsDebug_plus_70.h b/Marlin/src/HAL/AVR/pinsDebug_plus_70.h index fa479cfe8f..6565acd523 100644 --- a/Marlin/src/HAL/AVR/pinsDebug_plus_70.h +++ b/Marlin/src/HAL/AVR/pinsDebug_plus_70.h @@ -48,92 +48,92 @@ const uint8_t PROGMEM digital_pin_to_port_PGM_plus_70[] = { // PORTLIST // ------------------------ - PE , // PE 0 ** 0 ** USART0_RX - PE , // PE 1 ** 1 ** USART0_TX - PE , // PE 4 ** 2 ** PWM2 - PE , // PE 5 ** 3 ** PWM3 - PG , // PG 5 ** 4 ** PWM4 - PE , // PE 3 ** 5 ** PWM5 - PH , // PH 3 ** 6 ** PWM6 - PH , // PH 4 ** 7 ** PWM7 - PH , // PH 5 ** 8 ** PWM8 - PH , // PH 6 ** 9 ** PWM9 - PB , // PB 4 ** 10 ** PWM10 - PB , // PB 5 ** 11 ** PWM11 - PB , // PB 6 ** 12 ** PWM12 - PB , // PB 7 ** 13 ** PWM13 - PJ , // PJ 1 ** 14 ** USART3_TX - PJ , // PJ 0 ** 15 ** USART3_RX - PH , // PH 1 ** 16 ** USART2_TX - PH , // PH 0 ** 17 ** USART2_RX - PD , // PD 3 ** 18 ** USART1_TX - PD , // PD 2 ** 19 ** USART1_RX - PD , // PD 1 ** 20 ** I2C_SDA - PD , // PD 0 ** 21 ** I2C_SCL - PA , // PA 0 ** 22 ** D22 - PA , // PA 1 ** 23 ** D23 - PA , // PA 2 ** 24 ** D24 - PA , // PA 3 ** 25 ** D25 - PA , // PA 4 ** 26 ** D26 - PA , // PA 5 ** 27 ** D27 - PA , // PA 6 ** 28 ** D28 - PA , // PA 7 ** 29 ** D29 - PC , // PC 7 ** 30 ** D30 - PC , // PC 6 ** 31 ** D31 - PC , // PC 5 ** 32 ** D32 - PC , // PC 4 ** 33 ** D33 - PC , // PC 3 ** 34 ** D34 - PC , // PC 2 ** 35 ** D35 - PC , // PC 1 ** 36 ** D36 - PC , // PC 0 ** 37 ** D37 - PD , // PD 7 ** 38 ** D38 - PG , // PG 2 ** 39 ** D39 - PG , // PG 1 ** 40 ** D40 - PG , // PG 0 ** 41 ** D41 - PL , // PL 7 ** 42 ** D42 - PL , // PL 6 ** 43 ** D43 - PL , // PL 5 ** 44 ** D44 - PL , // PL 4 ** 45 ** D45 - PL , // PL 3 ** 46 ** D46 - PL , // PL 2 ** 47 ** D47 - PL , // PL 1 ** 48 ** D48 - PL , // PL 0 ** 49 ** D49 - PB , // PB 3 ** 50 ** SPI_MISO - PB , // PB 2 ** 51 ** SPI_MOSI - PB , // PB 1 ** 52 ** SPI_SCK - PB , // PB 0 ** 53 ** SPI_SS - PF , // PF 0 ** 54 ** A0 - PF , // PF 1 ** 55 ** A1 - PF , // PF 2 ** 56 ** A2 - PF , // PF 3 ** 57 ** A3 - PF , // PF 4 ** 58 ** A4 - PF , // PF 5 ** 59 ** A5 - PF , // PF 6 ** 60 ** A6 - PF , // PF 7 ** 61 ** A7 - PK , // PK 0 ** 62 ** A8 - PK , // PK 1 ** 63 ** A9 - PK , // PK 2 ** 64 ** A10 - PK , // PK 3 ** 65 ** A11 - PK , // PK 4 ** 66 ** A12 - PK , // PK 5 ** 67 ** A13 - PK , // PK 6 ** 68 ** A14 - PK , // PK 7 ** 69 ** A15 - PG , // PG 4 ** 70 ** - PG , // PG 3 ** 71 ** - PJ , // PJ 2 ** 72 ** - PJ , // PJ 3 ** 73 ** - PJ , // PJ 7 ** 74 ** - PJ , // PJ 4 ** 75 ** - PJ , // PJ 5 ** 76 ** - PJ , // PJ 6 ** 77 ** - PE , // PE 2 ** 78 ** - PE , // PE 6 ** 79 ** - PE , // PE 7 ** 80 ** - PD , // PD 4 ** 81 ** - PD , // PD 5 ** 82 ** - PD , // PD 6 ** 83 ** - PH , // PH 2 ** 84 ** - PH , // PH 7 ** 85 ** + PE, // PE 0 ** 0 ** USART0_RX + PE, // PE 1 ** 1 ** USART0_TX + PE, // PE 4 ** 2 ** PWM2 + PE, // PE 5 ** 3 ** PWM3 + PG, // PG 5 ** 4 ** PWM4 + PE, // PE 3 ** 5 ** PWM5 + PH, // PH 3 ** 6 ** PWM6 + PH, // PH 4 ** 7 ** PWM7 + PH, // PH 5 ** 8 ** PWM8 + PH, // PH 6 ** 9 ** PWM9 + PB, // PB 4 ** 10 ** PWM10 + PB, // PB 5 ** 11 ** PWM11 + PB, // PB 6 ** 12 ** PWM12 + PB, // PB 7 ** 13 ** PWM13 + PJ, // PJ 1 ** 14 ** USART3_TX + PJ, // PJ 0 ** 15 ** USART3_RX + PH, // PH 1 ** 16 ** USART2_TX + PH, // PH 0 ** 17 ** USART2_RX + PD, // PD 3 ** 18 ** USART1_TX + PD, // PD 2 ** 19 ** USART1_RX + PD, // PD 1 ** 20 ** I2C_SDA + PD, // PD 0 ** 21 ** I2C_SCL + PA, // PA 0 ** 22 ** D22 + PA, // PA 1 ** 23 ** D23 + PA, // PA 2 ** 24 ** D24 + PA, // PA 3 ** 25 ** D25 + PA, // PA 4 ** 26 ** D26 + PA, // PA 5 ** 27 ** D27 + PA, // PA 6 ** 28 ** D28 + PA, // PA 7 ** 29 ** D29 + PC, // PC 7 ** 30 ** D30 + PC, // PC 6 ** 31 ** D31 + PC, // PC 5 ** 32 ** D32 + PC, // PC 4 ** 33 ** D33 + PC, // PC 3 ** 34 ** D34 + PC, // PC 2 ** 35 ** D35 + PC, // PC 1 ** 36 ** D36 + PC, // PC 0 ** 37 ** D37 + PD, // PD 7 ** 38 ** D38 + PG, // PG 2 ** 39 ** D39 + PG, // PG 1 ** 40 ** D40 + PG, // PG 0 ** 41 ** D41 + PL, // PL 7 ** 42 ** D42 + PL, // PL 6 ** 43 ** D43 + PL, // PL 5 ** 44 ** D44 + PL, // PL 4 ** 45 ** D45 + PL, // PL 3 ** 46 ** D46 + PL, // PL 2 ** 47 ** D47 + PL, // PL 1 ** 48 ** D48 + PL, // PL 0 ** 49 ** D49 + PB, // PB 3 ** 50 ** SPI_MISO + PB, // PB 2 ** 51 ** SPI_MOSI + PB, // PB 1 ** 52 ** SPI_SCK + PB, // PB 0 ** 53 ** SPI_SS + PF, // PF 0 ** 54 ** A0 + PF, // PF 1 ** 55 ** A1 + PF, // PF 2 ** 56 ** A2 + PF, // PF 3 ** 57 ** A3 + PF, // PF 4 ** 58 ** A4 + PF, // PF 5 ** 59 ** A5 + PF, // PF 6 ** 60 ** A6 + PF, // PF 7 ** 61 ** A7 + PK, // PK 0 ** 62 ** A8 + PK, // PK 1 ** 63 ** A9 + PK, // PK 2 ** 64 ** A10 + PK, // PK 3 ** 65 ** A11 + PK, // PK 4 ** 66 ** A12 + PK, // PK 5 ** 67 ** A13 + PK, // PK 6 ** 68 ** A14 + PK, // PK 7 ** 69 ** A15 + PG, // PG 4 ** 70 ** + PG, // PG 3 ** 71 ** + PJ, // PJ 2 ** 72 ** + PJ, // PJ 3 ** 73 ** + PJ, // PJ 7 ** 74 ** + PJ, // PJ 4 ** 75 ** + PJ, // PJ 5 ** 76 ** + PJ, // PJ 6 ** 77 ** + PE, // PE 2 ** 78 ** + PE, // PE 6 ** 79 ** + PE, // PE 7 ** 80 ** + PD, // PD 4 ** 81 ** + PD, // PD 5 ** 82 ** + PD, // PD 6 ** 83 ** + PH, // PH 2 ** 84 ** + PH, // PH 7 ** 85 ** }; #define digitalPinToPort_plus_70(P) ( pgm_read_byte( digital_pin_to_port_PGM_plus_70 + (P) ) ) @@ -141,92 +141,92 @@ const uint8_t PROGMEM digital_pin_to_port_PGM_plus_70[] = { const uint8_t PROGMEM digital_pin_to_bit_mask_PGM_plus_70[] = { // PIN IN PORT // ------------------------ - _BV( 0 ) , // PE 0 ** 0 ** USART0_RX - _BV( 1 ) , // PE 1 ** 1 ** USART0_TX - _BV( 4 ) , // PE 4 ** 2 ** PWM2 - _BV( 5 ) , // PE 5 ** 3 ** PWM3 - _BV( 5 ) , // PG 5 ** 4 ** PWM4 - _BV( 3 ) , // PE 3 ** 5 ** PWM5 - _BV( 3 ) , // PH 3 ** 6 ** PWM6 - _BV( 4 ) , // PH 4 ** 7 ** PWM7 - _BV( 5 ) , // PH 5 ** 8 ** PWM8 - _BV( 6 ) , // PH 6 ** 9 ** PWM9 - _BV( 4 ) , // PB 4 ** 10 ** PWM10 - _BV( 5 ) , // PB 5 ** 11 ** PWM11 - _BV( 6 ) , // PB 6 ** 12 ** PWM12 - _BV( 7 ) , // PB 7 ** 13 ** PWM13 - _BV( 1 ) , // PJ 1 ** 14 ** USART3_TX - _BV( 0 ) , // PJ 0 ** 15 ** USART3_RX - _BV( 1 ) , // PH 1 ** 16 ** USART2_TX - _BV( 0 ) , // PH 0 ** 17 ** USART2_RX - _BV( 3 ) , // PD 3 ** 18 ** USART1_TX - _BV( 2 ) , // PD 2 ** 19 ** USART1_RX - _BV( 1 ) , // PD 1 ** 20 ** I2C_SDA - _BV( 0 ) , // PD 0 ** 21 ** I2C_SCL - _BV( 0 ) , // PA 0 ** 22 ** D22 - _BV( 1 ) , // PA 1 ** 23 ** D23 - _BV( 2 ) , // PA 2 ** 24 ** D24 - _BV( 3 ) , // PA 3 ** 25 ** D25 - _BV( 4 ) , // PA 4 ** 26 ** D26 - _BV( 5 ) , // PA 5 ** 27 ** D27 - _BV( 6 ) , // PA 6 ** 28 ** D28 - _BV( 7 ) , // PA 7 ** 29 ** D29 - _BV( 7 ) , // PC 7 ** 30 ** D30 - _BV( 6 ) , // PC 6 ** 31 ** D31 - _BV( 5 ) , // PC 5 ** 32 ** D32 - _BV( 4 ) , // PC 4 ** 33 ** D33 - _BV( 3 ) , // PC 3 ** 34 ** D34 - _BV( 2 ) , // PC 2 ** 35 ** D35 - _BV( 1 ) , // PC 1 ** 36 ** D36 - _BV( 0 ) , // PC 0 ** 37 ** D37 - _BV( 7 ) , // PD 7 ** 38 ** D38 - _BV( 2 ) , // PG 2 ** 39 ** D39 - _BV( 1 ) , // PG 1 ** 40 ** D40 - _BV( 0 ) , // PG 0 ** 41 ** D41 - _BV( 7 ) , // PL 7 ** 42 ** D42 - _BV( 6 ) , // PL 6 ** 43 ** D43 - _BV( 5 ) , // PL 5 ** 44 ** D44 - _BV( 4 ) , // PL 4 ** 45 ** D45 - _BV( 3 ) , // PL 3 ** 46 ** D46 - _BV( 2 ) , // PL 2 ** 47 ** D47 - _BV( 1 ) , // PL 1 ** 48 ** D48 - _BV( 0 ) , // PL 0 ** 49 ** D49 - _BV( 3 ) , // PB 3 ** 50 ** SPI_MISO - _BV( 2 ) , // PB 2 ** 51 ** SPI_MOSI - _BV( 1 ) , // PB 1 ** 52 ** SPI_SCK - _BV( 0 ) , // PB 0 ** 53 ** SPI_SS - _BV( 0 ) , // PF 0 ** 54 ** A0 - _BV( 1 ) , // PF 1 ** 55 ** A1 - _BV( 2 ) , // PF 2 ** 56 ** A2 - _BV( 3 ) , // PF 3 ** 57 ** A3 - _BV( 4 ) , // PF 4 ** 58 ** A4 - _BV( 5 ) , // PF 5 ** 59 ** A5 - _BV( 6 ) , // PF 6 ** 60 ** A6 - _BV( 7 ) , // PF 7 ** 61 ** A7 - _BV( 0 ) , // PK 0 ** 62 ** A8 - _BV( 1 ) , // PK 1 ** 63 ** A9 - _BV( 2 ) , // PK 2 ** 64 ** A10 - _BV( 3 ) , // PK 3 ** 65 ** A11 - _BV( 4 ) , // PK 4 ** 66 ** A12 - _BV( 5 ) , // PK 5 ** 67 ** A13 - _BV( 6 ) , // PK 6 ** 68 ** A14 - _BV( 7 ) , // PK 7 ** 69 ** A15 - _BV( 4 ) , // PG 4 ** 70 ** - _BV( 3 ) , // PG 3 ** 71 ** - _BV( 2 ) , // PJ 2 ** 72 ** - _BV( 3 ) , // PJ 3 ** 73 ** - _BV( 7 ) , // PJ 7 ** 74 ** - _BV( 4 ) , // PJ 4 ** 75 ** - _BV( 5 ) , // PJ 5 ** 76 ** - _BV( 6 ) , // PJ 6 ** 77 ** - _BV( 2 ) , // PE 2 ** 78 ** - _BV( 6 ) , // PE 6 ** 79 ** - _BV( 7 ) , // PE 7 ** 80 ** - _BV( 4 ) , // PD 4 ** 81 ** - _BV( 5 ) , // PD 5 ** 82 ** - _BV( 6 ) , // PD 6 ** 83 ** - _BV( 2 ) , // PH 2 ** 84 ** - _BV( 7 ) , // PH 7 ** 85 ** + _BV( 0 ), // PE 0 ** 0 ** USART0_RX + _BV( 1 ), // PE 1 ** 1 ** USART0_TX + _BV( 4 ), // PE 4 ** 2 ** PWM2 + _BV( 5 ), // PE 5 ** 3 ** PWM3 + _BV( 5 ), // PG 5 ** 4 ** PWM4 + _BV( 3 ), // PE 3 ** 5 ** PWM5 + _BV( 3 ), // PH 3 ** 6 ** PWM6 + _BV( 4 ), // PH 4 ** 7 ** PWM7 + _BV( 5 ), // PH 5 ** 8 ** PWM8 + _BV( 6 ), // PH 6 ** 9 ** PWM9 + _BV( 4 ), // PB 4 ** 10 ** PWM10 + _BV( 5 ), // PB 5 ** 11 ** PWM11 + _BV( 6 ), // PB 6 ** 12 ** PWM12 + _BV( 7 ), // PB 7 ** 13 ** PWM13 + _BV( 1 ), // PJ 1 ** 14 ** USART3_TX + _BV( 0 ), // PJ 0 ** 15 ** USART3_RX + _BV( 1 ), // PH 1 ** 16 ** USART2_TX + _BV( 0 ), // PH 0 ** 17 ** USART2_RX + _BV( 3 ), // PD 3 ** 18 ** USART1_TX + _BV( 2 ), // PD 2 ** 19 ** USART1_RX + _BV( 1 ), // PD 1 ** 20 ** I2C_SDA + _BV( 0 ), // PD 0 ** 21 ** I2C_SCL + _BV( 0 ), // PA 0 ** 22 ** D22 + _BV( 1 ), // PA 1 ** 23 ** D23 + _BV( 2 ), // PA 2 ** 24 ** D24 + _BV( 3 ), // PA 3 ** 25 ** D25 + _BV( 4 ), // PA 4 ** 26 ** D26 + _BV( 5 ), // PA 5 ** 27 ** D27 + _BV( 6 ), // PA 6 ** 28 ** D28 + _BV( 7 ), // PA 7 ** 29 ** D29 + _BV( 7 ), // PC 7 ** 30 ** D30 + _BV( 6 ), // PC 6 ** 31 ** D31 + _BV( 5 ), // PC 5 ** 32 ** D32 + _BV( 4 ), // PC 4 ** 33 ** D33 + _BV( 3 ), // PC 3 ** 34 ** D34 + _BV( 2 ), // PC 2 ** 35 ** D35 + _BV( 1 ), // PC 1 ** 36 ** D36 + _BV( 0 ), // PC 0 ** 37 ** D37 + _BV( 7 ), // PD 7 ** 38 ** D38 + _BV( 2 ), // PG 2 ** 39 ** D39 + _BV( 1 ), // PG 1 ** 40 ** D40 + _BV( 0 ), // PG 0 ** 41 ** D41 + _BV( 7 ), // PL 7 ** 42 ** D42 + _BV( 6 ), // PL 6 ** 43 ** D43 + _BV( 5 ), // PL 5 ** 44 ** D44 + _BV( 4 ), // PL 4 ** 45 ** D45 + _BV( 3 ), // PL 3 ** 46 ** D46 + _BV( 2 ), // PL 2 ** 47 ** D47 + _BV( 1 ), // PL 1 ** 48 ** D48 + _BV( 0 ), // PL 0 ** 49 ** D49 + _BV( 3 ), // PB 3 ** 50 ** SPI_MISO + _BV( 2 ), // PB 2 ** 51 ** SPI_MOSI + _BV( 1 ), // PB 1 ** 52 ** SPI_SCK + _BV( 0 ), // PB 0 ** 53 ** SPI_SS + _BV( 0 ), // PF 0 ** 54 ** A0 + _BV( 1 ), // PF 1 ** 55 ** A1 + _BV( 2 ), // PF 2 ** 56 ** A2 + _BV( 3 ), // PF 3 ** 57 ** A3 + _BV( 4 ), // PF 4 ** 58 ** A4 + _BV( 5 ), // PF 5 ** 59 ** A5 + _BV( 6 ), // PF 6 ** 60 ** A6 + _BV( 7 ), // PF 7 ** 61 ** A7 + _BV( 0 ), // PK 0 ** 62 ** A8 + _BV( 1 ), // PK 1 ** 63 ** A9 + _BV( 2 ), // PK 2 ** 64 ** A10 + _BV( 3 ), // PK 3 ** 65 ** A11 + _BV( 4 ), // PK 4 ** 66 ** A12 + _BV( 5 ), // PK 5 ** 67 ** A13 + _BV( 6 ), // PK 6 ** 68 ** A14 + _BV( 7 ), // PK 7 ** 69 ** A15 + _BV( 4 ), // PG 4 ** 70 ** + _BV( 3 ), // PG 3 ** 71 ** + _BV( 2 ), // PJ 2 ** 72 ** + _BV( 3 ), // PJ 3 ** 73 ** + _BV( 7 ), // PJ 7 ** 74 ** + _BV( 4 ), // PJ 4 ** 75 ** + _BV( 5 ), // PJ 5 ** 76 ** + _BV( 6 ), // PJ 6 ** 77 ** + _BV( 2 ), // PE 2 ** 78 ** + _BV( 6 ), // PE 6 ** 79 ** + _BV( 7 ), // PE 7 ** 80 ** + _BV( 4 ), // PD 4 ** 81 ** + _BV( 5 ), // PD 5 ** 82 ** + _BV( 6 ), // PD 6 ** 83 ** + _BV( 2 ), // PH 2 ** 84 ** + _BV( 7 ), // PH 7 ** 85 ** }; #define digitalPinToBitMask_plus_70(P) ( pgm_read_byte( digital_pin_to_bit_mask_PGM_plus_70 + (P) ) ) @@ -234,86 +234,86 @@ const uint8_t PROGMEM digital_pin_to_bit_mask_PGM_plus_70[] = { const uint8_t PROGMEM digital_pin_to_timer_PGM_plus_70[] = { // TIMERS // ------------------------ - NOT_ON_TIMER , // PE 0 ** 0 ** USART0_RX - NOT_ON_TIMER , // PE 1 ** 1 ** USART0_TX - TIMER3B , // PE 4 ** 2 ** PWM2 - TIMER3C , // PE 5 ** 3 ** PWM3 - TIMER0B , // PG 5 ** 4 ** PWM4 - TIMER3A , // PE 3 ** 5 ** PWM5 - TIMER4A , // PH 3 ** 6 ** PWM6 - TIMER4B , // PH 4 ** 7 ** PWM7 - TIMER4C , // PH 5 ** 8 ** PWM8 - TIMER2B , // PH 6 ** 9 ** PWM9 - TIMER2A , // PB 4 ** 10 ** PWM10 - TIMER1A , // PB 5 ** 11 ** PWM11 - TIMER1B , // PB 6 ** 12 ** PWM12 - TIMER0A , // PB 7 ** 13 ** PWM13 - NOT_ON_TIMER , // PJ 1 ** 14 ** USART3_TX - NOT_ON_TIMER , // PJ 0 ** 15 ** USART3_RX - NOT_ON_TIMER , // PH 1 ** 16 ** USART2_TX - NOT_ON_TIMER , // PH 0 ** 17 ** USART2_RX - NOT_ON_TIMER , // PD 3 ** 18 ** USART1_TX - NOT_ON_TIMER , // PD 2 ** 19 ** USART1_RX - NOT_ON_TIMER , // PD 1 ** 20 ** I2C_SDA - NOT_ON_TIMER , // PD 0 ** 21 ** I2C_SCL - NOT_ON_TIMER , // PA 0 ** 22 ** D22 - NOT_ON_TIMER , // PA 1 ** 23 ** D23 - NOT_ON_TIMER , // PA 2 ** 24 ** D24 - NOT_ON_TIMER , // PA 3 ** 25 ** D25 - NOT_ON_TIMER , // PA 4 ** 26 ** D26 - NOT_ON_TIMER , // PA 5 ** 27 ** D27 - NOT_ON_TIMER , // PA 6 ** 28 ** D28 - NOT_ON_TIMER , // PA 7 ** 29 ** D29 - NOT_ON_TIMER , // PC 7 ** 30 ** D30 - NOT_ON_TIMER , // PC 6 ** 31 ** D31 - NOT_ON_TIMER , // PC 5 ** 32 ** D32 - NOT_ON_TIMER , // PC 4 ** 33 ** D33 - NOT_ON_TIMER , // PC 3 ** 34 ** D34 - NOT_ON_TIMER , // PC 2 ** 35 ** D35 - NOT_ON_TIMER , // PC 1 ** 36 ** D36 - NOT_ON_TIMER , // PC 0 ** 37 ** D37 - NOT_ON_TIMER , // PD 7 ** 38 ** D38 - NOT_ON_TIMER , // PG 2 ** 39 ** D39 - NOT_ON_TIMER , // PG 1 ** 40 ** D40 - NOT_ON_TIMER , // PG 0 ** 41 ** D41 - NOT_ON_TIMER , // PL 7 ** 42 ** D42 - NOT_ON_TIMER , // PL 6 ** 43 ** D43 - TIMER5C , // PL 5 ** 44 ** D44 - TIMER5B , // PL 4 ** 45 ** D45 - TIMER5A , // PL 3 ** 46 ** D46 - NOT_ON_TIMER , // PL 2 ** 47 ** D47 - NOT_ON_TIMER , // PL 1 ** 48 ** D48 - NOT_ON_TIMER , // PL 0 ** 49 ** D49 - NOT_ON_TIMER , // PB 3 ** 50 ** SPI_MISO - NOT_ON_TIMER , // PB 2 ** 51 ** SPI_MOSI - NOT_ON_TIMER , // PB 1 ** 52 ** SPI_SCK - NOT_ON_TIMER , // PB 0 ** 53 ** SPI_SS - NOT_ON_TIMER , // PF 0 ** 54 ** A0 - NOT_ON_TIMER , // PF 1 ** 55 ** A1 - NOT_ON_TIMER , // PF 2 ** 56 ** A2 - NOT_ON_TIMER , // PF 3 ** 57 ** A3 - NOT_ON_TIMER , // PF 4 ** 58 ** A4 - NOT_ON_TIMER , // PF 5 ** 59 ** A5 - NOT_ON_TIMER , // PF 6 ** 60 ** A6 - NOT_ON_TIMER , // PF 7 ** 61 ** A7 - NOT_ON_TIMER , // PK 0 ** 62 ** A8 - NOT_ON_TIMER , // PK 1 ** 63 ** A9 - NOT_ON_TIMER , // PK 2 ** 64 ** A10 - NOT_ON_TIMER , // PK 3 ** 65 ** A11 - NOT_ON_TIMER , // PK 4 ** 66 ** A12 - NOT_ON_TIMER , // PK 5 ** 67 ** A13 - NOT_ON_TIMER , // PK 6 ** 68 ** A14 - NOT_ON_TIMER , // PK 7 ** 69 ** A15 - NOT_ON_TIMER , // PG 4 ** 70 ** - NOT_ON_TIMER , // PG 3 ** 71 ** - NOT_ON_TIMER , // PJ 2 ** 72 ** - NOT_ON_TIMER , // PJ 3 ** 73 ** - NOT_ON_TIMER , // PJ 7 ** 74 ** - NOT_ON_TIMER , // PJ 4 ** 75 ** - NOT_ON_TIMER , // PJ 5 ** 76 ** - NOT_ON_TIMER , // PJ 6 ** 77 ** - NOT_ON_TIMER , // PE 2 ** 78 ** - NOT_ON_TIMER , // PE 6 ** 79 ** + NOT_ON_TIMER, // PE 0 ** 0 ** USART0_RX + NOT_ON_TIMER, // PE 1 ** 1 ** USART0_TX + TIMER3B, // PE 4 ** 2 ** PWM2 + TIMER3C, // PE 5 ** 3 ** PWM3 + TIMER0B, // PG 5 ** 4 ** PWM4 + TIMER3A, // PE 3 ** 5 ** PWM5 + TIMER4A, // PH 3 ** 6 ** PWM6 + TIMER4B, // PH 4 ** 7 ** PWM7 + TIMER4C, // PH 5 ** 8 ** PWM8 + TIMER2B, // PH 6 ** 9 ** PWM9 + TIMER2A, // PB 4 ** 10 ** PWM10 + TIMER1A, // PB 5 ** 11 ** PWM11 + TIMER1B, // PB 6 ** 12 ** PWM12 + TIMER0A, // PB 7 ** 13 ** PWM13 + NOT_ON_TIMER, // PJ 1 ** 14 ** USART3_TX + NOT_ON_TIMER, // PJ 0 ** 15 ** USART3_RX + NOT_ON_TIMER, // PH 1 ** 16 ** USART2_TX + NOT_ON_TIMER, // PH 0 ** 17 ** USART2_RX + NOT_ON_TIMER, // PD 3 ** 18 ** USART1_TX + NOT_ON_TIMER, // PD 2 ** 19 ** USART1_RX + NOT_ON_TIMER, // PD 1 ** 20 ** I2C_SDA + NOT_ON_TIMER, // PD 0 ** 21 ** I2C_SCL + NOT_ON_TIMER, // PA 0 ** 22 ** D22 + NOT_ON_TIMER, // PA 1 ** 23 ** D23 + NOT_ON_TIMER, // PA 2 ** 24 ** D24 + NOT_ON_TIMER, // PA 3 ** 25 ** D25 + NOT_ON_TIMER, // PA 4 ** 26 ** D26 + NOT_ON_TIMER, // PA 5 ** 27 ** D27 + NOT_ON_TIMER, // PA 6 ** 28 ** D28 + NOT_ON_TIMER, // PA 7 ** 29 ** D29 + NOT_ON_TIMER, // PC 7 ** 30 ** D30 + NOT_ON_TIMER, // PC 6 ** 31 ** D31 + NOT_ON_TIMER, // PC 5 ** 32 ** D32 + NOT_ON_TIMER, // PC 4 ** 33 ** D33 + NOT_ON_TIMER, // PC 3 ** 34 ** D34 + NOT_ON_TIMER, // PC 2 ** 35 ** D35 + NOT_ON_TIMER, // PC 1 ** 36 ** D36 + NOT_ON_TIMER, // PC 0 ** 37 ** D37 + NOT_ON_TIMER, // PD 7 ** 38 ** D38 + NOT_ON_TIMER, // PG 2 ** 39 ** D39 + NOT_ON_TIMER, // PG 1 ** 40 ** D40 + NOT_ON_TIMER, // PG 0 ** 41 ** D41 + NOT_ON_TIMER, // PL 7 ** 42 ** D42 + NOT_ON_TIMER, // PL 6 ** 43 ** D43 + TIMER5C, // PL 5 ** 44 ** D44 + TIMER5B, // PL 4 ** 45 ** D45 + TIMER5A, // PL 3 ** 46 ** D46 + NOT_ON_TIMER, // PL 2 ** 47 ** D47 + NOT_ON_TIMER, // PL 1 ** 48 ** D48 + NOT_ON_TIMER, // PL 0 ** 49 ** D49 + NOT_ON_TIMER, // PB 3 ** 50 ** SPI_MISO + NOT_ON_TIMER, // PB 2 ** 51 ** SPI_MOSI + NOT_ON_TIMER, // PB 1 ** 52 ** SPI_SCK + NOT_ON_TIMER, // PB 0 ** 53 ** SPI_SS + NOT_ON_TIMER, // PF 0 ** 54 ** A0 + NOT_ON_TIMER, // PF 1 ** 55 ** A1 + NOT_ON_TIMER, // PF 2 ** 56 ** A2 + NOT_ON_TIMER, // PF 3 ** 57 ** A3 + NOT_ON_TIMER, // PF 4 ** 58 ** A4 + NOT_ON_TIMER, // PF 5 ** 59 ** A5 + NOT_ON_TIMER, // PF 6 ** 60 ** A6 + NOT_ON_TIMER, // PF 7 ** 61 ** A7 + NOT_ON_TIMER, // PK 0 ** 62 ** A8 + NOT_ON_TIMER, // PK 1 ** 63 ** A9 + NOT_ON_TIMER, // PK 2 ** 64 ** A10 + NOT_ON_TIMER, // PK 3 ** 65 ** A11 + NOT_ON_TIMER, // PK 4 ** 66 ** A12 + NOT_ON_TIMER, // PK 5 ** 67 ** A13 + NOT_ON_TIMER, // PK 6 ** 68 ** A14 + NOT_ON_TIMER, // PK 7 ** 69 ** A15 + NOT_ON_TIMER, // PG 4 ** 70 ** + NOT_ON_TIMER, // PG 3 ** 71 ** + NOT_ON_TIMER, // PJ 2 ** 72 ** + NOT_ON_TIMER, // PJ 3 ** 73 ** + NOT_ON_TIMER, // PJ 7 ** 74 ** + NOT_ON_TIMER, // PJ 4 ** 75 ** + NOT_ON_TIMER, // PJ 5 ** 76 ** + NOT_ON_TIMER, // PJ 6 ** 77 ** + NOT_ON_TIMER, // PE 2 ** 78 ** + NOT_ON_TIMER, // PE 6 ** 79 ** }; #define digitalPinToTimer_plus_70(P) ( pgm_read_byte( digital_pin_to_timer_PGM_plus_70 + (P) ) ) diff --git a/Marlin/src/HAL/DUE/HAL_SPI.cpp b/Marlin/src/HAL/DUE/HAL_SPI.cpp index 5bbc4223bb..e44549357e 100644 --- a/Marlin/src/HAL/DUE/HAL_SPI.cpp +++ b/Marlin/src/HAL/DUE/HAL_SPI.cpp @@ -208,8 +208,8 @@ A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */ A("bfi %[bin],%[work],#0,#1") /* Store read bit as the bit 0 */ - : [bin]"+r"(bin), - [work]"+r"(work) + : [bin]"+r"( bin ), + [work]"+r"( work ) : [bitband_miso_port]"r"( BITBAND_MISO_PORT ), [sck_mask]"r"( SCK_MASK ), [sck_port]"r"( SCK_PORT_PLUS30 ) @@ -350,7 +350,7 @@ static void spiRxBlock0(uint8_t *ptr, uint32_t todo) { uint32_t bin = 0; uint32_t work = 0; - uint32_t BITBAND_MISO_PORT = BITBAND_ADDRESS( ((uint32_t)PORT(SD_MISO_PIN))+0x3C, PIN_SHIFT(SD_MISO_PIN)); /* PDSR of port in bitband area */ + uint32_t BITBAND_MISO_PORT = BITBAND_ADDRESS(((uint32_t)PORT(SD_MISO_PIN))+0x3C, PIN_SHIFT(SD_MISO_PIN)); /* PDSR of port in bitband area */ uint32_t SCK_PORT_PLUS30 = ((uint32_t) PORT(SD_SCK_PIN)) + 0x30; /* SODR of port */ uint32_t SCK_MASK = PIN_MASK(SD_SCK_PIN); @@ -412,10 +412,10 @@ A("strb.w %[bin], [%[ptr]], #1") /* Store read value into buffer, increment buffer pointer */ A("bne.n loop%=") /* Repeat until done */ - : [ptr]"+r"(ptr), - [todo]"+r"(todo), - [bin]"+r"(bin), - [work]"+r"(work) + : [ptr]"+r"( ptr ), + [todo]"+r"( todo ), + [bin]"+r"( bin ), + [work]"+r"( work ) : [bitband_miso_port]"r"( BITBAND_MISO_PORT ), [sck_mask]"r"( SCK_MASK ), [sck_port]"r"( SCK_PORT_PLUS30 ) diff --git a/Marlin/src/HAL/RP2040/timers.h b/Marlin/src/HAL/RP2040/timers.h index 83fdc0a2fc..512c6ba465 100644 --- a/Marlin/src/HAL/RP2040/timers.h +++ b/Marlin/src/HAL/RP2040/timers.h @@ -131,19 +131,19 @@ FORCE_INLINE static void HAL_timer_set_compare(const uint8_t timer_num, hal_time switch (timer_num) { case 0: - alarm_pool_add_alarm_in_us(HAL_timer_pool_0 ,compare , HAL_timer_alarm_pool_0_callback ,0 ,false ); + alarm_pool_add_alarm_in_us(HAL_timer_pool_0, compare, HAL_timer_alarm_pool_0_callback, 0, false); break; case 1: - alarm_pool_add_alarm_in_us(HAL_timer_pool_1 ,compare , HAL_timer_alarm_pool_1_callback ,0 ,false ); + alarm_pool_add_alarm_in_us(HAL_timer_pool_1, compare, HAL_timer_alarm_pool_1_callback, 0, false); break; case 2: - alarm_pool_add_alarm_in_us(HAL_timer_pool_2 ,compare , HAL_timer_alarm_pool_2_callback ,0 ,false ); + alarm_pool_add_alarm_in_us(HAL_timer_pool_2, compare, HAL_timer_alarm_pool_2_callback, 0, false); break; case 3: - alarm_pool_add_alarm_in_us(HAL_timer_pool_3 ,compare , HAL_timer_alarm_pool_3_callback ,0 ,false ); + alarm_pool_add_alarm_in_us(HAL_timer_pool_3, compare, HAL_timer_alarm_pool_3_callback, 0, false); break; } } diff --git a/Marlin/src/HAL/STM32F1/HAL_N32.h b/Marlin/src/HAL/STM32F1/HAL_N32.h index 7162e2b971..8b47ef4b96 100644 --- a/Marlin/src/HAL/STM32F1/HAL_N32.h +++ b/Marlin/src/HAL/STM32F1/HAL_N32.h @@ -239,8 +239,8 @@ typedef struct { #define ADC_WORKMODE_SLOW_INTERL ((uint32_t)0x00080000) #define ADC_WORKMODE_ALTER_TRIG ((uint32_t)0x00090000) -#define ADC_EXT_TRIGCONV_T1_CC3 ((uint32_t)0x00040000) //!< For ADC1, ADC2 , ADC3 and ADC4 -#define ADC_EXT_TRIGCONV_NONE ((uint32_t)0x000E0000) //!< For ADC1, ADC2 , ADC3 and ADC4 +#define ADC_EXT_TRIGCONV_T1_CC3 ((uint32_t)0x00040000) //!< For ADC1, ADC2, ADC3, and ADC4 +#define ADC_EXT_TRIGCONV_NONE ((uint32_t)0x000E0000) //!< For ADC1, ADC2, ADC3, and ADC4 #define ADC_DAT_ALIGN_R ((uint32_t)0x00000000) #define ADC_DAT_ALIGN_L ((uint32_t)0x00000800) @@ -603,9 +603,9 @@ typedef struct { #define DMA_CHCFG7_PINC ((uint16_t)0x0040) //!< Peripheral increment mode #define DMA_CHCFG7_MINC ((uint16_t)0x0080) //!< Memory increment mode -#define DMA_CHCFG7_PSIZE , ((uint16_t)0x0300) //!< PSIZE[1:0] bits (Peripheral size) -#define DMA_CHCFG7_PSIZE_0 ((uint16_t)0x0100) //!< Bit 0 -#define DMA_CHCFG7_PSIZE_1 ((uint16_t)0x0200) //!< Bit 1 +#define DMA_CHCFG7_PSIZE ((uint16_t)0x0300) //!< PSIZE[1:0] bits (Peripheral size) +#define DMA_CHCFG7_PSIZE_0 ((uint16_t)0x0100) //!< Bit 0 +#define DMA_CHCFG7_PSIZE_1 ((uint16_t)0x0200) //!< Bit 1 #define DMA_CHCFG7_MSIZE ((uint16_t)0x0C00) //!< MSIZE[1:0] bits (Memory size) #define DMA_CHCFG7_MSIZE_0 ((uint16_t)0x0400) //!< Bit 0 @@ -627,9 +627,9 @@ typedef struct { #define DMA_CHCFG8_PINC ((uint16_t)0x0040) //!< Peripheral increment mode #define DMA_CHCFG8_MINC ((uint16_t)0x0080) //!< Memory increment mode -#define DMA_CHCFG8_PSIZE , ((uint16_t)0x0300) //!< PSIZE[1:0] bits (Peripheral size) -#define DMA_CHCFG8_PSIZE_0 ((uint16_t)0x0100) //!< Bit 0 -#define DMA_CHCFG8_PSIZE_1 ((uint16_t)0x0200) //!< Bit 1 +#define DMA_CHCFG8_PSIZE ((uint16_t)0x0300) //!< PSIZE[1:0] bits (Peripheral size) +#define DMA_CHCFG8_PSIZE_0 ((uint16_t)0x0100) //!< Bit 0 +#define DMA_CHCFG8_PSIZE_1 ((uint16_t)0x0200) //!< Bit 1 #define DMA_CHCFG8_MSIZE ((uint16_t)0x0C00) //!< MSIZE[1:0] bits (Memory size) #define DMA_CHCFG8_MSIZE_0 ((uint16_t)0x0400) //!< Bit 0 diff --git a/Marlin/src/HAL/STM32F1/sdio.cpp b/Marlin/src/HAL/STM32F1/sdio.cpp index 5bb1ddb6c5..258422eba3 100644 --- a/Marlin/src/HAL/STM32F1/sdio.cpp +++ b/Marlin/src/HAL/STM32F1/sdio.cpp @@ -219,7 +219,7 @@ bool SDIO_CmdAppSetBusWidth(uint32_t rsa, uint32_t argument) { bool SDIO_CmdAppOperCommand(uint32_t sdType) { if (!SDIO_CmdAppCommand(0)) return false; - SDIO_SendCommand(ACMD41_SD_APP_OP_COND , SDMMC_VOLTAGE_WINDOW_SD | sdType); + SDIO_SendCommand(ACMD41_SD_APP_OP_COND, SDMMC_VOLTAGE_WINDOW_SD | sdType); return SDIO_GetCmdResp3(); } diff --git a/Marlin/src/HAL/TEENSY31_32/fastio.h b/Marlin/src/HAL/TEENSY31_32/fastio.h index 622799ec8c..b582c7bfec 100644 --- a/Marlin/src/HAL/TEENSY31_32/fastio.h +++ b/Marlin/src/HAL/TEENSY31_32/fastio.h @@ -53,17 +53,17 @@ #define _SET_INPUT(P) do{ \ CORE_PIN ## P ## _CONFIG = PORT_PCR_MUX(1); \ - GPIO_BITBAND(CORE_PIN ## P ## _DDRREG , CORE_PIN ## P ## _BIT) = 0; \ + GPIO_BITBAND(CORE_PIN ## P ## _DDRREG, CORE_PIN ## P ## _BIT) = 0; \ }while(0) #define _SET_OUTPUT(P) do{ \ CORE_PIN ## P ## _CONFIG = PORT_PCR_MUX(1)|PORT_PCR_SRE|PORT_PCR_DSE; \ - GPIO_BITBAND(CORE_PIN ## P ## _DDRREG , CORE_PIN ## P ## _BIT) = 1; \ + GPIO_BITBAND(CORE_PIN ## P ## _DDRREG, CORE_PIN ## P ## _BIT) = 1; \ }while(0) #define _SET_INPUT_PULLUP(P) do{ \ CORE_PIN ## P ## _CONFIG = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS; \ - GPIO_BITBAND(CORE_PIN ## P ## _DDRREG , CORE_PIN ## P ## _BIT) = 0; \ + GPIO_BITBAND(CORE_PIN ## P ## _DDRREG, CORE_PIN ## P ## _BIT) = 0; \ }while(0) #define _IS_INPUT(P) ((CORE_PIN ## P ## _DDRREG & CORE_PIN ## P ## _BITMASK) == 0) diff --git a/Marlin/src/HAL/TEENSY35_36/fastio.h b/Marlin/src/HAL/TEENSY35_36/fastio.h index 622799ec8c..b582c7bfec 100644 --- a/Marlin/src/HAL/TEENSY35_36/fastio.h +++ b/Marlin/src/HAL/TEENSY35_36/fastio.h @@ -53,17 +53,17 @@ #define _SET_INPUT(P) do{ \ CORE_PIN ## P ## _CONFIG = PORT_PCR_MUX(1); \ - GPIO_BITBAND(CORE_PIN ## P ## _DDRREG , CORE_PIN ## P ## _BIT) = 0; \ + GPIO_BITBAND(CORE_PIN ## P ## _DDRREG, CORE_PIN ## P ## _BIT) = 0; \ }while(0) #define _SET_OUTPUT(P) do{ \ CORE_PIN ## P ## _CONFIG = PORT_PCR_MUX(1)|PORT_PCR_SRE|PORT_PCR_DSE; \ - GPIO_BITBAND(CORE_PIN ## P ## _DDRREG , CORE_PIN ## P ## _BIT) = 1; \ + GPIO_BITBAND(CORE_PIN ## P ## _DDRREG, CORE_PIN ## P ## _BIT) = 1; \ }while(0) #define _SET_INPUT_PULLUP(P) do{ \ CORE_PIN ## P ## _CONFIG = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS; \ - GPIO_BITBAND(CORE_PIN ## P ## _DDRREG , CORE_PIN ## P ## _BIT) = 0; \ + GPIO_BITBAND(CORE_PIN ## P ## _DDRREG, CORE_PIN ## P ## _BIT) = 0; \ }while(0) #define _IS_INPUT(P) ((CORE_PIN ## P ## _DDRREG & CORE_PIN ## P ## _BITMASK) == 0) diff --git a/Marlin/src/core/serial_base.h b/Marlin/src/core/serial_base.h index a2f49417b7..a8700f3d23 100644 --- a/Marlin/src/core/serial_base.h +++ b/Marlin/src/core/serial_base.h @@ -220,7 +220,7 @@ struct SerialBase { // On non 2-complement CPU, there would be no possible representation for 2147483648. write('-'); } - printNumber_unsigned((uint_fixed_print_t)n , base); + printNumber_unsigned((uint_fixed_print_t)n, base); } // Print a decimal number diff --git a/Marlin/src/core/types.h b/Marlin/src/core/types.h index 395dc430f5..0de49771ee 100644 --- a/Marlin/src/core/types.h +++ b/Marlin/src/core/types.h @@ -892,8 +892,8 @@ struct XYZEval { // Absolute difference between two objects FI constexpr XYZEval diff(const XYZEval &rs) const { return LOGICAL_AXIS_ARRAY(T(_ABS(e - rs.e)), T(_ABS(x - rs.x)), T(_ABS(y - rs.y)), T(_ABS(z - rs.z)), T(_ABS(i - rs.i)), T(_ABS(j - rs.j)), T(_ABS(k - rs.k)), T(_ABS(u - rs.u)), T(_ABS(v - rs.v)), T(_ABS(w - rs.w)) ); } - FI constexpr XYZEval diff(const XYZval &rs) const { return LOGICAL_AXIS_ARRAY(0 , T(_ABS(x - rs.x)), T(_ABS(y - rs.y)), T(_ABS(z - rs.z)), T(_ABS(i - rs.i)), T(_ABS(j - rs.j)), T(_ABS(k - rs.k)), T(_ABS(u - rs.u)), T(_ABS(v - rs.v)), T(_ABS(w - rs.w)) ); } - FI constexpr XYZEval diff(const XYval &rs) const { return LOGICAL_AXIS_ARRAY(0 , T(_ABS(x - rs.x)), T(_ABS(y - rs.y)), z, i, j, k, u, v, w ); } + FI constexpr XYZEval diff(const XYZval &rs) const { return LOGICAL_AXIS_ARRAY(0, T(_ABS(x - rs.x)), T(_ABS(y - rs.y)), T(_ABS(z - rs.z)), T(_ABS(i - rs.i)), T(_ABS(j - rs.j)), T(_ABS(k - rs.k)), T(_ABS(u - rs.u)), T(_ABS(v - rs.v)), T(_ABS(w - rs.w)) ); } + FI constexpr XYZEval diff(const XYval &rs) const { return LOGICAL_AXIS_ARRAY(0, T(_ABS(x - rs.x)), T(_ABS(y - rs.y)), z, i, j, k, u, v, w ); } // Modifier operators FI XYZEval& operator+=(const XYval &rs) { XY_CODE(x += rs.x, y += rs.y); return *this; } diff --git a/Marlin/src/feature/bedlevel/ubl/ubl.h b/Marlin/src/feature/bedlevel/ubl/ubl.h index b08cb812f8..84ecc3a6c7 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl.h +++ b/Marlin/src/feature/bedlevel/ubl/ubl.h @@ -70,7 +70,7 @@ private: static void move_z_with_encoder(const_float_t multiplier); static float measure_point_with_encoder(); static float measure_business_card_thickness(); - static void manually_probe_remaining_mesh(const xy_pos_t&, const_float_t , const_float_t , const bool) __O0; + static void manually_probe_remaining_mesh(const xy_pos_t&, const_float_t, const_float_t, const bool) __O0; static void fine_tune_mesh(const xy_pos_t &pos, const bool do_ubl_mesh_map) __O0; #endif diff --git a/Marlin/src/gcode/host/M360.cpp b/Marlin/src/gcode/host/M360.cpp index 535ed48039..63071f6113 100644 --- a/Marlin/src/gcode/host/M360.cpp +++ b/Marlin/src/gcode/host/M360.cpp @@ -44,7 +44,7 @@ static void config_line(PGM_P const name, const float val, PGM_P const pref=null SERIAL_ECHOLN(val); } static void config_line(FSTR_P const name, const float val, FSTR_P const pref=nullptr, const int8_t ind=-1) { - config_line(FTOP(name), val, FTOP(pref) , ind); + config_line(FTOP(name), val, FTOP(pref), ind); } static void config_line_e(const int8_t e, PGM_P const name, const float val) { config_line(name, val, PSTR("Extr."), e + 1); diff --git a/Marlin/src/inc/Conditionals-2-LCD.h b/Marlin/src/inc/Conditionals-2-LCD.h index 2462231593..633cd2beb6 100644 --- a/Marlin/src/inc/Conditionals-2-LCD.h +++ b/Marlin/src/inc/Conditionals-2-LCD.h @@ -78,7 +78,7 @@ #define MKS_MINI_12864 #endif -// MKS_MINI_12864_V3 , BTT_MINI_12864 and BEEZ_MINI_12864 are nearly identical to FYSETC_MINI_12864_2_1 +// MKS_MINI_12864_V3, BTT_MINI_12864 and BEEZ_MINI_12864 are nearly identical to FYSETC_MINI_12864_2_1 #if ANY(MKS_MINI_12864_V3, BTT_MINI_12864, BEEZ_MINI_12864) #define FYSETC_MINI_12864_2_1 #endif diff --git a/Marlin/src/lcd/e3v2/jyersui/dwin.cpp b/Marlin/src/lcd/e3v2/jyersui/dwin.cpp index b9c637d722..5811ac11bb 100644 --- a/Marlin/src/lcd/e3v2/jyersui/dwin.cpp +++ b/Marlin/src/lcd/e3v2/jyersui/dwin.cpp @@ -427,7 +427,7 @@ private: v1 = -rmax; v2 = rmin; } - jyersDWIN.updateStatus(TS(GET_TEXT_F(MSG_COLORS_RED), ' ', p_float_t(v1, 3) , F("..0.."), p_float_t(v2, 3), ' ', GET_TEXT_F(MSG_COLORS_GREEN))); + jyersDWIN.updateStatus(TS(GET_TEXT_F(MSG_COLORS_RED), ' ', p_float_t(v1, 3), F("..0.."), p_float_t(v2, 3), ' ', GET_TEXT_F(MSG_COLORS_GREEN))); drawing_mesh = false; } @@ -3033,7 +3033,7 @@ void JyersDWIN::menuItemHandler(const uint8_t menu, const uint8_t item, bool dra drawMenuItem(row, ICON_StepY, F("M48 Probe Test")); else { gcode.process_subcommands_now( - TS(F("G28O\nM48X") , p_float_t((X_BED_SIZE + X_MIN_POS) / 2.0f, 3), 'Y', p_float_t((Y_BED_SIZE + Y_MIN_POS) / 2.0f, 3), 'P', testcount) + TS(F("G28O\nM48X"), p_float_t((X_BED_SIZE + X_MIN_POS) / 2.0f, 3), 'Y', p_float_t((Y_BED_SIZE + Y_MIN_POS) / 2.0f, 3), 'P', testcount) ); } break; diff --git a/Marlin/src/lcd/e3v2/proui/menus.cpp b/Marlin/src/lcd/e3v2/proui/menus.cpp index 7edf32169d..0451944645 100644 --- a/Marlin/src/lcd/e3v2/proui/menus.cpp +++ b/Marlin/src/lcd/e3v2/proui/menus.cpp @@ -100,7 +100,7 @@ void toggleCheckboxLine(bool &checked) { } void drawMenuIntValue(uint16_t bcolor, const uint8_t line, uint8_t iNum, const int32_t value/*=0*/) { - DWINUI::drawSignedInt(hmiData.colorText, bcolor, iNum , VALX, MBASE(line) - 1, value); + DWINUI::drawSignedInt(hmiData.colorText, bcolor, iNum, VALX, MBASE(line) - 1, value); } void onDrawMenuItem(MenuItem* menuitem, int8_t line) { @@ -163,7 +163,7 @@ void DrawItemEdit(const bool selected) { switch (checkkey) { case ID_SetIntNoDraw: if (menuData.liveUpdate) menuData.liveUpdate(); break; case ID_SetInt: - case ID_SetPInt: DWINUI::drawSignedInt(hmiData.colorText, bcolor, iNum , VALX, MBASE(currentMenu->line()) - 1, menuData.value); break; + case ID_SetPInt: DWINUI::drawSignedInt(hmiData.colorText, bcolor, iNum, VALX, MBASE(currentMenu->line()) - 1, menuData.value); break; case ID_SetFloat: case ID_SetPFloat: DWINUI::drawSignedFloat(hmiData.colorText, bcolor, iNum, menuData.dp, VALX - 2 * DWINUI::fontWidth(), MBASE(currentMenu->line()), menuData.value / POW(10, menuData.dp)); break; default: break; diff --git a/Marlin/src/lcd/extui/anycubic_chiron/chiron_tft.cpp b/Marlin/src/lcd/extui/anycubic_chiron/chiron_tft.cpp index 9e38face6f..e6e8c88155 100644 --- a/Marlin/src/lcd/extui/anycubic_chiron/chiron_tft.cpp +++ b/Marlin/src/lcd/extui/anycubic_chiron/chiron_tft.cpp @@ -130,7 +130,7 @@ void ChironTFT::idleLoop() { void ChironTFT::printerKilled(FSTR_P const error, FSTR_P const component) { tftSendLn(AC_msg_kill_lcd); #if ACDEBUG(AC_MARLIN) - DEBUG_ECHOLNPGM("printerKilled()\nerror: ", error , "\ncomponent: ", component); + DEBUG_ECHOLNPGM("printerKilled()\nerror: ", error, "\ncomponent: ", component); #endif } @@ -875,7 +875,7 @@ void ChironTFT::panelProcess(uint8_t req) { const float currval = getMeshPoint(pos); setMeshPoint(pos, constrain(currval + Zshift, AC_LOWEST_MESHPOINT_VAL, 2)); #if ACDEBUG(AC_INFO) - DEBUG_ECHOLNPGM("Change mesh point X", x," Y",y ," from ", currval, " to ", getMeshPoint(pos) ); + DEBUG_ECHOLNPGM("Change mesh point X", x," Y", y," from ", currval, " to ", getMeshPoint(pos) ); #endif } const float currZOffset = getZOffset_mm(); diff --git a/Marlin/src/lcd/extui/anycubic_vyper/dgus_tft.cpp b/Marlin/src/lcd/extui/anycubic_vyper/dgus_tft.cpp index d23b10898e..696cfad684 100644 --- a/Marlin/src/lcd/extui/anycubic_vyper/dgus_tft.cpp +++ b/Marlin/src/lcd/extui/anycubic_vyper/dgus_tft.cpp @@ -64,7 +64,7 @@ namespace Anycubic { DgusTFT::page25, DgusTFT::page26, DgusTFT::page27, DgusTFT::page28, DgusTFT::page29, DgusTFT::page30, DgusTFT::page31, DgusTFT::page32 #if HAS_LEVELING - , DgusTFT::page33 , DgusTFT::page34 + , DgusTFT::page33, DgusTFT::page34 #endif }; @@ -1108,7 +1108,7 @@ namespace Anycubic { */ } else if (0x82 == data_buf[0]) { - // send_cmd_to_pc(cmd ,start ); + // send_cmd_to_pc(cmd, start ); } } } diff --git a/Marlin/src/lcd/extui/dgus/fysetc/DGUSDisplayDef.cpp b/Marlin/src/lcd/extui/dgus/fysetc/DGUSDisplayDef.cpp index 24e472be05..9ec98779c8 100644 --- a/Marlin/src/lcd/extui/dgus/fysetc/DGUSDisplayDef.cpp +++ b/Marlin/src/lcd/extui/dgus/fysetc/DGUSDisplayDef.cpp @@ -311,7 +311,7 @@ const struct VPMapping VPMap[] PROGMEM = { { DGUS_SCREEN_PID_E, VPList_PIDE0 }, { DGUS_SCREEN_PID_BED, VPList_PIDBED }, { DGUS_SCREEN_INFOS, VPList_Infos }, - { 0 , nullptr } // List is terminated with an nullptr as table entry. + { 0, nullptr } // List is terminated with an nullptr as table entry. }; const char MarlinVersion[] PROGMEM = SHORT_BUILD_VERSION; diff --git a/Marlin/src/lcd/extui/dgus/fysetc/DGUSDisplayDef.h b/Marlin/src/lcd/extui/dgus/fysetc/DGUSDisplayDef.h index 3bac9cf2c6..1ba2a25ea3 100644 --- a/Marlin/src/lcd/extui/dgus/fysetc/DGUSDisplayDef.h +++ b/Marlin/src/lcd/extui/dgus/fysetc/DGUSDisplayDef.h @@ -121,13 +121,13 @@ constexpr uint16_t VP_MOTOR_LOCK_UNLOCK = 0x2130; // Power loss recovery constexpr uint16_t VP_POWER_LOSS_RECOVERY = 0x2180; -// Fan Control Buttons , switch between "off" and "on" +// Fan Control Buttons, switch between "off" and "on" constexpr uint16_t VP_FAN0_CONTROL = 0x2200; constexpr uint16_t VP_FAN1_CONTROL = 0x2202; constexpr uint16_t VP_FAN2_CONTROL = 0x2204; constexpr uint16_t VP_FAN3_CONTROL = 0x2206; -// Heater Control Buttons , triged between "cool down" and "heat PLA" state +// Heater Control Buttons, triged between "cool down" and "heat PLA" state constexpr uint16_t VP_E0_CONTROL = 0x2210; constexpr uint16_t VP_E1_CONTROL = 0x2212; //constexpr uint16_t VP_E2_CONTROL = 0x2214; @@ -148,7 +148,7 @@ constexpr uint16_t VP_E1_BED_PREHEAT = 0x2222; constexpr uint16_t VP_E0_FILAMENT_LOAD_UNLOAD = 0x2300; constexpr uint16_t VP_E1_FILAMENT_LOAD_UNLOAD = 0x2302; -// Settings store , reset +// Settings store, reset constexpr uint16_t VP_SETTINGS = 0x2400; // PID autotune @@ -258,7 +258,7 @@ constexpr uint16_t VP_BED_STATUS = 0x331C; constexpr uint16_t VP_MOVE_OPTION = 0x3400; // Step per mm -constexpr uint16_t VP_X_STEP_PER_MM = 0x3600; // at the moment , uint16_t , 0~1638.4 +constexpr uint16_t VP_X_STEP_PER_MM = 0x3600; // at the moment, uint16_t, 0~1638.4 //constexpr uint16_t VP_X2_STEP_PER_MM = 0x3602; constexpr uint16_t VP_Y_STEP_PER_MM = 0x3604; //constexpr uint16_t VP_Y2_STEP_PER_MM = 0x3606; @@ -272,10 +272,10 @@ constexpr uint16_t VP_E1_STEP_PER_MM = 0x3612; //constexpr uint16_t VP_E5_STEP_PER_MM = 0x361A; // PIDs -constexpr uint16_t VP_E0_PID_P = 0x3700; // at the moment , uint16_t , 0~1638.4 +constexpr uint16_t VP_E0_PID_P = 0x3700; // at the moment, uint16_t, 0~1638.4 constexpr uint16_t VP_E0_PID_I = 0x3702; constexpr uint16_t VP_E0_PID_D = 0x3704; -constexpr uint16_t VP_E1_PID_P = 0x3706; // at the moment , uint16_t , 0~1638.4 +constexpr uint16_t VP_E1_PID_P = 0x3706; // at the moment, uint16_t, 0~1638.4 constexpr uint16_t VP_E1_PID_I = 0x3708; constexpr uint16_t VP_E1_PID_D = 0x370A; constexpr uint16_t VP_BED_PID_P = 0x3710; diff --git a/Marlin/src/lcd/extui/dgus/hiprecy/DGUSDisplayDef.cpp b/Marlin/src/lcd/extui/dgus/hiprecy/DGUSDisplayDef.cpp index 79e0ccf942..db0ebbc903 100644 --- a/Marlin/src/lcd/extui/dgus/hiprecy/DGUSDisplayDef.cpp +++ b/Marlin/src/lcd/extui/dgus/hiprecy/DGUSDisplayDef.cpp @@ -308,7 +308,7 @@ const struct VPMapping VPMap[] PROGMEM = { { DGUS_SCREEN_PID_E, VPList_PIDE0 }, { DGUS_SCREEN_PID_BED, VPList_PIDBED }, { DGUS_SCREEN_INFOS, VPList_Infos }, - { 0 , nullptr } // List is terminated with an nullptr as table entry. + { 0, nullptr } // List is terminated with an nullptr as table entry. }; const char MarlinVersion[] PROGMEM = SHORT_BUILD_VERSION; diff --git a/Marlin/src/lcd/extui/dgus/hiprecy/DGUSDisplayDef.h b/Marlin/src/lcd/extui/dgus/hiprecy/DGUSDisplayDef.h index a5e0d327a4..f7a716f4d5 100644 --- a/Marlin/src/lcd/extui/dgus/hiprecy/DGUSDisplayDef.h +++ b/Marlin/src/lcd/extui/dgus/hiprecy/DGUSDisplayDef.h @@ -121,13 +121,13 @@ constexpr uint16_t VP_MOTOR_LOCK_UNLOCK = 0x2130; // Power loss recovery constexpr uint16_t VP_POWER_LOSS_RECOVERY = 0x2180; -// Fan Control Buttons , switch between "off" and "on" +// Fan Control Buttons, switch between "off" and "on" constexpr uint16_t VP_FAN0_CONTROL = 0x2200; constexpr uint16_t VP_FAN1_CONTROL = 0x2202; //constexpr uint16_t VP_FAN2_CONTROL = 0x2204; //constexpr uint16_t VP_FAN3_CONTROL = 0x2206; -// Heater Control Buttons , triged between "cool down" and "heat PLA" state +// Heater Control Buttons, triged between "cool down" and "heat PLA" state constexpr uint16_t VP_E0_CONTROL = 0x2210; constexpr uint16_t VP_E1_CONTROL = 0x2212; //constexpr uint16_t VP_E2_CONTROL = 0x2214; @@ -147,7 +147,7 @@ constexpr uint16_t VP_E0_BED_PREHEAT = 0x2220; // Filament load and unload constexpr uint16_t VP_E0_FILAMENT_LOAD_UNLOAD = 0x2300; -// Settings store , reset +// Settings store, reset constexpr uint16_t VP_SETTINGS = 0x2400; // PID autotune @@ -257,7 +257,7 @@ constexpr uint16_t VP_BED_STATUS = 0x331C; constexpr uint16_t VP_MOVE_OPTION = 0x3400; // Step per mm -constexpr uint16_t VP_X_STEP_PER_MM = 0x3600; // at the moment , uint16_t , 0~1638.4 +constexpr uint16_t VP_X_STEP_PER_MM = 0x3600; // at the moment, uint16_t, 0~1638.4 //constexpr uint16_t VP_X2_STEP_PER_MM = 0x3602; constexpr uint16_t VP_Y_STEP_PER_MM = 0x3604; //constexpr uint16_t VP_Y2_STEP_PER_MM = 0x3606; @@ -271,7 +271,7 @@ constexpr uint16_t VP_E0_STEP_PER_MM = 0x3610; //constexpr uint16_t VP_E5_STEP_PER_MM = 0x361A; // PIDs -constexpr uint16_t VP_E0_PID_P = 0x3700; // at the moment , uint16_t , 0~1638.4 +constexpr uint16_t VP_E0_PID_P = 0x3700; // at the moment, uint16_t, 0~1638.4 constexpr uint16_t VP_E0_PID_I = 0x3702; constexpr uint16_t VP_E0_PID_D = 0x3704; constexpr uint16_t VP_BED_PID_P = 0x3710; diff --git a/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp b/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp index 4a67f78b8c..b108dab0a0 100644 --- a/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp +++ b/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp @@ -327,7 +327,7 @@ const uint16_t MKSList_MotionConfig[] PROGMEM = { const uint16_t MKSList_EX_Config[] PROGMEM = { INFO_BAR - VP_MIN_EX_T,VP_Min_EX_T_E, + VP_MIN_EX_T, VP_Min_EX_T_E, 0x0000 }; @@ -666,9 +666,9 @@ const struct DGUS_VP_Variable ListOfVP[] PROGMEM = { VPHELPER(VP_SD_Print_LiveAdjustZ_Confirm, nullptr, screen.zOffsetConfirm, nullptr), - VPHELPER(VP_ZOffset_Distance,nullptr ,screen.getZoffsetDistance, nullptr), + VPHELPER(VP_ZOffset_Distance, nullptr, screen.getZoffsetDistance, nullptr), VPHELPER(VP_MESH_LEVEL_ADJUST, nullptr, screen.meshLevelDistanceConfig, nullptr), - VPHELPER(VP_MESH_LEVEL_POINT,nullptr, screen.meshLevel, nullptr), + VPHELPER(VP_MESH_LEVEL_POINT, nullptr, screen.meshLevel, nullptr), #if ENABLED(PREVENT_COLD_EXTRUSION) VPHELPER(VP_Min_EX_T_E, &thermalManager.extrude_min_temp, screen.getMinExtrudeTemp, screen.sendWordValueToDisplay), @@ -709,9 +709,9 @@ const struct DGUS_VP_Variable ListOfVP[] PROGMEM = { VPHELPER(VP_ZOffset_DE_DIS, &z_offset_add, nullptr, screen.sendFloatAsLongValueToDisplay<2>), #endif #if HAS_BED_PROBE - VPHELPER(VP_OFFSET_X, &probe.offset.x, screen.getOffsetValue,screen.sendFloatAsLongValueToDisplay<2>), - VPHELPER(VP_OFFSET_Y, &probe.offset.y, screen.getOffsetValue,screen.sendFloatAsLongValueToDisplay<2>), - VPHELPER(VP_OFFSET_Z, &probe.offset.z, screen.getOffsetValue,screen.sendFloatAsLongValueToDisplay<2>), + VPHELPER(VP_OFFSET_X, &probe.offset.x, screen.getOffsetValue, screen.sendFloatAsLongValueToDisplay<2>), + VPHELPER(VP_OFFSET_Y, &probe.offset.y, screen.getOffsetValue, screen.sendFloatAsLongValueToDisplay<2>), + VPHELPER(VP_OFFSET_Z, &probe.offset.z, screen.getOffsetValue, screen.sendFloatAsLongValueToDisplay<2>), #endif #else VPHELPER(VP_SD_FileSelected, nullptr, screen.printReturn, nullptr), diff --git a/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.h b/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.h index a0e5b5d731..ba5508e441 100644 --- a/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.h +++ b/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.h @@ -301,7 +301,7 @@ constexpr uint16_t SP_T_Bed_Set = 0x5040; constexpr uint16_t VP_Y_HOME = 0x2338; constexpr uint16_t VP_Z_HOME = 0x233A; - // Fan Control Buttons , switch between "off" and "on" + // Fan Control Buttons, switch between "off" and "on" constexpr uint16_t VP_FAN0_CONTROL = 0x2350; constexpr uint16_t VP_FAN1_CONTROL = 0x2352; constexpr uint16_t VP_FAN2_CONTROL = 0x2354; @@ -350,7 +350,7 @@ constexpr uint16_t SP_T_Bed_Set = 0x5040; constexpr uint16_t VP_FAN3_STATUS = 0x2716; // Step per mm - constexpr uint16_t VP_X_STEP_PER_MM = 0x2900; // at the moment , uint16_t , 0~1638.4 + constexpr uint16_t VP_X_STEP_PER_MM = 0x2900; // at the moment, uint16_t, 0~1638.4 constexpr uint16_t VP_Y_STEP_PER_MM = 0x2904; constexpr uint16_t VP_Z_STEP_PER_MM = 0x2908; constexpr uint16_t VP_E0_STEP_PER_MM = 0x2910; @@ -450,10 +450,10 @@ constexpr uint16_t SP_T_Bed_Set = 0x5040; constexpr uint16_t VP_PrintTime_S = 0x3504; // PIDs - constexpr uint16_t VP_E0_PID_P = 0x3700; // at the moment , uint16_t , 0~1638.4 + constexpr uint16_t VP_E0_PID_P = 0x3700; // at the moment, uint16_t, 0~1638.4 constexpr uint16_t VP_E0_PID_I = 0x3702; constexpr uint16_t VP_E0_PID_D = 0x3704; - constexpr uint16_t VP_E1_PID_P = 0x3706; // at the moment , uint16_t , 0~1638.4 + constexpr uint16_t VP_E1_PID_P = 0x3706; // at the moment, uint16_t, 0~1638.4 constexpr uint16_t VP_E1_PID_I = 0x3708; constexpr uint16_t VP_E1_PID_D = 0x370A; constexpr uint16_t VP_BED_PID_P = 0x3710; @@ -482,7 +482,7 @@ constexpr uint16_t SP_T_Bed_Set = 0x5040; constexpr uint16_t VP_Z_PARK_POS = 0x3904; /* -------------------------------0x4000-0x4FFF------------------------------- */ - // Heater Control Buttons , triged between "cool down" and "heat PLA" state + // Heater Control Buttons, triged between "cool down" and "heat PLA" state constexpr uint16_t VP_E0_CONTROL = 0x4010; constexpr uint16_t VP_E1_CONTROL = 0x4012; constexpr uint16_t VP_BED_CONTROL = 0x401C; @@ -495,7 +495,7 @@ constexpr uint16_t SP_T_Bed_Set = 0x5040; //constexpr uint16_t VP_E0_FILAMENT_LOAD_UNLOAD = 0x4030; //constexpr uint16_t VP_E1_FILAMENT_LOAD_UNLOAD = 0x4032; - // Settings store , reset + // Settings store, reset // Level data constexpr uint16_t VP_Level_Point_One_X = 0x4100; diff --git a/Marlin/src/lcd/extui/dgus/origin/DGUSDisplayDef.cpp b/Marlin/src/lcd/extui/dgus/origin/DGUSDisplayDef.cpp index ac408e8d9c..2cb7bd6f83 100644 --- a/Marlin/src/lcd/extui/dgus/origin/DGUSDisplayDef.cpp +++ b/Marlin/src/lcd/extui/dgus/origin/DGUSDisplayDef.cpp @@ -119,7 +119,7 @@ const struct VPMapping VPMap[] PROGMEM = { { DGUS_SCREEN_FLOWRATES, VPList_SD_FlowRates }, { DGUS_SCREEN_SDPRINTMANIPULATION, VPList_SD_PrintManipulation }, { DGUS_SCREEN_SDFILELIST, VPList_SDFileList }, - { 0 , nullptr } // List is terminated with an nullptr as table entry. + { 0, nullptr } // List is terminated with an nullptr as table entry. }; const char MarlinVersion[] PROGMEM = SHORT_BUILD_VERSION; diff --git a/Marlin/src/lcd/extui/dgus/origin/DGUSDisplayDef.h b/Marlin/src/lcd/extui/dgus/origin/DGUSDisplayDef.h index d34b90b45f..6b5b780283 100644 --- a/Marlin/src/lcd/extui/dgus/origin/DGUSDisplayDef.h +++ b/Marlin/src/lcd/extui/dgus/origin/DGUSDisplayDef.h @@ -116,13 +116,13 @@ constexpr uint16_t VP_MOTOR_LOCK_UNLOCK = 0x2130; // Power loss recovery constexpr uint16_t VP_POWER_LOSS_RECOVERY = 0x2180; -// Fan Control Buttons , switch between "off" and "on" +// Fan Control Buttons, switch between "off" and "on" constexpr uint16_t VP_FAN0_CONTROL = 0x2200; constexpr uint16_t VP_FAN1_CONTROL = 0x2202; //constexpr uint16_t VP_FAN2_CONTROL = 0x2204; //constexpr uint16_t VP_FAN3_CONTROL = 0x2206; -// Heater Control Buttons , triged between "cool down" and "heat PLA" state +// Heater Control Buttons, triged between "cool down" and "heat PLA" state constexpr uint16_t VP_E0_CONTROL = 0x2210; constexpr uint16_t VP_E1_CONTROL = 0x2212; //constexpr uint16_t VP_E2_CONTROL = 0x2214; @@ -143,7 +143,7 @@ constexpr uint16_t VP_E1_BED_CONTROL = 0x2222; constexpr uint16_t VP_E0_FILAMENT_LOAD_UNLOAD = 0x2300; constexpr uint16_t VP_E1_FILAMENT_LOAD_UNLOAD = 0x2302; -// Settings store , reset +// Settings store, reset constexpr uint16_t VP_SETTINGS = 0x2400; // PID autotune @@ -247,7 +247,7 @@ constexpr uint16_t VP_BED_STATUS = 0x331C; constexpr uint16_t VP_MOVE_OPTION = 0x3400; // Step per mm -constexpr uint16_t VP_X_STEP_PER_MM = 0x3600; // at the moment , uint16_t , 0~1638.4 +constexpr uint16_t VP_X_STEP_PER_MM = 0x3600; // at the moment, uint16_t, 0~1638.4 //constexpr uint16_t VP_X2_STEP_PER_MM = 0x3602; constexpr uint16_t VP_Y_STEP_PER_MM = 0x3604; //constexpr uint16_t VP_Y2_STEP_PER_MM = 0x3606; @@ -261,7 +261,7 @@ constexpr uint16_t VP_E0_STEP_PER_MM = 0x3610; //constexpr uint16_t VP_E5_STEP_PER_MM = 0x361A; // PIDs -constexpr uint16_t VP_E0_PID_P = 0x3700; // at the moment , uint16_t , 0~1638.4 +constexpr uint16_t VP_E0_PID_P = 0x3700; // at the moment, uint16_t, 0~1638.4 constexpr uint16_t VP_E0_PID_I = 0x3702; constexpr uint16_t VP_E0_PID_D = 0x3704; constexpr uint16_t VP_BED_PID_P = 0x3710; diff --git a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/scripts/font2cpp.py b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/scripts/font2cpp.py index 98a2420497..8d066d876a 100755 --- a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/scripts/font2cpp.py +++ b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/scripts/font2cpp.py @@ -56,7 +56,7 @@ class WriteSource: data.append(0) # Combine each two adjacent values into one i = iter(data) - data = list(map(lambda a, b: a << 4 | b, i ,i)) + data = list(map(lambda a, b: a << 4 | b, i, i)) # Pack the data data = pack_rle(data) # Convert values into hex strings diff --git a/Marlin/src/lcd/extui/mks_ui/tft_Language_en.h b/Marlin/src/lcd/extui/mks_ui/tft_Language_en.h index 5195986e35..f012b17ea7 100644 --- a/Marlin/src/lcd/extui/mks_ui/tft_Language_en.h +++ b/Marlin/src/lcd/extui/mks_ui/tft_Language_en.h @@ -399,8 +399,8 @@ #define FILAMENT_DIALOG_LOAD_CONFIRM1_TIPS_EN "Heat completed,please load filament \nto extruder,and click \nfor start loading." #define FILAMENT_DIALOG_LOAD_CONFIRM2_TIPS_EN "Please load filament to extruder,\nand click for start loading." #define FILAMENT_DIALOG_UNLOAD_CONFIRM_TIPS_EN "Heat completed,please \nclick for start unloading.!" -#define FILAMENT_DIALOG_LOADING_TIPS_EN "Is loading ,please wait!" -#define FILAMENT_DIALOG_UNLOADING_TIPS_EN "Is unloading,please wait!" +#define FILAMENT_DIALOG_LOADING_TIPS_EN "Is loading, please wait!" +#define FILAMENT_DIALOG_UNLOADING_TIPS_EN "Is unloading, please wait!" #define FILAMENT_DIALOG_LOAD_COMPLETE_TIPS_EN "Load filament completed,\nclick for return!" #define FILAMENT_DIALOG_UNLOAD_COMPLETE_TIPS_EN "Unload filament completed,\nclick for return!" diff --git a/Marlin/src/lcd/extui/mks_ui/tft_Language_it.h b/Marlin/src/lcd/extui/mks_ui/tft_Language_it.h index b74842afef..2be8f7d17b 100644 --- a/Marlin/src/lcd/extui/mks_ui/tft_Language_it.h +++ b/Marlin/src/lcd/extui/mks_ui/tft_Language_it.h @@ -149,8 +149,8 @@ #define FILAMENT_DIALOG_LOAD_CONFIRM1_TIPS_IT "Heat completed,please load filament \nto extruder,and click \nfor start loading." #define FILAMENT_DIALOG_LOAD_CONFIRM2_TIPS_IT "Please load filament to extruder,\nand click for start loading." #define FILAMENT_DIALOG_UNLOAD_CONFIRM_TIPS_IT "Heat completed,please \nclick for start unloading.!" -#define FILAMENT_DIALOG_LOADING_TIPS_IT "Is loading ,please wait!" -#define FILAMENT_DIALOG_UNLOADING_TIPS_IT "Is unloading,please wait!" +#define FILAMENT_DIALOG_LOADING_TIPS_IT "Is loading, please wait!" +#define FILAMENT_DIALOG_UNLOADING_TIPS_IT "Is unloading, please wait!" #define FILAMENT_DIALOG_LOAD_COMPLETE_TIPS_IT "Load filament completed,\nclick for return!" #define FILAMENT_DIALOG_UNLOAD_COMPLETE_TIPS_IT "Unload filament completed,\nclick for return!" diff --git a/Marlin/src/lcd/extui/mks_ui/tft_Language_ru.h b/Marlin/src/lcd/extui/mks_ui/tft_Language_ru.h index da36ed14c7..aced93f4b6 100644 --- a/Marlin/src/lcd/extui/mks_ui/tft_Language_ru.h +++ b/Marlin/src/lcd/extui/mks_ui/tft_Language_ru.h @@ -148,8 +148,8 @@ #define FILAMENT_DIALOG_LOAD_CONFIRM1_TIPS_RU "Heat completed,please load filament \nto extruder,and click \nfor start loading." #define FILAMENT_DIALOG_LOAD_CONFIRM2_TIPS_RU "Please load filament to extruder,\nand click for start loading." #define FILAMENT_DIALOG_UNLOAD_CONFIRM_TIPS_RU "Heat completed,please \nclick for start unloading.!" -#define FILAMENT_DIALOG_LOADING_TIPS_RU "Is loading ,please wait!" -#define FILAMENT_DIALOG_UNLOADING_TIPS_RU "Is unloading,please wait!" +#define FILAMENT_DIALOG_LOADING_TIPS_RU "Is loading, please wait!" +#define FILAMENT_DIALOG_UNLOADING_TIPS_RU "Is unloading, please wait!" #define FILAMENT_DIALOG_LOAD_COMPLETE_TIPS_RU "Load filament completed,\nclick for return!" #define FILAMENT_DIALOG_UNLOAD_COMPLETE_TIPS_RU "Unload filament completed,\nclick for return!" diff --git a/Marlin/src/lcd/extui/ui_api.h b/Marlin/src/lcd/extui/ui_api.h index dfe393e39a..5e781706bc 100644 --- a/Marlin/src/lcd/extui/ui_api.h +++ b/Marlin/src/lcd/extui/ui_api.h @@ -430,7 +430,7 @@ namespace ExtUI { float getPID_Kp(const extruder_t); float getPID_Ki(const extruder_t); float getPID_Kd(const extruder_t); - void setPID(const_float_t, const_float_t , const_float_t , extruder_t); + void setPID(const_float_t, const_float_t, const_float_t, extruder_t); void startPIDTune(const celsius_t, extruder_t); #endif @@ -439,7 +439,7 @@ namespace ExtUI { float getBedPID_Kp(); float getBedPID_Ki(); float getBedPID_Kd(); - void setBedPID(const_float_t, const_float_t , const_float_t); + void setBedPID(const_float_t, const_float_t, const_float_t); void startBedPIDTune(const celsius_t); #endif diff --git a/Marlin/src/lcd/tft/ui_color_ui.cpp b/Marlin/src/lcd/tft/ui_color_ui.cpp index 64eed045e1..8186650070 100644 --- a/Marlin/src/lcd/tft/ui_color_ui.cpp +++ b/Marlin/src/lcd/tft/ui_color_ui.cpp @@ -248,21 +248,21 @@ void MarlinUI::draw_status_screen() { tft.add_rectangle(0, 0, COORDINATES_W, COORDINATES_H, COLOR_AXIS_HOMED); #if HAS_X_AXIS && defined(X_MARK_X) && defined(X_MARK_Y) && defined(X_VALUE_X) && defined(X_VALUE_Y) - tft.add_text(X_MARK_X, X_MARK_Y, COLOR_AXIS_HOMED , "X"); + tft.add_text(X_MARK_X, X_MARK_Y, COLOR_AXIS_HOMED, "X"); const bool nhx = axis_should_home(X_AXIS); tft_string.set(blink && nhx ? "?" : ftostr4sign(LOGICAL_X_POSITION(current_position.x))); tft.add_text(X_VALUE_X, X_VALUE_Y, nhx ? COLOR_AXIS_NOT_HOMED : COLOR_AXIS_HOMED, tft_string); #endif #if HAS_Y_AXIS && defined(Y_MARK_X) && defined(Y_MARK_Y) && defined(Y_VALUE_X) && defined(Y_VALUE_Y) - tft.add_text(Y_MARK_X, Y_MARK_Y, COLOR_AXIS_HOMED , "Y"); + tft.add_text(Y_MARK_X, Y_MARK_Y, COLOR_AXIS_HOMED, "Y"); const bool nhy = axis_should_home(Y_AXIS); tft_string.set(blink && nhy ? "?" : ftostr4sign(LOGICAL_Y_POSITION(current_position.y))); tft.add_text(Y_VALUE_X, Y_VALUE_Y, nhy ? COLOR_AXIS_NOT_HOMED : COLOR_AXIS_HOMED, tft_string); #endif #if HAS_Z_AXIS && defined(Z_MARK_X) && defined(Z_MARK_Y) && defined(Z_VALUE_X) && defined(Z_VALUE_Y) && defined(Z_VALUE_OFFSET) - tft.add_text(Z_MARK_X, Z_MARK_Y, COLOR_AXIS_HOMED , "Z"); + tft.add_text(Z_MARK_X, Z_MARK_Y, COLOR_AXIS_HOMED, "Z"); uint16_t offset = Z_VALUE_OFFSET; const bool nhz = axis_should_home(Z_AXIS); if (blink && nhz) diff --git a/Marlin/src/module/scara.cpp b/Marlin/src/module/scara.cpp index d6656d36d8..50aaf56196 100644 --- a/Marlin/src/module/scara.cpp +++ b/Marlin/src/module/scara.cpp @@ -223,7 +223,7 @@ float segments_per_second = DEFAULT_SEGMENTS_PER_SECOND; //const int x_axis_home_dir = TOOL_X_HOME_DIR(active_extruder); - //const xy_pos_t pos { max_length(X_AXIS) , max_length(Y_AXIS) }; + //const xy_pos_t pos { max_length(X_AXIS), max_length(Y_AXIS) }; //const float mlz = max_length(X_AXIS), // Move all carriages together linearly until an endstop is hit. @@ -293,7 +293,7 @@ float segments_per_second = DEFAULT_SEGMENTS_PER_SECOND; delta.set(DEGREES(THETA), DEGREES(PHI), DEGREES(PSI)); - //SERIAL_ECHOLNPGM(" SCARA (x,y,z) ", spos.x , ",", spos.y, ",", spos.z, " Rho=", RHO, " Rho2=", RHO2, " Theta=", THETA, " Phi=", PHI, " Psi=", PSI, " Gamma=", GAMMA); + //SERIAL_ECHOLNPGM(" SCARA (x,y,z) ", spos.x, ",", spos.y, ",", spos.z, " Rho=", RHO, " Rho2=", RHO2, " Theta=", THETA, " Phi=", PHI, " Psi=", PSI, " Gamma=", GAMMA); } #endif diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index 7da051f9d7..169d86a72f 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -1755,7 +1755,7 @@ void Temperature::mintemp_error(const heater_id_t heater_id OPTARG(ERR_INCLUDE_T float ambient_xfer_coeff = mpc.ambient_xfer_coeff_fan0; #if ENABLED(MPC_INCLUDE_FAN) const uint8_t fan_index = TERN(SINGLEFAN, 0, ee); - const float fan_fraction = TERN_(MPC_FAN_0_ACTIVE_HOTEND, !this_hotend ? 0.0f : ) fan_speed[fan_index] * RECIPROCAL(255); + const float fan_fraction = TERN_(MPC_FAN_0_ACTIVE_HOTEND, !this_hotend ? 0.0f :) fan_speed[fan_index] * RECIPROCAL(255); ambient_xfer_coeff += fan_fraction * mpc.fan255_adjustment; #endif @@ -3589,7 +3589,7 @@ void Temperature::disable_all_heaters() { #define THERMO_SEL(A,B,C) (hindex > 1 ? (C) : hindex == 1 ? (B) : (A)) #define MAXTC_CS_WRITE(V) do{ switch (hindex) { case 1: WRITE(TEMP_1_CS_PIN, V); break; case 2: WRITE(TEMP_2_CS_PIN, V); break; default: WRITE(TEMP_0_CS_PIN, V); } }while(0) #elif MAX_TC_COUNT > 1 - #define THERMO_SEL(A,B,C) ( hindex == 1 ? (B) : (A)) + #define THERMO_SEL(A,B,C) (hindex == 1 ? (B) : (A)) #define MAXTC_CS_WRITE(V) do{ switch (hindex) { case 1: WRITE(TEMP_1_CS_PIN, V); break; default: WRITE(TEMP_0_CS_PIN, V); } }while(0) #endif #else diff --git a/Marlin/src/module/thermistor/thermistor_666.h b/Marlin/src/module/thermistor/thermistor_666.h index 14a03c23b5..1b3a3a4615 100644 --- a/Marlin/src/module/thermistor/thermistor_666.h +++ b/Marlin/src/module/thermistor/thermistor_666.h @@ -42,7 +42,7 @@ constexpr temp_entry_t temptable_666[] PROGMEM = { { OV( 86), 176 }, { OV(103), 166 }, { OV(120), 157 }, - { OV(137) ,150 }, + { OV(137), 150 }, { OV(154), 144 }, { OV(172), 138 }, { OV(189), 134 }, diff --git a/Marlin/src/pins/sam/pins_ALLIGATOR_R2.h b/Marlin/src/pins/sam/pins_ALLIGATOR_R2.h index 6f6182a684..5e9df26fdd 100644 --- a/Marlin/src/pins/sam/pins_ALLIGATOR_R2.h +++ b/Marlin/src/pins/sam/pins_ALLIGATOR_R2.h @@ -92,7 +92,7 @@ #define MICROSTEP32 HIGH,HIGH,LOW #endif -//#define MOTOR_FAULT_PIN 22 // PB26 , motor X-Y-Z-E0 motor FAULT +//#define MOTOR_FAULT_PIN 22 // PB26, motor X-Y-Z-E0 motor FAULT // // Temperature Sensors diff --git a/Marlin/src/pins/samd/pins_BRICOLEMON_LITE_V1_0.h b/Marlin/src/pins/samd/pins_BRICOLEMON_LITE_V1_0.h index 7e145ccc0e..98ec48de80 100644 --- a/Marlin/src/pins/samd/pins_BRICOLEMON_LITE_V1_0.h +++ b/Marlin/src/pins/samd/pins_BRICOLEMON_LITE_V1_0.h @@ -36,7 +36,7 @@ #endif #ifndef BOARD_INFO_NAME - #define BOARD_INFO_NAME "BRICOLEMON LITE V1.0" // , Lemoncrest & BricoGeek collaboration. + #define BOARD_INFO_NAME "BRICOLEMON LITE V1.0" // Lemoncrest & BricoGeek collaboration. #endif /** diff --git a/Marlin/src/pins/samd/pins_BRICOLEMON_V1_0.h b/Marlin/src/pins/samd/pins_BRICOLEMON_V1_0.h index c00caa73a4..37f0b79f6b 100644 --- a/Marlin/src/pins/samd/pins_BRICOLEMON_V1_0.h +++ b/Marlin/src/pins/samd/pins_BRICOLEMON_V1_0.h @@ -30,7 +30,7 @@ #endif #ifndef BOARD_INFO_NAME - #define BOARD_INFO_NAME "BRICOLEMON V1.0" // , Lemoncrest & BricoGeek collaboration. + #define BOARD_INFO_NAME "BRICOLEMON V1.0" // Lemoncrest & BricoGeek collaboration. #endif /** diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs3/dyn_SWI/dyn_SWI.h b/Marlin/src/sd/usb_flashdrive/lib-uhs3/dyn_SWI/dyn_SWI.h index 652b43fd2e..cb99851fdd 100644 --- a/Marlin/src/sd/usb_flashdrive/lib-uhs3/dyn_SWI/dyn_SWI.h +++ b/Marlin/src/sd/usb_flashdrive/lib-uhs3/dyn_SWI/dyn_SWI.h @@ -79,7 +79,7 @@ extern "C" #define NVIC_GET_PENDING(n) NVIC_GetPendingIRQ((IRQn_Type)n) #define NVIC_SET_PENDING(n) NVIC_SetPendingIRQ((IRQn_Type)n) #define NVIC_ENABLE_IRQ(n) NVIC_EnableIRQ((IRQn_Type)n) -#define NVIC_SET_PRIORITY(n ,p) NVIC_SetPriority((IRQn_Type)n, (uint32_t) p) +#define NVIC_SET_PRIORITY(n, p) NVIC_SetPriority((IRQn_Type)n, (uint32_t) p) //extern "C" { // extern uint32_t _VectorsRam[VECTORTABLE_SIZE] __attribute__((aligned(VECTORTABLE_ALIGNMENT))); //} diff --git a/buildroot/share/PlatformIO/scripts/exc.S b/buildroot/share/PlatformIO/scripts/exc.S index 1db462bb23..3a61701aca 100644 --- a/buildroot/share/PlatformIO/scripts/exc.S +++ b/buildroot/share/PlatformIO/scripts/exc.S @@ -81,7 +81,7 @@ __exc_usagefault: .thumb_func __default_exc: ldr r2, NVIC_CCR @ Enable returning to thread mode even if there are - mov r1 ,#1 @ pending exceptions. See flag NONEBASETHRDENA. + mov r1, #1 @ pending exceptions. See flag NONEBASETHRDENA. str r1, [r2] cpsid i @ Disable global interrupts ldr r2, SYSTICK_CSR @ Disable systick handler diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FLY_D5/ldscript.ld b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D5/ldscript.ld index e86d8aa274..9d9d6e5a59 100644 --- a/buildroot/share/PlatformIO/variants/MARLIN_FLY_D5/ldscript.ld +++ b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D5/ldscript.ld @@ -37,7 +37,7 @@ _Min_Stack_Size = 0x400; /* required amount of stack */ MEMORY { RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 16K - FLASH (rx) : ORIGIN = 0x8000000 , LENGTH = 128K + FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 128K } /* Sections */ diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FLY_D7/ldscript.ld b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D7/ldscript.ld index e86d8aa274..9d9d6e5a59 100644 --- a/buildroot/share/PlatformIO/variants/MARLIN_FLY_D7/ldscript.ld +++ b/buildroot/share/PlatformIO/variants/MARLIN_FLY_D7/ldscript.ld @@ -37,7 +37,7 @@ _Min_Stack_Size = 0x400; /* required amount of stack */ MEMORY { RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 16K - FLASH (rx) : ORIGIN = 0x8000000 , LENGTH = 128K + FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 128K } /* Sections */ diff --git a/buildroot/share/PlatformIO/variants/MARLIN_MEGA_EXTENDED/pins_arduino.h b/buildroot/share/PlatformIO/variants/MARLIN_MEGA_EXTENDED/pins_arduino.h index cae4d83024..2d342f57c7 100644 --- a/buildroot/share/PlatformIO/variants/MARLIN_MEGA_EXTENDED/pins_arduino.h +++ b/buildroot/share/PlatformIO/variants/MARLIN_MEGA_EXTENDED/pins_arduino.h @@ -168,274 +168,274 @@ const uint16_t PROGMEM port_to_input_PGM[] = { const uint8_t PROGMEM digital_pin_to_port_PGM[] = { // PORTLIST // ------------------------------------------- - PE , // PE 0 ** 0 ** USART0_RX - PE , // PE 1 ** 1 ** USART0_TX - PE , // PE 4 ** 2 ** PWM2 - PE , // PE 5 ** 3 ** PWM3 - PG , // PG 5 ** 4 ** PWM4 - PE , // PE 3 ** 5 ** PWM5 - PH , // PH 3 ** 6 ** PWM6 - PH , // PH 4 ** 7 ** PWM7 - PH , // PH 5 ** 8 ** PWM8 - PH , // PH 6 ** 9 ** PWM9 - PB , // PB 4 ** 10 ** PWM10 - PB , // PB 5 ** 11 ** PWM11 - PB , // PB 6 ** 12 ** PWM12 - PB , // PB 7 ** 13 ** PWM13 - PJ , // PJ 1 ** 14 ** USART3_TX - PJ , // PJ 0 ** 15 ** USART3_RX - PH , // PH 1 ** 16 ** USART2_TX - PH , // PH 0 ** 17 ** USART2_RX - PD , // PD 3 ** 18 ** USART1_TX - PD , // PD 2 ** 19 ** USART1_RX - PD , // PD 1 ** 20 ** I2C_SDA - PD , // PD 0 ** 21 ** I2C_SCL - PA , // PA 0 ** 22 ** D22 - PA , // PA 1 ** 23 ** D23 - PA , // PA 2 ** 24 ** D24 - PA , // PA 3 ** 25 ** D25 - PA , // PA 4 ** 26 ** D26 - PA , // PA 5 ** 27 ** D27 - PA , // PA 6 ** 28 ** D28 - PA , // PA 7 ** 29 ** D29 - PC , // PC 7 ** 30 ** D30 - PC , // PC 6 ** 31 ** D31 - PC , // PC 5 ** 32 ** D32 - PC , // PC 4 ** 33 ** D33 - PC , // PC 3 ** 34 ** D34 - PC , // PC 2 ** 35 ** D35 - PC , // PC 1 ** 36 ** D36 - PC , // PC 0 ** 37 ** D37 - PD , // PD 7 ** 38 ** D38 - PG , // PG 2 ** 39 ** D39 - PG , // PG 1 ** 40 ** D40 - PG , // PG 0 ** 41 ** D41 - PL , // PL 7 ** 42 ** D42 - PL , // PL 6 ** 43 ** D43 - PL , // PL 5 ** 44 ** D44 - PL , // PL 4 ** 45 ** D45 - PL , // PL 3 ** 46 ** D46 - PL , // PL 2 ** 47 ** D47 - PL , // PL 1 ** 48 ** D48 - PL , // PL 0 ** 49 ** D49 - PB , // PB 3 ** 50 ** SPI_MISO - PB , // PB 2 ** 51 ** SPI_MOSI - PB , // PB 1 ** 52 ** SPI_SCK - PB , // PB 0 ** 53 ** SPI_SS - PF , // PF 0 ** 54 ** A0 - PF , // PF 1 ** 55 ** A1 - PF , // PF 2 ** 56 ** A2 - PF , // PF 3 ** 57 ** A3 - PF , // PF 4 ** 58 ** A4 - PF , // PF 5 ** 59 ** A5 - PF , // PF 6 ** 60 ** A6 - PF , // PF 7 ** 61 ** A7 - PK , // PK 0 ** 62 ** A8 - PK , // PK 1 ** 63 ** A9 - PK , // PK 2 ** 64 ** A10 - PK , // PK 3 ** 65 ** A11 - PK , // PK 4 ** 66 ** A12 - PK , // PK 5 ** 67 ** A13 - PK , // PK 6 ** 68 ** A14 - PK , // PK 7 ** 69 ** A15 - PG , // PG 4 ** 70 ** D70 - PG , // PG 3 ** 71 ** D71 - PJ , // PJ 2 ** 72 ** D72 - PJ , // PJ 3 ** 73 ** D73 - PJ , // PJ 7 ** 74 ** D74 - PJ , // PJ 4 ** 75 ** D75 - PJ , // PJ 5 ** 76 ** D76 - PJ , // PJ 6 ** 77 ** D77 - PE , // PE 2 ** 78 ** D78 - PE , // PE 6 ** 79 ** D79 - PE , // PE 7 ** 80 ** D80 - PD , // PD 4 ** 81 ** D81 - PD , // PD 5 ** 82 ** D82 - PD , // PD 6 ** 83 ** D83 - PH , // PH 2 ** 84 ** D84 - PH , // PH 7 ** 85 ** D85 + PE, // PE 0 ** 0 ** USART0_RX + PE, // PE 1 ** 1 ** USART0_TX + PE, // PE 4 ** 2 ** PWM2 + PE, // PE 5 ** 3 ** PWM3 + PG, // PG 5 ** 4 ** PWM4 + PE, // PE 3 ** 5 ** PWM5 + PH, // PH 3 ** 6 ** PWM6 + PH, // PH 4 ** 7 ** PWM7 + PH, // PH 5 ** 8 ** PWM8 + PH, // PH 6 ** 9 ** PWM9 + PB, // PB 4 ** 10 ** PWM10 + PB, // PB 5 ** 11 ** PWM11 + PB, // PB 6 ** 12 ** PWM12 + PB, // PB 7 ** 13 ** PWM13 + PJ, // PJ 1 ** 14 ** USART3_TX + PJ, // PJ 0 ** 15 ** USART3_RX + PH, // PH 1 ** 16 ** USART2_TX + PH, // PH 0 ** 17 ** USART2_RX + PD, // PD 3 ** 18 ** USART1_TX + PD, // PD 2 ** 19 ** USART1_RX + PD, // PD 1 ** 20 ** I2C_SDA + PD, // PD 0 ** 21 ** I2C_SCL + PA, // PA 0 ** 22 ** D22 + PA, // PA 1 ** 23 ** D23 + PA, // PA 2 ** 24 ** D24 + PA, // PA 3 ** 25 ** D25 + PA, // PA 4 ** 26 ** D26 + PA, // PA 5 ** 27 ** D27 + PA, // PA 6 ** 28 ** D28 + PA, // PA 7 ** 29 ** D29 + PC, // PC 7 ** 30 ** D30 + PC, // PC 6 ** 31 ** D31 + PC, // PC 5 ** 32 ** D32 + PC, // PC 4 ** 33 ** D33 + PC, // PC 3 ** 34 ** D34 + PC, // PC 2 ** 35 ** D35 + PC, // PC 1 ** 36 ** D36 + PC, // PC 0 ** 37 ** D37 + PD, // PD 7 ** 38 ** D38 + PG, // PG 2 ** 39 ** D39 + PG, // PG 1 ** 40 ** D40 + PG, // PG 0 ** 41 ** D41 + PL, // PL 7 ** 42 ** D42 + PL, // PL 6 ** 43 ** D43 + PL, // PL 5 ** 44 ** D44 + PL, // PL 4 ** 45 ** D45 + PL, // PL 3 ** 46 ** D46 + PL, // PL 2 ** 47 ** D47 + PL, // PL 1 ** 48 ** D48 + PL, // PL 0 ** 49 ** D49 + PB, // PB 3 ** 50 ** SPI_MISO + PB, // PB 2 ** 51 ** SPI_MOSI + PB, // PB 1 ** 52 ** SPI_SCK + PB, // PB 0 ** 53 ** SPI_SS + PF, // PF 0 ** 54 ** A0 + PF, // PF 1 ** 55 ** A1 + PF, // PF 2 ** 56 ** A2 + PF, // PF 3 ** 57 ** A3 + PF, // PF 4 ** 58 ** A4 + PF, // PF 5 ** 59 ** A5 + PF, // PF 6 ** 60 ** A6 + PF, // PF 7 ** 61 ** A7 + PK, // PK 0 ** 62 ** A8 + PK, // PK 1 ** 63 ** A9 + PK, // PK 2 ** 64 ** A10 + PK, // PK 3 ** 65 ** A11 + PK, // PK 4 ** 66 ** A12 + PK, // PK 5 ** 67 ** A13 + PK, // PK 6 ** 68 ** A14 + PK, // PK 7 ** 69 ** A15 + PG, // PG 4 ** 70 ** D70 + PG, // PG 3 ** 71 ** D71 + PJ, // PJ 2 ** 72 ** D72 + PJ, // PJ 3 ** 73 ** D73 + PJ, // PJ 7 ** 74 ** D74 + PJ, // PJ 4 ** 75 ** D75 + PJ, // PJ 5 ** 76 ** D76 + PJ, // PJ 6 ** 77 ** D77 + PE, // PE 2 ** 78 ** D78 + PE, // PE 6 ** 79 ** D79 + PE, // PE 7 ** 80 ** D80 + PD, // PD 4 ** 81 ** D81 + PD, // PD 5 ** 82 ** D82 + PD, // PD 6 ** 83 ** D83 + PH, // PH 2 ** 84 ** D84 + PH, // PH 7 ** 85 ** D85 }; const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = { // PIN IN PORT // ------------------------------------------- - _BV( 0 ) , // PE 0 ** 0 ** USART0_RX - _BV( 1 ) , // PE 1 ** 1 ** USART0_TX - _BV( 4 ) , // PE 4 ** 2 ** PWM2 - _BV( 5 ) , // PE 5 ** 3 ** PWM3 - _BV( 5 ) , // PG 5 ** 4 ** PWM4 - _BV( 3 ) , // PE 3 ** 5 ** PWM5 - _BV( 3 ) , // PH 3 ** 6 ** PWM6 - _BV( 4 ) , // PH 4 ** 7 ** PWM7 - _BV( 5 ) , // PH 5 ** 8 ** PWM8 - _BV( 6 ) , // PH 6 ** 9 ** PWM9 - _BV( 4 ) , // PB 4 ** 10 ** PWM10 - _BV( 5 ) , // PB 5 ** 11 ** PWM11 - _BV( 6 ) , // PB 6 ** 12 ** PWM12 - _BV( 7 ) , // PB 7 ** 13 ** PWM13 - _BV( 1 ) , // PJ 1 ** 14 ** USART3_TX - _BV( 0 ) , // PJ 0 ** 15 ** USART3_RX - _BV( 1 ) , // PH 1 ** 16 ** USART2_TX - _BV( 0 ) , // PH 0 ** 17 ** USART2_RX - _BV( 3 ) , // PD 3 ** 18 ** USART1_TX - _BV( 2 ) , // PD 2 ** 19 ** USART1_RX - _BV( 1 ) , // PD 1 ** 20 ** I2C_SDA - _BV( 0 ) , // PD 0 ** 21 ** I2C_SCL - _BV( 0 ) , // PA 0 ** 22 ** D22 - _BV( 1 ) , // PA 1 ** 23 ** D23 - _BV( 2 ) , // PA 2 ** 24 ** D24 - _BV( 3 ) , // PA 3 ** 25 ** D25 - _BV( 4 ) , // PA 4 ** 26 ** D26 - _BV( 5 ) , // PA 5 ** 27 ** D27 - _BV( 6 ) , // PA 6 ** 28 ** D28 - _BV( 7 ) , // PA 7 ** 29 ** D29 - _BV( 7 ) , // PC 7 ** 30 ** D30 - _BV( 6 ) , // PC 6 ** 31 ** D31 - _BV( 5 ) , // PC 5 ** 32 ** D32 - _BV( 4 ) , // PC 4 ** 33 ** D33 - _BV( 3 ) , // PC 3 ** 34 ** D34 - _BV( 2 ) , // PC 2 ** 35 ** D35 - _BV( 1 ) , // PC 1 ** 36 ** D36 - _BV( 0 ) , // PC 0 ** 37 ** D37 - _BV( 7 ) , // PD 7 ** 38 ** D38 - _BV( 2 ) , // PG 2 ** 39 ** D39 - _BV( 1 ) , // PG 1 ** 40 ** D40 - _BV( 0 ) , // PG 0 ** 41 ** D41 - _BV( 7 ) , // PL 7 ** 42 ** D42 - _BV( 6 ) , // PL 6 ** 43 ** D43 - _BV( 5 ) , // PL 5 ** 44 ** D44 - _BV( 4 ) , // PL 4 ** 45 ** D45 - _BV( 3 ) , // PL 3 ** 46 ** D46 - _BV( 2 ) , // PL 2 ** 47 ** D47 - _BV( 1 ) , // PL 1 ** 48 ** D48 - _BV( 0 ) , // PL 0 ** 49 ** D49 - _BV( 3 ) , // PB 3 ** 50 ** SPI_MISO - _BV( 2 ) , // PB 2 ** 51 ** SPI_MOSI - _BV( 1 ) , // PB 1 ** 52 ** SPI_SCK - _BV( 0 ) , // PB 0 ** 53 ** SPI_SS - _BV( 0 ) , // PF 0 ** 54 ** A0 - _BV( 1 ) , // PF 1 ** 55 ** A1 - _BV( 2 ) , // PF 2 ** 56 ** A2 - _BV( 3 ) , // PF 3 ** 57 ** A3 - _BV( 4 ) , // PF 4 ** 58 ** A4 - _BV( 5 ) , // PF 5 ** 59 ** A5 - _BV( 6 ) , // PF 6 ** 60 ** A6 - _BV( 7 ) , // PF 7 ** 61 ** A7 - _BV( 0 ) , // PK 0 ** 62 ** A8 - _BV( 1 ) , // PK 1 ** 63 ** A9 - _BV( 2 ) , // PK 2 ** 64 ** A10 - _BV( 3 ) , // PK 3 ** 65 ** A11 - _BV( 4 ) , // PK 4 ** 66 ** A12 - _BV( 5 ) , // PK 5 ** 67 ** A13 - _BV( 6 ) , // PK 6 ** 68 ** A14 - _BV( 7 ) , // PK 7 ** 69 ** A15 - _BV( 4 ) , // PG 4 ** 70 ** D70 - _BV( 3 ) , // PG 3 ** 71 ** D71 - _BV( 2 ) , // PJ 2 ** 72 ** D72 - _BV( 3 ) , // PJ 3 ** 73 ** D73 - _BV( 7 ) , // PJ 7 ** 74 ** D74 - _BV( 4 ) , // PJ 4 ** 75 ** D75 - _BV( 5 ) , // PJ 5 ** 76 ** D76 - _BV( 6 ) , // PJ 6 ** 77 ** D77 - _BV( 2 ) , // PE 2 ** 78 ** D78 - _BV( 6 ) , // PE 6 ** 79 ** D79 - _BV( 7 ) , // PE 7 ** 80 ** D80 - _BV( 4 ) , // PD 4 ** 81 ** D81 - _BV( 5 ) , // PD 5 ** 82 ** D82 - _BV( 6 ) , // PD 6 ** 83 ** D83 - _BV( 2 ) , // PH 2 ** 84 ** D84 - _BV( 7 ) , // PH 7 ** 85 ** D85 + _BV( 0 ), // PE 0 ** 0 ** USART0_RX + _BV( 1 ), // PE 1 ** 1 ** USART0_TX + _BV( 4 ), // PE 4 ** 2 ** PWM2 + _BV( 5 ), // PE 5 ** 3 ** PWM3 + _BV( 5 ), // PG 5 ** 4 ** PWM4 + _BV( 3 ), // PE 3 ** 5 ** PWM5 + _BV( 3 ), // PH 3 ** 6 ** PWM6 + _BV( 4 ), // PH 4 ** 7 ** PWM7 + _BV( 5 ), // PH 5 ** 8 ** PWM8 + _BV( 6 ), // PH 6 ** 9 ** PWM9 + _BV( 4 ), // PB 4 ** 10 ** PWM10 + _BV( 5 ), // PB 5 ** 11 ** PWM11 + _BV( 6 ), // PB 6 ** 12 ** PWM12 + _BV( 7 ), // PB 7 ** 13 ** PWM13 + _BV( 1 ), // PJ 1 ** 14 ** USART3_TX + _BV( 0 ), // PJ 0 ** 15 ** USART3_RX + _BV( 1 ), // PH 1 ** 16 ** USART2_TX + _BV( 0 ), // PH 0 ** 17 ** USART2_RX + _BV( 3 ), // PD 3 ** 18 ** USART1_TX + _BV( 2 ), // PD 2 ** 19 ** USART1_RX + _BV( 1 ), // PD 1 ** 20 ** I2C_SDA + _BV( 0 ), // PD 0 ** 21 ** I2C_SCL + _BV( 0 ), // PA 0 ** 22 ** D22 + _BV( 1 ), // PA 1 ** 23 ** D23 + _BV( 2 ), // PA 2 ** 24 ** D24 + _BV( 3 ), // PA 3 ** 25 ** D25 + _BV( 4 ), // PA 4 ** 26 ** D26 + _BV( 5 ), // PA 5 ** 27 ** D27 + _BV( 6 ), // PA 6 ** 28 ** D28 + _BV( 7 ), // PA 7 ** 29 ** D29 + _BV( 7 ), // PC 7 ** 30 ** D30 + _BV( 6 ), // PC 6 ** 31 ** D31 + _BV( 5 ), // PC 5 ** 32 ** D32 + _BV( 4 ), // PC 4 ** 33 ** D33 + _BV( 3 ), // PC 3 ** 34 ** D34 + _BV( 2 ), // PC 2 ** 35 ** D35 + _BV( 1 ), // PC 1 ** 36 ** D36 + _BV( 0 ), // PC 0 ** 37 ** D37 + _BV( 7 ), // PD 7 ** 38 ** D38 + _BV( 2 ), // PG 2 ** 39 ** D39 + _BV( 1 ), // PG 1 ** 40 ** D40 + _BV( 0 ), // PG 0 ** 41 ** D41 + _BV( 7 ), // PL 7 ** 42 ** D42 + _BV( 6 ), // PL 6 ** 43 ** D43 + _BV( 5 ), // PL 5 ** 44 ** D44 + _BV( 4 ), // PL 4 ** 45 ** D45 + _BV( 3 ), // PL 3 ** 46 ** D46 + _BV( 2 ), // PL 2 ** 47 ** D47 + _BV( 1 ), // PL 1 ** 48 ** D48 + _BV( 0 ), // PL 0 ** 49 ** D49 + _BV( 3 ), // PB 3 ** 50 ** SPI_MISO + _BV( 2 ), // PB 2 ** 51 ** SPI_MOSI + _BV( 1 ), // PB 1 ** 52 ** SPI_SCK + _BV( 0 ), // PB 0 ** 53 ** SPI_SS + _BV( 0 ), // PF 0 ** 54 ** A0 + _BV( 1 ), // PF 1 ** 55 ** A1 + _BV( 2 ), // PF 2 ** 56 ** A2 + _BV( 3 ), // PF 3 ** 57 ** A3 + _BV( 4 ), // PF 4 ** 58 ** A4 + _BV( 5 ), // PF 5 ** 59 ** A5 + _BV( 6 ), // PF 6 ** 60 ** A6 + _BV( 7 ), // PF 7 ** 61 ** A7 + _BV( 0 ), // PK 0 ** 62 ** A8 + _BV( 1 ), // PK 1 ** 63 ** A9 + _BV( 2 ), // PK 2 ** 64 ** A10 + _BV( 3 ), // PK 3 ** 65 ** A11 + _BV( 4 ), // PK 4 ** 66 ** A12 + _BV( 5 ), // PK 5 ** 67 ** A13 + _BV( 6 ), // PK 6 ** 68 ** A14 + _BV( 7 ), // PK 7 ** 69 ** A15 + _BV( 4 ), // PG 4 ** 70 ** D70 + _BV( 3 ), // PG 3 ** 71 ** D71 + _BV( 2 ), // PJ 2 ** 72 ** D72 + _BV( 3 ), // PJ 3 ** 73 ** D73 + _BV( 7 ), // PJ 7 ** 74 ** D74 + _BV( 4 ), // PJ 4 ** 75 ** D75 + _BV( 5 ), // PJ 5 ** 76 ** D76 + _BV( 6 ), // PJ 6 ** 77 ** D77 + _BV( 2 ), // PE 2 ** 78 ** D78 + _BV( 6 ), // PE 6 ** 79 ** D79 + _BV( 7 ), // PE 7 ** 80 ** D80 + _BV( 4 ), // PD 4 ** 81 ** D81 + _BV( 5 ), // PD 5 ** 82 ** D82 + _BV( 6 ), // PD 6 ** 83 ** D83 + _BV( 2 ), // PH 2 ** 84 ** D84 + _BV( 7 ), // PH 7 ** 85 ** D85 }; const uint8_t PROGMEM digital_pin_to_timer_PGM[] = { // TIMERS // ------------------------------------------- - NOT_ON_TIMER , // PE 0 ** 0 ** USART0_RX - NOT_ON_TIMER , // PE 1 ** 1 ** USART0_TX - TIMER3B , // PE 4 ** 2 ** PWM2 - TIMER3C , // PE 5 ** 3 ** PWM3 - TIMER0B , // PG 5 ** 4 ** PWM4 - TIMER3A , // PE 3 ** 5 ** PWM5 - TIMER4A , // PH 3 ** 6 ** PWM6 - TIMER4B , // PH 4 ** 7 ** PWM7 - TIMER4C , // PH 5 ** 8 ** PWM8 - TIMER2B , // PH 6 ** 9 ** PWM9 - TIMER2A , // PB 4 ** 10 ** PWM10 - TIMER1A , // PB 5 ** 11 ** PWM11 - TIMER1B , // PB 6 ** 12 ** PWM12 - TIMER0A , // PB 7 ** 13 ** PWM13 - NOT_ON_TIMER , // PJ 1 ** 14 ** USART3_TX - NOT_ON_TIMER , // PJ 0 ** 15 ** USART3_RX - NOT_ON_TIMER , // PH 1 ** 16 ** USART2_TX - NOT_ON_TIMER , // PH 0 ** 17 ** USART2_RX - NOT_ON_TIMER , // PD 3 ** 18 ** USART1_TX - NOT_ON_TIMER , // PD 2 ** 19 ** USART1_RX - NOT_ON_TIMER , // PD 1 ** 20 ** I2C_SDA - NOT_ON_TIMER , // PD 0 ** 21 ** I2C_SCL - NOT_ON_TIMER , // PA 0 ** 22 ** D22 - NOT_ON_TIMER , // PA 1 ** 23 ** D23 - NOT_ON_TIMER , // PA 2 ** 24 ** D24 - NOT_ON_TIMER , // PA 3 ** 25 ** D25 - NOT_ON_TIMER , // PA 4 ** 26 ** D26 - NOT_ON_TIMER , // PA 5 ** 27 ** D27 - NOT_ON_TIMER , // PA 6 ** 28 ** D28 - NOT_ON_TIMER , // PA 7 ** 29 ** D29 - NOT_ON_TIMER , // PC 7 ** 30 ** D30 - NOT_ON_TIMER , // PC 6 ** 31 ** D31 - NOT_ON_TIMER , // PC 5 ** 32 ** D32 - NOT_ON_TIMER , // PC 4 ** 33 ** D33 - NOT_ON_TIMER , // PC 3 ** 34 ** D34 - NOT_ON_TIMER , // PC 2 ** 35 ** D35 - NOT_ON_TIMER , // PC 1 ** 36 ** D36 - NOT_ON_TIMER , // PC 0 ** 37 ** D37 - NOT_ON_TIMER , // PD 7 ** 38 ** D38 - NOT_ON_TIMER , // PG 2 ** 39 ** D39 - NOT_ON_TIMER , // PG 1 ** 40 ** D40 - NOT_ON_TIMER , // PG 0 ** 41 ** D41 - NOT_ON_TIMER , // PL 7 ** 42 ** D42 - NOT_ON_TIMER , // PL 6 ** 43 ** D43 - TIMER5C , // PL 5 ** 44 ** D44 - TIMER5B , // PL 4 ** 45 ** D45 - TIMER5A , // PL 3 ** 46 ** D46 - NOT_ON_TIMER , // PL 2 ** 47 ** D47 - NOT_ON_TIMER , // PL 1 ** 48 ** D48 - NOT_ON_TIMER , // PL 0 ** 49 ** D49 - NOT_ON_TIMER , // PB 3 ** 50 ** SPI_MISO - NOT_ON_TIMER , // PB 2 ** 51 ** SPI_MOSI - NOT_ON_TIMER , // PB 1 ** 52 ** SPI_SCK - NOT_ON_TIMER , // PB 0 ** 53 ** SPI_SS - NOT_ON_TIMER , // PF 0 ** 54 ** A0 - NOT_ON_TIMER , // PF 1 ** 55 ** A1 - NOT_ON_TIMER , // PF 2 ** 56 ** A2 - NOT_ON_TIMER , // PF 3 ** 57 ** A3 - NOT_ON_TIMER , // PF 4 ** 58 ** A4 - NOT_ON_TIMER , // PF 5 ** 59 ** A5 - NOT_ON_TIMER , // PF 6 ** 60 ** A6 - NOT_ON_TIMER , // PF 7 ** 61 ** A7 - NOT_ON_TIMER , // PK 0 ** 62 ** A8 - NOT_ON_TIMER , // PK 1 ** 63 ** A9 - NOT_ON_TIMER , // PK 2 ** 64 ** A10 - NOT_ON_TIMER , // PK 3 ** 65 ** A11 - NOT_ON_TIMER , // PK 4 ** 66 ** A12 - NOT_ON_TIMER , // PK 5 ** 67 ** A13 - NOT_ON_TIMER , // PK 6 ** 68 ** A14 - NOT_ON_TIMER , // PK 7 ** 69 ** A15 - NOT_ON_TIMER , // PG 4 ** 70 ** D70 - NOT_ON_TIMER , // PG 3 ** 71 ** D71 - NOT_ON_TIMER , // PJ 2 ** 72 ** D72 - NOT_ON_TIMER , // PJ 3 ** 73 ** D73 - NOT_ON_TIMER , // PJ 7 ** 74 ** D74 - NOT_ON_TIMER , // PJ 4 ** 75 ** D75 - NOT_ON_TIMER , // PJ 5 ** 76 ** D76 - NOT_ON_TIMER , // PJ 6 ** 77 ** D77 - NOT_ON_TIMER , // PE 2 ** 78 ** D78 - NOT_ON_TIMER , // PE 6 ** 79 ** D79 - NOT_ON_TIMER , // PE 7 ** 80 ** D80 - NOT_ON_TIMER , // PD 4 ** 81 ** D81 - NOT_ON_TIMER , // PD 5 ** 82 ** D82 - NOT_ON_TIMER , // PD 6 ** 83 ** D83 - NOT_ON_TIMER , // PH 2 ** 84 ** D84 - NOT_ON_TIMER , // PH 7 ** 85 ** D85 + NOT_ON_TIMER, // PE 0 ** 0 ** USART0_RX + NOT_ON_TIMER, // PE 1 ** 1 ** USART0_TX + TIMER3B, // PE 4 ** 2 ** PWM2 + TIMER3C, // PE 5 ** 3 ** PWM3 + TIMER0B, // PG 5 ** 4 ** PWM4 + TIMER3A, // PE 3 ** 5 ** PWM5 + TIMER4A, // PH 3 ** 6 ** PWM6 + TIMER4B, // PH 4 ** 7 ** PWM7 + TIMER4C, // PH 5 ** 8 ** PWM8 + TIMER2B, // PH 6 ** 9 ** PWM9 + TIMER2A, // PB 4 ** 10 ** PWM10 + TIMER1A, // PB 5 ** 11 ** PWM11 + TIMER1B, // PB 6 ** 12 ** PWM12 + TIMER0A, // PB 7 ** 13 ** PWM13 + NOT_ON_TIMER, // PJ 1 ** 14 ** USART3_TX + NOT_ON_TIMER, // PJ 0 ** 15 ** USART3_RX + NOT_ON_TIMER, // PH 1 ** 16 ** USART2_TX + NOT_ON_TIMER, // PH 0 ** 17 ** USART2_RX + NOT_ON_TIMER, // PD 3 ** 18 ** USART1_TX + NOT_ON_TIMER, // PD 2 ** 19 ** USART1_RX + NOT_ON_TIMER, // PD 1 ** 20 ** I2C_SDA + NOT_ON_TIMER, // PD 0 ** 21 ** I2C_SCL + NOT_ON_TIMER, // PA 0 ** 22 ** D22 + NOT_ON_TIMER, // PA 1 ** 23 ** D23 + NOT_ON_TIMER, // PA 2 ** 24 ** D24 + NOT_ON_TIMER, // PA 3 ** 25 ** D25 + NOT_ON_TIMER, // PA 4 ** 26 ** D26 + NOT_ON_TIMER, // PA 5 ** 27 ** D27 + NOT_ON_TIMER, // PA 6 ** 28 ** D28 + NOT_ON_TIMER, // PA 7 ** 29 ** D29 + NOT_ON_TIMER, // PC 7 ** 30 ** D30 + NOT_ON_TIMER, // PC 6 ** 31 ** D31 + NOT_ON_TIMER, // PC 5 ** 32 ** D32 + NOT_ON_TIMER, // PC 4 ** 33 ** D33 + NOT_ON_TIMER, // PC 3 ** 34 ** D34 + NOT_ON_TIMER, // PC 2 ** 35 ** D35 + NOT_ON_TIMER, // PC 1 ** 36 ** D36 + NOT_ON_TIMER, // PC 0 ** 37 ** D37 + NOT_ON_TIMER, // PD 7 ** 38 ** D38 + NOT_ON_TIMER, // PG 2 ** 39 ** D39 + NOT_ON_TIMER, // PG 1 ** 40 ** D40 + NOT_ON_TIMER, // PG 0 ** 41 ** D41 + NOT_ON_TIMER, // PL 7 ** 42 ** D42 + NOT_ON_TIMER, // PL 6 ** 43 ** D43 + TIMER5C, // PL 5 ** 44 ** D44 + TIMER5B, // PL 4 ** 45 ** D45 + TIMER5A, // PL 3 ** 46 ** D46 + NOT_ON_TIMER, // PL 2 ** 47 ** D47 + NOT_ON_TIMER, // PL 1 ** 48 ** D48 + NOT_ON_TIMER, // PL 0 ** 49 ** D49 + NOT_ON_TIMER, // PB 3 ** 50 ** SPI_MISO + NOT_ON_TIMER, // PB 2 ** 51 ** SPI_MOSI + NOT_ON_TIMER, // PB 1 ** 52 ** SPI_SCK + NOT_ON_TIMER, // PB 0 ** 53 ** SPI_SS + NOT_ON_TIMER, // PF 0 ** 54 ** A0 + NOT_ON_TIMER, // PF 1 ** 55 ** A1 + NOT_ON_TIMER, // PF 2 ** 56 ** A2 + NOT_ON_TIMER, // PF 3 ** 57 ** A3 + NOT_ON_TIMER, // PF 4 ** 58 ** A4 + NOT_ON_TIMER, // PF 5 ** 59 ** A5 + NOT_ON_TIMER, // PF 6 ** 60 ** A6 + NOT_ON_TIMER, // PF 7 ** 61 ** A7 + NOT_ON_TIMER, // PK 0 ** 62 ** A8 + NOT_ON_TIMER, // PK 1 ** 63 ** A9 + NOT_ON_TIMER, // PK 2 ** 64 ** A10 + NOT_ON_TIMER, // PK 3 ** 65 ** A11 + NOT_ON_TIMER, // PK 4 ** 66 ** A12 + NOT_ON_TIMER, // PK 5 ** 67 ** A13 + NOT_ON_TIMER, // PK 6 ** 68 ** A14 + NOT_ON_TIMER, // PK 7 ** 69 ** A15 + NOT_ON_TIMER, // PG 4 ** 70 ** D70 + NOT_ON_TIMER, // PG 3 ** 71 ** D71 + NOT_ON_TIMER, // PJ 2 ** 72 ** D72 + NOT_ON_TIMER, // PJ 3 ** 73 ** D73 + NOT_ON_TIMER, // PJ 7 ** 74 ** D74 + NOT_ON_TIMER, // PJ 4 ** 75 ** D75 + NOT_ON_TIMER, // PJ 5 ** 76 ** D76 + NOT_ON_TIMER, // PJ 6 ** 77 ** D77 + NOT_ON_TIMER, // PE 2 ** 78 ** D78 + NOT_ON_TIMER, // PE 6 ** 79 ** D79 + NOT_ON_TIMER, // PE 7 ** 80 ** D80 + NOT_ON_TIMER, // PD 4 ** 81 ** D81 + NOT_ON_TIMER, // PD 5 ** 82 ** D82 + NOT_ON_TIMER, // PD 6 ** 83 ** D83 + NOT_ON_TIMER, // PH 2 ** 84 ** D84 + NOT_ON_TIMER, // PH 7 ** 85 ** D85 }; #endif diff --git a/buildroot/share/PlatformIO/variants/marlin_maple_CHITU_F103/board.cpp b/buildroot/share/PlatformIO/variants/marlin_maple_CHITU_F103/board.cpp index 8a4320a664..afaece9760 100644 --- a/buildroot/share/PlatformIO/variants/marlin_maple_CHITU_F103/board.cpp +++ b/buildroot/share/PlatformIO/variants/marlin_maple_CHITU_F103/board.cpp @@ -131,74 +131,74 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { {&gpioc, NULL, NULL, 14, 0, ADCx}, /* PC14 OSC32_IN */ {&gpioc, NULL, NULL, 15, 0, ADCx}, /* PC15 OSC32_OUT */ - {&gpiod, NULL, NULL, 0, 0, ADCx} , /* PD0 OSC_IN */ - {&gpiod, NULL, NULL, 1, 0, ADCx} , /* PD1 OSC_OUT */ - {&gpiod, NULL, NULL, 2, 0, ADCx} , /* PD2 TIM3_ETR/UART5_RX SDIO_CMD */ + {&gpiod, NULL, NULL, 0, 0, ADCx}, /* PD0 OSC_IN */ + {&gpiod, NULL, NULL, 1, 0, ADCx}, /* PD1 OSC_OUT */ + {&gpiod, NULL, NULL, 2, 0, ADCx}, /* PD2 TIM3_ETR/UART5_RX SDIO_CMD */ - {&gpiod, NULL, NULL, 3, 0, ADCx} , /* PD3 FSMC_CLK */ - {&gpiod, NULL, NULL, 4, 0, ADCx} , /* PD4 FSMC_NOE */ - {&gpiod, NULL, NULL, 5, 0, ADCx} , /* PD5 FSMC_NWE */ - {&gpiod, NULL, NULL, 6, 0, ADCx} , /* PD6 FSMC_NWAIT */ - {&gpiod, NULL, NULL, 7, 0, ADCx} , /* PD7 FSMC_NE1/FSMC_NCE2 */ - {&gpiod, NULL, NULL, 8, 0, ADCx} , /* PD8 FSMC_D13 */ - {&gpiod, NULL, NULL, 9, 0, ADCx} , /* PD9 FSMC_D14 */ - {&gpiod, NULL, NULL, 10, 0, ADCx} , /* PD10 FSMC_D15 */ - {&gpiod, NULL, NULL, 11, 0, ADCx} , /* PD11 FSMC_A16 */ - {&gpiod, NULL, NULL, 12, 0, ADCx} , /* PD12 FSMC_A17 */ - {&gpiod, NULL, NULL, 13, 0, ADCx} , /* PD13 FSMC_A18 */ - {&gpiod, NULL, NULL, 14, 0, ADCx} , /* PD14 FSMC_D0 */ - {&gpiod, NULL, NULL, 15, 0, ADCx} , /* PD15 FSMC_D1 */ + {&gpiod, NULL, NULL, 3, 0, ADCx}, /* PD3 FSMC_CLK */ + {&gpiod, NULL, NULL, 4, 0, ADCx}, /* PD4 FSMC_NOE */ + {&gpiod, NULL, NULL, 5, 0, ADCx}, /* PD5 FSMC_NWE */ + {&gpiod, NULL, NULL, 6, 0, ADCx}, /* PD6 FSMC_NWAIT */ + {&gpiod, NULL, NULL, 7, 0, ADCx}, /* PD7 FSMC_NE1/FSMC_NCE2 */ + {&gpiod, NULL, NULL, 8, 0, ADCx}, /* PD8 FSMC_D13 */ + {&gpiod, NULL, NULL, 9, 0, ADCx}, /* PD9 FSMC_D14 */ + {&gpiod, NULL, NULL, 10, 0, ADCx}, /* PD10 FSMC_D15 */ + {&gpiod, NULL, NULL, 11, 0, ADCx}, /* PD11 FSMC_A16 */ + {&gpiod, NULL, NULL, 12, 0, ADCx}, /* PD12 FSMC_A17 */ + {&gpiod, NULL, NULL, 13, 0, ADCx}, /* PD13 FSMC_A18 */ + {&gpiod, NULL, NULL, 14, 0, ADCx}, /* PD14 FSMC_D0 */ + {&gpiod, NULL, NULL, 15, 0, ADCx}, /* PD15 FSMC_D1 */ - {&gpioe, NULL, NULL, 0, 0, ADCx} , /* PE0 */ - {&gpioe, NULL, NULL, 1, 0, ADCx} , /* PE1 */ - {&gpioe, NULL, NULL, 2, 0, ADCx} , /* PE2 */ - {&gpioe, NULL, NULL, 3, 0, ADCx} , /* PE3 */ - {&gpioe, NULL, NULL, 4, 0, ADCx} , /* PE4 */ - {&gpioe, NULL, NULL, 5, 0, ADCx} , /* PE5 */ - {&gpioe, NULL, NULL, 6, 0, ADCx} , /* PE6 */ - {&gpioe, NULL, NULL, 7, 0, ADCx} , /* PE7 */ - {&gpioe, NULL, NULL, 8, 0, ADCx} , /* PE8 */ - {&gpioe, NULL, NULL, 9, 0, ADCx} , /* PE9 */ - {&gpioe, NULL, NULL, 10, 0, ADCx} , /* PE10 */ - {&gpioe, NULL, NULL, 11, 0, ADCx} , /* PE11 */ - {&gpioe, NULL, NULL, 12, 0, ADCx} , /* PE12 */ - {&gpioe, NULL, NULL, 13, 0, ADCx} , /* PE13 */ - {&gpioe, NULL, NULL, 14, 0, ADCx} , /* PE14 */ - {&gpioe, NULL, NULL, 15, 0, ADCx} , /* PE15 */ + {&gpioe, NULL, NULL, 0, 0, ADCx}, /* PE0 */ + {&gpioe, NULL, NULL, 1, 0, ADCx}, /* PE1 */ + {&gpioe, NULL, NULL, 2, 0, ADCx}, /* PE2 */ + {&gpioe, NULL, NULL, 3, 0, ADCx}, /* PE3 */ + {&gpioe, NULL, NULL, 4, 0, ADCx}, /* PE4 */ + {&gpioe, NULL, NULL, 5, 0, ADCx}, /* PE5 */ + {&gpioe, NULL, NULL, 6, 0, ADCx}, /* PE6 */ + {&gpioe, NULL, NULL, 7, 0, ADCx}, /* PE7 */ + {&gpioe, NULL, NULL, 8, 0, ADCx}, /* PE8 */ + {&gpioe, NULL, NULL, 9, 0, ADCx}, /* PE9 */ + {&gpioe, NULL, NULL, 10, 0, ADCx}, /* PE10 */ + {&gpioe, NULL, NULL, 11, 0, ADCx}, /* PE11 */ + {&gpioe, NULL, NULL, 12, 0, ADCx}, /* PE12 */ + {&gpioe, NULL, NULL, 13, 0, ADCx}, /* PE13 */ + {&gpioe, NULL, NULL, 14, 0, ADCx}, /* PE14 */ + {&gpioe, NULL, NULL, 15, 0, ADCx}, /* PE15 */ - {&gpiof, NULL, NULL, 0, 0, ADCx} , /* PF0 */ - {&gpiof, NULL, NULL, 1, 0, ADCx} , /* PF1 */ - {&gpiof, NULL, NULL, 2, 0, ADCx} , /* PF2 */ - {&gpiof, NULL, NULL, 3, 0, ADCx} , /* PF3 */ - {&gpiof, NULL, NULL, 4, 0, ADCx} , /* PF4 */ - {&gpiof, NULL, NULL, 5, 0, ADCx} , /* PF5 */ - {&gpiof, NULL, NULL, 6, 0, ADCx} , /* PF6 */ - {&gpiof, NULL, NULL, 7, 0, ADCx} , /* PF7 */ - {&gpiof, NULL, NULL, 8, 0, ADCx} , /* PF8 */ - {&gpiof, NULL, NULL, 9, 0, ADCx} , /* PF9 */ - {&gpiof, NULL, NULL, 10, 0, ADCx} , /* PF10 */ - {&gpiof, NULL, NULL, 11, 0, ADCx} , /* PF11 */ - {&gpiof, NULL, NULL, 12, 0, ADCx} , /* PF12 */ - {&gpiof, NULL, NULL, 13, 0, ADCx} , /* PF13 */ - {&gpiof, NULL, NULL, 14, 0, ADCx} , /* PF14 */ - {&gpiof, NULL, NULL, 15, 0, ADCx} , /* PF15 */ + {&gpiof, NULL, NULL, 0, 0, ADCx}, /* PF0 */ + {&gpiof, NULL, NULL, 1, 0, ADCx}, /* PF1 */ + {&gpiof, NULL, NULL, 2, 0, ADCx}, /* PF2 */ + {&gpiof, NULL, NULL, 3, 0, ADCx}, /* PF3 */ + {&gpiof, NULL, NULL, 4, 0, ADCx}, /* PF4 */ + {&gpiof, NULL, NULL, 5, 0, ADCx}, /* PF5 */ + {&gpiof, NULL, NULL, 6, 0, ADCx}, /* PF6 */ + {&gpiof, NULL, NULL, 7, 0, ADCx}, /* PF7 */ + {&gpiof, NULL, NULL, 8, 0, ADCx}, /* PF8 */ + {&gpiof, NULL, NULL, 9, 0, ADCx}, /* PF9 */ + {&gpiof, NULL, NULL, 10, 0, ADCx}, /* PF10 */ + {&gpiof, NULL, NULL, 11, 0, ADCx}, /* PF11 */ + {&gpiof, NULL, NULL, 12, 0, ADCx}, /* PF12 */ + {&gpiof, NULL, NULL, 13, 0, ADCx}, /* PF13 */ + {&gpiof, NULL, NULL, 14, 0, ADCx}, /* PF14 */ + {&gpiof, NULL, NULL, 15, 0, ADCx}, /* PF15 */ - {&gpiog, NULL, NULL, 0, 0, ADCx} , /* PG0 */ - {&gpiog, NULL, NULL, 1, 0, ADCx} , /* PG1 */ - {&gpiog, NULL, NULL, 2, 0, ADCx} , /* PG2 */ - {&gpiog, NULL, NULL, 3, 0, ADCx} , /* PG3 */ - {&gpiog, NULL, NULL, 4, 0, ADCx} , /* PG4 */ - {&gpiog, NULL, NULL, 5, 0, ADCx} , /* PG5 */ - {&gpiog, NULL, NULL, 6, 0, ADCx} , /* PG6 */ - {&gpiog, NULL, NULL, 7, 0, ADCx} , /* PG7 */ - {&gpiog, NULL, NULL, 8, 0, ADCx} , /* PG8 */ - {&gpiog, NULL, NULL, 9, 0, ADCx} , /* PG9 */ - {&gpiog, NULL, NULL, 10, 0, ADCx} , /* PG10 */ - {&gpiog, NULL, NULL, 11, 0, ADCx} , /* PG11 */ - {&gpiog, NULL, NULL, 12, 0, ADCx} , /* PG12 */ - {&gpiog, NULL, NULL, 13, 0, ADCx} , /* PG13 */ - {&gpiog, NULL, NULL, 14, 0, ADCx} , /* PG14 */ - {&gpiog, NULL, NULL, 15, 0, ADCx} /* PG15 */ + {&gpiog, NULL, NULL, 0, 0, ADCx}, /* PG0 */ + {&gpiog, NULL, NULL, 1, 0, ADCx}, /* PG1 */ + {&gpiog, NULL, NULL, 2, 0, ADCx}, /* PG2 */ + {&gpiog, NULL, NULL, 3, 0, ADCx}, /* PG3 */ + {&gpiog, NULL, NULL, 4, 0, ADCx}, /* PG4 */ + {&gpiog, NULL, NULL, 5, 0, ADCx}, /* PG5 */ + {&gpiog, NULL, NULL, 6, 0, ADCx}, /* PG6 */ + {&gpiog, NULL, NULL, 7, 0, ADCx}, /* PG7 */ + {&gpiog, NULL, NULL, 8, 0, ADCx}, /* PG8 */ + {&gpiog, NULL, NULL, 9, 0, ADCx}, /* PG9 */ + {&gpiog, NULL, NULL, 10, 0, ADCx}, /* PG10 */ + {&gpiog, NULL, NULL, 11, 0, ADCx}, /* PG11 */ + {&gpiog, NULL, NULL, 12, 0, ADCx}, /* PG12 */ + {&gpiog, NULL, NULL, 13, 0, ADCx}, /* PG13 */ + {&gpiog, NULL, NULL, 14, 0, ADCx}, /* PG14 */ + {&gpiog, NULL, NULL, 15, 0, ADCx} /* PG15 */ }; /* Basically everything that is defined as having a timer us PWM */ diff --git a/buildroot/share/PlatformIO/variants/marlin_maple_MEEB_3DP/board.cpp b/buildroot/share/PlatformIO/variants/marlin_maple_MEEB_3DP/board.cpp index 5ddeb1f1d9..332c9f005e 100644 --- a/buildroot/share/PlatformIO/variants/marlin_maple_MEEB_3DP/board.cpp +++ b/buildroot/share/PlatformIO/variants/marlin_maple_MEEB_3DP/board.cpp @@ -132,9 +132,9 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { {&gpioc, NULL, NULL, 14, 0, ADCx}, /* PC14 OSC32_IN */ {&gpioc, NULL, NULL, 15, 0, ADCx}, /* PC15 OSC32_OUT */ - {&gpiod, NULL, NULL, 0, 0, ADCx} , /* PD0 OSC_IN */ - {&gpiod, NULL, NULL, 1, 0, ADCx} , /* PD1 OSC_OUT */ - {&gpiod, NULL, NULL, 2, 0, ADCx} , /* PD2 TIM3_ETR/UART5_RX SDIO_CMD */ + {&gpiod, NULL, NULL, 0, 0, ADCx}, /* PD0 OSC_IN */ + {&gpiod, NULL, NULL, 1, 0, ADCx}, /* PD1 OSC_OUT */ + {&gpiod, NULL, NULL, 2, 0, ADCx}, /* PD2 TIM3_ETR/UART5_RX SDIO_CMD */ }; /* Basically everything that is defined as having a timer us PWM */ diff --git a/buildroot/share/scripts/createTemperatureLookupMarlin.py b/buildroot/share/scripts/createTemperatureLookupMarlin.py index eb8c094957..5515681bfc 100755 --- a/buildroot/share/scripts/createTemperatureLookupMarlin.py +++ b/buildroot/share/scripts/createTemperatureLookupMarlin.py @@ -141,7 +141,7 @@ def main(argv): for temp in temps: adc = t.adc(temp) - print(" { OV(%7.2f), %4s }%s // v=%.3f\tr=%.3f\tres=%.3f degC/count" % (adc , temp, \ + print(" { OV(%7.2f), %4s }%s // v=%.3f\tr=%.3f\tres=%.3f degC/count" % (adc, temp, \ ',' if temp != temps[-1] else ' ', \ t.voltage(adc), \ t.resist( adc), \ diff --git a/buildroot/tests/BTT_GTR_V1_0 b/buildroot/tests/BTT_GTR_V1_0 index c6cb7d5feb..e40f3ffa53 100755 --- a/buildroot/tests/BTT_GTR_V1_0 +++ b/buildroot/tests/BTT_GTR_V1_0 @@ -36,7 +36,7 @@ opt_set MOTHERBOARD BOARD_BTT_GTR_V1_0 SERIAL_PORT -1 \ EXTRUDERS 3 TEMP_SENSOR_1 1 TEMP_SENSOR_2 1 \ SERVO1_PIN PE9 SERVO2_PIN PE11 \ SERVO_DELAY '{ 300, 300, 300 }' \ - SWITCHING_TOOLHEAD_X_POS '{ 215, 0 ,0 }' \ + SWITCHING_TOOLHEAD_X_POS '{ 215, 0, 0 }' \ MPC_HEATER_POWER '{ 40.0f, 40.0f, 40.0f }' \ MPC_BLOCK_HEAT_CAPACITY '{ 16.7f, 16.7f, 16.7f }' \ MPC_SENSOR_RESPONSIVENESS '{ 0.22f, 0.22f, 0.22f }' \ diff --git a/docs/Cutter.md b/docs/Cutter.md index 8f4b7e67aa..207036c6e8 100644 --- a/docs/Cutter.md +++ b/docs/Cutter.md @@ -4,7 +4,7 @@ With Marlin version 2.0.9.x or higher, Laser improvements were introduced that e ### Architecture -Laser selectable feature capability is defined through 4 global mode flags within G-code ,laser/spindle, planner and stepper routines. The default mode maintains the standard laser function. G-Codes are received, processed and parsed to determine what mode to set through M3, M4 and M5 commands. When the inline mode parameter set is detected, laser power processing will be driven through the planner and stepper routines. Handling of the initial power values and settings are performed by G-Code parsing and the laser/spindle routines. +Laser selectable feature capability is defined through 4 global mode flags within G-code, laser/spindle, planner and stepper routines. The default mode maintains the standard laser function. G-Codes are received, processed and parsed to determine what mode to set through M3, M4 and M5 commands. When the inline mode parameter set is detected, laser power processing will be driven through the planner and stepper routines. Handling of the initial power values and settings are performed by G-Code parsing and the laser/spindle routines. Inline power feeds from the block->inline_power variable into the planner's laser.power when in continuous power mode. Further power adjustment will be applied if the laser power trap feature is active otherwise laser.power is used as set in the stepper for the entire block. When laser power trap is active the power levels are step incremented during acceleration and step decremented during deceleration. diff --git a/ini/hc32.ini b/ini/hc32.ini index a99614beec..8a55e3b495 100644 --- a/ini/hc32.ini +++ b/ini/hc32.ini @@ -33,12 +33,12 @@ platform_packages = framework-hc32f46x-ddl@https://github.com/shadow578/framewor board = generic_hc32f460 build_src_filter = ${common.default_src_filter} + + build_type = release -build_flags = -D ARDUINO_ARCH_HC32 - -D PLATFORM_M997_SUPPORT # Enable M997 command - # NOTE: DDL and Arduino debug mode are - # automatically enabled with MARLIN_DEV_MODE - #-D __DEBUG # force DDL debug mode - #-D __CORE_DEBUG # force Arduino core debug mode +build_flags = -DARDUINO_ARCH_HC32 + -DPLATFORM_M997_SUPPORT # Enable M997 command + # NOTE: DDL and Arduino debug mode are + # automatically enabled with MARLIN_DEV_MODE + #-D__DEBUG # force DDL debug mode + #-D__CORE_DEBUG # force Arduino core debug mode # HC32 app configuration file board_build.app_config = Marlin/src/HAL/HC32/app_config.h From 8cb6e57789e76e5cf359f276b5993f9d8c771ac0 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Thu, 10 Apr 2025 00:31:25 +0000 Subject: [PATCH 198/787] [cron] Bump distribution date (2025-04-10) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index d071d96c66..6982c994d4 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-04-08" +//#define STRING_DISTRIBUTION_DATE "2025-04-10" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 13b8eee07e..4e7935271a 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-04-08" + #define STRING_DISTRIBUTION_DATE "2025-04-10" #endif /** From 893dddcbd1a7da69eeb09092fe265e12aa34539a Mon Sep 17 00:00:00 2001 From: Keith Bennett <13375512+thisiskeithb@users.noreply.github.com> Date: Sat, 12 Apr 2025 13:12:31 -0700 Subject: [PATCH 199/787] =?UTF-8?q?=F0=9F=93=9D=20Malyan=20LCD=20uses=20en?= =?UTF-8?q?coders=20(#27781)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/Configuration.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 69cae47ee1..af7e17ad05 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -3282,7 +3282,7 @@ #endif // -// Touch-screen LCD for Malyan M200/M300 printers +// LCD for Malyan M200/M300 printers // //#define MALYAN_LCD From d1947fac07e326c749c3617591872b7ff471ec79 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Sun, 13 Apr 2025 00:56:12 +0000 Subject: [PATCH 200/787] [cron] Bump distribution date (2025-04-13) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 6982c994d4..cb253de7bc 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-04-10" +//#define STRING_DISTRIBUTION_DATE "2025-04-13" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 4e7935271a..aa30ba6e18 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-04-10" + #define STRING_DISTRIBUTION_DATE "2025-04-13" #endif /** From 6d2dfcaa1cb55d11e3689094144ada1751fe2ff5 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sat, 12 Apr 2025 16:13:49 -0500 Subject: [PATCH 201/787] =?UTF-8?q?=F0=9F=A9=B9=20Fix=20i2c=20encoder=20re?= =?UTF-8?q?port?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/feature/encoder_i2c.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/src/feature/encoder_i2c.cpp b/Marlin/src/feature/encoder_i2c.cpp index 55bde4ca62..3d9466f7ed 100644 --- a/Marlin/src/feature/encoder_i2c.cpp +++ b/Marlin/src/feature/encoder_i2c.cpp @@ -652,7 +652,7 @@ void I2CPositionEncodersMgr::report_position(const int8_t idx, const bool units, else { if (noOffset) { const int32_t raw_count = encoders[idx].get_raw_count(); - SERIAL_CHAR(AXIS_CHAR(encoders[idx).get_axis()], ' '); + SERIAL_CHAR(AXIS_CHAR(encoders[idx].get_axis()), ' '); for (uint8_t j = 31; j > 0; j--) SERIAL_ECHO((bool)(0x00000001 & (raw_count >> j))); @@ -707,7 +707,7 @@ void I2CPositionEncodersMgr::change_module_address(const uint8_t oldaddr, const // and enable it (it will likely have failed initialization on power-up, before the address change). const int8_t idx = idx_from_addr(newaddr); if (idx >= 0 && !encoders[idx].get_active()) { - SERIAL_CHAR(AXIS_CHAR(encoders[idx).get_axis()]); + SERIAL_CHAR(AXIS_CHAR(encoders[idx].get_axis())); SERIAL_ECHOLNPGM(" axis encoder was not detected on printer startup. Trying again."); encoders[idx].set_active(encoders[idx].passes_test(true)); } From a55355d088c94b8c12bbccaf708fe986d0448c14 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sun, 13 Apr 2025 00:55:58 -0500 Subject: [PATCH 202/787] =?UTF-8?q?=F0=9F=9A=B8=20FT=20Motion=20menu=20fix?= =?UTF-8?q?,=20neaten?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/lcd/language/language_en.h | 4 ++-- Marlin/src/lcd/language/language_it.h | 4 ++-- Marlin/src/lcd/language/language_ru.h | 4 ++-- Marlin/src/lcd/language/language_tr.h | 4 ++-- Marlin/src/lcd/menu/menu_motion.cpp | 18 ++++++------------ Marlin/src/libs/numtostr.cpp | 2 +- 6 files changed, 15 insertions(+), 21 deletions(-) diff --git a/Marlin/src/lcd/language/language_en.h b/Marlin/src/lcd/language/language_en.h index 54740c923e..686a0b759c 100644 --- a/Marlin/src/lcd/language/language_en.h +++ b/Marlin/src/lcd/language/language_en.h @@ -894,7 +894,7 @@ namespace LanguageNarrow_en { LSTR MSG_BACKLASH_SMOOTHING = _UxGT("Smoothing"); LSTR MSG_FIXED_TIME_MOTION = _UxGT("Fixed-Time Motion"); - LSTR MSG_FTM_CMPN_MODE = _UxGT("@ Comp. Mode:"); + LSTR MSG_FTM_CMPN_MODE = _UxGT("@ Comp. Mode: $"); LSTR MSG_FTM_ZV = _UxGT("ZV"); LSTR MSG_FTM_ZVD = _UxGT("ZVD"); LSTR MSG_FTM_ZVDD = _UxGT("ZVDD"); @@ -905,7 +905,7 @@ namespace LanguageNarrow_en { LSTR MSG_FTM_MZV = _UxGT("MZV"); //LSTR MSG_FTM_ULENDO_FBS = _UxGT("Ulendo FBS"); //LSTR MSG_FTM_DISCTF = _UxGT("DISCTF"); - LSTR MSG_FTM_DYN_MODE = _UxGT("DF Mode:"); + LSTR MSG_FTM_DYN_MODE = _UxGT("DF Mode: $"); LSTR MSG_FTM_Z_BASED = _UxGT("Z-based"); LSTR MSG_FTM_MASS_BASED = _UxGT("Mass-based"); LSTR MSG_FTM_BASE_FREQ_N = _UxGT("@ Base Freq."); diff --git a/Marlin/src/lcd/language/language_it.h b/Marlin/src/lcd/language/language_it.h index 1e81514440..c1b5366332 100644 --- a/Marlin/src/lcd/language/language_it.h +++ b/Marlin/src/lcd/language/language_it.h @@ -861,8 +861,8 @@ namespace LanguageNarrow_it { LSTR MSG_BACKLASH_SMOOTHING = _UxGT("Appianamento"); LSTR MSG_FIXED_TIME_MOTION = _UxGT("Movimento a Tempo-Fisso"); - LSTR MSG_FTM_CMPN_MODE = _UxGT("@ Modo Comp:"); - LSTR MSG_FTM_DYN_MODE = _UxGT("Modo DF:"); + LSTR MSG_FTM_CMPN_MODE = _UxGT("@ Modo Comp: $"); + LSTR MSG_FTM_DYN_MODE = _UxGT("Modo DF: $"); LSTR MSG_FTM_Z_BASED = _UxGT("Base-Z"); LSTR MSG_FTM_MASS_BASED = _UxGT("Base-Massa"); LSTR MSG_FTM_BASE_FREQ_N = _UxGT("@ Freq. base"); diff --git a/Marlin/src/lcd/language/language_ru.h b/Marlin/src/lcd/language/language_ru.h index 92011f66a6..991fd638ef 100644 --- a/Marlin/src/lcd/language/language_ru.h +++ b/Marlin/src/lcd/language/language_ru.h @@ -811,7 +811,7 @@ namespace LanguageNarrow_ru { // did not translate as there is no local terms/slang yet LSTR MSG_FIXED_TIME_MOTION = _UxGT("FT Motion"); - LSTR MSG_FTM_CMPN_MODE = _UxGT("@ Режим комп.:"); + LSTR MSG_FTM_CMPN_MODE = _UxGT("@ Режим комп.: $"); LSTR MSG_FTM_ZV = _UxGT("ZV"); LSTR MSG_FTM_ZVD = _UxGT("ZVD"); LSTR MSG_FTM_EI = _UxGT("EI"); @@ -820,7 +820,7 @@ namespace LanguageNarrow_ru { LSTR MSG_FTM_MZV = _UxGT("MZV"); //LSTR MSG_FTM_ULENDO_FBS = _UxGT("Ulendo ФBС"); //LSTR MSG_FTM_DISCTF = _UxGT("DISCTF"); - LSTR MSG_FTM_DYN_MODE = _UxGT("DF Mode:"); + LSTR MSG_FTM_DYN_MODE = _UxGT("DF Mode: $"); LSTR MSG_FTM_Z_BASED = _UxGT("Z-based"); LSTR MSG_FTM_MASS_BASED = _UxGT("Mass-based"); LSTR MSG_FTM_BASE_FREQ_N = _UxGT("@ Base Freq."); diff --git a/Marlin/src/lcd/language/language_tr.h b/Marlin/src/lcd/language/language_tr.h index b52ded8db8..947f094fa6 100644 --- a/Marlin/src/lcd/language/language_tr.h +++ b/Marlin/src/lcd/language/language_tr.h @@ -796,7 +796,7 @@ namespace LanguageNarrow_tr { LSTR MSG_BACKLASH_SMOOTHING = _UxGT("Yumuşatma"); LSTR MSG_FIXED_TIME_MOTION = _UxGT("Sabit Zamanlı Hareket"); - LSTR MSG_FTM_CMPN_MODE = _UxGT("@ Telafi Modu:"); + LSTR MSG_FTM_CMPN_MODE = _UxGT("@ Telafi Modu: $"); LSTR MSG_FTM_ZV = _UxGT("ZV"); LSTR MSG_FTM_ZVD = _UxGT("ZVD"); LSTR MSG_FTM_ZVDD = _UxGT("ZVDD"); @@ -807,7 +807,7 @@ namespace LanguageNarrow_tr { LSTR MSG_FTM_MZV = _UxGT("MZV"); //LSTR MSG_FTM_ULENDO_FBS = _UxGT("Ulendo FBS"); //LSTR MSG_FTM_DISCTF = _UxGT("DISCTF"); - LSTR MSG_FTM_DYN_MODE = _UxGT("DF Modu:"); + LSTR MSG_FTM_DYN_MODE = _UxGT("DF Modu: $"); LSTR MSG_FTM_Z_BASED = _UxGT("Z-based"); LSTR MSG_FTM_MASS_BASED = _UxGT("Mass-based"); LSTR MSG_FTM_BASE_FREQ_N = _UxGT("@ Base Freq."); diff --git a/Marlin/src/lcd/menu/menu_motion.cpp b/Marlin/src/lcd/menu/menu_motion.cpp index f6f13e2a4e..e2adbfded2 100644 --- a/Marlin/src/lcd/menu/menu_motion.cpp +++ b/Marlin/src/lcd/menu/menu_motion.cpp @@ -426,8 +426,7 @@ void menu_move() { // Show only when FT Motion is active (or optionally always show) if (c.active || ENABLED(FT_MOTION_NO_MENU_TOGGLE)) { #if HAS_X_AXIS - SUBMENU_N(X_AXIS, MSG_FTM_CMPN_MODE, menu_ftm_shaper_x); - MENU_ITEM_ADDON_START_RJ(5); lcd_put_u8str(shaper_name[X_AXIS]); MENU_ITEM_ADDON_END(); + SUBMENU_N_S(X_AXIS, shaper_name[X_AXIS], MSG_FTM_CMPN_MODE, menu_ftm_shaper_x); if (AXIS_HAS_SHAPER(X)) { EDIT_ITEM_FAST_N(float42_52, X_AXIS, MSG_FTM_BASE_FREQ_N, &c.baseFreq.x, FTM_MIN_SHAPE_FREQ, (FTM_FS) / 2, ftMotion.update_shaping_params); @@ -437,8 +436,7 @@ void menu_move() { } #endif #if HAS_Y_AXIS - SUBMENU_N(Y_AXIS, MSG_FTM_CMPN_MODE, menu_ftm_shaper_y); - MENU_ITEM_ADDON_START_RJ(5); lcd_put_u8str(shaper_name[Y_AXIS]); MENU_ITEM_ADDON_END(); + SUBMENU_N_S(Y_AXIS, shaper_name[Y_AXIS], MSG_FTM_CMPN_MODE, menu_ftm_shaper_y); if (AXIS_HAS_SHAPER(Y)) { EDIT_ITEM_FAST_N(float42_52, Y_AXIS, MSG_FTM_BASE_FREQ_N, &c.baseFreq.y, FTM_MIN_SHAPE_FREQ, (FTM_FS) / 2, ftMotion.update_shaping_params); @@ -449,8 +447,7 @@ void menu_move() { #endif #if HAS_DYNAMIC_FREQ - SUBMENU(MSG_FTM_DYN_MODE, menu_ftm_dyn_mode); - MENU_ITEM_ADDON_START_RJ(11); lcd_put_u8str(dmode); MENU_ITEM_ADDON_END(); + SUBMENU_S(dmode, MSG_FTM_DYN_MODE, menu_ftm_dyn_mode); if (c.dynFreqMode != dynFreqMode_DISABLED) { #if HAS_X_AXIS EDIT_ITEM_FAST_N(float42_52, X_AXIS, MSG_FTM_DFREQ_K_N, &c.dynFreqK.x, 0.0f, 20.0f); @@ -489,16 +486,13 @@ void menu_move() { BACK_ITEM(MSG_TUNE); #if HAS_X_AXIS - SUBMENU_N(X_AXIS, MSG_FTM_CMPN_MODE, menu_ftm_shaper_x); - MENU_ITEM_ADDON_START_RJ(5); lcd_put_u8str(shaper_name[X_AXIS]); MENU_ITEM_ADDON_END(); + SUBMENU_N_S(X_AXIS, shaper_name[X_AXIS], MSG_FTM_CMPN_MODE, menu_ftm_shaper_x); #endif #if HAS_Y_AXIS - SUBMENU_N(Y_AXIS, MSG_FTM_CMPN_MODE, menu_ftm_shaper_y); - MENU_ITEM_ADDON_START_RJ(5); lcd_put_u8str(shaper_name[Y_AXIS]); MENU_ITEM_ADDON_END(); + SUBMENU_N_S(Y_AXIS, shaper_name[Y_AXIS], MSG_FTM_CMPN_MODE, menu_ftm_shaper_y); #endif #if HAS_DYNAMIC_FREQ - SUBMENU(MSG_FTM_DYN_MODE, menu_ftm_dyn_mode); - MENU_ITEM_ADDON_START_RJ(dmode.length()); lcd_put_u8str(dmode); MENU_ITEM_ADDON_END(); + SUBMENU_S(dmode, MSG_FTM_DYN_MODE, menu_ftm_dyn_mode); #endif #if HAS_EXTRUDERS EDIT_ITEM(bool, MSG_LINEAR_ADVANCE, &c.linearAdvEna); diff --git a/Marlin/src/libs/numtostr.cpp b/Marlin/src/libs/numtostr.cpp index aa00b5d6e2..830e9b356b 100644 --- a/Marlin/src/libs/numtostr.cpp +++ b/Marlin/src/libs/numtostr.cpp @@ -406,8 +406,8 @@ inline const char* ftostrX2rj(const_float_t f, const int index=1) { case 1: conv[1] = RJDIGIT(i, 100000); case 2: conv[2] = RJDIGIT(i, 10000); case 3: conv[3] = RJDIGIT(i, 1000); - case 4: conv[4] = RJDIGIT(i, 100); } + conv[4] = DIGIMOD(i, 100); conv[5] = '.'; conv[6] = DIGIMOD(i, 10); conv[7] = DIGIMOD(i, 1); From aee25d75ea2b8e8b0a6b90fb366d0fc9ea2db584 Mon Sep 17 00:00:00 2001 From: narno2202 <130909513+narno2202@users.noreply.github.com> Date: Sun, 13 Apr 2025 08:36:21 +0200 Subject: [PATCH 203/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20DGU?= =?UTF-8?q?SScreenHandler=20hack=20for=20MKS=20(#27789)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/lcd/extui/dgus/DGUSScreenHandler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/src/lcd/extui/dgus/DGUSScreenHandler.cpp b/Marlin/src/lcd/extui/dgus/DGUSScreenHandler.cpp index 38b3d93853..79353a4e23 100644 --- a/Marlin/src/lcd/extui/dgus/DGUSScreenHandler.cpp +++ b/Marlin/src/lcd/extui/dgus/DGUSScreenHandler.cpp @@ -326,7 +326,7 @@ void DGUSScreenHandler::sendHeaterStatusToDisplay(DGUS_VP_Variable &var) { void DGUSScreenHandler::sdCardError() { DGUSScreenHandler::sdCardRemoved(); #if DGUS_LCD_UI_MKS - sendInfoScreenMKS(F("NOTICE"), nullptr, F("SD card error"), nullptr, mks_language_index); + screen.sendInfoScreenMKS(F("NOTICE"), nullptr, F("SD card error"), nullptr, mks_language_index); #else sendInfoScreen(F("NOTICE"), nullptr, F("SD card error"), nullptr); #endif From c173ecd89ae636c2deaf7310a626569b6a6c4797 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sun, 13 Apr 2025 02:06:50 -0500 Subject: [PATCH 204/787] =?UTF-8?q?=F0=9F=8E=A8=20Misc.=20serial=20echo/ch?= =?UTF-8?q?ar?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/MarlinCore.cpp | 6 ++-- Marlin/src/core/bug_on.h | 8 ++--- Marlin/src/core/utility.cpp | 11 ++---- Marlin/src/feature/cancel_object.cpp | 2 +- Marlin/src/feature/encoder_i2c.cpp | 53 ++++++++++++---------------- Marlin/src/libs/hex_print.cpp | 2 +- Marlin/src/sd/cardreader.cpp | 23 ++++-------- 7 files changed, 40 insertions(+), 65 deletions(-) diff --git a/Marlin/src/MarlinCore.cpp b/Marlin/src/MarlinCore.cpp index bfe69ba94e..f2b2589ee6 100644 --- a/Marlin/src/MarlinCore.cpp +++ b/Marlin/src/MarlinCore.cpp @@ -428,8 +428,7 @@ inline void manage_inactivity(const bool no_stepper_sleep=false) { if (gcode.stepper_max_timed_out(ms)) { SERIAL_ERROR_START(); - SERIAL_ECHOPGM(STR_KILL_PRE); - SERIAL_ECHOLNPGM(STR_KILL_INACTIVE_TIME, parser.command_ptr); + SERIAL_ECHOLN(F(STR_KILL_PRE), F(STR_KILL_INACTIVE_TIME), parser.command_ptr); kill(); } @@ -497,8 +496,7 @@ inline void manage_inactivity(const bool no_stepper_sleep=false) { // ---------------------------------------------------------------- if (killCount >= KILL_DELAY) { SERIAL_ERROR_START(); - SERIAL_ECHOPGM(STR_KILL_PRE); - SERIAL_ECHOLNPGM(STR_KILL_BUTTON); + SERIAL_ECHOLN(F(STR_KILL_PRE), F(STR_KILL_BUTTON)); kill(); } #endif diff --git a/Marlin/src/core/bug_on.h b/Marlin/src/core/bug_on.h index 7f1243ed40..8ff565ff73 100644 --- a/Marlin/src/core/bug_on.h +++ b/Marlin/src/core/bug_on.h @@ -27,12 +27,12 @@ // Useful macro for stopping the CPU on an unexpected condition // This is used like SERIAL_ECHOPGM, that is: a key-value call of the local variables you want // to dump to the serial port before stopping the CPU. - // \/ Don't replace by SERIAL_ECHOPGM since ONLY_FILENAME cannot be transformed to a PGM string on Arduino and it breaks building - #define BUG_ON(V...) do { SERIAL_ECHO(ONLY_FILENAME); SERIAL_ECHO(__LINE__); SERIAL_ECHOLNPGM(": "); SERIAL_ECHOLNPGM(V); SERIAL_FLUSHTX(); *(char*)0 = 42; } while(0) + // \/ Don't use SERIAL_ECHOPGM with ONLY_FILENAME. It can't be a PGM string, + #define BUG_ON(V...) do { SERIAL_ECHOLN(ONLY_FILENAME, __LINE__, F(": ")); SERIAL_ECHOLNPGM(V); SERIAL_FLUSHTX(); *(char*)0 = 42; } while(0) #elif ENABLED(MARLIN_DEV_MODE) // Don't stop the CPU here, but at least dump the bug on the serial port - // \/ Don't replace by SERIAL_ECHOPGM since ONLY_FILENAME cannot be transformed to a PGM string on Arduino and it breaks building - #define BUG_ON(V...) do { SERIAL_ECHO(ONLY_FILENAME); SERIAL_ECHO(__LINE__); SERIAL_ECHOLNPGM(": BUG!"); SERIAL_ECHOLNPGM(V); SERIAL_FLUSHTX(); } while(0) + // \/ Don't use SERIAL_ECHOPGM with ONLY_FILENAME. It can't be a PGM string, + #define BUG_ON(V...) do { SERIAL_ECHOLN(ONLY_FILENAME, __LINE__, F(": BUG!")); SERIAL_ECHOLNPGM(V); SERIAL_FLUSHTX(); } while(0) #else // Release mode, let's ignore the bug #define BUG_ON(V...) NOOP diff --git a/Marlin/src/core/utility.cpp b/Marlin/src/core/utility.cpp index 6a8452bfaa..cc49cf2cfb 100644 --- a/Marlin/src/core/utility.cpp +++ b/Marlin/src/core/utility.cpp @@ -154,10 +154,8 @@ void safe_delay(millis_t ms) { const float rz = bedlevel.get_z_correction(current_position); SERIAL_ECHO(ftostr43sign(rz, '+')); #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT) - if (planner.z_fade_height) { - SERIAL_ECHOPGM(" (", ftostr43sign(rz * planner.fade_scaling_factor_for_z(current_position.z), '+')); - SERIAL_CHAR(')'); - } + if (planner.z_fade_height) + SERIAL_ECHO(F(" ("), ftostr43sign(rz * planner.fade_scaling_factor_for_z(current_position.z), '+'), C(')')); #endif #endif } @@ -176,10 +174,7 @@ void safe_delay(millis_t ms) { SERIAL_ECHOPGM("MBL Adjustment Z", ftostr43sign(z_offset + z_correction, '+')); #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT) if (planner.z_fade_height) { - SERIAL_ECHOPGM(" (", ftostr43sign( - z_offset + z_correction * planner.fade_scaling_factor_for_z(current_position.z), '+' - )); - SERIAL_CHAR(')'); + SERIAL_ECHO(F(" ("), ftostr43sign(z_offset + z_correction * planner.fade_scaling_factor_for_z(current_position.z), '+'), C(')')); } #endif } diff --git a/Marlin/src/feature/cancel_object.cpp b/Marlin/src/feature/cancel_object.cpp index 818661b1f0..c17c9988e4 100644 --- a/Marlin/src/feature/cancel_object.cpp +++ b/Marlin/src/feature/cancel_object.cpp @@ -72,7 +72,7 @@ void CancelObject::report() { SERIAL_ECHO_START(); SERIAL_ECHOPGM("Canceled:"); for (int i = 0; i < state.object_count; i++) - if (TEST(state.canceled, i)) { SERIAL_CHAR(' '); SERIAL_ECHO(i); } + if (TEST(state.canceled, i)) SERIAL_ECHO(C(' '), i); SERIAL_EOL(); } diff --git a/Marlin/src/feature/encoder_i2c.cpp b/Marlin/src/feature/encoder_i2c.cpp index 3d9466f7ed..1930176aa6 100644 --- a/Marlin/src/feature/encoder_i2c.cpp +++ b/Marlin/src/feature/encoder_i2c.cpp @@ -168,8 +168,7 @@ void I2CPositionEncoder::update() { float sumP = 0; for (uint8_t i = 0; i < I2CPE_ERR_PRST_ARRAY_SIZE; ++i) sumP += errPrst[i]; const int32_t errorP = int32_t(sumP * RECIPROCAL(I2CPE_ERR_PRST_ARRAY_SIZE)); - SERIAL_CHAR(AXIS_CHAR(encoderAxis)); - SERIAL_ECHOLNPGM(" : CORRECT ERR ", errorP * planner.mm_per_step[encoderAxis], "mm"); + SERIAL_ECHOLN(C(AXIS_CHAR(encoderAxis)), F(" : CORRECT ERR "), errorP * planner.mm_per_step[encoderAxis], F("mm")); babystep.add_steps(encoderAxis, -LROUND(errorP)); errPrstIdx = 0; } @@ -188,8 +187,7 @@ void I2CPositionEncoder::update() { if (ABS(error) > I2CPE_ERR_CNT_THRESH * planner.settings.axis_steps_per_mm[encoderAxis]) { const millis_t ms = millis(); if (ELAPSED(ms, nextErrorCountTime)) { - SERIAL_CHAR(AXIS_CHAR(encoderAxis)); - SERIAL_ECHOLNPGM(" : LARGE ERR ", error, "; diffSum=", diffSum); + SERIAL_ECHOLN(C(AXIS_CHAR(encoderAxis)), F(" : LARGE ERR "), error, F("; diffSum="), diffSum); errorCount++; nextErrorCountTime = ms + I2CPE_ERR_CNT_DEBOUNCE_MS; } @@ -208,8 +206,7 @@ void I2CPositionEncoder::set_homed() { homed = trusted = true; #ifdef I2CPE_DEBUG - SERIAL_CHAR(AXIS_CHAR(encoderAxis)); - SERIAL_ECHOLNPGM(" axis encoder homed, offset of ", zeroOffset, " ticks."); + SERIAL_ECHO(C(AXIS_CHAR(encoderAxis)), F(" axis encoder homed, offset of "), zeroOffset, F(" ticks.\n")); #endif } } @@ -219,8 +216,7 @@ void I2CPositionEncoder::set_unhomed() { homed = trusted = false; #ifdef I2CPE_DEBUG - SERIAL_CHAR(AXIS_CHAR(encoderAxis)); - SERIAL_ECHOLNPGM(" axis encoder unhomed."); + SERIAL_ECHO(C(AXIS_CHAR(encoderAxis)), F(" axis encoder unhomed.\n")); #endif } @@ -247,10 +243,8 @@ float I2CPositionEncoder::get_axis_error_mm(const bool report) { diff = actual - target, error = ABS(diff) > 10000 ? 0 : diff; // Huge error is a bad reading - if (report) { - SERIAL_CHAR(AXIS_CHAR(encoderAxis)); - SERIAL_ECHOLNPGM(" axis target=", target, "mm; actual=", actual, "mm; err=", error, "mm"); - } + if (report) + SERIAL_ECHO(C(AXIS_CHAR(encoderAxis)), F(" axis target="), target, F("mm; actual="), actual, F("mm; err="), error, F("mm\n")); return error; } @@ -282,10 +276,8 @@ int32_t I2CPositionEncoder::get_axis_error_steps(const bool report) { errorPrev = error; - if (report) { - SERIAL_CHAR(AXIS_CHAR(encoderAxis)); - SERIAL_ECHOLNPGM(" axis target=", target, "; actual=", encoderCountInStepperTicksScaled, "; err=", error); - } + if (report) + SERIAL_ECHOLN(C(AXIS_CHAR(encoderAxis)), F(" axis target="), target, F("; actual="), encoderCountInStepperTicksScaled, F("; err="), error); if (suppressOutput) { if (report) SERIAL_ECHOLNPGM("!Discontinuity. Suppressing error."); @@ -647,23 +639,22 @@ void I2CPositionEncodersMgr::init() { void I2CPositionEncodersMgr::report_position(const int8_t idx, const bool units, const bool noOffset) { CHECK_IDX(); - if (units) + if (units) { SERIAL_ECHOLN(noOffset ? encoders[idx].mm_from_count(encoders[idx].get_raw_count()) : encoders[idx].get_position_mm()); - else { - if (noOffset) { - const int32_t raw_count = encoders[idx].get_raw_count(); - SERIAL_CHAR(AXIS_CHAR(encoders[idx].get_axis()), ' '); - - for (uint8_t j = 31; j > 0; j--) - SERIAL_ECHO((bool)(0x00000001 & (raw_count >> j))); - - SERIAL_ECHO((bool)(0x00000001 & raw_count)); - SERIAL_CHAR(' '); - SERIAL_ECHOLN(raw_count); - } - else - SERIAL_ECHOLN(encoders[idx].get_position()); + return; } + + if (noOffset) { + const int32_t raw_count = encoders[idx].get_raw_count(); + SERIAL_CHAR(AXIS_CHAR(encoders[idx].get_axis()), ' '); + + for (uint8_t j = 31; j >= 0; j--) + SERIAL_ECHO(TEST32(raw_count, j)); + + SERIAL_ECHOLN(C(' '), raw_count); + } + else + SERIAL_ECHOLN(encoders[idx].get_position()); } void I2CPositionEncodersMgr::change_module_address(const uint8_t oldaddr, const uint8_t newaddr) { diff --git a/Marlin/src/libs/hex_print.cpp b/Marlin/src/libs/hex_print.cpp index 9ff3fc6eb2..f0095b18ce 100644 --- a/Marlin/src/libs/hex_print.cpp +++ b/Marlin/src/libs/hex_print.cpp @@ -59,7 +59,7 @@ char* hex_address(const void * const a) { void print_hex_nybble(const uint8_t n) { SERIAL_CHAR(hex_nybble(n)); } void print_hex_byte(const uint8_t b) { SERIAL_ECHO(hex_byte(b)); } void print_hex_word(const uint16_t w) { SERIAL_ECHO(_hex_word(w)); } -void print_hex_address(const void * const w) { SERIAL_ECHO(hex_address(w)); } +void print_hex_address(const void * const a) { SERIAL_ECHO(hex_address(a)); } void print_hex_long(const uint32_t w, const char delimiter/*='\0'*/, const bool prefix/*=false*/) { if (prefix) SERIAL_ECHOPGM("0x"); diff --git a/Marlin/src/sd/cardreader.cpp b/Marlin/src/sd/cardreader.cpp index 68b5846c2f..647e071c72 100644 --- a/Marlin/src/sd/cardreader.cpp +++ b/Marlin/src/sd/cardreader.cpp @@ -330,24 +330,21 @@ void CardReader::printListing(MediaFile parent, const char * const prepend, cons } } else if (is_visible_entity(p OPTARG(CUSTOM_FIRMWARE_UPLOAD, onlyBin))) { - if (prepend) { SERIAL_ECHO(prepend); SERIAL_CHAR('/'); } - SERIAL_ECHO(createFilename(filename, p)); - SERIAL_CHAR(' '); - SERIAL_ECHO(p.fileSize); + if (prepend) SERIAL_ECHO(prepend, C('/')); + SERIAL_ECHO(createFilename(filename, p), C(' '), p.fileSize); if (includeTime) { - SERIAL_CHAR(' '); uint16_t crmodDate = p.lastWriteDate, crmodTime = p.lastWriteTime; if (crmodDate < p.creationDate || (crmodDate == p.creationDate && crmodTime < p.creationTime)) { crmodDate = p.creationDate; crmodTime = p.creationTime; } - SERIAL_ECHOPGM("0x", hex_word(crmodDate)); + SERIAL_ECHOPGM(" 0x", hex_word(crmodDate)); print_hex_word(crmodTime); } #if ENABLED(LONG_FILENAME_HOST_SUPPORT) if (includeLong) { SERIAL_CHAR(' '); - if (prependLong) { SERIAL_ECHO(prependLong); SERIAL_CHAR('/'); } + if (prependLong) SERIAL_ECHO(prependLong, C('/')); SERIAL_ECHO(longFilename[0] ? longFilename : filename); } #endif @@ -470,10 +467,7 @@ void CardReader::printSelectedFilename() { SERIAL_ECHO(dosFilename); #if ENABLED(LONG_FILENAME_HOST_SUPPORT) selectFileByName(dosFilename); - if (longFilename[0]) { - SERIAL_CHAR(' '); - SERIAL_ECHO(longFilename); - } + if (longFilename[0]) SERIAL_ECHO(C(' '), longFilename); #endif } else @@ -856,11 +850,8 @@ void CardReader::report_status(TERN_(QUIETER_AUTO_REPORT_SD_STATUS, const bool i if (has_job) old_sdpos = sdpos; #endif - if (has_job) { - SERIAL_ECHOPGM(STR_SD_PRINTING_BYTE, sdpos); - SERIAL_CHAR('/'); - SERIAL_ECHOLN(filesize); - } + if (has_job) + SERIAL_ECHOLN(F(STR_SD_PRINTING_BYTE), sdpos, C('/'), filesize); else SERIAL_ECHOLNPGM(STR_SD_NOT_PRINTING); } From 9a6bf16938eaa1bbb8ba4e15c691ccc53f10c371 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sun, 13 Apr 2025 03:18:35 -0500 Subject: [PATCH 205/787] =?UTF-8?q?=F0=9F=9A=B8=20Some=20default=20filamen?= =?UTF-8?q?t=20runout=20pins?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/pins/mega/pins_HJC2560C_REV2.h | 12 ++++++++---- Marlin/src/pins/ramps/pins_ULTIMAIN_2.h | 10 ++++++++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/Marlin/src/pins/mega/pins_HJC2560C_REV2.h b/Marlin/src/pins/mega/pins_HJC2560C_REV2.h index 38e6617f51..4b454f2968 100644 --- a/Marlin/src/pins/mega/pins_HJC2560C_REV2.h +++ b/Marlin/src/pins/mega/pins_HJC2560C_REV2.h @@ -22,7 +22,7 @@ #pragma once /** - * Geeetech HJC2560-C Rev 2.x board pin assignments + * Geeetech HJC2560-C Rev 1.x and 2.x board pin assignments * ATmega2560 */ @@ -78,6 +78,13 @@ #endif #define DEFAULT_PWM_MOTOR_CURRENT { 1300, 1300, 1250 } +// +// Filament Runout Sensor +// +#ifndef FIL_RUNOUT_PIN + #define FIL_RUNOUT_PIN 24 // Filament runout +#endif + // // Temperature Sensors // @@ -138,9 +145,6 @@ //#ifndef LCD_CONTRAST_PIN // #define LCD_CONTRAST_PIN 5 // LCD_Contrast //#endif - #ifndef FIL_RUNOUT_PIN - #define FIL_RUNOUT_PIN 24 // Filament runout - #endif #else #define LCD_PINS_D5 21 #define LCD_PINS_D6 5 diff --git a/Marlin/src/pins/ramps/pins_ULTIMAIN_2.h b/Marlin/src/pins/ramps/pins_ULTIMAIN_2.h index 448c79a8d2..4633bfc037 100644 --- a/Marlin/src/pins/ramps/pins_ULTIMAIN_2.h +++ b/Marlin/src/pins/ramps/pins_ULTIMAIN_2.h @@ -89,6 +89,16 @@ #endif #define DEFAULT_PWM_MOTOR_CURRENT {1300, 1300, 1250} +// +// Filament Runout Sensor +// +#ifndef FIL_RUNOUT_PIN + #define FIL_RUNOUT_PIN 54 // ADC0 +#endif +#ifndef FIL_RUNOUT2_PIN + #define FIL_RUNOUT2_PIN 55 // ADC1 +#endif + // // Temperature Sensors // From db427415376db9ed4f4287a6a5b6b8842575446d Mon Sep 17 00:00:00 2001 From: ellensp <530024+ellensp@users.noreply.github.com> Date: Sun, 13 Apr 2025 20:27:45 +1200 Subject: [PATCH 206/787] =?UTF-8?q?=F0=9F=94=A7=20Raise=20MBL=20grid=20siz?= =?UTF-8?q?e=20limit=20(#27790)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Scott Lahteine --- Marlin/Configuration.h | 2 +- Marlin/src/inc/SanityCheck.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index af7e17ad05..faa6f56843 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -2276,7 +2276,7 @@ //=========================================================================== #define MESH_INSET 10 // Set Mesh bounds as an inset region of the bed - #define GRID_MAX_POINTS_X 3 // Don't use more than 7 points per axis, implementation limited. + #define GRID_MAX_POINTS_X 3 #define GRID_MAX_POINTS_Y GRID_MAX_POINTS_X //#define MESH_G28_REST_ORIGIN // After homing all axes ('G28' or 'G28 XYZ') rest Z at Z_MIN_POS diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index fa06bac9f5..c40a2f7632 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -1649,8 +1649,8 @@ static_assert(NUM_SERVOS <= NUM_SERVO_PLUGS, "NUM_SERVOS (or some servo index) i #elif ENABLED(MESH_BED_LEVELING) #if ENABLED(DELTA) #error "MESH_BED_LEVELING is not compatible with DELTA printers." - #elif (GRID_MAX_POINTS_X) > 9 || (GRID_MAX_POINTS_Y) > 9 - #error "GRID_MAX_POINTS_X and GRID_MAX_POINTS_Y must be less than 10 for MBL." + #elif !WITHIN(GRID_MAX_POINTS_X, 2, 255) || !WITHIN(GRID_MAX_POINTS_Y, 2, 255) + #error "GRID_MAX_POINTS_[XY] must be between 2 and 255 for MESH_BED_LEVELING." #endif #endif From 69464790e220a7a96eb92d3f47a57c44dadd2c75 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Mon, 14 Apr 2025 00:32:24 +0000 Subject: [PATCH 207/787] [cron] Bump distribution date (2025-04-14) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index cb253de7bc..008997c83a 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-04-13" +//#define STRING_DISTRIBUTION_DATE "2025-04-14" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index aa30ba6e18..ba062ee43d 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-04-13" + #define STRING_DISTRIBUTION_DATE "2025-04-14" #endif /** From 7d82f95df879250286c6cf230784bc0d217fda19 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Mon, 14 Apr 2025 16:45:12 -0500 Subject: [PATCH 208/787] =?UTF-8?q?=F0=9F=A9=B9=20Fix=20DWIN=5FCREALITY=5F?= =?UTF-8?q?LCD=5FSTD=5FICONS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/lcd/e3v2/common/dwin_set.h | 38 ++++++++++++++++++++------- Marlin/src/lcd/e3v2/jyersui/dwin.cpp | 16 +++++------ Marlin/src/lcd/e3v2/jyersui/dwin.h | 32 ++-------------------- 3 files changed, 38 insertions(+), 48 deletions(-) diff --git a/Marlin/src/lcd/e3v2/common/dwin_set.h b/Marlin/src/lcd/e3v2/common/dwin_set.h index 644efb40ba..f59bb74cd3 100644 --- a/Marlin/src/lcd/e3v2/common/dwin_set.h +++ b/Marlin/src/lcd/e3v2/common/dwin_set.h @@ -132,17 +132,7 @@ #define ICON_Printer_0 93 #define ICON_Box 200 #define ICON_Checkbox 201 -#define ICON_Fade 202 -#define ICON_Mesh 203 -#define ICON_Tilt 204 -#define ICON_Brightness 205 #define ICON_Probe 206 -#define ICON_AxisD 249 -#define ICON_AxisBR 250 -#define ICON_AxisTR 251 -#define ICON_AxisBL 252 -#define ICON_AxisTL 253 -#define ICON_AxisC 254 #define ICON_Folder ICON_More #define ICON_AdvSet ICON_Language @@ -162,3 +152,31 @@ #define ICON_FWRetZRaise ICON_MoveZ #define ICON_FWRecSpeed ICON_Setspeed #define ICON_FWRecExtra ICON_StepE + +#if DISABLED(DWIN_CREALITY_LCD_STD_ICONS) + // Index of custom icons should be >= CUSTOM_ICON_START + #define CUSTOM_ICON_START 200 + #define ICON_Checkbox_F ICON_Box + #define ICON_Checkbox_T ICON_Checkbox + #define ICON_Fade 202 + #define ICON_Mesh 203 + #define ICON_Tilt 204 + #define ICON_Brightness 205 + #define ICON_AxisD 249 + #define ICON_AxisBR 250 + #define ICON_AxisTR 251 + #define ICON_AxisBL 252 + #define ICON_AxisTL 253 + #define ICON_AxisC 254 +#else + #define ICON_Fade ICON_Version + #define ICON_Mesh ICON_Version + #define ICON_Tilt ICON_Version + #define ICON_Brightness ICON_Version + #define ICON_AxisD ICON_Axis + #define ICON_AxisBR ICON_Axis + #define ICON_AxisTR ICON_Axis + #define ICON_AxisBL ICON_Axis + #define ICON_AxisTL ICON_Axis + #define ICON_AxisC ICON_Axis +#endif diff --git a/Marlin/src/lcd/e3v2/jyersui/dwin.cpp b/Marlin/src/lcd/e3v2/jyersui/dwin.cpp index 5811ac11bb..d582b96ed7 100644 --- a/Marlin/src/lcd/e3v2/jyersui/dwin.cpp +++ b/Marlin/src/lcd/e3v2/jyersui/dwin.cpp @@ -523,18 +523,18 @@ void JyersDWIN::drawMenuItem(const uint8_t row, const uint8_t icon/*=0*/, FSTR_P } void JyersDWIN::drawCheckbox(const uint8_t row, const bool value) { - #if ENABLED(DWIN_CREALITY_LCD_CUSTOM_ICONS) // Draw appropriate checkbox icon + #if DISABLED(DWIN_CREALITY_LCD_STD_ICONS) // Draw appropriate checkbox icon dwinIconShow(ICON, (value ? ICON_Checkbox_T : ICON_Checkbox_F), 226, MBASE(row) - 3); #else // Draw a basic checkbox using rectangles and lines dwinDrawRectangle(1, COLOR_BG_BLACK, 226, MBASE(row) - 3, 226 + 20, MBASE(row) - 3 + 20); - dwinDrawRectangle(0, COLOR_WHITE, 226, MBASE(row) - 3, 226 + 20, MBASE(row) - 3 + 20); + dwinDrawRectangle(0, COLOR_WHITE, 226, MBASE(row) - 3, 226 + 20, MBASE(row) - 3 + 20); if (value) { - dwinDrawLine(COLOR_CHECKBOX, 227, MBASE(row) - 3 + 11, 226 + 8, MBASE(row) - 3 + 17); - dwinDrawLine(COLOR_CHECKBOX, 227 + 8, MBASE(row) - 3 + 17, 226 + 19, MBASE(row) - 3 + 1); - dwinDrawLine(COLOR_CHECKBOX, 227, MBASE(row) - 3 + 12, 226 + 8, MBASE(row) - 3 + 18); - dwinDrawLine(COLOR_CHECKBOX, 227 + 8, MBASE(row) - 3 + 18, 226 + 19, MBASE(row) - 3 + 2); - dwinDrawLine(COLOR_CHECKBOX, 227, MBASE(row) - 3 + 13, 226 + 8, MBASE(row) - 3 + 19); - dwinDrawLine(COLOR_CHECKBOX, 227 + 8, MBASE(row) - 3 + 19, 226 + 19, MBASE(row) - 3 + 3); + dwinDrawLine(COLOR_CHECKBOX, 227, MBASE(row) - 3 + 11, 226 + 8, MBASE(row) - 3 + 17); + dwinDrawLine(COLOR_CHECKBOX, 227 + 8, MBASE(row) - 3 + 17, 226 + 19, MBASE(row) - 3 + 1); + dwinDrawLine(COLOR_CHECKBOX, 227, MBASE(row) - 3 + 12, 226 + 8, MBASE(row) - 3 + 18); + dwinDrawLine(COLOR_CHECKBOX, 227 + 8, MBASE(row) - 3 + 18, 226 + 19, MBASE(row) - 3 + 2); + dwinDrawLine(COLOR_CHECKBOX, 227, MBASE(row) - 3 + 13, 226 + 8, MBASE(row) - 3 + 19); + dwinDrawLine(COLOR_CHECKBOX, 227 + 8, MBASE(row) - 3 + 19, 226 + 19, MBASE(row) - 3 + 3); } #endif } diff --git a/Marlin/src/lcd/e3v2/jyersui/dwin.h b/Marlin/src/lcd/e3v2/jyersui/dwin.h index 48e413efbb..40c7490e30 100644 --- a/Marlin/src/lcd/e3v2/jyersui/dwin.h +++ b/Marlin/src/lcd/e3v2/jyersui/dwin.h @@ -26,7 +26,6 @@ */ #include "dwin_lcd.h" -#include "../common/dwin_set.h" #include "../common/dwin_font.h" #include "../common/dwin_color.h" #include "../common/encoder.h" @@ -35,7 +34,8 @@ #include "../../../inc/MarlinConfigPre.h" -//#define DWIN_CREALITY_LCD_CUSTOM_ICONS +#define DWIN_CREALITY_LCD_STD_ICONS +#include "../common/dwin_set.h" enum processID : uint8_t { Proc_Main, Proc_Print, Proc_Menu, Proc_Value, Proc_Option, @@ -120,34 +120,6 @@ enum menuID : uint8_t { ID_PreheatHotend }; -// Custom icons -#if ENABLED(DWIN_CREALITY_LCD_CUSTOM_ICONS) - // index of every custom icon should be >= CUSTOM_ICON_START - #define CUSTOM_ICON_START ICON_Checkbox_F - #define ICON_Checkbox_F 200 - #define ICON_Checkbox_T 201 - #define ICON_Fade 202 - #define ICON_Mesh 203 - #define ICON_Tilt 204 - #define ICON_Brightness 205 - #define ICON_AxisD 249 - #define ICON_AxisBR 250 - #define ICON_AxisTR 251 - #define ICON_AxisBL 252 - #define ICON_AxisTL 253 - #define ICON_AxisC 254 -#else - #define ICON_Fade ICON_Version - #define ICON_Mesh ICON_Version - #define ICON_Tilt ICON_Version - #define ICON_Brightness ICON_Version - #define ICON_AxisD ICON_Axis - #define ICON_AxisBR ICON_Axis - #define ICON_AxisTR ICON_Axis - #define ICON_AxisBL ICON_Axis - #define ICON_AxisTL ICON_Axis - #define ICON_AxisC ICON_Axis -#endif enum colorID : uint8_t { Default, White, Green, Cyan, Blue, Magenta, Red, Orange, Yellow, Brown, Black From b5d7b4aee6352009346fe968e6367215dcecb25b Mon Sep 17 00:00:00 2001 From: DerAndere <26200979+DerAndere1@users.noreply.github.com> Date: Mon, 14 Apr 2025 23:50:26 +0200 Subject: [PATCH 209/787] =?UTF-8?q?=E2=9C=A8=20DEFAULT=5FACCELERATION=5FSP?= =?UTF-8?q?INDLE=20(#27759)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/Configuration_adv.h | 2 ++ Marlin/src/feature/spindle_laser.cpp | 27 ++++++++++++--- Marlin/src/feature/spindle_laser.h | 9 +++-- Marlin/src/inc/Conditionals-4-adv.h | 3 ++ Marlin/src/inc/SanityCheck.h | 2 ++ Marlin/src/lcd/e3v2/common/limits.h | 6 ++++ Marlin/src/lcd/e3v2/creality/dwin.cpp | 24 +++++++++++++ Marlin/src/lcd/e3v2/creality/dwin.h | 9 +++++ Marlin/src/lcd/language/language_en.h | 1 + Marlin/src/lcd/menu/menu_advanced.cpp | 11 ++++++ Marlin/src/module/settings.cpp | 50 +++++++++++++++++++++++++-- buildroot/tests/mega1280 | 3 +- 12 files changed, 136 insertions(+), 11 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 2e0ca3d4a1..d4b4307b05 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -3682,6 +3682,8 @@ #define SPEED_POWER_MIN 5000 // (RPM) #define SPEED_POWER_MAX 30000 // (RPM) SuperPID router controller 0 - 30,000 RPM #define SPEED_POWER_STARTUP 25000 // (RPM) M3/M4 speed/power default (with no arguments) + + //#define DEFAULT_ACCELERATION_SPINDLE 1000 // (°/s/s) Default spindle acceleration (speed change with time) #endif #else diff --git a/Marlin/src/feature/spindle_laser.cpp b/Marlin/src/feature/spindle_laser.cpp index b83c1c1797..5f0ea7dd7b 100644 --- a/Marlin/src/feature/spindle_laser.cpp +++ b/Marlin/src/feature/spindle_laser.cpp @@ -43,6 +43,10 @@ bool SpindleLaser::enable_state; // Virtual uint8_t SpindleLaser::power, // Actual power output 0-255 ocr or "0 = off" > 0 = "on" SpindleLaser::last_power_applied; // = 0 // Basic power state tracking +#if HAS_SPINDLE_ACCELERATION + uint32_t SpindleLaser::acceleration_spindle_deg_per_s2; // (°/s/s) Spindle acceleration. Initialized by settings.load +#endif + #if ENABLED(LASER_FEATURE) cutter_test_pulse_t SpindleLaser::testPulse = 50; // (ms) Test fire pulse default duration uint8_t SpindleLaser::last_block_power; // = 0 // Track power changes for dynamic inline power @@ -100,7 +104,22 @@ void SpindleLaser::init() { #if ENABLED(HAL_CAN_SET_PWM_FREQ) && SPINDLE_LASER_FREQUENCY hal.set_pwm_frequency(pin_t(SPINDLE_LASER_PWM_PIN), frequency); #endif - hal.set_pwm_duty(pin_t(SPINDLE_LASER_PWM_PIN), ocr ^ SPINDLE_LASER_PWM_OFF); + #if HAS_SPINDLE_ACCELERATION + const int16_t diff = ocr - last_power_applied; + const uint8_t abs_diff = ABS(diff); + uint8_t current_ocr = last_power_applied; + // Duration between ocr increments. SPEED_POWER_MAX is in RPM. + const millis_t duration = (float(SPEED_POWER_MAX) * (60000.f / 2550.f) / float(acceleration_spindle_deg_per_s2)) * abs_diff; + millis_t next_ocr_change = millis() + duration; + while (current_ocr != ocr) { + while (PENDING(millis(), next_ocr_change)) idle(); + current_ocr += diff > 0 ? 1 : -1; + hal.set_pwm_duty(pin_t(SPINDLE_LASER_PWM_PIN), current_ocr ^ SPINDLE_LASER_PWM_OFF); + next_ocr_change += duration; + } + #else + hal.set_pwm_duty(pin_t(SPINDLE_LASER_PWM_PIN), ocr ^ SPINDLE_LASER_PWM_OFF); + #endif } void SpindleLaser::set_ocr(const uint8_t ocr) { @@ -111,10 +130,10 @@ void SpindleLaser::init() { } void SpindleLaser::ocr_off() { + _set_ocr(0); #if PIN_EXISTS(SPINDLE_LASER_ENA) WRITE(SPINDLE_LASER_ENA_PIN, !SPINDLE_LASER_ACTIVE_STATE); // Cutter OFF #endif - _set_ocr(0); } #endif // SPINDLE_LASER_USE_PWM @@ -127,9 +146,8 @@ void SpindleLaser::init() { */ void SpindleLaser::apply_power(const uint8_t opwr) { if (enabled() || opwr == 0) { // 0 check allows us to disable where no ENA pin exists - // Test and set the last power used to improve performance + // Test the last power used to improve performance if (opwr == last_power_applied) return; - last_power_applied = opwr; // Handle PWM driven or just simple on/off #if ENABLED(SPINDLE_LASER_USE_PWM) if (CUTTER_UNIT_IS(RPM) && unitPower == 0) @@ -146,6 +164,7 @@ void SpindleLaser::apply_power(const uint8_t opwr) { WRITE(SPINDLE_LASER_ENA_PIN, enabled() ? SPINDLE_LASER_ACTIVE_STATE : !SPINDLE_LASER_ACTIVE_STATE); isReadyForUI = true; #endif + last_power_applied = opwr; } else { #if PIN_EXISTS(SPINDLE_LASER_ENA) diff --git a/Marlin/src/feature/spindle_laser.h b/Marlin/src/feature/spindle_laser.h index a443d7df5e..a283f0786d 100644 --- a/Marlin/src/feature/spindle_laser.h +++ b/Marlin/src/feature/spindle_laser.h @@ -109,11 +109,14 @@ public: static uint8_t power, last_power_applied; // Basic power state tracking - static cutter_frequency_t frequency; // Set PWM frequency; range: 2K-50K + static cutter_frequency_t frequency; // (Hz) Laser/Spindle PWM frequency (2000..50000) - static cutter_power_t menuPower, // Power as set via LCD menu in PWM, Percentage or RPM - unitPower; // Power as displayed status in PWM, Percentage or RPM + static cutter_power_t menuPower, // Power as set via LCD menu in PWM, Percentage, or RPM + unitPower; // Power as displayed status in PWM, Percentage, or RPM + #if HAS_SPINDLE_ACCELERATION + static uint32_t acceleration_spindle_deg_per_s2; // (°/s/s) Spindle acceleration + #endif static void init(); #if ENABLED(HAL_CAN_SET_PWM_FREQ) && SPINDLE_LASER_FREQUENCY diff --git a/Marlin/src/inc/Conditionals-4-adv.h b/Marlin/src/inc/Conditionals-4-adv.h index 653a754700..109fca6b29 100644 --- a/Marlin/src/inc/Conditionals-4-adv.h +++ b/Marlin/src/inc/Conditionals-4-adv.h @@ -1090,6 +1090,9 @@ #define _CUTTER_POWER_RPM 3 #define _CUTTER_POWER(V) _CAT(_CUTTER_POWER_, V) #define CUTTER_UNIT_IS(V) (_CUTTER_POWER(CUTTER_POWER_UNIT) == _CUTTER_POWER(V)) + #if DEFAULT_ACCELERATION_SPINDLE + #define HAS_SPINDLE_ACCELERATION 1 + #endif #endif #if !defined(__AVR__) || !defined(USBCON) diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index c40a2f7632..169f84983c 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -4072,6 +4072,8 @@ static_assert(_PLUS_TEST(3), "DEFAULT_MAX_ACCELERATION values must be positive." #error "SPINDLE_LASER_PWM_INVERT is required for (SPINDLE|LASER)_FEATURE." #elif !(defined(SPEED_POWER_MIN) && defined(SPEED_POWER_MAX) && defined(SPEED_POWER_STARTUP)) #error "SPINDLE_LASER_USE_PWM equation constant(s) missing." + #elif DEFAULT_ACCELERATION_SPINDLE > SPEED_POWER_MAX - SPEED_POWER_MIN + #error "DEFAULT_ACCELERATION_SPINDLE must be <= SPEED_POWER_MAX - SPEED_POWER_MIN." #elif _PIN_CONFLICT(X_MIN) #error "SPINDLE_LASER_PWM_PIN conflicts with X_MIN_PIN." #elif _PIN_CONFLICT(X_MAX) diff --git a/Marlin/src/lcd/e3v2/common/limits.h b/Marlin/src/lcd/e3v2/common/limits.h index 560c8735a7..c773240b28 100644 --- a/Marlin/src/lcd/e3v2/common/limits.h +++ b/Marlin/src/lcd/e3v2/common/limits.h @@ -65,6 +65,12 @@ constexpr xyze_float_t max_acceleration_edit_values = #endif ; +#if HAS_SPINDLE_ACCELERATION + constexpr float min_acceleration_edit_values_spindle = 1, + default_acceleration_spindle = DEFAULT_ACCELERATION_SPINDLE, + max_acceleration_edit_values_spindle = default_acceleration_spindle * DEFAULT_MAX_MULTIPLIER; +#endif + // // Max Jerk limits // diff --git a/Marlin/src/lcd/e3v2/creality/dwin.cpp b/Marlin/src/lcd/e3v2/creality/dwin.cpp index fcbeecde83..56830086fd 100644 --- a/Marlin/src/lcd/e3v2/creality/dwin.cpp +++ b/Marlin/src/lcd/e3v2/creality/dwin.cpp @@ -1595,6 +1595,27 @@ void hmiMaxAccelerationXYZE() { drawEditInteger4(select_acc.now, hmiValues.maxAcceleration, true); } + +#if HAS_SPINDLE_ACCELERATION + + void hmiSpindleAcceleration() { + EncoderState encoder_diffState = encoderReceiveAnalyze(); + if (encoder_diffState == ENCODER_DIFF_NO) return; + if (applyEncoder(encoder_diffState, hmiValues.spindleAcceleration)) { + checkkey = ID_SpindleAcceleration; + encoderRate.enabled = false; + cutter.spindle_acceleration_deg_per_s2 = hmiValues.spindleAcceleration; + drawEditInteger4(select_acc.now, hmiValues.spindleAcceleration); + return; + } + // SpindleAcceleration limit + LIMIT(hmiValues.spindleAcceleration, min_acceleration_edit_values_spindle, max_acceleration_edit_values_spindle); + // SpindleAcceleration value + drawEditInteger4(select_acc.now, hmiValues.spindleAcceleration, true); + } + +#endif // HAS_SPINDLE_ACCELERATION + #if ENABLED(CLASSIC_JERK) void hmiMaxJerkXYZE() { @@ -4283,6 +4304,9 @@ void dwinHandleScreen() { case ID_PrintSpeed: hmiPrintSpeed(); break; case ID_MaxSpeedValue: hmiMaxFeedspeedXYZE(); break; case ID_MaxAccelerationValue: hmiMaxAccelerationXYZE(); break; + #if HAS_SPINDLE_ACCELERATION + case ID_SpindleAccelerationValue: hmiSpindleAcceleration(); break; + #endif #if ENABLED(CLASSIC_JERK) case ID_MaxJerkValue: hmiMaxJerkXYZE(); break; #endif diff --git a/Marlin/src/lcd/e3v2/creality/dwin.h b/Marlin/src/lcd/e3v2/creality/dwin.h index fce52d8cf4..50723d015c 100644 --- a/Marlin/src/lcd/e3v2/creality/dwin.h +++ b/Marlin/src/lcd/e3v2/creality/dwin.h @@ -53,6 +53,9 @@ enum processID : uint8_t { #endif ID_MaxSpeed, ID_MaxSpeedValue, ID_MaxAcceleration, ID_MaxAccelerationValue, + #if HAS_SPINDLE_ACCELERATION + ID_SpindleAccelerationValue, + #endif ID_MaxJerk, ID_MaxJerkValue, ID_Step, ID_StepValue, ID_HomeOff, ID_HomeOffX, ID_HomeOffY, ID_HomeOffZ, @@ -105,6 +108,9 @@ typedef struct { int16_t printSpeed = 100; float maxFeedSpeed = 0; float maxAcceleration = 0; + #if HAS_SPINDLE_ACCELERATION + float spindleAcceleration = 0; + #endif float maxJerkScaled = 0; float maxStepScaled = 0; float offset_value = 0; @@ -203,6 +209,9 @@ void hmiPrintSpeed(); void hmiMaxFeedspeedXYZE(); void hmiMaxAccelerationXYZE(); +#if HAS_SPINDLE_ACCELERATION + void hmiSpindleAcceleration(); +#endif void hmiMaxJerkXYZE(); #if ENABLED(EDITABLE_STEPS_PER_UNIT) void hmiStepXYZE(); diff --git a/Marlin/src/lcd/language/language_en.h b/Marlin/src/lcd/language/language_en.h index 686a0b759c..d184c0358f 100644 --- a/Marlin/src/lcd/language/language_en.h +++ b/Marlin/src/lcd/language/language_en.h @@ -452,6 +452,7 @@ namespace LanguageNarrow_en { LSTR MSG_AMAX_EN = _UxGT("Max * Accel"); LSTR MSG_A_RETRACT = _UxGT("Retract Accel"); LSTR MSG_A_TRAVEL = _UxGT("Travel Accel"); + LSTR MSG_A_SPINDLE = _UxGT("Spindle Accel"); LSTR MSG_INPUT_SHAPING = _UxGT("Input Shaping"); LSTR MSG_SHAPING_ENABLE_N = _UxGT("Enable @ shaping"); LSTR MSG_SHAPING_DISABLE_N = _UxGT("Disable @ shaping"); diff --git a/Marlin/src/lcd/menu/menu_advanced.cpp b/Marlin/src/lcd/menu/menu_advanced.cpp index 99ece89f27..8080a23ba4 100644 --- a/Marlin/src/lcd/menu/menu_advanced.cpp +++ b/Marlin/src/lcd/menu/menu_advanced.cpp @@ -37,6 +37,10 @@ #include "../../gcode/parser.h" #endif +#if HAS_SPINDLE_ACCELERATION + #include "../../feature/spindle_laser.h" +#endif + #if HAS_BED_PROBE #include "../../module/probe.h" #endif @@ -511,6 +515,9 @@ void menu_backlash(); #else const xyze_ulong_t &max_accel_edit_scaled = max_accel_edit; #endif + #if HAS_SPINDLE_ACCELERATION + constexpr uint32_t max_spindle_accel_edit = 99000; + #endif START_MENU(); BACK_ITEM(MSG_ADVANCED_SETTINGS); @@ -544,6 +551,10 @@ void menu_backlash(); EDIT_ITEM_FAST(long5_25, MSG_AMAX_E, &planner.settings.max_acceleration_mm_per_s2[E_AXIS], 100, max_accel_edit_scaled.e, []{ planner.refresh_acceleration_rates(); }); #endif + #if HAS_SPINDLE_ACCELERATION + EDIT_ITEM_FAST(long5_25, MSG_A_SPINDLE, &cutter.acceleration_spindle_deg_per_s2, 100, max_spindle_accel_edit); + #endif + #ifdef XY_FREQUENCY_LIMIT EDIT_ITEM(int8, MSG_XY_FREQUENCY_LIMIT, &planner.xy_freq_limit_hz, 0, 100, planner.refresh_frequency_limit, true); editable.uint8 = uint8_t(LROUND(planner.xy_freq_min_speed_factor * 255)); // percent to u8 diff --git a/Marlin/src/module/settings.cpp b/Marlin/src/module/settings.cpp index 4205261a3c..7062164dc9 100644 --- a/Marlin/src/module/settings.cpp +++ b/Marlin/src/module/settings.cpp @@ -60,6 +60,10 @@ #include "../HAL/shared/eeprom_api.h" #endif +#if HAS_SPINDLE_ACCELERATION + #include "../feature/spindle_laser.h" +#endif + #if HAS_BED_PROBE #include "probe.h" #endif @@ -252,6 +256,13 @@ typedef struct SettingsDataStruct { xyz_pos_t hotend_offset[HOTENDS - 1]; // M218 XYZ #endif + // + // Spindle Acceleration + // + #if HAS_SPINDLE_ACCELERATION + uint32_t acceleration_spindle; // cutter.acceleration_spindle_deg_per_s2 + #endif + // // FILAMENT_RUNOUT_SENSOR // @@ -941,7 +952,7 @@ void MarlinSettings::postprocess() { #endif // NUM_AXES // - // Hotend Offsets, if any + // Hotend Offsets // { #if HAS_HOTEND_OFFSET @@ -951,6 +962,16 @@ void MarlinSettings::postprocess() { #endif } + // + // Spindle Acceleration + // + { + #if HAS_SPINDLE_ACCELERATION + _FIELD_TEST(acceleration_spindle); + EEPROM_WRITE(cutter.acceleration_spindle_deg_per_s2); + #endif + } + // // Filament Runout Sensor // @@ -1985,7 +2006,7 @@ void MarlinSettings::postprocess() { #endif // NUM_AXES // - // Hotend Offsets, if any + // Hotend Offsets // { #if HAS_HOTEND_OFFSET @@ -1995,6 +2016,16 @@ void MarlinSettings::postprocess() { #endif } + // + // Spindle Acceleration + // + { + #if HAS_SPINDLE_ACCELERATION + _FIELD_TEST(acceleration_spindle); + EEPROM_READ(cutter.acceleration_spindle_deg_per_s2); + #endif + } + // // Filament Runout Sensor // @@ -2003,7 +2034,7 @@ void MarlinSettings::postprocess() { _FIELD_TEST(runout_sensor_enabled); EEPROM_READ(runout_sensor_enabled); #if HAS_FILAMENT_SENSOR - if (!validating) runout.enabled = runout_sensor_enabled < 0 ? FIL_RUNOUT_ENABLED_DEFAULT : runout_sensor_enabled; + if (!validating) runout.enabled = runout_sensor_enabled < 0 ? FIL_RUNOUT_ENABLED_DEFAULT : runout_sensor_enabled; #endif TERN_(HAS_FILAMENT_SENSOR, if (runout.enabled) runout.reset()); @@ -3286,14 +3317,27 @@ void MarlinSettings::reset() { TERN_(HAS_JUNCTION_DEVIATION, planner.junction_deviation_mm = float(JUNCTION_DEVIATION_MM)); + // + // Home Offset + // #if HAS_SCARA_OFFSET scara_home_offset.reset(); #elif HAS_HOME_OFFSET home_offset.reset(); #endif + // + // Hotend Offsets + // TERN_(HAS_HOTEND_OFFSET, reset_hotend_offsets()); + // + // Spindle Acceleration + // + #if HAS_SPINDLE_ACCELERATION + cutter.acceleration_spindle_deg_per_s2 = DEFAULT_ACCELERATION_SPINDLE; + #endif + // // Filament Runout Sensor // diff --git a/buildroot/tests/mega1280 b/buildroot/tests/mega1280 index 1b1a8f86b7..6d703ac8f6 100755 --- a/buildroot/tests/mega1280 +++ b/buildroot/tests/mega1280 @@ -19,7 +19,8 @@ restore_configs opt_set LCD_LANGUAGE an \ POWER_MONITOR_CURRENT_PIN 14 POWER_MONITOR_VOLTAGE_PIN 15 \ CLOSED_LOOP_ENABLE_PIN 44 CLOSED_LOOP_MOVE_COMPLETE_PIN 45 -opt_enable SPINDLE_FEATURE ULTIMAKERCONTROLLER LCD_BED_LEVELING EDITABLE_HOMING_FEEDRATE \ +opt_enable SPINDLE_FEATURE DEFAULT_ACCELERATION_SPINDLE \ + ULTIMAKERCONTROLLER LCD_BED_LEVELING EDITABLE_HOMING_FEEDRATE \ EEPROM_SETTINGS EEPROM_BOOT_SILENT EEPROM_AUTO_INIT \ SENSORLESS_BACKOFF_MM HOMING_BACKOFF_POST_MM HOME_Y_BEFORE_X CODEPENDENT_XY_HOMING \ MESH_BED_LEVELING ENABLE_LEVELING_FADE_HEIGHT MESH_G28_REST_ORIGIN \ From 5e8a5230a35400c9a9ce833f2b0de7ef865cdc6e Mon Sep 17 00:00:00 2001 From: feldi12 <25982433+feldi12@users.noreply.github.com> Date: Tue, 15 Apr 2025 00:08:40 +0200 Subject: [PATCH 210/787] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20Optimize=20PID,=20?= =?UTF-8?q?increase=20PID=20range=20(#27740)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/Configuration.h | 2 +- Marlin/src/lcd/sovol_rts/sovol_rts.cpp | 6 +++--- Marlin/src/module/temperature.h | 13 +++++-------- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index faa6f56843..91a3b342b6 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -899,7 +899,7 @@ #if ANY(PIDTEMP, PIDTEMPBED, PIDTEMPCHAMBER) //#define PID_OPENLOOP // Puts PID in open loop. M104/M140 sets the output power from 0 to PID_MAX //#define SLOW_PWM_HEATERS // PWM with very low frequency (roughly 0.125Hz=8s) and minimum state time of approximately 1s useful for heaters driven by a relay - #define PID_FUNCTIONAL_RANGE 10 // If the temperature difference between the target temperature and the actual temperature + #define PID_FUNCTIONAL_RANGE 20 // If the temperature difference between the target temperature and the actual temperature // is more than PID_FUNCTIONAL_RANGE then the PID will be shut off and the heater will be set to min/max. //#define PID_EDIT_MENU // Add PID editing to the "Advanced Settings" menu. (~700 bytes of flash) diff --git a/Marlin/src/lcd/sovol_rts/sovol_rts.cpp b/Marlin/src/lcd/sovol_rts/sovol_rts.cpp index c92850494b..dcd5d9b384 100644 --- a/Marlin/src/lcd/sovol_rts/sovol_rts.cpp +++ b/Marlin/src/lcd/sovol_rts/sovol_rts.cpp @@ -1312,9 +1312,9 @@ void RTS::handleData() { #endif #if ENABLED(PIDTEMPBED) - case Hot_Bed_P: thermalManager.temp_bed.pid.Kp = float(recdat.data[0]) / 100.0f; break; - case Hot_Bed_I: thermalManager.temp_bed.pid.Ki = float(recdat.data[0]) * 8.0f / 10000.0f; break; - case Hot_Bed_D: thermalManager.temp_bed.pid.Kd = float(recdat.data[0]) / 0.8f; break; + case Hot_Bed_P: thermalManager.temp_bed.pid.set_Kp(float(recdat.data[0]) / 100.0f); break; + case Hot_Bed_I: thermalManager.temp_bed.pid.set_Ki(float(recdat.data[0]) * 8.0f / 10000.0f); break; + case Hot_Bed_D: thermalManager.temp_bed.pid.set_Kd(float(recdat.data[0]) / 0.8f); break; #endif #if HAS_X_AXIS diff --git a/Marlin/src/module/temperature.h b/Marlin/src/module/temperature.h index 934b1b1246..77c16bba0a 100644 --- a/Marlin/src/module/temperature.h +++ b/Marlin/src/module/temperature.h @@ -173,7 +173,7 @@ typedef struct { float p, i, d, c, f; } raw_pidcf_t; struct PID_t { protected: bool pid_reset = true; - float temp_iState = 0.0f, temp_dState = 0.0f; + float temp_dState = 0; float work_p = 0, work_i = 0, work_d = 0; public: @@ -217,17 +217,14 @@ typedef struct { float p, i, d, c, f; } raw_pidcf_t; } else { if (pid_reset) { + work_i = 0; + work_d = 0; pid_reset = false; - temp_iState = 0.0; - work_d = 0.0; } - const float max_power_over_i_gain = float(MAX_POW) / Ki - float(MIN_POW); - temp_iState = constrain(temp_iState + pid_error, 0, max_power_over_i_gain); - work_p = Kp * pid_error; - work_i = Ki * temp_iState; - work_d = work_d + PID_K2 * (Kd * (temp_dState - current) - work_d); + work_i = constrain(work_i + Ki * pid_error, 0, float(MAX_POW - MIN_POW)); + work_d += (Kd * (temp_dState - current) - work_d) * PID_K2; output_pow = constrain(work_p + work_i + work_d + float(MIN_POW), 0, MAX_POW); } From 7cd1b7708f1679015a9247876ca3f0367a2fc3a5 Mon Sep 17 00:00:00 2001 From: B Date: Mon, 14 Apr 2025 15:52:51 -0700 Subject: [PATCH 211/787] =?UTF-8?q?=F0=9F=90=9B=20Fix=20Servos=20in=20GD32?= =?UTF-8?q?=20HAL=20(#27791)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/HAL/GD32_MFL/Servo.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/Marlin/src/HAL/GD32_MFL/Servo.cpp b/Marlin/src/HAL/GD32_MFL/Servo.cpp index d5f8533544..6cbcbc049b 100644 --- a/Marlin/src/HAL/GD32_MFL/Servo.cpp +++ b/Marlin/src/HAL/GD32_MFL/Servo.cpp @@ -41,23 +41,26 @@ static uint32_t servo_interrupt_priority = NVIC_EncodePriority(NVIC_GetPriorityG // This must be called after the MFL Servo class has initialized the timer. // To be safe this is currently called after every call to attach(). static void fixServoTimerInterruptPriority() { - NVIC_SetPriority(getTimerUpIRQ(TIMER_SERVO), servo_interrupt_priority); + auto& servoTimerIdx = GeneralTimer::get_instance(static_cast(TIMER_SERVO)); + NVIC_SetPriority(servoTimerIdx.getTimerUpIRQ(), servo_interrupt_priority); } // Default constructor for libServo class. // Initializes the servo delay, pause state, and pause value. // Registers the servo instance in the servos array. -libServo::libServo() : delay(servoDelay[servoCount]), +libServo::libServo() : + delay(servoDelay[servoCount]), was_attached_before_pause(false), - value_before_pause(0) { + value_before_pause(0) +{ servos[servoCount++] = this; } // Attaches a servo to a specified pin. int8_t libServo::attach(const int pin) { if (servoCount >= MAX_SERVOS) return -1; - if (pin > 0) servo_pin = pin; - auto result = mflServo.attach(servo_pin); + if (pin > 0) servoPin = pin; + auto result = mflServo.attach(servoPin); fixServoTimerInterruptPriority(); return result; } @@ -65,8 +68,8 @@ int8_t libServo::attach(const int pin) { // Attaches a servo to a specified pin with minimum and maximum pulse widths. int8_t libServo::attach(const int pin, const int min, const int max) { if (servoCount >= MAX_SERVOS) return -1; - if (pin > 0) servo_pin = pin; - auto result = mflServo.attach(servo_pin, min, max); + if (pin > 0) servoPin = pin; + auto result = mflServo.attach(servoPin, min, max); fixServoTimerInterruptPriority(); return result; } From 1d4c002c2ab0ed67edb3a7fcc2f5463844f02d7c Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Tue, 15 Apr 2025 00:30:55 +0000 Subject: [PATCH 212/787] [cron] Bump distribution date (2025-04-15) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 008997c83a..11822b4b13 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-04-14" +//#define STRING_DISTRIBUTION_DATE "2025-04-15" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index ba062ee43d..65e128bdf9 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-04-14" + #define STRING_DISTRIBUTION_DATE "2025-04-15" #endif /** From 1242e875aadcb5b5ef8a9f54fd99f32a0adbdde8 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 15 Apr 2025 15:49:23 -0500 Subject: [PATCH 213/787] =?UTF-8?q?=F0=9F=9A=B8=20More=20frequent=20button?= =?UTF-8?q?=20polling=20(#27797)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/Configuration_adv.h | 2 ++ Marlin/src/inc/Conditionals-5-post.h | 4 ++++ Marlin/src/module/temperature.cpp | 11 ++++++++--- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index d4b4307b05..73073762f1 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -2268,6 +2268,8 @@ #define ADC_BUTTON_DEBOUNCE_DELAY 16 // (count) Increase if buttons bounce or repeat too fast #endif +//#define FAST_BUTTON_POLLING // Poll buttons at ~1kHz on 8-bit AVR. Set to 'false' for slow polling on 32-bit. + // @section safety /** diff --git a/Marlin/src/inc/Conditionals-5-post.h b/Marlin/src/inc/Conditionals-5-post.h index 9b16f515d6..380e8e6071 100644 --- a/Marlin/src/inc/Conditionals-5-post.h +++ b/Marlin/src/inc/Conditionals-5-post.h @@ -3557,6 +3557,10 @@ #define HAS_ROTARY_ENCODER 1 #endif +#if defined(CPU_32_BIT) && !defined(FAST_BUTTON_POLLING) + #define FAST_BUTTON_POLLING +#endif + #if PIN_EXISTS(SAFE_POWER) && DISABLED(DISABLE_DRIVER_SAFE_POWER_PROTECT) #define HAS_DRIVER_SAFE_POWER_PROTECT 1 #endif diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index 169d86a72f..5c9f122067 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -4283,10 +4283,15 @@ void Temperature::isr() { #endif // SLOW_PWM_HEATERS // - // Update lcd buttons 488 times per second + // Update lcd buttons at ~488Hz or ~976Hz // - static bool do_buttons; - if ((do_buttons ^= true)) ui.update_buttons(); + #if ENABLED(FAST_BUTTON_POLLING) + constexpr bool do_buttons = true; + #else + static bool do_buttons; + do_buttons ^= true; + #endif + if (do_buttons) ui.update_buttons(); /** * One sensor is sampled on every other call of the ISR. From f149e14d1a18fef4089d907d15083afc182c4e6b Mon Sep 17 00:00:00 2001 From: Andrew <18502096+classicrocker883@users.noreply.github.com> Date: Tue, 15 Apr 2025 18:36:27 -0400 Subject: [PATCH 214/787] =?UTF-8?q?=F0=9F=9A=B8=20Fix=20missing=20"echo:"?= =?UTF-8?q?=20in=20some=20reports=20(#27794)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/feature/ethernet.cpp | 42 +++++++++++++++ Marlin/src/feature/ethernet.h | 6 +++ Marlin/src/gcode/config/M200-M205.cpp | 6 +-- .../src/gcode/feature/network/M552-M554.cpp | 52 +++---------------- Marlin/src/gcode/feature/nonlinear/M592.cpp | 2 +- Marlin/src/gcode/feature/pause/M603.cpp | 1 - Marlin/src/gcode/feature/trinamic/M569.cpp | 2 +- Marlin/src/gcode/gcode.h | 6 +-- Marlin/src/gcode/probe/M423.cpp | 3 +- Marlin/src/gcode/temp/M86_M87.cpp | 2 +- Marlin/src/module/settings.cpp | 15 ++---- 11 files changed, 71 insertions(+), 66 deletions(-) diff --git a/Marlin/src/feature/ethernet.cpp b/Marlin/src/feature/ethernet.cpp index 9b022b4e17..cdf176f832 100644 --- a/Marlin/src/feature/ethernet.cpp +++ b/Marlin/src/feature/ethernet.cpp @@ -172,4 +172,46 @@ void MarlinEthernet::check() { } } +void say_ethernet() { SERIAL_ECHOPGM(" Ethernet "); } + +void MarlinEthernet::ETH0_report(const bool forReplay/*=true*/) { + say_ethernet(); + SERIAL_ECHO_TERNARY(ethernet.hardware_enabled, "port ", "en", "dis", "abled.\n"); + if (ethernet.hardware_enabled) { + say_ethernet(); + SERIAL_ECHO_TERNARY(ethernet.have_telnet_client, "client ", "en", "dis", "abled.\n"); + } + else + SERIAL_ECHOLNPGM("Send 'M552 S1' to enable."); +} + +void MarlinEthernet::MAC_report(const bool forReplay/*=true*/) { + if (!forReplay) SERIAL_ECHO_START(); + SERIAL_ECHOPGM("MAC: "); + if (ethernet.hardware_enabled) { + uint8_t mac[6]; + Ethernet.MACAddress(mac); + for (uint8_t i = 0; i < 6; ++i) { + if (mac[i] < 0x10) SERIAL_CHAR('0'); + SERIAL_PRINT(mac[i], PrintBase::Hex); + if (i < 5) SERIAL_CHAR(':'); + } + } + else + SERIAL_ECHOPGM("Disabled"); + SERIAL_EOL(); +} + +// Display current values when the link is active, +// otherwise show the stored values +void MarlinEthernet::ip_report(const uint16_t cmd, FSTR_P const post, const IPAddress &ipo, const bool forReplay/*=true*/) { + if (!forReplay) SERIAL_ECHO_START(); + SERIAL_ECHO(F(" M"), cmd, C(' ')); + for (uint8_t i = 0; i < 4; ++i) { + SERIAL_ECHO(ipo[i]); + if (i < 3) SERIAL_CHAR('.'); + } + SERIAL_ECHOLN(F(" ; "), post); +} + #endif // HAS_ETHERNET diff --git a/Marlin/src/feature/ethernet.h b/Marlin/src/feature/ethernet.h index 70a58efce7..7aa364fc3c 100644 --- a/Marlin/src/feature/ethernet.h +++ b/Marlin/src/feature/ethernet.h @@ -25,6 +25,8 @@ #include #endif +#include "../HAL/shared/Marduino.h" + // Teensy 4.1 uses internal MAC Address class MarlinEthernet { @@ -34,6 +36,10 @@ class MarlinEthernet { static EthernetClient telnetClient; static void init(); static void check(); + + static void ETH0_report(const bool forReplay=true); + static void MAC_report(const bool forReplay=true); + static void ip_report(const uint16_t cmd, FSTR_P const post, const IPAddress &ipo, const bool forReplay=true); }; extern MarlinEthernet ethernet; diff --git a/Marlin/src/gcode/config/M200-M205.cpp b/Marlin/src/gcode/config/M200-M205.cpp index a0466fbeab..a55813aeae 100644 --- a/Marlin/src/gcode/config/M200-M205.cpp +++ b/Marlin/src/gcode/config/M200-M205.cpp @@ -78,10 +78,10 @@ TERN_(MARLIN_SMALL_BUILD, return); if (!forReplay) { - report_heading(forReplay, F(STR_FILAMENT_SETTINGS), false); + report_heading(false, F(STR_FILAMENT_SETTINGS), false); if (!parser.volumetric_enabled) SERIAL_ECHOPGM(" (Disabled):"); SERIAL_EOL(); - report_echo_start(forReplay); + report_echo_start(false); } #if EXTRUDERS == 1 @@ -231,7 +231,7 @@ void GcodeSuite::M203_report(const bool forReplay/*=true*/) { #if ENABLED(DISTINCT_E_FACTORS) for (uint8_t i = 0; i < E_STEPPERS; ++i) { - if (!forReplay) SERIAL_ECHO_START(); + report_echo_start(forReplay); SERIAL_ECHOLNPGM_P( PSTR(" M203 T"), i , SP_E_STR, VOLUMETRIC_UNIT(planner.settings.max_feedrate_mm_s[E_AXIS_N(i)]) diff --git a/Marlin/src/gcode/feature/network/M552-M554.cpp b/Marlin/src/gcode/feature/network/M552-M554.cpp index 9a09a973c8..fc965fc3bd 100644 --- a/Marlin/src/gcode/feature/network/M552-M554.cpp +++ b/Marlin/src/gcode/feature/network/M552-M554.cpp @@ -28,44 +28,6 @@ #include "../../../core/serial.h" #include "../../gcode.h" -void say_ethernet() { SERIAL_ECHOPGM(" Ethernet "); } - -void ETH0_report() { - say_ethernet(); - SERIAL_ECHO_TERNARY(ethernet.hardware_enabled, "port ", "en", "dis", "abled.\n"); - if (ethernet.hardware_enabled) { - say_ethernet(); - SERIAL_ECHO_TERNARY(ethernet.have_telnet_client, "client ", "en", "dis", "abled.\n"); - } - else - SERIAL_ECHOLNPGM("Send 'M552 S1' to enable."); -} - -void MAC_report() { - uint8_t mac[6]; - if (ethernet.hardware_enabled) { - Ethernet.MACAddress(mac); - SERIAL_ECHOPGM(" MAC: "); - for (uint8_t i = 0; i < 6; ++i) { - if (mac[i] < 16) SERIAL_CHAR('0'); - SERIAL_PRINT(mac[i], PrintBase::Hex); - if (i < 5) SERIAL_CHAR(':'); - } - } - SERIAL_EOL(); -} - -// Display current values when the link is active, -// otherwise show the stored values -void ip_report(const uint16_t cmd, FSTR_P const post, const IPAddress &ipo) { - SERIAL_CHAR('M'); SERIAL_ECHO(cmd); SERIAL_CHAR(' '); - for (uint8_t i = 0; i < 4; ++i) { - SERIAL_ECHO(ipo[i]); - if (i < 3) SERIAL_CHAR('.'); - } - SERIAL_ECHOLN(F(" ; "), post); -} - /** * M552: Set IP address, enable/disable network interface * @@ -92,13 +54,13 @@ void GcodeSuite::M552() { } } const bool nopar = !seenS && !seenP; - if (nopar || seenS) ETH0_report(); + if (nopar || seenS) ethernet.ETH0_report(); if (nopar || seenP) M552_report(); } -void GcodeSuite::M552_report() { +void GcodeSuite::M552_report(const bool forReplay/*=true*/) { TERN_(MARLIN_SMALL_BUILD, return); - ip_report(552, F("ip address"), Ethernet.linkStatus() == LinkON ? Ethernet.localIP() : ethernet.ip); + ethernet.ip_report(552, F("ip address"), Ethernet.linkStatus() == LinkON ? Ethernet.localIP() : ethernet.ip, forReplay); } /** @@ -111,9 +73,9 @@ void GcodeSuite::M553() { M553_report(); } -void GcodeSuite::M553_report() { +void GcodeSuite::M553_report(const bool forReplay/*=true*/) { TERN_(MARLIN_SMALL_BUILD, return); - ip_report(553, F("subnet mask"), Ethernet.linkStatus() == LinkON ? Ethernet.subnetMask() : ethernet.subnet); + ethernet.ip_report(553, F("subnet mask"), Ethernet.linkStatus() == LinkON ? Ethernet.subnetMask() : ethernet.subnet, forReplay); } /** @@ -126,9 +88,9 @@ void GcodeSuite::M554() { M554_report(); } -void GcodeSuite::M554_report() { +void GcodeSuite::M554_report(const bool forReplay/*=true*/) { TERN_(MARLIN_SMALL_BUILD, return); - ip_report(554, F("gateway"), Ethernet.linkStatus() == LinkON ? Ethernet.gatewayIP() : ethernet.gateway); + ethernet.ip_report(554, F("gateway"), Ethernet.linkStatus() == LinkON ? Ethernet.gatewayIP() : ethernet.gateway, forReplay); } #endif // HAS_ETHERNET diff --git a/Marlin/src/gcode/feature/nonlinear/M592.cpp b/Marlin/src/gcode/feature/nonlinear/M592.cpp index 2fc02133ec..77a6258ddc 100644 --- a/Marlin/src/gcode/feature/nonlinear/M592.cpp +++ b/Marlin/src/gcode/feature/nonlinear/M592.cpp @@ -29,7 +29,7 @@ void GcodeSuite::M592_report(const bool forReplay/*=true*/) { TERN_(MARLIN_SMALL_BUILD, return); - report_heading(forReplay, F(STR_NONLINEAR_EXTRUSION)); + report_heading_etc(forReplay, F(STR_NONLINEAR_EXTRUSION)); SERIAL_ECHOLNPGM(" M592 A", stepper.ne.A, " B", stepper.ne.B, " C", stepper.ne.C); } diff --git a/Marlin/src/gcode/feature/pause/M603.cpp b/Marlin/src/gcode/feature/pause/M603.cpp index fcc042f58e..fd8a779ae0 100644 --- a/Marlin/src/gcode/feature/pause/M603.cpp +++ b/Marlin/src/gcode/feature/pause/M603.cpp @@ -64,7 +64,6 @@ void GcodeSuite::M603_report(const bool forReplay/*=true*/) { TERN_(MARLIN_SMALL_BUILD, return); report_heading(forReplay, F(STR_FILAMENT_LOAD_UNLOAD)); - #if EXTRUDERS == 1 report_echo_start(forReplay); SERIAL_ECHOPGM(" M603 L", LINEAR_UNIT(fc_settings[0].load_length), " U", LINEAR_UNIT(fc_settings[0].unload_length), " ;"); diff --git a/Marlin/src/gcode/feature/trinamic/M569.cpp b/Marlin/src/gcode/feature/trinamic/M569.cpp index 06a4992ceb..99bbf6ed35 100644 --- a/Marlin/src/gcode/feature/trinamic/M569.cpp +++ b/Marlin/src/gcode/feature/trinamic/M569.cpp @@ -160,7 +160,7 @@ void GcodeSuite::M569_report(const bool forReplay/*=true*/) { report_heading(forReplay, F(STR_DRIVER_STEPPING_MODE)); auto say_M569 = [](const bool forReplay, FSTR_P const etc=nullptr, const bool eol=false) { - if (!forReplay) SERIAL_ECHO_START(); + report_echo_start(forReplay); SERIAL_ECHOPGM(" M569 S1"); if (etc) SERIAL_ECHO(C(' '), etc); if (eol) SERIAL_EOL(); diff --git a/Marlin/src/gcode/gcode.h b/Marlin/src/gcode/gcode.h index 911820ee7b..706a7387db 100644 --- a/Marlin/src/gcode/gcode.h +++ b/Marlin/src/gcode/gcode.h @@ -1137,11 +1137,11 @@ private: #if HAS_ETHERNET static void M552(); - static void M552_report(); + static void M552_report(const bool forReplay=true); static void M553(); - static void M553_report(); + static void M553_report(const bool forReplay=true); static void M554(); - static void M554_report(); + static void M554_report(const bool forReplay=true); #endif #if HAS_STEALTHCHOP diff --git a/Marlin/src/gcode/probe/M423.cpp b/Marlin/src/gcode/probe/M423.cpp index 7ab887eb64..17941d64f3 100644 --- a/Marlin/src/gcode/probe/M423.cpp +++ b/Marlin/src/gcode/probe/M423.cpp @@ -88,10 +88,11 @@ void GcodeSuite::M423() { void GcodeSuite::M423_report(const bool forReplay/*=true*/) { TERN_(MARLIN_SMALL_BUILD, return); - report_heading(forReplay, F("X-Twist Correction")); + report_heading_etc(forReplay, F("X-Twist Correction")); SERIAL_ECHOLNPGM(" M423 A", xatc.start, " I", xatc.spacing); for (uint8_t x = 0; x < XATC_MAX_POINTS; ++x) { const float z = xatc.z_offset[x]; + report_echo_start(forReplay); SERIAL_ECHOPGM(" M423 X", x, " Z"); serial_offset(isnan(z) ? 0 : z); SERIAL_EOL(); diff --git a/Marlin/src/gcode/temp/M86_M87.cpp b/Marlin/src/gcode/temp/M86_M87.cpp index 502052e87b..442d325c56 100644 --- a/Marlin/src/gcode/temp/M86_M87.cpp +++ b/Marlin/src/gcode/temp/M86_M87.cpp @@ -37,7 +37,7 @@ void GcodeSuite::M86_report(const bool forReplay/*=true*/) { TERN_(MARLIN_SMALL_BUILD, return); hotend_idle_settings_t &c = hotend_idle.cfg; - report_heading(forReplay, F("Hotend Idle Timeout")); + report_heading_etc(forReplay, F("Hotend Idle Timeout")); SERIAL_ECHOLNPGM(" M86" #if HAS_HEATED_BED " B", c.bed_target, diff --git a/Marlin/src/module/settings.cpp b/Marlin/src/module/settings.cpp index 7062164dc9..a6714b3e6a 100644 --- a/Marlin/src/module/settings.cpp +++ b/Marlin/src/module/settings.cpp @@ -190,11 +190,6 @@ #pragma pack(push, 1) // No padding between variables -#if HAS_ETHERNET - void ETH0_report(); - void MAC_report(); -#endif - #define _EN_ITEM(N) , E##N #define _EN1_ITEM(N) , E##N:1 @@ -4210,11 +4205,11 @@ void MarlinSettings::reset() { #if HAS_ETHERNET CONFIG_ECHO_HEADING("Ethernet"); - if (!forReplay) ETH0_report(); - CONFIG_ECHO_START(); SERIAL_ECHO_SP(2); MAC_report(); - CONFIG_ECHO_START(); SERIAL_ECHO_SP(2); gcode.M552_report(); - CONFIG_ECHO_START(); SERIAL_ECHO_SP(2); gcode.M553_report(); - CONFIG_ECHO_START(); SERIAL_ECHO_SP(2); gcode.M554_report(); + if (!forReplay) ethernet.ETH0_report(false); + ethernet.MAC_report(forReplay); + gcode.M552_report(forReplay); + gcode.M553_report(forReplay); + gcode.M554_report(forReplay); #endif TERN_(HAS_MULTI_LANGUAGE, gcode.M414_report(forReplay)); From c0e108b21df5452e7376d48797cbaf7ac8b63904 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Wed, 16 Apr 2025 00:30:52 +0000 Subject: [PATCH 215/787] [cron] Bump distribution date (2025-04-16) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 11822b4b13..2015e2ce0a 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-04-15" +//#define STRING_DISTRIBUTION_DATE "2025-04-16" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 65e128bdf9..cb0252d149 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-04-15" + #define STRING_DISTRIBUTION_DATE "2025-04-16" #endif /** From 8867c458311c7e5c34ad73a4fb95c716bbd90bc7 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Wed, 16 Apr 2025 14:26:52 -0500 Subject: [PATCH 216/787] =?UTF-8?q?=F0=9F=8E=A8=20Fix=20and/or=20warning?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/gcode/feature/digipot/M907-M910.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/src/gcode/feature/digipot/M907-M910.cpp b/Marlin/src/gcode/feature/digipot/M907-M910.cpp index a73f88ca89..425d27a72d 100644 --- a/Marlin/src/gcode/feature/digipot/M907-M910.cpp +++ b/Marlin/src/gcode/feature/digipot/M907-M910.cpp @@ -104,11 +104,11 @@ void GcodeSuite::M907() { // X Y I J K U V W - All aliases to set the current for "most axes." // Only the value of the last given parameter is used. - if (ENABLED(HAS_X_Y_XY_I_J_K_U_V_W) && NUM_AXIS_GANG( + if (ENABLED(HAS_X_Y_XY_I_J_K_U_V_W) && (NUM_AXIS_GANG( parser.seenval('X'), || parser.seenval('Y'), || false, || parser.seenval('I'), || parser.seenval('J'), || parser.seenval('K'), || parser.seenval('U'), || parser.seenval('V'), || parser.seenval('W') - )) + ))) stepper.set_digipot_current(0, parser.value_int()); // Z - Set the current just for the Z axis From f3be22c4ffbd016a0dcac19eaf3649c8c7eec3e5 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Wed, 16 Apr 2025 14:29:31 -0500 Subject: [PATCH 217/787] =?UTF-8?q?=F0=9F=8E=A8=20Delete=20libsam=5Fsam3x8?= =?UTF-8?q?e=5Fgcc=5Frel.a.txt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../libsam_sam3x8e_gcc_rel.a.txt | 576 ------------------ 1 file changed, 576 deletions(-) delete mode 100644 buildroot/share/PlatformIO/variants/MARLIN_ARCHIM/libsam_sam3x8e_gcc_rel.a.txt diff --git a/buildroot/share/PlatformIO/variants/MARLIN_ARCHIM/libsam_sam3x8e_gcc_rel.a.txt b/buildroot/share/PlatformIO/variants/MARLIN_ARCHIM/libsam_sam3x8e_gcc_rel.a.txt deleted file mode 100644 index 9b614811bd..0000000000 --- a/buildroot/share/PlatformIO/variants/MARLIN_ARCHIM/libsam_sam3x8e_gcc_rel.a.txt +++ /dev/null @@ -1,576 +0,0 @@ - -adc10_sam3u.o: - -adc12_sam3u.o: - -adc_sam3snxa.o: - -pio.o: -00000000 T PIO_Clear -00000000 T PIO_Configure -00000000 T PIO_DisableInterrupt -00000000 T PIO_Get -00000000 T PIO_GetOutputDataStatus -00000000 T PIO_PullUp -00000000 T PIO_Set -00000000 T PIO_SetDebounceFilter -00000000 T PIO_SetInput -00000000 T PIO_SetOutput -00000000 T PIO_SetPeripheral - -pmc.o: -00000000 T pmc_clr_fast_startup_input -00000000 T pmc_disable_all_pck -00000000 T pmc_disable_all_periph_clk -00000000 T pmc_disable_interrupt -00000000 T pmc_disable_pck -00000000 T pmc_disable_periph_clk -00000000 T pmc_disable_pllack -00000000 T pmc_disable_udpck -00000000 T pmc_disable_upll_clock -00000000 T pmc_enable_all_pck -00000000 T pmc_enable_all_periph_clk -00000000 T pmc_enable_backupmode -00000000 T pmc_enable_interrupt -00000000 T pmc_enable_pck -00000000 T pmc_enable_periph_clk -00000000 T pmc_enable_pllack -00000000 T pmc_enable_sleepmode -00000000 T pmc_enable_udpck -00000000 T pmc_enable_upll_clock -00000000 T pmc_enable_waitmode -00000000 T pmc_get_interrupt_mask -00000000 T pmc_get_status -00000000 T pmc_get_writeprotect_status -00000000 T pmc_is_locked_pllack -00000000 T pmc_is_locked_upll -00000000 T pmc_is_pck_enabled -00000000 T pmc_is_periph_clk_enabled -00000000 T pmc_mck_set_prescaler -00000000 T pmc_mck_set_source -00000000 T pmc_osc_disable_fastrc -00000000 T pmc_osc_disable_xtal -00000000 T pmc_osc_enable_fastrc -00000000 T pmc_osc_is_ready_32kxtal -00000000 T pmc_osc_is_ready_mainck -00000000 T pmc_pck_set_prescaler -00000000 T pmc_pck_set_source -00000000 T pmc_set_fast_startup_input -00000000 T pmc_set_writeprotect -00000000 T pmc_switch_mainck_to_fastrc -00000000 T pmc_switch_mainck_to_xtal -00000000 T pmc_switch_mck_to_mainck -00000000 T pmc_switch_mck_to_pllack -00000000 T pmc_switch_mck_to_sclk -00000000 T pmc_switch_mck_to_upllck -00000000 T pmc_switch_pck_to_mainck -00000000 T pmc_switch_pck_to_pllack -00000000 T pmc_switch_pck_to_sclk -00000000 T pmc_switch_pck_to_upllck -00000000 T pmc_switch_sclk_to_32kxtal -00000000 T pmc_switch_udpck_to_pllack -00000000 T pmc_switch_udpck_to_upllck - -pwmc.o: -00000000 t FindClockConfiguration -00000000 T PWMC_ConfigureChannel -00000000 T PWMC_ConfigureChannelExt -00000000 T PWMC_ConfigureClocks -00000000 T PWMC_ConfigureComparisonUnit -00000000 T PWMC_ConfigureEventLineMode -00000000 T PWMC_ConfigureSyncChannel -00000000 T PWMC_DisableChannel -00000000 T PWMC_DisableChannelIt -00000000 T PWMC_DisableIt -00000000 T PWMC_DisableOverrideOutput -00000000 T PWMC_EnableChannel -00000000 T PWMC_EnableChannelIt -00000000 T PWMC_EnableFaultProtection -00000000 T PWMC_EnableIt -00000000 T PWMC_EnableOverrideOutput -00000000 T PWMC_FaultClear -00000000 T PWMC_SetDeadTime -00000000 T PWMC_SetDutyCycle -00000000 T PWMC_SetFaultMode -00000000 T PWMC_SetFaultProtectionValue -00000000 T PWMC_SetOverrideValue -00000000 T PWMC_SetPeriod -00000000 T PWMC_SetSyncChannelUpdatePeriod -00000000 T PWMC_SetSyncChannelUpdateUnlock -00000000 T PWMC_WriteBuffer - U __assert_func -00000000 r __func__.6793 -00000000 r __func__.6804 -00000000 r __func__.6819 -00000000 r __func__.6830 -00000000 r __func__.6841 -00000000 r __func__.6848 -00000000 r __func__.6932 -00000000 r __func__.6938 - -rtc.o: -00000000 T RTC_ClearSCCR -00000000 T RTC_DisableIt -00000000 T RTC_EnableIt -00000000 T RTC_GetDate -00000000 T RTC_GetHourMode -00000000 T RTC_GetSR -00000000 T RTC_GetTime -00000000 T RTC_SetDate -00000000 T RTC_SetDateAlarm -00000000 T RTC_SetHourMode -00000000 T RTC_SetTime -00000000 T RTC_SetTimeAlarm - U __assert_func -00000000 r __func__.6790 -00000000 r __func__.6799 -00000000 r __func__.6804 - -rtt.o: -00000000 T RTT_EnableIT -00000000 T RTT_GetStatus -00000000 T RTT_GetTime -00000000 T RTT_SetAlarm -00000000 T RTT_SetPrescaler - U __assert_func -00000000 r __func__.6797 -00000000 r __func__.6805 - -spi.o: -00000000 T SPI_Configure -00000000 T SPI_ConfigureNPCS -00000000 T SPI_Disable -00000000 T SPI_DisableIt -00000000 T SPI_Enable -00000000 T SPI_EnableIt -00000000 T SPI_GetStatus -00000000 T SPI_IsFinished -00000000 T SPI_Read -00000000 T SPI_Write - U pmc_enable_periph_clk - -tc.o: -00000000 T TC_Configure -00000000 T TC_FindMckDivisor -00000000 T TC_GetStatus -00000000 T TC_ReadCV -00000000 T TC_SetRA -00000000 T TC_SetRB -00000000 T TC_SetRC -00000000 T TC_Start -00000000 T TC_Stop - U __assert_func -00000000 r __func__.6792 -00000000 r __func__.6798 -00000000 r __func__.6804 - -timetick.o: -00000000 T GetTickCount -00000000 T Sleep -00000000 T TimeTick_Configure -00000000 T TimeTick_Increment -00000000 T Wait -00000000 b _dwTickCount - -twi.o: -00000000 T TWI_ByteReceived -00000000 T TWI_ByteSent -00000000 T TWI_ConfigureMaster -00000000 T TWI_ConfigureSlave -00000000 T TWI_Disable -00000000 T TWI_DisableIt -00000000 T TWI_EnableIt -00000000 T TWI_GetMaskedStatus -00000000 T TWI_GetStatus -00000000 T TWI_ReadByte -00000000 T TWI_SendSTOPCondition -00000000 T TWI_SetClock -00000000 T TWI_StartRead -00000000 T TWI_StartWrite -00000000 T TWI_Stop -00000000 T TWI_TransferComplete -00000000 T TWI_WriteByte - U __assert_func -00000000 r __func__.7151 -00000000 r __func__.7157 -00000000 r __func__.7172 -00000000 r __func__.7176 -00000000 r __func__.7184 -00000000 r __func__.7191 -00000000 r __func__.7195 -00000000 r __func__.7200 -00000000 r __func__.7208 -00000000 r __func__.7222 -00000000 r __func__.7227 -00000000 r __func__.7231 -00000000 r __func__.7236 -00000000 r __func__.7240 - -usart.o: -00000000 T USART_Configure -00000000 T USART_DisableIt -00000000 T USART_EnableIt -00000000 T USART_GetChar -00000000 T USART_GetStatus -00000000 T USART_IsDataAvailable -00000000 T USART_IsRxReady -00000000 T USART_PutChar -00000000 T USART_Read -00000000 T USART_ReadBuffer -00000000 T USART_SetIrdaFilter -00000000 T USART_SetReceiverEnabled -00000000 T USART_SetTransmitterEnabled -00000000 T USART_Write -00000000 T USART_WriteBuffer - U __assert_func -00000000 r __func__.7068 - -wdt.o: -00000000 T WDT_Disable -00000000 T WDT_Enable -00000000 T WDT_GetPeriod -00000000 T WDT_GetStatus -00000000 T WDT_Restart - -system_sam3xa.o: -00000000 D SystemCoreClock -00000000 T SystemCoreClockUpdate -00000000 T SystemInit -00000000 T system_init_flash - -startup_sam3xa.o: - U ADC_Handler - U BusFault_Handler - U CAN0_Handler - U CAN1_Handler - U DACC_Handler - U DMAC_Handler - U DebugMon_Handler - U EFC0_Handler - U EFC1_Handler - U EMAC_Handler - U HSMCI_Handler - U HardFault_Handler - U MemManage_Handler - U NMI_Handler - U PIOA_Handler - U PIOB_Handler - U PIOC_Handler - U PIOD_Handler - U PMC_Handler - U PWM_Handler - U PendSV_Handler - U RSTC_Handler - U RTC_Handler - U RTT_Handler -00000000 T Reset_Handler - U SMC_Handler - U SPI0_Handler - U SSC_Handler - U SUPC_Handler - U SVC_Handler - U SysTick_Handler - U TC0_Handler - U TC1_Handler - U TC2_Handler - U TC3_Handler - U TC4_Handler - U TC5_Handler - U TC6_Handler - U TC7_Handler - U TC8_Handler - U TRNG_Handler - U TWI0_Handler - U TWI1_Handler - U UART_Handler - U UOTGHS_Handler - U USART0_Handler - U USART1_Handler - U USART2_Handler - U USART3_Handler - U UsageFault_Handler - U WDT_Handler - U _erelocate - U _estack - U _etext - U _ezero - U _sfixed - U _srelocate - U _szero -00000000 R exception_table - U main - -adc.o: -00000000 T adc_configure_power_save -00000000 T adc_configure_sequence -00000000 T adc_configure_timing -00000000 T adc_configure_trigger -00000000 T adc_disable_all_channel -00000000 T adc_disable_anch -00000000 T adc_disable_channel -00000000 T adc_disable_channel_differential_input -00000000 T adc_disable_channel_input_offset -00000000 T adc_disable_interrupt -00000000 T adc_disable_tag -00000000 T adc_disable_ts -00000000 T adc_enable_all_channel -00000000 T adc_enable_anch -00000000 T adc_enable_channel -00000000 T adc_enable_channel_differential_input -00000000 T adc_enable_channel_input_offset -00000000 T adc_enable_interrupt -00000000 T adc_enable_tag -00000000 T adc_enable_ts -00000000 T adc_get_actual_adc_clock -00000000 T adc_get_channel_status -00000000 T adc_get_channel_value -00000000 T adc_get_comparison_mode -00000000 T adc_get_interrupt_mask -00000000 T adc_get_latest_value -00000000 T adc_get_overrun_status -00000000 T adc_get_pdc_base -00000000 T adc_get_status -00000000 T adc_get_tag -00000000 T adc_get_writeprotect_status -00000000 T adc_init -00000000 T adc_set_bias_current -00000000 T adc_set_channel_input_gain -00000000 T adc_set_comparison_channel -00000000 T adc_set_comparison_mode -00000000 T adc_set_comparison_window -00000000 T adc_set_resolution -00000000 T adc_set_writeprotect -00000000 T adc_start -00000000 T adc_start_sequencer -00000000 T adc_stop -00000000 T adc_stop_sequencer - -udp.o: - -udphs.o: - -uotghs.o: -00000000 T UOTGHS_Handler -00000000 B gpf_isr - -interrupt_sam_nvic.o: -00000000 D g_interrupt_enabled - -uotghs_device.o: -00000000 T UDD_Attach -00000000 T UDD_ClearIN -00000000 T UDD_ClearOUT -00000000 T UDD_ClearSetupInt -00000000 T UDD_Detach -00000000 T UDD_FifoByteCount -00000000 T UDD_GetFrameNumber -00000000 T UDD_Init -00000000 T UDD_InitEP -00000000 T UDD_InitEndpoints -00000000 T UDD_ReadWriteAllowed -00000000 T UDD_ReceivedSetupInt -00000000 T UDD_Recv -00000000 T UDD_Recv8 -00000000 T UDD_ReleaseRX -00000000 T UDD_ReleaseTX -00000000 T UDD_Send -00000000 T UDD_Send8 -00000000 T UDD_SetAddress -00000000 T UDD_SetStack -00000000 T UDD_Stall -00000000 T UDD_WaitForINOrOUT -00000000 T UDD_WaitIN -00000000 T UDD_WaitOUT - U g_interrupt_enabled - U gpf_isr - U pmc_enable_periph_clk - U pmc_enable_udpck - U pmc_enable_upll_clock - U pmc_switch_udpck_to_upllck -00000000 b ul_recv_fifo_ptr -00000000 b ul_send_fifo_ptr - -uotghs_host.o: -00000000 T UHD_BusReset -00000000 T UHD_GetVBUSState -00000000 t UHD_ISR -00000000 T UHD_Init -00000000 T UHD_Pipe0_Alloc -00000000 T UHD_Pipe_Alloc -00000000 T UHD_Pipe_Free -00000000 T UHD_Pipe_Is_Transfer_Complete -00000000 T UHD_Pipe_Read -00000000 T UHD_Pipe_Send -00000000 T UHD_Pipe_Write -00000000 T UHD_SetStack - U g_interrupt_enabled - U gpf_isr - U pmc_enable_periph_clk - U pmc_enable_udpck - U pmc_enable_upll_clock - U pmc_switch_udpck_to_upllck -00000000 b uhd_state - -dacc.o: -00000000 T dacc_disable_channel -00000000 T dacc_disable_interrupt -00000000 T dacc_disable_trigger -00000000 T dacc_enable_channel -00000000 T dacc_enable_flexible_selection -00000000 T dacc_enable_interrupt -00000000 T dacc_get_analog_control -00000000 T dacc_get_channel_status -00000000 T dacc_get_interrupt_mask -00000000 T dacc_get_interrupt_status -00000000 T dacc_get_pdc_base -00000000 T dacc_get_writeprotect_status -00000000 T dacc_reset -00000000 T dacc_set_analog_control -00000000 T dacc_set_channel_selection -00000000 T dacc_set_power_save -00000000 T dacc_set_timing -00000000 T dacc_set_transfer_mode -00000000 T dacc_set_trigger -00000000 T dacc_set_writeprotect -00000000 T dacc_write_conversion_data - -can.o: -00000000 R can_bit_time -00000000 T can_disable -00000000 T can_disable_autobaud_listen_mode -00000000 T can_disable_interrupt -00000000 T can_disable_low_power_mode -00000000 T can_disable_overload_frame -00000000 T can_disable_time_triggered_mode -00000000 T can_disable_timer_freeze -00000000 T can_disable_tx_repeat -00000000 T can_enable -00000000 T can_enable_autobaud_listen_mode -00000000 T can_enable_interrupt -00000000 T can_enable_low_power_mode -00000000 T can_enable_overload_frame -00000000 T can_enable_time_triggered_mode -00000000 T can_enable_timer_freeze -00000000 T can_enable_tx_repeat -00000000 T can_get_internal_timer_value -00000000 T can_get_interrupt_mask -00000000 T can_get_rx_error_cnt -00000000 T can_get_status -00000000 T can_get_timestamp_value -00000000 T can_get_tx_error_cnt -00000000 T can_global_send_abort_cmd -00000000 T can_global_send_transfer_cmd -00000000 T can_init -00000000 T can_mailbox_get_status -00000000 T can_mailbox_init -00000000 T can_mailbox_read -00000000 T can_mailbox_send_abort_cmd -00000000 T can_mailbox_send_transfer_cmd -00000000 T can_mailbox_set_timemark -00000000 T can_mailbox_tx_remote_frame -00000000 T can_mailbox_write -00000000 T can_reset_all_mailbox -00000000 T can_reset_internal_timer -00000000 T can_reset_mailbox_data -00000000 T can_set_rx_sync_stage -00000000 T can_set_timestamp_capture_point - U memset - -efc.o: -00000000 T efc_disable_frdy_interrupt -00000000 T efc_enable_frdy_interrupt -00000000 T efc_get_flash_access_mode -00000000 T efc_get_result -00000000 T efc_get_status -00000000 T efc_get_wait_state -00000000 T efc_init -00000000 T efc_perform_command -0000006c T efc_perform_fcr -00000000 T efc_perform_read_sequence -00000000 T efc_set_flash_access_mode -00000000 T efc_set_wait_state -00000068 T efc_write_fmr -00000000 b iap_perform_command.7049 - -gpbr.o: -00000000 T gpbr_read -00000000 T gpbr_write - -ssc.o: - U memset -00000000 T ssc_disable_interrupt -00000000 T ssc_disable_rx -00000000 T ssc_disable_tx -00000000 T ssc_disable_tx_frame_sync_data -00000000 T ssc_enable_interrupt -00000000 T ssc_enable_rx -00000000 T ssc_enable_tx -00000000 T ssc_enable_tx_frame_sync_data -00000000 T ssc_get_interrupt_mask -00000000 T ssc_get_rx_access -00000000 T ssc_get_rx_compare -00000000 T ssc_get_status -00000000 T ssc_get_tx_access -00000000 T ssc_get_writeprotect_status -00000000 T ssc_i2s_set_receiver -00000000 T ssc_i2s_set_transmitter -00000000 T ssc_is_rx_enabled -00000000 T ssc_is_rx_ready -00000000 T ssc_is_tx_empty -00000000 T ssc_is_tx_enabled -00000000 T ssc_is_tx_ready -00000000 T ssc_read -00000000 T ssc_read_sync_data -00000000 T ssc_reset -00000000 T ssc_set_clock_divider -00000000 T ssc_set_loop_mode -00000000 T ssc_set_normal_mode -00000000 T ssc_set_receiver -00000000 T ssc_set_rx_compare -00000000 T ssc_set_rx_stop_selection -00000000 T ssc_set_td_default_level -00000000 T ssc_set_transmitter -00000000 T ssc_set_writeprotect -00000000 T ssc_write -00000000 T ssc_write_sync_data - -trng.o: -00000000 T trng_disable -00000000 T trng_disable_interrupt -00000000 T trng_enable -00000000 T trng_enable_interrupt -00000000 T trng_get_interrupt_mask -00000000 T trng_get_interrupt_status -00000000 T trng_read_output_data - -rstc.o: -00000000 T rstc_disable_user_reset -00000000 T rstc_disable_user_reset_interrupt -00000000 T rstc_enable_user_reset -00000000 T rstc_enable_user_reset_interrupt -00000000 T rstc_get_reset_cause -00000000 T rstc_get_status -00000000 T rstc_reset_extern -00000000 T rstc_set_external_reset -00000000 T rstc_start_software_reset - -emac.o: -00000000 t circ_inc -00000000 T emac_dev_get_tx_load -00000000 T emac_dev_init -00000000 T emac_dev_read -00000000 T emac_dev_reset -00000000 T emac_dev_set_rx_callback -00000000 T emac_dev_set_tx_wakeup_callback -00000000 T emac_dev_write -00000000 T emac_handler -00000000 T emac_phy_read -00000000 T emac_phy_write -00000000 t emac_reset_rx_mem -00000000 t emac_reset_tx_mem -00000000 b gs_rx_desc -00000000 b gs_tx_callback -00000000 b gs_tx_desc -00000000 b gs_uc_rx_buffer -00000000 b gs_uc_tx_buffer - U memcpy From bd382fb8a128ac0ab36b4c539646812dd470eb37 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Wed, 16 Apr 2025 14:43:53 -0500 Subject: [PATCH 218/787] =?UTF-8?q?=F0=9F=94=A8=20Suppress=20generate=5Fve?= =?UTF-8?q?rsion=20(for=20now)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- buildroot/bin/generate_version | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/buildroot/bin/generate_version b/buildroot/bin/generate_version index ff85fe7ecf..edc25e18af 100755 --- a/buildroot/bin/generate_version +++ b/buildroot/bin/generate_version @@ -3,12 +3,19 @@ # generate_version # # Make a Version.h file to accompany CUSTOM_VERSION_FILE +# Invoked automatically by Arduino IDE # # Authors: jbrazio, thinkyhead, InsanityAutomation, rfinnie # set -e +# Only run if ALLOW_GENERATE_VERSION is set +if [[ "$ALLOW_GENERATE_VERSION" != "1" ]]; then + echo "Skipping generate_version because ALLOW_GENERATE_VERSION is not set." + exit 0 +fi + DIR="${1:-Marlin}" READ_FILE="${READ_FILE:-${DIR}/Version.h}" WRITE_FILE="${WRITE_FILE:-${READ_FILE}}" From 62c1c116f74713a50577d1992b423de40c3bc0c5 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Thu, 17 Apr 2025 00:30:15 +0000 Subject: [PATCH 219/787] [cron] Bump distribution date (2025-04-17) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 2015e2ce0a..b7b07dd43d 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-04-16" +//#define STRING_DISTRIBUTION_DATE "2025-04-17" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index cb0252d149..c34074006d 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-04-16" + #define STRING_DISTRIBUTION_DATE "2025-04-17" #endif /** From 58f03953b8a6d8c86ec2d82000b6b7d33712b1a8 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Thu, 17 Apr 2025 15:42:21 -0500 Subject: [PATCH 220/787] =?UTF-8?q?=F0=9F=A9=B9=20Fix=20Linear=20Advance?= =?UTF-8?q?=20edit=20item?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/lcd/menu/menu_advanced.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/src/lcd/menu/menu_advanced.cpp b/Marlin/src/lcd/menu/menu_advanced.cpp index 8080a23ba4..2ffdee798d 100644 --- a/Marlin/src/lcd/menu/menu_advanced.cpp +++ b/Marlin/src/lcd/menu/menu_advanced.cpp @@ -736,7 +736,7 @@ void menu_advanced_settings() { EDIT_ITEM(float42_52, MSG_ADVANCE_K, &planner.extruder_advance_K[0], 0, 10); #else EXTRUDER_LOOP() - EDIT_ITEM_N(float42_52, n, MSG_ADVANCE_K_E, &planner.extruder_advance_K[e], 0, 10); + EDIT_ITEM_N(float42_52, e, MSG_ADVANCE_K_E, &planner.extruder_advance_K[e], 0, 10); #endif #endif From 4ea75ad284107959ea33dbb7875a55a689594faf Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Thu, 17 Apr 2025 15:43:40 -0500 Subject: [PATCH 221/787] =?UTF-8?q?=F0=9F=8E=A8=20Cosmetic=20updates,=20fi?= =?UTF-8?q?x=20alias=20warning?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/HAL/ESP32/i2s.cpp | 16 ++--- Marlin/src/feature/max7219.cpp | 2 +- .../src/feature/mmu3/mmu3_error_converter.cpp | 8 +-- Marlin/src/inc/SanityCheck.h | 2 +- Marlin/src/lcd/menu/menu_advanced.cpp | 10 +++- Marlin/src/lcd/menu/menu_item.h | 8 +++ Marlin/src/module/planner.cpp | 60 +++++++++---------- 7 files changed, 59 insertions(+), 47 deletions(-) diff --git a/Marlin/src/HAL/ESP32/i2s.cpp b/Marlin/src/HAL/ESP32/i2s.cpp index 4b17db3daf..6aeeb0e3dc 100644 --- a/Marlin/src/HAL/ESP32/i2s.cpp +++ b/Marlin/src/HAL/ESP32/i2s.cpp @@ -145,7 +145,7 @@ static void IRAM_ATTR i2s_intr_handler_default(void *arg) { void stepperTask(void *parameter) { uint32_t nextMainISR = 0; #if ENABLED(LIN_ADVANCE) - uint32_t nextAdvanceISR = Stepper::LA_ADV_NEVER; + uint32_t nextAdvanceISR = stepper.LA_ADV_NEVER; #endif for (;;) { @@ -167,13 +167,13 @@ void stepperTask(void *parameter) { if (!using_ftMotion) { if (!nextMainISR) { - Stepper::pulse_phase_isr(); - nextMainISR = Stepper::block_phase_isr(); + stepper.pulse_phase_isr(); + nextMainISR = stepper.block_phase_isr(); } #if ENABLED(LIN_ADVANCE) else if (!nextAdvanceISR) { - Stepper::advance_isr(); - nextAdvanceISR = Stepper::la_interval; + stepper.advance_isr(); + nextAdvanceISR = stepper.la_interval; } #endif else @@ -182,10 +182,10 @@ void stepperTask(void *parameter) { nextMainISR--; #if ENABLED(LIN_ADVANCE) - if (nextAdvanceISR == Stepper::LA_ADV_NEVER) - nextAdvanceISR = Stepper::la_interval; + if (nextAdvanceISR == stepper.LA_ADV_NEVER) + nextAdvanceISR = stepper.la_interval; - if (nextAdvanceISR && nextAdvanceISR != Stepper::LA_ADV_NEVER) + if (nextAdvanceISR && nextAdvanceISR != stepper.LA_ADV_NEVER) nextAdvanceISR--; #endif } diff --git a/Marlin/src/feature/max7219.cpp b/Marlin/src/feature/max7219.cpp index 5a25ea6710..5a61922c1d 100644 --- a/Marlin/src/feature/max7219.cpp +++ b/Marlin/src/feature/max7219.cpp @@ -757,7 +757,7 @@ void Max7219::idle_tasks() { #ifdef MAX7219_DEBUG_MULTISTEPPING static uint8_t last_multistepping = 0; - const uint8_t multistepping = Stepper::steps_per_isr; + const uint8_t multistepping = stepper.steps_per_isr; if (multistepping != last_multistepping) { static uint8_t log2_old = 0; uint8_t log2_new = 0; diff --git a/Marlin/src/feature/mmu3/mmu3_error_converter.cpp b/Marlin/src/feature/mmu3/mmu3_error_converter.cpp index d5d124427e..d7fc651fbd 100644 --- a/Marlin/src/feature/mmu3/mmu3_error_converter.cpp +++ b/Marlin/src/feature/mmu3/mmu3_error_converter.cpp @@ -196,16 +196,16 @@ namespace MMU3 { return FindErrorIndex(ERR_OTHER_UNKNOWN_ERROR); } - uint16_t PrusaErrorCode(const uint8_t i) { return (uint16_t)pgm_read_word(&errorCodes[i]); } + uint16_t PrusaErrorCode(const uint8_t i) { return pgm_read_word(errorCodes + i); } - FSTR_P const PrusaErrorTitle(const uint8_t i) { return (FSTR_P const)pgm_read_ptr(&errorTitles[i]); } - FSTR_P const PrusaErrorDesc(const uint8_t i) { return (FSTR_P const)pgm_read_ptr(&errorDescs[i]); } + FSTR_P const PrusaErrorTitle(const uint8_t i) { return (FSTR_P const)pgm_read_ptr(errorTitles + i); } + FSTR_P const PrusaErrorDesc(const uint8_t i) { return (FSTR_P const)pgm_read_ptr(errorDescs + i); } uint8_t PrusaErrorButtons(const uint8_t i) { return pgm_read_byte(errorButtons + i); } FSTR_P const PrusaErrorButtonTitle(const uint8_t bi) { // -1 represents the hidden NoOperation button which is not drawn in any way - return (FSTR_P const)pgm_read_ptr(&btnOperation[bi - 1]); + return (FSTR_P const)pgm_read_ptr(btnOperation + bi - 1); } Buttons ButtonPressed(const ErrorCode ec) { diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index 169f84983c..cd3c1cd573 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -4460,7 +4460,7 @@ static_assert(_PLUS_TEST(3), "DEFAULT_MAX_ACCELERATION values must be positive." * Direct Stepping requirements */ #if ENABLED(DIRECT_STEPPING) - #if ENABLED(CPU_32_BIT) + #ifdef CPU_32_BIT #error "Direct Stepping is not supported on 32-bit boards." #elif !IS_FULL_CARTESIAN #error "Direct Stepping is incompatible with enabled kinematics." diff --git a/Marlin/src/lcd/menu/menu_advanced.cpp b/Marlin/src/lcd/menu/menu_advanced.cpp index 2ffdee798d..137439c6df 100644 --- a/Marlin/src/lcd/menu/menu_advanced.cpp +++ b/Marlin/src/lcd/menu/menu_advanced.cpp @@ -104,6 +104,10 @@ void menu_backlash(); #endif #if DISABLED(NO_VOLUMETRICS) || ENABLED(ADVANCED_PAUSE_FEATURE) + #define HAS_ADV_FILAMENT_MENU 1 +#endif + +#if HAS_ADV_FILAMENT_MENU // // Advanced Settings > Filament // @@ -138,7 +142,7 @@ void menu_backlash(); EDIT_ITEM_FAST_N(float43, e, MSG_FILAMENT_DIAM_E, &planner.filament_size[e], 1.5f, 3.25f, planner.calculate_volumetric_multipliers); #endif } - #endif + #endif // !NO_VOLUMETRICS #if ENABLED(CONFIGURE_FILAMENT_CHANGE) constexpr float extrude_maxlength = TERN(PREVENT_LENGTHY_EXTRUDE, EXTRUDE_MAXLENGTH, 999); @@ -169,7 +173,7 @@ void menu_backlash(); END_MENU(); } -#endif // !NO_VOLUMETRICS || ADVANCED_PAUSE_FEATURE +#endif // HAS_ADV_FILAMENT_MENU // // Advanced Settings > Temperature helpers @@ -729,7 +733,7 @@ void menu_advanced_settings() { SUBMENU(MSG_TEMPERATURE, menu_advanced_temperature); #endif - #if DISABLED(NO_VOLUMETRICS) || ENABLED(ADVANCED_PAUSE_FEATURE) + #if HAS_ADV_FILAMENT_MENU SUBMENU(MSG_FILAMENT, menu_advanced_filament); #elif ENABLED(LIN_ADVANCE) #if DISTINCT_E < 2 diff --git a/Marlin/src/lcd/menu/menu_item.h b/Marlin/src/lcd/menu/menu_item.h index df2c90425c..af4558cefc 100644 --- a/Marlin/src/lcd/menu/menu_item.h +++ b/Marlin/src/lcd/menu/menu_item.h @@ -276,6 +276,14 @@ class MenuItem_bool : public MenuEditItemBase { * EDIT_ITEM(int3, MSG_SPEED, &feedrate_percentage, SPEED_EDIT_MIN, SPEED_EDIT_MAX) * MenuItem_int3::action(flabel, &feedrate_percentage, SPEED_EDIT_MIN, SPEED_EDIT_MAX) * MenuItem_int3::draw(sel, row, flabel, &feedrate_percentage, SPEED_EDIT_MIN, SPEED_EDIT_MAX) + * + * Variants use standard suffixes. N:Number Index, S:C-string for substitution, F:F-string label, f:F-string for substitution + * _MENU_ITEM_F(TYPE, V...) Item with optional data + * _MENU_ITEM_N_S_F(TYPE, N, S, V...) Item with index value, C-string, and optional data + * _MENU_ITEM_N_f_F(TYPE, N, f, V...) Item with index value and F-string + * _MENU_ITEM_N_F(TYPE, N, V...) Item with index value + * _MENU_ITEM_S_F(TYPE, S, V...) Item with a unique string + * _MENU_ITEM_f_F(TYPE, f, V...) Item with a unique F-string */ #if ENABLED(ENCODER_RATE_MULTIPLIER) diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index 561d13fa2a..b3df490cf0 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -780,7 +780,7 @@ block_t* Planner::get_current_block() { * by the provided factors. If entry_factor is 0 don't change the initial_rate. * Assumes that the implied initial_rate and final_rate are no less than * sqrt(block->acceleration_steps_per_s2 / 2). This is ensured through - * minimum_planner_speed_sqr / min_entry_speed_sqr though note there's one + * minimum_planner_speed_sqr / min_entry_speed_sqr - but there's one * exception in recalculate_trapezoids(). * * ############ VERY IMPORTANT ############ @@ -854,6 +854,8 @@ void Planner::calculate_trapezoid_for_block(block_t * const block, const_float_t block->accelerate_before = accelerate_steps; block->decelerate_start = block->step_event_count - decelerate_steps; block->initial_rate = initial_rate; + block->final_rate = final_rate; + #if ENABLED(S_CURVE_ACCELERATION) block->acceleration_time = acceleration_time; block->deceleration_time = deceleration_time; @@ -861,7 +863,6 @@ void Planner::calculate_trapezoid_for_block(block_t * const block, const_float_t block->deceleration_time_inverse = deceleration_time_inverse; block->cruise_rate = cruise_rate; #endif - block->final_rate = final_rate; #if ENABLED(LIN_ADVANCE) if (block->la_advance_rate) { @@ -892,30 +893,29 @@ void Planner::calculate_trapezoid_for_block(block_t * const block, const_float_t * Laser Trap Power works for all Jerk and Curve modes; however Arc-based moves will have issues since * the segments are usually too small. */ - if (cutter.cutter_mode == CUTTER_MODE_CONTINUOUS) { - if (planner.laser_inline.status.isPowered && planner.laser_inline.status.isEnabled) { - if (block->laser.power > 0) { - NOLESS(block->laser.power, laser_power_floor); - block->laser.trap_ramp_active_pwr = (block->laser.power - laser_power_floor) * (initial_rate / float(block->nominal_rate)) + laser_power_floor; - block->laser.trap_ramp_entry_incr = (block->laser.power - block->laser.trap_ramp_active_pwr) / accelerate_steps; - float laser_pwr = block->laser.power * (final_rate / float(block->nominal_rate)); - NOLESS(laser_pwr, laser_power_floor); - block->laser.trap_ramp_exit_decr = (block->laser.power - laser_pwr) / decelerate_steps; - #if ENABLED(DEBUG_LASER_TRAP) - SERIAL_ECHO_MSG("lp:",block->laser.power); - SERIAL_ECHO_MSG("as:",accelerate_steps); - SERIAL_ECHO_MSG("ds:",decelerate_steps); - SERIAL_ECHO_MSG("p.trap:",block->laser.trap_ramp_active_pwr); - SERIAL_ECHO_MSG("p.incr:",block->laser.trap_ramp_entry_incr); - SERIAL_ECHO_MSG("p.decr:",block->laser.trap_ramp_exit_decr); - #endif - } - else { - block->laser.trap_ramp_active_pwr = 0; - block->laser.trap_ramp_entry_incr = 0; - block->laser.trap_ramp_exit_decr = 0; - } - + if (cutter.cutter_mode == CUTTER_MODE_CONTINUOUS + && planner.laser_inline.status.isPowered && planner.laser_inline.status.isEnabled + ) { + if (block->laser.power > 0) { + NOLESS(block->laser.power, laser_power_floor); + block->laser.trap_ramp_active_pwr = (block->laser.power - laser_power_floor) * (initial_rate / float(block->nominal_rate)) + laser_power_floor; + block->laser.trap_ramp_entry_incr = (block->laser.power - block->laser.trap_ramp_active_pwr) / accelerate_steps; + float laser_pwr = block->laser.power * (final_rate / float(block->nominal_rate)); + NOLESS(laser_pwr, laser_power_floor); + block->laser.trap_ramp_exit_decr = (block->laser.power - laser_pwr) / decelerate_steps; + #if ENABLED(DEBUG_LASER_TRAP) + SERIAL_ECHO_MSG("lp:", block->laser.power); + SERIAL_ECHO_MSG("as:", accelerate_steps); + SERIAL_ECHO_MSG("ds:", decelerate_steps); + SERIAL_ECHO_MSG("p.trap:", block->laser.trap_ramp_active_pwr); + SERIAL_ECHO_MSG("p.incr:", block->laser.trap_ramp_entry_incr); + SERIAL_ECHO_MSG("p.decr:", block->laser.trap_ramp_exit_decr); + #endif + } + else { + block->laser.trap_ramp_active_pwr = 0; + block->laser.trap_ramp_entry_incr = 0; + block->laser.trap_ramp_exit_decr = 0; } } #endif // LASER_POWER_TRAP @@ -2440,7 +2440,7 @@ bool Planner::_populate_block( block->acceleration_steps_per_s2 = accel; block->acceleration = accel / steps_per_mm; #if DISABLED(S_CURVE_ACCELERATION) - block->acceleration_rate = (uint32_t)(accel * (float(1UL << 24) / (STEPPER_TIMER_RATE))); + block->acceleration_rate = uint32_t(accel * (float(1UL << 24) / (STEPPER_TIMER_RATE))); #endif #if ENABLED(LIN_ADVANCE) @@ -2448,10 +2448,10 @@ bool Planner::_populate_block( block->la_scaling = 0; if (use_advance_lead) { - // the Bresenham algorithm will convert this step rate into extruder steps + // The Bresenham algorithm will convert this step rate into extruder steps block->la_advance_rate = extruder_advance_K[E_INDEX_N(extruder)] * block->acceleration_steps_per_s2; - // reduce LA ISR frequency by calling it only often enough to ensure that there will + // Reduce LA ISR frequency by calling it only often enough to ensure that there will // never be more than four extruder steps per call for (uint32_t dividend = block->steps.e << 1; dividend <= (block->step_event_count >> 2); dividend <<= 1) block->la_scaling++; @@ -2461,7 +2461,7 @@ bool Planner::_populate_block( SERIAL_ECHOLNPGM("eISR running at > 10kHz: ", block->la_advance_rate); #endif } - #endif + #endif // LIN_ADVANCE // Formula for the average speed over a 1 step worth of distance if starting from zero and // accelerating at the current limit. Since we can only change the speed every step this is a From 65b8ced80ccb9462cf9052a80f8e7f8a2a832b81 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Thu, 17 Apr 2025 17:29:20 -0500 Subject: [PATCH 222/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Cla?= =?UTF-8?q?rify=20DEPLOY=5FALARM?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/feature/bltouch.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Marlin/src/feature/bltouch.h b/Marlin/src/feature/bltouch.h index 0f9f2e68ba..1371ec9f46 100644 --- a/Marlin/src/feature/bltouch.h +++ b/Marlin/src/feature/bltouch.h @@ -26,6 +26,7 @@ // BLTouch commands are sent as servo angles typedef unsigned char BLTCommand; +#define DEPLOY_ALARM true #define STOW_ALARM true #define BLTOUCH_DEPLOY 10 #define BLTOUCH_STOW 90 @@ -104,7 +105,7 @@ public: static bool triggered(); private: - static bool _deploy_query_alarm() { return command(BLTOUCH_DEPLOY, BLTOUCH_DEPLOY_DELAY); } + static bool _deploy_query_alarm() { return command(BLTOUCH_DEPLOY, BLTOUCH_DEPLOY_DELAY) == DEPLOY_ALARM; } static bool _stow_query_alarm() { return command(BLTOUCH_STOW, BLTOUCH_STOW_DELAY) == STOW_ALARM; } static void clear(); From 7b083be5c5dda3486642af7b4cea3853c1057162 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Fri, 18 Apr 2025 00:29:57 +0000 Subject: [PATCH 223/787] [cron] Bump distribution date (2025-04-18) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index b7b07dd43d..2260bfc119 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-04-17" +//#define STRING_DISTRIBUTION_DATE "2025-04-18" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index c34074006d..e4d0c6679b 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-04-17" + #define STRING_DISTRIBUTION_DATE "2025-04-18" #endif /** From a653c3aca02f4b0eb8da0c2b7f90c0bb33d8cb9c Mon Sep 17 00:00:00 2001 From: ellensp <530024+ellensp@users.noreply.github.com> Date: Sat, 19 Apr 2025 10:36:22 +1200 Subject: [PATCH 224/787] =?UTF-8?q?=F0=9F=8E=A8=20Binary=20Stream=20cleanu?= =?UTF-8?q?p=20(#27799)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/feature/binary_stream.h | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Marlin/src/feature/binary_stream.h b/Marlin/src/feature/binary_stream.h index b2d76c045a..304fdae300 100644 --- a/Marlin/src/feature/binary_stream.h +++ b/Marlin/src/feature/binary_stream.h @@ -134,19 +134,19 @@ private: public: static void idle() { - // If a transfer is interrupted and a file is left open, abort it after TIMEOUT ms + // If a transfer is interrupted and a file is left open, abort it after 'idle_period' ms const millis_t ms = millis(); if (transfer_active && ELAPSED(ms, idle_timeout)) { - idle_timeout = ms + IDLE_PERIOD; + idle_timeout = ms + idle_period; if (ELAPSED(ms, transfer_timeout)) transfer_abort(); } } static void process(uint8_t packet_type, char *buffer, const uint16_t length) { - transfer_timeout = millis() + TIMEOUT; + transfer_timeout = millis() + timeout; switch (static_cast(packet_type)) { case FileTransfer::QUERY: - SERIAL_ECHO(F("PFT:version:"), VERSION_MAJOR, C('.'), VERSION_MINOR, C('.'), VERSION_PATCH); + SERIAL_ECHO(F("PFT:version:"), version_major, C('.'), version_minor, C('.'), version_patch); #if ENABLED(BINARY_STREAM_COMPRESSION) SERIAL_ECHOLN(F(":compression:heatshrink,"), HEATSHRINK_STATIC_WINDOW_BITS, C(','), HEATSHRINK_STATIC_LOOKAHEAD_BITS); #else @@ -194,7 +194,7 @@ public: } } - static const uint16_t VERSION_MAJOR = 0, VERSION_MINOR = 1, VERSION_PATCH = 0, TIMEOUT = 10000, IDLE_PERIOD = 1000; + static const uint16_t version_major = 0, version_minor = 1, version_patch = 0, timeout = 10000, idle_period = 1000; }; class BinaryStream { @@ -209,7 +209,7 @@ public: struct Packet { // 10 byte protocol overhead, ascii with checksum and line number has a minimum of 7 increasing with line union Header { - static constexpr uint16_t HEADER_TOKEN = 0xB5AD; + static constexpr uint16_t header_token = 0xB5AD; struct [[gnu::packed]] { uint16_t token; // packet start token uint8_t sync; // stream sync, resend id and packet loss detection @@ -245,7 +245,7 @@ public: bytes_received = 0; checksum = 0; header_checksum = 0; - timeout = millis() + PACKET_MAX_WAIT; + timeout = millis() + packet_max_wait; buffer = nullptr; } } packet{}; @@ -272,14 +272,14 @@ public: } if (!bs_serial_data_available(card.transfer_port_index)) return false; data = bs_read_serial(card.transfer_port_index); - packet.timeout = millis() + PACKET_MAX_WAIT; + packet.timeout = millis() + packet_max_wait; return true; } template void receive(char (&buffer)[buffer_size]) { uint8_t data = 0; - millis_t transfer_window = millis() + RX_TIMESLICE; + millis_t transfer_window = millis() + rx_timeslice; #if HAS_MEDIA PORT_REDIRECT(SERIAL_PORTMASK(card.transfer_port_index)); @@ -299,7 +299,7 @@ public: case StreamState::PACKET_WAIT: if (!stream_read(data)) { idle(); return; } // no active packet so don't wait packet.header.data[1] = data; - if (packet.header.token == packet.header.HEADER_TOKEN) { + if (packet.header.token == packet.header.header_token) { packet.bytes_received = 2; stream_state = StreamState::PACKET_HEADER; } @@ -322,7 +322,7 @@ public: if (packet.header.checksum == packet.header_checksum) { // The SYNC control packet is a special case in that it doesn't require the stream sync to be correct if (static_cast(packet.header.protocol()) == Protocol::CONTROL && static_cast(packet.header.type()) == ProtocolControl::SYNC) { - SERIAL_ECHOLN(F("ss"), sync, C(','), buffer_size, C(','), VERSION_MAJOR, C('.'), VERSION_MINOR, C('.'), VERSION_PATCH); + SERIAL_ECHOLN(F("ss"), sync, C(','), buffer_size, C(','), version_major, C('.'), version_minor, C('.'), version_patch); stream_state = StreamState::PACKET_RESET; break; } @@ -398,7 +398,7 @@ public: stream_state = StreamState::PACKET_RESET; break; case StreamState::PACKET_RESEND: - if (packet_retries < MAX_RETRIES || MAX_RETRIES == 0) { + if (packet_retries < max_retries || max_retries == 0) { packet_retries++; stream_state = StreamState::PACKET_RESET; SERIAL_ECHO_MSG("Resend request ", packet_retries); @@ -446,7 +446,7 @@ public: SDFileTransferProtocol::idle(); } - static const uint16_t PACKET_MAX_WAIT = 500, RX_TIMESLICE = 20, MAX_RETRIES = 0, VERSION_MAJOR = 0, VERSION_MINOR = 1, VERSION_PATCH = 0; + static const uint16_t packet_max_wait = 500, rx_timeslice = 20, max_retries = 0, version_major = 0, version_minor = 1, version_patch = 0; uint8_t packet_retries, sync; uint16_t buffer_next_index; uint32_t bytes_received; From 3c32770faf895b9306a8433b6849da37a1b4e554 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Sat, 19 Apr 2025 00:28:50 +0000 Subject: [PATCH 225/787] [cron] Bump distribution date (2025-04-19) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 2260bfc119..bf36617e2c 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-04-18" +//#define STRING_DISTRIBUTION_DATE "2025-04-19" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index e4d0c6679b..b03913446a 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-04-18" + #define STRING_DISTRIBUTION_DATE "2025-04-19" #endif /** From d009c48b11d65897b7432a089c829c6ef2adee53 Mon Sep 17 00:00:00 2001 From: ellensp <530024+ellensp@users.noreply.github.com> Date: Sat, 19 Apr 2025 12:43:31 +1200 Subject: [PATCH 226/787] =?UTF-8?q?=E2=9C=A8=20Simulator:=20Virtual=20serv?= =?UTF-8?q?os,=20BLTouch=20(#27779)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Christopher Pepper --- Marlin/src/HAL/NATIVE_SIM/HAL.h | 10 +- Marlin/src/HAL/NATIVE_SIM/Servo.cpp | 104 ++++++++++++++++++ Marlin/src/HAL/NATIVE_SIM/Servo.h | 48 ++++++++ .../src/HAL/NATIVE_SIM/endstop_interrupts.h | 30 +++++ Marlin/src/HAL/NATIVE_SIM/servo_private.h | 79 ------------- Marlin/src/HAL/shared/servo.h | 30 ++--- ini/native.ini | 2 +- 7 files changed, 206 insertions(+), 97 deletions(-) create mode 100644 Marlin/src/HAL/NATIVE_SIM/Servo.cpp create mode 100644 Marlin/src/HAL/NATIVE_SIM/Servo.h create mode 100644 Marlin/src/HAL/NATIVE_SIM/endstop_interrupts.h delete mode 100644 Marlin/src/HAL/NATIVE_SIM/servo_private.h diff --git a/Marlin/src/HAL/NATIVE_SIM/HAL.h b/Marlin/src/HAL/NATIVE_SIM/HAL.h index f741d0b246..ffede7ef34 100644 --- a/Marlin/src/HAL/NATIVE_SIM/HAL.h +++ b/Marlin/src/HAL/NATIVE_SIM/HAL.h @@ -52,7 +52,9 @@ uint8_t _getc(); // ------------------------ #define CPU_32_BIT -#define SHARED_SERVOS HAS_SERVOS // Use shared/servos.cpp + +class Servo; +typedef Servo hal_servo_t; #define F_CPU 100000000 #define SystemCoreClock F_CPU @@ -232,8 +234,10 @@ public: * No option to invert the duty cycle [default = false] * No option to change the scale of the provided value to enable finer PWM duty control [default = 255] */ - static void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t=255, const bool=false) { - analogWrite(pin, v); + static void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size=255, const bool invert=false) { + auto value = map(v, 0, v_size, 0, UINT16_MAX); + value = invert ? UINT16_MAX - value : value; + analogWrite(pin, value); } static void set_pwm_frequency(const pin_t, int) {} diff --git a/Marlin/src/HAL/NATIVE_SIM/Servo.cpp b/Marlin/src/HAL/NATIVE_SIM/Servo.cpp new file mode 100644 index 0000000000..a15eda1bf6 --- /dev/null +++ b/Marlin/src/HAL/NATIVE_SIM/Servo.cpp @@ -0,0 +1,104 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#include "../platforms.h" + +#ifdef __PLAT_NATIVE_SIM__ + +#include "../../inc/MarlinConfig.h" + +#if HAS_SERVOS + +#include "Servo.h" + +//#define DEBUG_SERVOS +#define DEBUG_OUT ENABLED(DEBUG_SERVOS) +#include "../../../core/debug_out.h" + +uint8_t ServoCount = 0; // the total number of attached servos + +Servo::Servo() { + // Constructor stub + DEBUG_ECHOLNPGM("Debug Servo: constructor"); + this->servoIndex = ServoCount++; // assign a servo index to this instance +} + +uint8_t Servo::attach(int pin) { + // Attach stub + DEBUG_ECHOLNPGM("Debug Servo: attach to pin ", pin, " servo index ", this->servoIndex); + return attach(pin, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH); +} + +uint8_t Servo::attach(int pin, int min, int max) { + // Attach with min and max stub + DEBUG_ECHOLNPGM("Debug Servo: attach to pin ", pin, " with min ", min, " and max ", max); + if (pin > 0) servo_pin = pin; + return this->servoIndex; +} + +void Servo::detach() { + // Detach stub + DEBUG_ECHOLNPGM("Debug Servo: detach"); +} + +// If value is < 200 it is treated as an angle, otherwise as pulse width in microseconds +void Servo::write(int value) { + if (value < MIN_PULSE_WIDTH) { // treat values less than 544 as angles in degrees (valid values in microseconds are handled as microseconds) + value = map(constrain(value, 0, 180), 0, 180, SERVO_MIN_US(min), SERVO_MAX_US(max)); + } + writeMicroseconds(value); + DEBUG_ECHOLNPGM("Debug Servo: write ", value); +} + +void Servo::writeMicroseconds(int value) { + // Simulate the servo movement + this->value = value; + hal.set_pwm_duty(pin_t(this->servo_pin), (float(value) / 20000) * UINT16_MAX, UINT16_MAX); + DEBUG_ECHOLNPGM("Debug Servo: write microseconds ", value); +} + +int Servo::read() { + // Read stub + DEBUG_ECHOLNPGM("Debug Servo: read ", this->value); + return this->value; +} + +int Servo::readMicroseconds() { + // Read microseconds stub + DEBUG_ECHOLNPGM("Debug Servo: read microseconds"); + return 0; +} + +bool Servo::attached() { + // Attached stub + DEBUG_ECHOLNPGM("Debug Servo: attached"); + return false; +} + +int Servo::move(const unsigned char cmd) { + // Move stub + DEBUG_ECHOLNPGM("Debug Servo: move ", cmd); + write(cmd); + return 0; +} + +#endif // HAS_SERVOS +#endif // __PLAT_NATIVE_SIM__ diff --git a/Marlin/src/HAL/NATIVE_SIM/Servo.h b/Marlin/src/HAL/NATIVE_SIM/Servo.h new file mode 100644 index 0000000000..428871142c --- /dev/null +++ b/Marlin/src/HAL/NATIVE_SIM/Servo.h @@ -0,0 +1,48 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +#define MIN_PULSE_WIDTH 544 // the shortest pulse sent to a servo +#define MAX_PULSE_WIDTH 2400 // the longest pulse sent to a servo +#define DEFAULT_PULSE_WIDTH 1500 // default pulse width when servo is attached +#define SERVO_MIN_US(v) (MIN_PULSE_WIDTH - (v) * 4) // minimum value in uS for this servo +#define SERVO_MAX_US(v) (MAX_PULSE_WIDTH - (v) * 4) // maximum value in uS for this servo + +class Servo { +public: + Servo(); + uint8_t attach(int pin); // Attach the given pin to the next free channel, set pinMode, return channel number or INVALID_SERVO if failure + uint8_t attach(int pin, int min, int max); // As above but also set min and max values for writes. + void detach(); + void write(int value); // If value is < 200 it's treated as an angle, otherwise as pulse width in microseconds + void writeMicroseconds(int value); // Write pulse width in microseconds + int read(); // Return current pulse width as an angle between 0 and 180 degrees + int readMicroseconds(); // Return current pulse width in microseconds for this servo + bool attached(); // Return true if this servo is attached, otherwise false + int move (const unsigned char cmd); +private: + uint8_t servoIndex; // Index into the channel data for this servo + int8_t min; // Minimum is this value times 4 added to MIN_PULSE_WIDTH + int8_t max; // Maximum is this value times 4 added to MAX_PULSE_WIDTH + int value; // Pulse width in microseconds for this servo + int servo_pin = 0; // pin number for this servo +}; diff --git a/Marlin/src/HAL/NATIVE_SIM/endstop_interrupts.h b/Marlin/src/HAL/NATIVE_SIM/endstop_interrupts.h new file mode 100644 index 0000000000..e74c312274 --- /dev/null +++ b/Marlin/src/HAL/NATIVE_SIM/endstop_interrupts.h @@ -0,0 +1,30 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +#error "ENDSTOP_INTERRUPTS_FEATURE is not supported in this simulation environment." + +void setup_endstop_interrupts() { + // This function is a stub for setting up endstop interrupts. + // Since this is a simulation environment, actual hardware interrupts + // are not applicable. Add any necessary simulation-specific logic here. +} diff --git a/Marlin/src/HAL/NATIVE_SIM/servo_private.h b/Marlin/src/HAL/NATIVE_SIM/servo_private.h deleted file mode 100644 index e0eb30ab28..0000000000 --- a/Marlin/src/HAL/NATIVE_SIM/servo_private.h +++ /dev/null @@ -1,79 +0,0 @@ -/** - * Marlin 3D Printer Firmware - * Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * - * Based on Sprinter and grbl. - * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ -#pragma once - -/** - * servo.h - Interrupt driven Servo library for Arduino using 16 bit timers- Version 2 - * Copyright (c) 2009 Michael Margolis. All right reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/** - * Based on "servo.h - Interrupt driven Servo library for Arduino using 16 bit timers - - * Version 2 Copyright (c) 2009 Michael Margolis. All right reserved. - * - * The only modification was to update/delete macros to match the LPC176x. - * - */ - -#include - -// Macros -//values in microseconds -#define MIN_PULSE_WIDTH 544 // the shortest pulse sent to a servo -#define MAX_PULSE_WIDTH 2400 // the longest pulse sent to a servo -#define DEFAULT_PULSE_WIDTH 1500 // default pulse width when servo is attached -#define REFRESH_INTERVAL 20000 // minimum time to refresh servos in microseconds - -#define MAX_SERVOS 4 - -#define INVALID_SERVO 255 // flag indicating an invalid servo index - -// Types - -typedef struct { - uint8_t nbr : 8 ; // a pin number from 0 to 254 (255 signals invalid pin) - uint8_t isActive : 1 ; // true if this channel is enabled, pin not pulsed if false -} ServoPin_t; - -typedef struct { - ServoPin_t Pin; - unsigned int pulse_width; // pulse width in microseconds -} ServoInfo_t; - -// Global variables - -extern uint8_t ServoCount; -extern ServoInfo_t servo_info[MAX_SERVOS]; diff --git a/Marlin/src/HAL/shared/servo.h b/Marlin/src/HAL/shared/servo.h index 0101fcb628..85e645146c 100644 --- a/Marlin/src/HAL/shared/servo.h +++ b/Marlin/src/HAL/shared/servo.h @@ -59,7 +59,7 @@ * write() - Sets the servo angle in degrees. (invalid angle that is valid as pulse in microseconds is treated as microseconds) * writeMicroseconds() - Sets the servo pulse width in microseconds * read() - Gets the last written servo pulse width as an angle between 0 and 180. - * readMicroseconds() - Gets the last written servo pulse width in microseconds. (was read_us() in first release) + * readMicroseconds() - Gets the last written servo pulse width in microseconds. * attached() - Returns true if there is a servo attached. * detach() - Stops an attached servos from pulsing its i/o pin. * move(angle) - Sequence of attach(0), write(angle), @@ -86,6 +86,8 @@ #include "../ESP32/Servo.h" #elif defined(__PLAT_RP2040__) #include "../RP2040/Servo.h" +#elif defined(__PLAT_NATIVE_SIM__) + #include "../NATIVE_SIM/Servo.h" #else #include @@ -100,22 +102,22 @@ class Servo { public: Servo(); - int8_t attach(const int pin); // attach the given pin to the next free channel, set pinMode, return channel number (-1 on fail) - int8_t attach(const int pin, const int min, const int max); // as above but also sets min and max values for writes. + int8_t attach(const int pin); // Attach the given pin to the next free channel, set pinMode, return channel number (-1 on fail) + int8_t attach(const int pin, const int min, const int max); // As above but also set min and max values for writes. void detach(); - void write(int value); // if value is < 200 it is treated as an angle, otherwise as pulse width in microseconds - void writeMicroseconds(int value); // write pulse width in microseconds - void move(const int value); // attach the servo, then move to value - // if value is < 200 it is treated as an angle, otherwise as pulse width in microseconds - // if DEACTIVATE_SERVOS_AFTER_MOVE wait SERVO_DELAY, then detach - int read(); // returns current pulse width as an angle between 0 and 180 degrees - int readMicroseconds(); // returns current pulse width in microseconds for this servo (was read_us() in first release) - bool attached(); // return true if this servo is attached, otherwise false + void write(int value); // If value is < 200 it is treated as an angle, otherwise as pulse width in microseconds + void writeMicroseconds(int value); // Write pulse width in microseconds + void move(const int value); // Attach the servo, then move to value + // If value is < 200 it is treated as an angle, otherwise as pulse width in microseconds + // If DEACTIVATE_SERVOS_AFTER_MOVE wait SERVO_DELAY, then detach + int read(); // Return current pulse width as an angle between 0 and 180 degrees + int readMicroseconds(); // Return current pulse width in microseconds for this servo + bool attached(); // Return true if this servo is attached, otherwise false private: - uint8_t servoIndex; // index into the channel data for this servo - int8_t min; // minimum is this value times 4 added to MIN_PULSE_WIDTH - int8_t max; // maximum is this value times 4 added to MAX_PULSE_WIDTH + uint8_t servoIndex; // Index into the channel data for this servo + int8_t min; // Minimum is this value times 4 added to MIN_PULSE_WIDTH + int8_t max; // Maximum is this value times 4 added to MAX_PULSE_WIDTH }; #endif diff --git a/ini/native.ini b/ini/native.ini index 479155a78c..f01e72ca67 100644 --- a/ini/native.ini +++ b/ini/native.ini @@ -58,7 +58,7 @@ debug_build_flags = -fstack-protector-strong -g -g3 -ggdb lib_compat_mode = off build_src_filter = ${common.default_src_filter} + lib_deps = ${common.lib_deps} - MarlinSimUI=https://github.com/p3p/MarlinSimUI/archive/afe7c1c293.zip + MarlinSimUI=https://github.com/p3p/MarlinSimUI/archive/6ea016e104.zip Adafruit NeoPixel=https://github.com/p3p/Adafruit_NeoPixel/archive/c6b319f447.zip LiquidCrystal=https://github.com/p3p/LiquidCrystal/archive/322fb5fc23.zip extra_scripts = ${common.extra_scripts} From d40bf0d6b271baa6cea9181faef8470ac033fd3c Mon Sep 17 00:00:00 2001 From: B Date: Fri, 18 Apr 2025 17:53:18 -0700 Subject: [PATCH 227/787] =?UTF-8?q?=F0=9F=90=9B=20Fix=20GD32=20ignoring=20?= =?UTF-8?q?SERIAL=5FDMA=20on=20init=20(#27800)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/HAL/GD32_MFL/MarlinSerial.cpp | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/Marlin/src/HAL/GD32_MFL/MarlinSerial.cpp b/Marlin/src/HAL/GD32_MFL/MarlinSerial.cpp index c9b76a4ca4..271247295c 100644 --- a/Marlin/src/HAL/GD32_MFL/MarlinSerial.cpp +++ b/Marlin/src/HAL/GD32_MFL/MarlinSerial.cpp @@ -60,10 +60,9 @@ MarlinSerial& MarlinSerial::get_instance(usart::USART_Base Base, pin_size_t rxPi static MarlinSerial* current_serial_instance = nullptr; static void emergency_callback() { - if (current_serial_instance) { - uint8_t last_data = current_serial_instance->get_last_data(); - emergency_parser.update(current_serial_instance->emergency_state, last_data); - } + if (!current_serial_instance) return; + const uint8_t last_data = current_serial_instance->get_last_data(); + emergency_parser.update(current_serial_instance->emergency_state, last_data); } void MarlinSerial::register_emergency_callback(void (*callback)()) { @@ -72,26 +71,23 @@ MarlinSerial& MarlinSerial::get_instance(usart::USART_Base Base, pin_size_t rxPi #endif void MarlinSerial::begin(unsigned long baudrate, uint16_t config) { - UsartSerial::begin(baudrate, config); - #if DISABLED(SERIAL_DMA) - #if ENABLED(EMERGENCY_PARSER) - current_serial_instance = this; - register_emergency_callback(emergency_callback); - #endif + UsartSerial::begin(baudrate, config, ENABLED(SERIAL_DMA)); + #if ENABLED(EMERGENCY_PARSER) && DISABLED(SERIAL_DMA) + current_serial_instance = this; + register_emergency_callback(emergency_callback); #endif } void MarlinSerial::updateRxDmaBuffer() { #if ENABLED(EMERGENCY_PARSER) // Get the number of bytes available in the receive buffer - size_t available_bytes = usart_.available_for_read(true); - uint8_t data; + const size_t available_bytes = usart_.available_for_read(true); // Process only the available data for (size_t i = 0; i < available_bytes; ++i) { - if (usart_.read_rx_buffer(data)) { + uint8_t data; + if (usart_.read_rx_buffer(data)) emergency_parser.update(emergency_state, data); - } } #endif // Call the base class implementation to handle any additional updates From 067c830e840b69f04b7ce9f9d9a647cdf58090e1 Mon Sep 17 00:00:00 2001 From: B Date: Fri, 18 Apr 2025 17:55:26 -0700 Subject: [PATCH 228/787] =?UTF-8?q?=F0=9F=93=8C=20GD32=20platform=20v1.0.3?= =?UTF-8?q?=20(and=20Arduino=20v1.0.4)=20(#27801)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ini/gd32.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ini/gd32.ini b/ini/gd32.ini index e983f496ec..5187895021 100644 --- a/ini/gd32.ini +++ b/ini/gd32.ini @@ -10,7 +10,7 @@ #################################### [gd32_base] -platform = https://github.com/bmourit/platform-mfl/archive/refs/tags/V1.0.2.zip +platform = https://github.com/bmourit/platform-mfl/archive/refs/tags/V1.0.3.zip board_build.core = gd32 build_src_filter = ${common.default_src_filter} + + build_unflags = -std=gnu++11 -std=gnu++14 -std=gnu++17 From 26b3f0b00f897a0624fd96d064f50cb3cf54d3b2 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Fri, 18 Apr 2025 19:56:46 -0500 Subject: [PATCH 229/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Pla?= =?UTF-8?q?nner::max=5Fjerk=20always=20xyze=5Fpos=5Ft?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/module/planner.cpp | 2 +- Marlin/src/module/planner.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index b3df490cf0..881e11f4c0 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -157,7 +157,7 @@ uint32_t Planner::max_acceleration_steps_per_s2[DISTINCT_AXES]; // (steps/s^2) D float Planner::max_e_jerk[DISTINCT_E]; // Calculated from junction_deviation_mm #endif #else // CLASSIC_JERK - TERN(HAS_LINEAR_E_JERK, xyz_pos_t, xyze_pos_t) Planner::max_jerk; + xyze_pos_t Planner::max_jerk; #endif #if ENABLED(SD_ABORT_ON_ENDSTOP_HIT) diff --git a/Marlin/src/module/planner.h b/Marlin/src/module/planner.h index 318be33131..e8bacddd9f 100644 --- a/Marlin/src/module/planner.h +++ b/Marlin/src/module/planner.h @@ -494,7 +494,7 @@ class Planner { #endif #else // CLASSIC_JERK // (mm/s^2) M205 XYZ(E) - The largest speed change requiring no acceleration. - static TERN(HAS_LINEAR_E_JERK, xyz_pos_t, xyze_pos_t) max_jerk; + static xyze_pos_t max_jerk; #endif #if HAS_LEVELING From 87f26e77ff2180fc487e2547487915eee4d526cd Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Sun, 20 Apr 2025 00:33:22 +0000 Subject: [PATCH 230/787] [cron] Bump distribution date (2025-04-20) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index bf36617e2c..85663d4899 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-04-19" +//#define STRING_DISTRIBUTION_DATE "2025-04-20" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index b03913446a..f46988c11b 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-04-19" + #define STRING_DISTRIBUTION_DATE "2025-04-20" #endif /** From b97b09413f1cd805743240a1f3f0c94f4a10d1e2 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sat, 19 Apr 2025 20:04:59 -0500 Subject: [PATCH 231/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Add?= =?UTF-8?q?=20stepper/control.cpp?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/HAL/DUE/fastio/G2_PWM.cpp | 3 +- Marlin/src/HAL/DUE/fastio/G2_PWM.h | 5 +- Marlin/src/inc/Conditionals-5-post.h | 4 + Marlin/src/module/stepper.cpp | 735 --------------------- Marlin/src/module/stepper/control.cpp | 764 ++++++++++++++++++++++ Marlin/src/pins/sam/pins_PRINTRBOARD_G2.h | 8 +- ini/features.ini | 1 + 7 files changed, 776 insertions(+), 744 deletions(-) create mode 100644 Marlin/src/module/stepper/control.cpp diff --git a/Marlin/src/HAL/DUE/fastio/G2_PWM.cpp b/Marlin/src/HAL/DUE/fastio/G2_PWM.cpp index 403e3356e1..745e4205bc 100644 --- a/Marlin/src/HAL/DUE/fastio/G2_PWM.cpp +++ b/Marlin/src/HAL/DUE/fastio/G2_PWM.cpp @@ -40,11 +40,12 @@ * Some jitter in the Vref signal is OK so the interrupt priority is left at its default value. */ -#include "../../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfigPre.h" #if MB(PRINTRBOARD_G2) #include "G2_PWM.h" +#include "../../../module/stepper.h" #if PIN_EXISTS(MOTOR_CURRENT_PWM_X) #define G2_PWM_X 1 diff --git a/Marlin/src/HAL/DUE/fastio/G2_PWM.h b/Marlin/src/HAL/DUE/fastio/G2_PWM.h index 054eb2cf80..7fb2aaf7a8 100644 --- a/Marlin/src/HAL/DUE/fastio/G2_PWM.h +++ b/Marlin/src/HAL/DUE/fastio/G2_PWM.h @@ -26,10 +26,7 @@ * PR #7500. It is hardwired for the PRINTRBOARD_G2 Motor Current needs. */ -#include "../../../inc/MarlinConfigPre.h" -#include "../../../module/stepper.h" -//C:\Users\bobku\Documents\GitHub\Marlin-Bob-2\Marlin\src\module\stepper.h -//C:\Users\bobku\Documents\GitHub\Marlin-Bob-2\Marlin\src\HAL\HAL_DUE\G2_PWM.h +#include #define PWM_PERIOD_US 100 // base repetition rate in micro seconds diff --git a/Marlin/src/inc/Conditionals-5-post.h b/Marlin/src/inc/Conditionals-5-post.h index 380e8e6071..920031dcdb 100644 --- a/Marlin/src/inc/Conditionals-5-post.h +++ b/Marlin/src/inc/Conditionals-5-post.h @@ -3012,6 +3012,10 @@ #undef MICROSTEP_MODES #endif +#if MB(PRINTRBOARD_G2) || ANY(HAS_MOTOR_CURRENT_SPI, HAS_MOTOR_CURRENT_PWM, HAS_MICROSTEPS) + #define HAS_STEPPER_CONTROL 1 +#endif + /** * Helper Macros for heaters and extruder fan */ diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp index 85c7521960..1340cd9157 100644 --- a/Marlin/src/module/stepper.cpp +++ b/Marlin/src/module/stepper.cpp @@ -3627,738 +3627,3 @@ void Stepper::report_positions() { } #endif // BABYSTEPPING - -/** - * Software-controlled Stepper Motor Current - */ - -#if HAS_MOTOR_CURRENT_SPI - - // From Arduino DigitalPotControl example - void Stepper::set_digipot_value_spi(const int16_t address, const int16_t value) { - WRITE(DIGIPOTSS_PIN, LOW); // Take the SS pin low to select the chip - SPI.transfer(address); // Send the address and value via SPI - SPI.transfer(value); - WRITE(DIGIPOTSS_PIN, HIGH); // Take the SS pin high to de-select the chip - //delay(10); - } - -#endif // HAS_MOTOR_CURRENT_SPI - -#if HAS_MOTOR_CURRENT_PWM - - void Stepper::refresh_motor_power() { - if (!initialized) return; - for (uint8_t i = 0; i < COUNT(motor_current_setting); ++i) { - switch (i) { - #if ANY_PIN(MOTOR_CURRENT_PWM_XY, MOTOR_CURRENT_PWM_X, MOTOR_CURRENT_PWM_Y, MOTOR_CURRENT_PWM_I, MOTOR_CURRENT_PWM_J, MOTOR_CURRENT_PWM_K, MOTOR_CURRENT_PWM_U, MOTOR_CURRENT_PWM_V, MOTOR_CURRENT_PWM_W) - case 0: - #endif - #if HAS_MOTOR_CURRENT_PWM_Z - case 1: - #endif - #if HAS_MOTOR_CURRENT_PWM_E - case 2: - #endif - set_digipot_current(i, motor_current_setting[i]); - default: break; - } - } - } - -#endif // HAS_MOTOR_CURRENT_PWM - -#if !MB(PRINTRBOARD_G2) - - #if HAS_MOTOR_CURRENT_SPI || HAS_MOTOR_CURRENT_PWM - - void Stepper::set_digipot_current(const uint8_t driver, const int16_t current) { - if (WITHIN(driver, 0, COUNT(motor_current_setting) - 1)) - motor_current_setting[driver] = current; // update motor_current_setting - - if (!initialized) return; - - #if HAS_MOTOR_CURRENT_SPI - - //SERIAL_ECHOLNPGM("Digipotss current ", current); - - const uint8_t digipot_ch[] = DIGIPOT_CHANNELS; - set_digipot_value_spi(digipot_ch[driver], current); - - #elif HAS_MOTOR_CURRENT_PWM - - #define _WRITE_CURRENT_PWM(P) hal.set_pwm_duty(pin_t(MOTOR_CURRENT_PWM_## P ##_PIN), 255L * current / (MOTOR_CURRENT_PWM_RANGE)) - switch (driver) { - case 0: - #if PIN_EXISTS(MOTOR_CURRENT_PWM_X) - _WRITE_CURRENT_PWM(X); - #endif - #if PIN_EXISTS(MOTOR_CURRENT_PWM_Y) - _WRITE_CURRENT_PWM(Y); - #endif - #if PIN_EXISTS(MOTOR_CURRENT_PWM_XY) - _WRITE_CURRENT_PWM(XY); - #endif - #if PIN_EXISTS(MOTOR_CURRENT_PWM_I) - _WRITE_CURRENT_PWM(I); - #endif - #if PIN_EXISTS(MOTOR_CURRENT_PWM_J) - _WRITE_CURRENT_PWM(J); - #endif - #if PIN_EXISTS(MOTOR_CURRENT_PWM_K) - _WRITE_CURRENT_PWM(K); - #endif - #if PIN_EXISTS(MOTOR_CURRENT_PWM_U) - _WRITE_CURRENT_PWM(U); - #endif - #if PIN_EXISTS(MOTOR_CURRENT_PWM_V) - _WRITE_CURRENT_PWM(V); - #endif - #if PIN_EXISTS(MOTOR_CURRENT_PWM_W) - _WRITE_CURRENT_PWM(W); - #endif - break; - case 1: - #if HAS_MOTOR_CURRENT_PWM_Z - _WRITE_CURRENT_PWM(Z); - #endif - break; - case 2: - #if PIN_EXISTS(MOTOR_CURRENT_PWM_E) - _WRITE_CURRENT_PWM(E); - #endif - #if PIN_EXISTS(MOTOR_CURRENT_PWM_E0) - _WRITE_CURRENT_PWM(E0); - #endif - #if PIN_EXISTS(MOTOR_CURRENT_PWM_E1) - _WRITE_CURRENT_PWM(E1); - #endif - break; - } - #endif - } - - void Stepper::digipot_init() { - - #if HAS_MOTOR_CURRENT_SPI - - SPI.begin(); - SET_OUTPUT(DIGIPOTSS_PIN); - - for (uint8_t i = 0; i < COUNT(motor_current_setting); ++i) - set_digipot_current(i, motor_current_setting[i]); - - #elif HAS_MOTOR_CURRENT_PWM - - #ifdef __SAM3X8E__ - #define _RESET_CURRENT_PWM_FREQ(P) NOOP - #else - #define _RESET_CURRENT_PWM_FREQ(P) hal.set_pwm_frequency(pin_t(P), MOTOR_CURRENT_PWM_FREQUENCY) - #endif - #define INIT_CURRENT_PWM(P) do{ SET_PWM(MOTOR_CURRENT_PWM_## P ##_PIN); _RESET_CURRENT_PWM_FREQ(MOTOR_CURRENT_PWM_## P ##_PIN); }while(0) - - #if PIN_EXISTS(MOTOR_CURRENT_PWM_X) - INIT_CURRENT_PWM(X); - #endif - #if PIN_EXISTS(MOTOR_CURRENT_PWM_Y) - INIT_CURRENT_PWM(Y); - #endif - #if PIN_EXISTS(MOTOR_CURRENT_PWM_XY) - INIT_CURRENT_PWM(XY); - #endif - #if PIN_EXISTS(MOTOR_CURRENT_PWM_I) - INIT_CURRENT_PWM(I); - #endif - #if PIN_EXISTS(MOTOR_CURRENT_PWM_J) - INIT_CURRENT_PWM(J); - #endif - #if PIN_EXISTS(MOTOR_CURRENT_PWM_K) - INIT_CURRENT_PWM(K); - #endif - #if PIN_EXISTS(MOTOR_CURRENT_PWM_U) - INIT_CURRENT_PWM(U); - #endif - #if PIN_EXISTS(MOTOR_CURRENT_PWM_V) - INIT_CURRENT_PWM(V); - #endif - #if PIN_EXISTS(MOTOR_CURRENT_PWM_W) - INIT_CURRENT_PWM(W); - #endif - #if HAS_MOTOR_CURRENT_PWM_Z - INIT_CURRENT_PWM(Z); - #endif - #if PIN_EXISTS(MOTOR_CURRENT_PWM_E) - INIT_CURRENT_PWM(E); - #endif - #if PIN_EXISTS(MOTOR_CURRENT_PWM_E0) - INIT_CURRENT_PWM(E0); - #endif - #if PIN_EXISTS(MOTOR_CURRENT_PWM_E1) - INIT_CURRENT_PWM(E1); - #endif - - refresh_motor_power(); - - #endif - } - - #endif - -#else // PRINTRBOARD_G2 - - #include HAL_PATH(.., fastio/G2_PWM.h) - -#endif - -#if HAS_MICROSTEPS - - /** - * Software-controlled Microstepping - */ - - void Stepper::microstep_init() { - #if HAS_X_MS_PINS - SET_OUTPUT(X_MS1_PIN); SET_OUTPUT(X_MS2_PIN); - #if PIN_EXISTS(X_MS3) - SET_OUTPUT(X_MS3_PIN); - #endif - #endif - #if HAS_X2_MS_PINS - SET_OUTPUT(X2_MS1_PIN); SET_OUTPUT(X2_MS2_PIN); - #if PIN_EXISTS(X2_MS3) - SET_OUTPUT(X2_MS3_PIN); - #endif - #endif - #if HAS_Y_MS_PINS - SET_OUTPUT(Y_MS1_PIN); SET_OUTPUT(Y_MS2_PIN); - #if PIN_EXISTS(Y_MS3) - SET_OUTPUT(Y_MS3_PIN); - #endif - #endif - #if HAS_Y2_MS_PINS - SET_OUTPUT(Y2_MS1_PIN); SET_OUTPUT(Y2_MS2_PIN); - #if PIN_EXISTS(Y2_MS3) - SET_OUTPUT(Y2_MS3_PIN); - #endif - #endif - #if HAS_Z_MS_PINS - SET_OUTPUT(Z_MS1_PIN); SET_OUTPUT(Z_MS2_PIN); - #if PIN_EXISTS(Z_MS3) - SET_OUTPUT(Z_MS3_PIN); - #endif - #endif - #if HAS_Z2_MS_PINS - SET_OUTPUT(Z2_MS1_PIN); SET_OUTPUT(Z2_MS2_PIN); - #if PIN_EXISTS(Z2_MS3) - SET_OUTPUT(Z2_MS3_PIN); - #endif - #endif - #if HAS_Z3_MS_PINS - SET_OUTPUT(Z3_MS1_PIN); SET_OUTPUT(Z3_MS2_PIN); - #if PIN_EXISTS(Z3_MS3) - SET_OUTPUT(Z3_MS3_PIN); - #endif - #endif - #if HAS_Z4_MS_PINS - SET_OUTPUT(Z4_MS1_PIN); SET_OUTPUT(Z4_MS2_PIN); - #if PIN_EXISTS(Z4_MS3) - SET_OUTPUT(Z4_MS3_PIN); - #endif - #endif - #if HAS_I_MS_PINS - SET_OUTPUT(I_MS1_PIN); SET_OUTPUT(I_MS2_PIN); - #if PIN_EXISTS(I_MS3) - SET_OUTPUT(I_MS3_PIN); - #endif - #endif - #if HAS_J_MS_PINS - SET_OUTPUT(J_MS1_PIN); SET_OUTPUT(J_MS2_PIN); - #if PIN_EXISTS(J_MS3) - SET_OUTPUT(J_MS3_PIN); - #endif - #endif - #if HAS_K_MS_PINS - SET_OUTPUT(K_MS1_PIN); SET_OUTPUT(K_MS2_PIN); - #if PIN_EXISTS(K_MS3) - SET_OUTPUT(K_MS3_PIN); - #endif - #endif - #if HAS_U_MS_PINS - SET_OUTPUT(U_MS1_PIN); SET_OUTPUT(U_MS2_PIN); - #if PIN_EXISTS(U_MS3) - SET_OUTPUT(U_MS3_PIN); - #endif - #endif - #if HAS_V_MS_PINS - SET_OUTPUT(V_MS1_PIN); SET_OUTPUT(V_MS2_PIN); - #if PIN_EXISTS(V_MS3) - SET_OUTPUT(V_MS3_PIN); - #endif - #endif - #if HAS_W_MS_PINS - SET_OUTPUT(W_MS1_PIN); SET_OUTPUT(W_MS2_PIN); - #if PIN_EXISTS(W_MS3) - SET_OUTPUT(W_MS3_PIN); - #endif - #endif - #if HAS_E0_MS_PINS - SET_OUTPUT(E0_MS1_PIN); SET_OUTPUT(E0_MS2_PIN); - #if PIN_EXISTS(E0_MS3) - SET_OUTPUT(E0_MS3_PIN); - #endif - #endif - #if HAS_E1_MS_PINS - SET_OUTPUT(E1_MS1_PIN); SET_OUTPUT(E1_MS2_PIN); - #if PIN_EXISTS(E1_MS3) - SET_OUTPUT(E1_MS3_PIN); - #endif - #endif - #if HAS_E2_MS_PINS - SET_OUTPUT(E2_MS1_PIN); SET_OUTPUT(E2_MS2_PIN); - #if PIN_EXISTS(E2_MS3) - SET_OUTPUT(E2_MS3_PIN); - #endif - #endif - #if HAS_E3_MS_PINS - SET_OUTPUT(E3_MS1_PIN); SET_OUTPUT(E3_MS2_PIN); - #if PIN_EXISTS(E3_MS3) - SET_OUTPUT(E3_MS3_PIN); - #endif - #endif - #if HAS_E4_MS_PINS - SET_OUTPUT(E4_MS1_PIN); SET_OUTPUT(E4_MS2_PIN); - #if PIN_EXISTS(E4_MS3) - SET_OUTPUT(E4_MS3_PIN); - #endif - #endif - #if HAS_E5_MS_PINS - SET_OUTPUT(E5_MS1_PIN); SET_OUTPUT(E5_MS2_PIN); - #if PIN_EXISTS(E5_MS3) - SET_OUTPUT(E5_MS3_PIN); - #endif - #endif - #if HAS_E6_MS_PINS - SET_OUTPUT(E6_MS1_PIN); SET_OUTPUT(E6_MS2_PIN); - #if PIN_EXISTS(E6_MS3) - SET_OUTPUT(E6_MS3_PIN); - #endif - #endif - #if HAS_E7_MS_PINS - SET_OUTPUT(E7_MS1_PIN); SET_OUTPUT(E7_MS2_PIN); - #if PIN_EXISTS(E7_MS3) - SET_OUTPUT(E7_MS3_PIN); - #endif - #endif - - static const uint8_t microstep_modes[] = MICROSTEP_MODES; - for (uint16_t i = 0; i < COUNT(microstep_modes); i++) - microstep_mode(i, microstep_modes[i]); - } - - void Stepper::microstep_ms(const uint8_t driver, const int8_t ms1, const int8_t ms2, const int8_t ms3) { - if (ms1 >= 0) switch (driver) { - #if HAS_X_MS_PINS || HAS_X2_MS_PINS - case X_AXIS: - #if HAS_X_MS_PINS - WRITE(X_MS1_PIN, ms1); - #endif - #if HAS_X2_MS_PINS - WRITE(X2_MS1_PIN, ms1); - #endif - break; - #endif - #if HAS_Y_MS_PINS || HAS_Y2_MS_PINS - case Y_AXIS: - #if HAS_Y_MS_PINS - WRITE(Y_MS1_PIN, ms1); - #endif - #if HAS_Y2_MS_PINS - WRITE(Y2_MS1_PIN, ms1); - #endif - break; - #endif - #if HAS_SOME_Z_MS_PINS - case Z_AXIS: - #if HAS_Z_MS_PINS - WRITE(Z_MS1_PIN, ms1); - #endif - #if HAS_Z2_MS_PINS - WRITE(Z2_MS1_PIN, ms1); - #endif - #if HAS_Z3_MS_PINS - WRITE(Z3_MS1_PIN, ms1); - #endif - #if HAS_Z4_MS_PINS - WRITE(Z4_MS1_PIN, ms1); - #endif - break; - #endif - #if HAS_I_MS_PINS - case I_AXIS: WRITE(I_MS1_PIN, ms1); break; - #endif - #if HAS_J_MS_PINS - case J_AXIS: WRITE(J_MS1_PIN, ms1); break; - #endif - #if HAS_K_MS_PINS - case K_AXIS: WRITE(K_MS1_PIN, ms1); break; - #endif - #if HAS_U_MS_PINS - case U_AXIS: WRITE(U_MS1_PIN, ms1); break; - #endif - #if HAS_V_MS_PINS - case V_AXIS: WRITE(V_MS1_PIN, ms1); break; - #endif - #if HAS_W_MS_PINS - case W_AXIS: WRITE(W_MS1_PIN, ms1); break; - #endif - #if HAS_E0_MS_PINS - case E_AXIS: WRITE(E0_MS1_PIN, ms1); break; - #endif - #if HAS_E1_MS_PINS - case (E_AXIS + 1): WRITE(E1_MS1_PIN, ms1); break; - #endif - #if HAS_E2_MS_PINS - case (E_AXIS + 2): WRITE(E2_MS1_PIN, ms1); break; - #endif - #if HAS_E3_MS_PINS - case (E_AXIS + 3): WRITE(E3_MS1_PIN, ms1); break; - #endif - #if HAS_E4_MS_PINS - case (E_AXIS + 4): WRITE(E4_MS1_PIN, ms1); break; - #endif - #if HAS_E5_MS_PINS - case (E_AXIS + 5): WRITE(E5_MS1_PIN, ms1); break; - #endif - #if HAS_E6_MS_PINS - case (E_AXIS + 6): WRITE(E6_MS1_PIN, ms1); break; - #endif - #if HAS_E7_MS_PINS - case (E_AXIS + 7): WRITE(E7_MS1_PIN, ms1); break; - #endif - } - if (ms2 >= 0) switch (driver) { - #if HAS_X_MS_PINS || HAS_X2_MS_PINS - case X_AXIS: - #if HAS_X_MS_PINS - WRITE(X_MS2_PIN, ms2); - #endif - #if HAS_X2_MS_PINS - WRITE(X2_MS2_PIN, ms2); - #endif - break; - #endif - #if HAS_Y_MS_PINS || HAS_Y2_MS_PINS - case Y_AXIS: - #if HAS_Y_MS_PINS - WRITE(Y_MS2_PIN, ms2); - #endif - #if HAS_Y2_MS_PINS - WRITE(Y2_MS2_PIN, ms2); - #endif - break; - #endif - #if HAS_SOME_Z_MS_PINS - case Z_AXIS: - #if HAS_Z_MS_PINS - WRITE(Z_MS2_PIN, ms2); - #endif - #if HAS_Z2_MS_PINS - WRITE(Z2_MS2_PIN, ms2); - #endif - #if HAS_Z3_MS_PINS - WRITE(Z3_MS2_PIN, ms2); - #endif - #if HAS_Z4_MS_PINS - WRITE(Z4_MS2_PIN, ms2); - #endif - break; - #endif - #if HAS_I_MS_PINS - case I_AXIS: WRITE(I_MS2_PIN, ms2); break; - #endif - #if HAS_J_MS_PINS - case J_AXIS: WRITE(J_MS2_PIN, ms2); break; - #endif - #if HAS_K_MS_PINS - case K_AXIS: WRITE(K_MS2_PIN, ms2); break; - #endif - #if HAS_U_MS_PINS - case U_AXIS: WRITE(U_MS2_PIN, ms2); break; - #endif - #if HAS_V_MS_PINS - case V_AXIS: WRITE(V_MS2_PIN, ms2); break; - #endif - #if HAS_W_MS_PINS - case W_AXIS: WRITE(W_MS2_PIN, ms2); break; - #endif - #if HAS_E0_MS_PINS - case E_AXIS: WRITE(E0_MS2_PIN, ms2); break; - #endif - #if HAS_E1_MS_PINS - case (E_AXIS + 1): WRITE(E1_MS2_PIN, ms2); break; - #endif - #if HAS_E2_MS_PINS - case (E_AXIS + 2): WRITE(E2_MS2_PIN, ms2); break; - #endif - #if HAS_E3_MS_PINS - case (E_AXIS + 3): WRITE(E3_MS2_PIN, ms2); break; - #endif - #if HAS_E4_MS_PINS - case (E_AXIS + 4): WRITE(E4_MS2_PIN, ms2); break; - #endif - #if HAS_E5_MS_PINS - case (E_AXIS + 5): WRITE(E5_MS2_PIN, ms2); break; - #endif - #if HAS_E6_MS_PINS - case (E_AXIS + 6): WRITE(E6_MS2_PIN, ms2); break; - #endif - #if HAS_E7_MS_PINS - case (E_AXIS + 7): WRITE(E7_MS2_PIN, ms2); break; - #endif - } - if (ms3 >= 0) switch (driver) { - #if HAS_X_MS_PINS || HAS_X2_MS_PINS - case X_AXIS: - #if HAS_X_MS_PINS && PIN_EXISTS(X_MS3) - WRITE(X_MS3_PIN, ms3); - #endif - #if HAS_X2_MS_PINS && PIN_EXISTS(X2_MS3) - WRITE(X2_MS3_PIN, ms3); - #endif - break; - #endif - #if HAS_Y_MS_PINS || HAS_Y2_MS_PINS - case Y_AXIS: - #if HAS_Y_MS_PINS && PIN_EXISTS(Y_MS3) - WRITE(Y_MS3_PIN, ms3); - #endif - #if HAS_Y2_MS_PINS && PIN_EXISTS(Y2_MS3) - WRITE(Y2_MS3_PIN, ms3); - #endif - break; - #endif - #if HAS_SOME_Z_MS_PINS - case Z_AXIS: - #if HAS_Z_MS_PINS && PIN_EXISTS(Z_MS3) - WRITE(Z_MS3_PIN, ms3); - #endif - #if HAS_Z2_MS_PINS && PIN_EXISTS(Z2_MS3) - WRITE(Z2_MS3_PIN, ms3); - #endif - #if HAS_Z3_MS_PINS && PIN_EXISTS(Z3_MS3) - WRITE(Z3_MS3_PIN, ms3); - #endif - #if HAS_Z4_MS_PINS && PIN_EXISTS(Z4_MS3) - WRITE(Z4_MS3_PIN, ms3); - #endif - break; - #endif - #if HAS_I_MS_PINS && PIN_EXISTS(I_MS3) - case I_AXIS: WRITE(I_MS3_PIN, ms3); break; - #endif - #if HAS_J_MS_PINS && PIN_EXISTS(J_MS3) - case J_AXIS: WRITE(J_MS3_PIN, ms3); break; - #endif - #if HAS_K_MS_PINS && PIN_EXISTS(K_MS3) - case K_AXIS: WRITE(K_MS3_PIN, ms3); break; - #endif - #if HAS_U_MS_PINS && PIN_EXISTS(U_MS3) - case U_AXIS: WRITE(U_MS3_PIN, ms3); break; - #endif - #if HAS_V_MS_PINS && PIN_EXISTS(V_MS3) - case V_AXIS: WRITE(V_MS3_PIN, ms3); break; - #endif - #if HAS_W_MS_PINS && PIN_EXISTS(W_MS3) - case W_AXIS: WRITE(W_MS3_PIN, ms3); break; - #endif - #if HAS_E0_MS_PINS && PIN_EXISTS(E0_MS3) - case E_AXIS: WRITE(E0_MS3_PIN, ms3); break; - #endif - #if HAS_E1_MS_PINS && PIN_EXISTS(E1_MS3) - case (E_AXIS + 1): WRITE(E1_MS3_PIN, ms3); break; - #endif - #if HAS_E2_MS_PINS && PIN_EXISTS(E2_MS3) - case (E_AXIS + 2): WRITE(E2_MS3_PIN, ms3); break; - #endif - #if HAS_E3_MS_PINS && PIN_EXISTS(E3_MS3) - case (E_AXIS + 3): WRITE(E3_MS3_PIN, ms3); break; - #endif - #if HAS_E4_MS_PINS && PIN_EXISTS(E4_MS3) - case (E_AXIS + 4): WRITE(E4_MS3_PIN, ms3); break; - #endif - #if HAS_E5_MS_PINS && PIN_EXISTS(E5_MS3) - case (E_AXIS + 5): WRITE(E5_MS3_PIN, ms3); break; - #endif - #if HAS_E6_MS_PINS && PIN_EXISTS(E6_MS3) - case (E_AXIS + 6): WRITE(E6_MS3_PIN, ms3); break; - #endif - #if HAS_E7_MS_PINS && PIN_EXISTS(E7_MS3) - case (E_AXIS + 7): WRITE(E7_MS3_PIN, ms3); break; - #endif - } - } - - // MS1 MS2 MS3 Stepper Driver Microstepping mode table - #ifndef MICROSTEP1 - #define MICROSTEP1 LOW,LOW,LOW - #endif - #if ENABLED(HEROIC_STEPPER_DRIVERS) - #ifndef MICROSTEP128 - #define MICROSTEP128 LOW,HIGH,LOW - #endif - #else - #ifndef MICROSTEP2 - #define MICROSTEP2 HIGH,LOW,LOW - #endif - #ifndef MICROSTEP4 - #define MICROSTEP4 LOW,HIGH,LOW - #endif - #endif - #ifndef MICROSTEP8 - #define MICROSTEP8 HIGH,HIGH,LOW - #endif - #ifndef MICROSTEP16 - #define MICROSTEP16 HIGH,HIGH,LOW - #endif - - void Stepper::microstep_mode(const uint8_t driver, const uint8_t stepping_mode) { - switch (stepping_mode) { - #ifdef MICROSTEP1 - case 1: microstep_ms(driver, MICROSTEP1); break; - #endif - #ifdef MICROSTEP2 - case 2: microstep_ms(driver, MICROSTEP2); break; - #endif - #ifdef MICROSTEP4 - case 4: microstep_ms(driver, MICROSTEP4); break; - #endif - #ifdef MICROSTEP8 - case 8: microstep_ms(driver, MICROSTEP8); break; - #endif - #ifdef MICROSTEP16 - case 16: microstep_ms(driver, MICROSTEP16); break; - #endif - #ifdef MICROSTEP32 - case 32: microstep_ms(driver, MICROSTEP32); break; - #endif - #ifdef MICROSTEP64 - case 64: microstep_ms(driver, MICROSTEP64); break; - #endif - #ifdef MICROSTEP128 - case 128: microstep_ms(driver, MICROSTEP128); break; - #endif - - default: SERIAL_ERROR_MSG("Microsteps unavailable"); break; - } - } - - void Stepper::microstep_readings() { - #define PIN_CHAR(P) SERIAL_CHAR('0' + READ(P##_PIN)) - #define MS_LINE(A) do{ SERIAL_ECHOPGM(" " STRINGIFY(A) ":"); PIN_CHAR(A##_MS1); PIN_CHAR(A##_MS2); }while(0) - SERIAL_ECHOPGM("MS1|2|3 Pins"); - #if HAS_X_MS_PINS - MS_LINE(X); - #if PIN_EXISTS(X_MS3) - PIN_CHAR(X_MS3); - #endif - #endif - #if HAS_Y_MS_PINS - MS_LINE(Y); - #if PIN_EXISTS(Y_MS3) - PIN_CHAR(Y_MS3); - #endif - #endif - #if HAS_Z_MS_PINS - MS_LINE(Z); - #if PIN_EXISTS(Z_MS3) - PIN_CHAR(Z_MS3); - #endif - #endif - #if HAS_I_MS_PINS - MS_LINE(I); - #if PIN_EXISTS(I_MS3) - PIN_CHAR(I_MS3); - #endif - #endif - #if HAS_J_MS_PINS - MS_LINE(J); - #if PIN_EXISTS(J_MS3) - PIN_CHAR(J_MS3); - #endif - #endif - #if HAS_K_MS_PINS - MS_LINE(K); - #if PIN_EXISTS(K_MS3) - PIN_CHAR(K_MS3); - #endif - #endif - #if HAS_U_MS_PINS - MS_LINE(U); - #if PIN_EXISTS(U_MS3) - PIN_CHAR(U_MS3); - #endif - #endif - #if HAS_V_MS_PINS - MS_LINE(V); - #if PIN_EXISTS(V_MS3) - PIN_CHAR(V_MS3); - #endif - #endif - #if HAS_W_MS_PINS - MS_LINE(W); - #if PIN_EXISTS(W_MS3) - PIN_CHAR(W_MS3); - #endif - #endif - #if HAS_E0_MS_PINS - MS_LINE(E0); - #if PIN_EXISTS(E0_MS3) - PIN_CHAR(E0_MS3); - #endif - #endif - #if HAS_E1_MS_PINS - MS_LINE(E1); - #if PIN_EXISTS(E1_MS3) - PIN_CHAR(E1_MS3); - #endif - #endif - #if HAS_E2_MS_PINS - MS_LINE(E2); - #if PIN_EXISTS(E2_MS3) - PIN_CHAR(E2_MS3); - #endif - #endif - #if HAS_E3_MS_PINS - MS_LINE(E3); - #if PIN_EXISTS(E3_MS3) - PIN_CHAR(E3_MS3); - #endif - #endif - #if HAS_E4_MS_PINS - MS_LINE(E4); - #if PIN_EXISTS(E4_MS3) - PIN_CHAR(E4_MS3); - #endif - #endif - #if HAS_E5_MS_PINS - MS_LINE(E5); - #if PIN_EXISTS(E5_MS3) - PIN_CHAR(E5_MS3); - #endif - #endif - #if HAS_E6_MS_PINS - MS_LINE(E6); - #if PIN_EXISTS(E6_MS3) - PIN_CHAR(E6_MS3); - #endif - #endif - #if HAS_E7_MS_PINS - MS_LINE(E7); - #if PIN_EXISTS(E7_MS3) - PIN_CHAR(E7_MS3); - #endif - #endif - SERIAL_EOL(); - } - -#endif // HAS_MICROSTEPS diff --git a/Marlin/src/module/stepper/control.cpp b/Marlin/src/module/stepper/control.cpp new file mode 100644 index 0000000000..0d523c8ed5 --- /dev/null +++ b/Marlin/src/module/stepper/control.cpp @@ -0,0 +1,764 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * stepper/control.cpp + * Control for Stepper Motor Current and Driver Micro-stepping + * (other than Trinamic UART / SPI). + */ + +#include "../stepper.h" + +#if MB(PRINTRBOARD_G2) + #include HAL_PATH(../.., fastio/G2_PWM.h) +#endif + +/** + * Software-controlled Stepper Motor Current + */ + +#if HAS_MOTOR_CURRENT_SPI + + // From Arduino DigitalPotControl example + void Stepper::set_digipot_value_spi(const int16_t address, const int16_t value) { + WRITE(DIGIPOTSS_PIN, LOW); // Take the SS pin low to select the chip + SPI.transfer(address); // Send the address and value via SPI + SPI.transfer(value); + WRITE(DIGIPOTSS_PIN, HIGH); // Take the SS pin high to de-select the chip + //delay(10); + } + +#endif // HAS_MOTOR_CURRENT_SPI + +#if HAS_MOTOR_CURRENT_PWM + + void Stepper::refresh_motor_power() { + if (!initialized) return; + for (uint8_t i = 0; i < COUNT(motor_current_setting); ++i) { + switch (i) { + #if ANY_PIN(MOTOR_CURRENT_PWM_XY, MOTOR_CURRENT_PWM_X, MOTOR_CURRENT_PWM_Y, MOTOR_CURRENT_PWM_I, MOTOR_CURRENT_PWM_J, MOTOR_CURRENT_PWM_K, MOTOR_CURRENT_PWM_U, MOTOR_CURRENT_PWM_V, MOTOR_CURRENT_PWM_W) + case 0: + #endif + #if HAS_MOTOR_CURRENT_PWM_Z + case 1: + #endif + #if HAS_MOTOR_CURRENT_PWM_E + case 2: + #endif + set_digipot_current(i, motor_current_setting[i]); + default: break; + } + } + } + +#endif // HAS_MOTOR_CURRENT_PWM + +/** + * PWM-controlled Stepper Motor Current + */ + +#if !MB(PRINTRBOARD_G2) && (HAS_MOTOR_CURRENT_SPI || HAS_MOTOR_CURRENT_PWM) + + void Stepper::set_digipot_current(const uint8_t driver, const int16_t current) { + if (WITHIN(driver, 0, COUNT(motor_current_setting) - 1)) + motor_current_setting[driver] = current; // update motor_current_setting + + if (!initialized) return; + + #if HAS_MOTOR_CURRENT_SPI + + //SERIAL_ECHOLNPGM("Digipotss current ", current); + + const uint8_t digipot_ch[] = DIGIPOT_CHANNELS; + set_digipot_value_spi(digipot_ch[driver], current); + + #elif HAS_MOTOR_CURRENT_PWM + + #define _WRITE_CURRENT_PWM(P) hal.set_pwm_duty(pin_t(MOTOR_CURRENT_PWM_## P ##_PIN), 255L * current / (MOTOR_CURRENT_PWM_RANGE)) + switch (driver) { + case 0: + #if PIN_EXISTS(MOTOR_CURRENT_PWM_X) + _WRITE_CURRENT_PWM(X); + #endif + #if PIN_EXISTS(MOTOR_CURRENT_PWM_Y) + _WRITE_CURRENT_PWM(Y); + #endif + #if PIN_EXISTS(MOTOR_CURRENT_PWM_XY) + _WRITE_CURRENT_PWM(XY); + #endif + #if PIN_EXISTS(MOTOR_CURRENT_PWM_I) + _WRITE_CURRENT_PWM(I); + #endif + #if PIN_EXISTS(MOTOR_CURRENT_PWM_J) + _WRITE_CURRENT_PWM(J); + #endif + #if PIN_EXISTS(MOTOR_CURRENT_PWM_K) + _WRITE_CURRENT_PWM(K); + #endif + #if PIN_EXISTS(MOTOR_CURRENT_PWM_U) + _WRITE_CURRENT_PWM(U); + #endif + #if PIN_EXISTS(MOTOR_CURRENT_PWM_V) + _WRITE_CURRENT_PWM(V); + #endif + #if PIN_EXISTS(MOTOR_CURRENT_PWM_W) + _WRITE_CURRENT_PWM(W); + #endif + break; + case 1: + #if HAS_MOTOR_CURRENT_PWM_Z + _WRITE_CURRENT_PWM(Z); + #endif + break; + case 2: + #if PIN_EXISTS(MOTOR_CURRENT_PWM_E) + _WRITE_CURRENT_PWM(E); + #endif + #if PIN_EXISTS(MOTOR_CURRENT_PWM_E0) + _WRITE_CURRENT_PWM(E0); + #endif + #if PIN_EXISTS(MOTOR_CURRENT_PWM_E1) + _WRITE_CURRENT_PWM(E1); + #endif + break; + } + #endif + } + + void Stepper::digipot_init() { + + #if HAS_MOTOR_CURRENT_SPI + + SPI.begin(); + SET_OUTPUT(DIGIPOTSS_PIN); + + for (uint8_t i = 0; i < COUNT(motor_current_setting); ++i) + set_digipot_current(i, motor_current_setting[i]); + + #elif HAS_MOTOR_CURRENT_PWM + + #ifdef __SAM3X8E__ + #define _RESET_CURRENT_PWM_FREQ(P) NOOP + #else + #define _RESET_CURRENT_PWM_FREQ(P) hal.set_pwm_frequency(pin_t(P), MOTOR_CURRENT_PWM_FREQUENCY) + #endif + #define INIT_CURRENT_PWM(P) do{ SET_PWM(MOTOR_CURRENT_PWM_## P ##_PIN); _RESET_CURRENT_PWM_FREQ(MOTOR_CURRENT_PWM_## P ##_PIN); }while(0) + + #if PIN_EXISTS(MOTOR_CURRENT_PWM_X) + INIT_CURRENT_PWM(X); + #endif + #if PIN_EXISTS(MOTOR_CURRENT_PWM_Y) + INIT_CURRENT_PWM(Y); + #endif + #if PIN_EXISTS(MOTOR_CURRENT_PWM_XY) + INIT_CURRENT_PWM(XY); + #endif + #if PIN_EXISTS(MOTOR_CURRENT_PWM_I) + INIT_CURRENT_PWM(I); + #endif + #if PIN_EXISTS(MOTOR_CURRENT_PWM_J) + INIT_CURRENT_PWM(J); + #endif + #if PIN_EXISTS(MOTOR_CURRENT_PWM_K) + INIT_CURRENT_PWM(K); + #endif + #if PIN_EXISTS(MOTOR_CURRENT_PWM_U) + INIT_CURRENT_PWM(U); + #endif + #if PIN_EXISTS(MOTOR_CURRENT_PWM_V) + INIT_CURRENT_PWM(V); + #endif + #if PIN_EXISTS(MOTOR_CURRENT_PWM_W) + INIT_CURRENT_PWM(W); + #endif + #if HAS_MOTOR_CURRENT_PWM_Z + INIT_CURRENT_PWM(Z); + #endif + #if PIN_EXISTS(MOTOR_CURRENT_PWM_E) + INIT_CURRENT_PWM(E); + #endif + #if PIN_EXISTS(MOTOR_CURRENT_PWM_E0) + INIT_CURRENT_PWM(E0); + #endif + #if PIN_EXISTS(MOTOR_CURRENT_PWM_E1) + INIT_CURRENT_PWM(E1); + #endif + + refresh_motor_power(); + + #endif + } + +#endif + +/** + * Software-controlled Microstepping with digital pins + */ + +#if HAS_MICROSTEPS + + void Stepper::microstep_init() { + #if HAS_X_MS_PINS + SET_OUTPUT(X_MS1_PIN); SET_OUTPUT(X_MS2_PIN); + #if PIN_EXISTS(X_MS3) + SET_OUTPUT(X_MS3_PIN); + #endif + #endif + #if HAS_X2_MS_PINS + SET_OUTPUT(X2_MS1_PIN); SET_OUTPUT(X2_MS2_PIN); + #if PIN_EXISTS(X2_MS3) + SET_OUTPUT(X2_MS3_PIN); + #endif + #endif + #if HAS_Y_MS_PINS + SET_OUTPUT(Y_MS1_PIN); SET_OUTPUT(Y_MS2_PIN); + #if PIN_EXISTS(Y_MS3) + SET_OUTPUT(Y_MS3_PIN); + #endif + #endif + #if HAS_Y2_MS_PINS + SET_OUTPUT(Y2_MS1_PIN); SET_OUTPUT(Y2_MS2_PIN); + #if PIN_EXISTS(Y2_MS3) + SET_OUTPUT(Y2_MS3_PIN); + #endif + #endif + #if HAS_Z_MS_PINS + SET_OUTPUT(Z_MS1_PIN); SET_OUTPUT(Z_MS2_PIN); + #if PIN_EXISTS(Z_MS3) + SET_OUTPUT(Z_MS3_PIN); + #endif + #endif + #if HAS_Z2_MS_PINS + SET_OUTPUT(Z2_MS1_PIN); SET_OUTPUT(Z2_MS2_PIN); + #if PIN_EXISTS(Z2_MS3) + SET_OUTPUT(Z2_MS3_PIN); + #endif + #endif + #if HAS_Z3_MS_PINS + SET_OUTPUT(Z3_MS1_PIN); SET_OUTPUT(Z3_MS2_PIN); + #if PIN_EXISTS(Z3_MS3) + SET_OUTPUT(Z3_MS3_PIN); + #endif + #endif + #if HAS_Z4_MS_PINS + SET_OUTPUT(Z4_MS1_PIN); SET_OUTPUT(Z4_MS2_PIN); + #if PIN_EXISTS(Z4_MS3) + SET_OUTPUT(Z4_MS3_PIN); + #endif + #endif + #if HAS_I_MS_PINS + SET_OUTPUT(I_MS1_PIN); SET_OUTPUT(I_MS2_PIN); + #if PIN_EXISTS(I_MS3) + SET_OUTPUT(I_MS3_PIN); + #endif + #endif + #if HAS_J_MS_PINS + SET_OUTPUT(J_MS1_PIN); SET_OUTPUT(J_MS2_PIN); + #if PIN_EXISTS(J_MS3) + SET_OUTPUT(J_MS3_PIN); + #endif + #endif + #if HAS_K_MS_PINS + SET_OUTPUT(K_MS1_PIN); SET_OUTPUT(K_MS2_PIN); + #if PIN_EXISTS(K_MS3) + SET_OUTPUT(K_MS3_PIN); + #endif + #endif + #if HAS_U_MS_PINS + SET_OUTPUT(U_MS1_PIN); SET_OUTPUT(U_MS2_PIN); + #if PIN_EXISTS(U_MS3) + SET_OUTPUT(U_MS3_PIN); + #endif + #endif + #if HAS_V_MS_PINS + SET_OUTPUT(V_MS1_PIN); SET_OUTPUT(V_MS2_PIN); + #if PIN_EXISTS(V_MS3) + SET_OUTPUT(V_MS3_PIN); + #endif + #endif + #if HAS_W_MS_PINS + SET_OUTPUT(W_MS1_PIN); SET_OUTPUT(W_MS2_PIN); + #if PIN_EXISTS(W_MS3) + SET_OUTPUT(W_MS3_PIN); + #endif + #endif + #if HAS_E0_MS_PINS + SET_OUTPUT(E0_MS1_PIN); SET_OUTPUT(E0_MS2_PIN); + #if PIN_EXISTS(E0_MS3) + SET_OUTPUT(E0_MS3_PIN); + #endif + #endif + #if HAS_E1_MS_PINS + SET_OUTPUT(E1_MS1_PIN); SET_OUTPUT(E1_MS2_PIN); + #if PIN_EXISTS(E1_MS3) + SET_OUTPUT(E1_MS3_PIN); + #endif + #endif + #if HAS_E2_MS_PINS + SET_OUTPUT(E2_MS1_PIN); SET_OUTPUT(E2_MS2_PIN); + #if PIN_EXISTS(E2_MS3) + SET_OUTPUT(E2_MS3_PIN); + #endif + #endif + #if HAS_E3_MS_PINS + SET_OUTPUT(E3_MS1_PIN); SET_OUTPUT(E3_MS2_PIN); + #if PIN_EXISTS(E3_MS3) + SET_OUTPUT(E3_MS3_PIN); + #endif + #endif + #if HAS_E4_MS_PINS + SET_OUTPUT(E4_MS1_PIN); SET_OUTPUT(E4_MS2_PIN); + #if PIN_EXISTS(E4_MS3) + SET_OUTPUT(E4_MS3_PIN); + #endif + #endif + #if HAS_E5_MS_PINS + SET_OUTPUT(E5_MS1_PIN); SET_OUTPUT(E5_MS2_PIN); + #if PIN_EXISTS(E5_MS3) + SET_OUTPUT(E5_MS3_PIN); + #endif + #endif + #if HAS_E6_MS_PINS + SET_OUTPUT(E6_MS1_PIN); SET_OUTPUT(E6_MS2_PIN); + #if PIN_EXISTS(E6_MS3) + SET_OUTPUT(E6_MS3_PIN); + #endif + #endif + #if HAS_E7_MS_PINS + SET_OUTPUT(E7_MS1_PIN); SET_OUTPUT(E7_MS2_PIN); + #if PIN_EXISTS(E7_MS3) + SET_OUTPUT(E7_MS3_PIN); + #endif + #endif + + static const uint8_t microstep_modes[] = MICROSTEP_MODES; + for (uint16_t i = 0; i < COUNT(microstep_modes); i++) + microstep_mode(i, microstep_modes[i]); + } + + void Stepper::microstep_ms(const uint8_t driver, const int8_t ms1, const int8_t ms2, const int8_t ms3) { + if (ms1 >= 0) switch (driver) { + #if HAS_X_MS_PINS || HAS_X2_MS_PINS + case X_AXIS: + #if HAS_X_MS_PINS + WRITE(X_MS1_PIN, ms1); + #endif + #if HAS_X2_MS_PINS + WRITE(X2_MS1_PIN, ms1); + #endif + break; + #endif + #if HAS_Y_MS_PINS || HAS_Y2_MS_PINS + case Y_AXIS: + #if HAS_Y_MS_PINS + WRITE(Y_MS1_PIN, ms1); + #endif + #if HAS_Y2_MS_PINS + WRITE(Y2_MS1_PIN, ms1); + #endif + break; + #endif + #if HAS_SOME_Z_MS_PINS + case Z_AXIS: + #if HAS_Z_MS_PINS + WRITE(Z_MS1_PIN, ms1); + #endif + #if HAS_Z2_MS_PINS + WRITE(Z2_MS1_PIN, ms1); + #endif + #if HAS_Z3_MS_PINS + WRITE(Z3_MS1_PIN, ms1); + #endif + #if HAS_Z4_MS_PINS + WRITE(Z4_MS1_PIN, ms1); + #endif + break; + #endif + #if HAS_I_MS_PINS + case I_AXIS: WRITE(I_MS1_PIN, ms1); break; + #endif + #if HAS_J_MS_PINS + case J_AXIS: WRITE(J_MS1_PIN, ms1); break; + #endif + #if HAS_K_MS_PINS + case K_AXIS: WRITE(K_MS1_PIN, ms1); break; + #endif + #if HAS_U_MS_PINS + case U_AXIS: WRITE(U_MS1_PIN, ms1); break; + #endif + #if HAS_V_MS_PINS + case V_AXIS: WRITE(V_MS1_PIN, ms1); break; + #endif + #if HAS_W_MS_PINS + case W_AXIS: WRITE(W_MS1_PIN, ms1); break; + #endif + #if HAS_E0_MS_PINS + case E_AXIS: WRITE(E0_MS1_PIN, ms1); break; + #endif + #if HAS_E1_MS_PINS + case (E_AXIS + 1): WRITE(E1_MS1_PIN, ms1); break; + #endif + #if HAS_E2_MS_PINS + case (E_AXIS + 2): WRITE(E2_MS1_PIN, ms1); break; + #endif + #if HAS_E3_MS_PINS + case (E_AXIS + 3): WRITE(E3_MS1_PIN, ms1); break; + #endif + #if HAS_E4_MS_PINS + case (E_AXIS + 4): WRITE(E4_MS1_PIN, ms1); break; + #endif + #if HAS_E5_MS_PINS + case (E_AXIS + 5): WRITE(E5_MS1_PIN, ms1); break; + #endif + #if HAS_E6_MS_PINS + case (E_AXIS + 6): WRITE(E6_MS1_PIN, ms1); break; + #endif + #if HAS_E7_MS_PINS + case (E_AXIS + 7): WRITE(E7_MS1_PIN, ms1); break; + #endif + } + if (ms2 >= 0) switch (driver) { + #if HAS_X_MS_PINS || HAS_X2_MS_PINS + case X_AXIS: + #if HAS_X_MS_PINS + WRITE(X_MS2_PIN, ms2); + #endif + #if HAS_X2_MS_PINS + WRITE(X2_MS2_PIN, ms2); + #endif + break; + #endif + #if HAS_Y_MS_PINS || HAS_Y2_MS_PINS + case Y_AXIS: + #if HAS_Y_MS_PINS + WRITE(Y_MS2_PIN, ms2); + #endif + #if HAS_Y2_MS_PINS + WRITE(Y2_MS2_PIN, ms2); + #endif + break; + #endif + #if HAS_SOME_Z_MS_PINS + case Z_AXIS: + #if HAS_Z_MS_PINS + WRITE(Z_MS2_PIN, ms2); + #endif + #if HAS_Z2_MS_PINS + WRITE(Z2_MS2_PIN, ms2); + #endif + #if HAS_Z3_MS_PINS + WRITE(Z3_MS2_PIN, ms2); + #endif + #if HAS_Z4_MS_PINS + WRITE(Z4_MS2_PIN, ms2); + #endif + break; + #endif + #if HAS_I_MS_PINS + case I_AXIS: WRITE(I_MS2_PIN, ms2); break; + #endif + #if HAS_J_MS_PINS + case J_AXIS: WRITE(J_MS2_PIN, ms2); break; + #endif + #if HAS_K_MS_PINS + case K_AXIS: WRITE(K_MS2_PIN, ms2); break; + #endif + #if HAS_U_MS_PINS + case U_AXIS: WRITE(U_MS2_PIN, ms2); break; + #endif + #if HAS_V_MS_PINS + case V_AXIS: WRITE(V_MS2_PIN, ms2); break; + #endif + #if HAS_W_MS_PINS + case W_AXIS: WRITE(W_MS2_PIN, ms2); break; + #endif + #if HAS_E0_MS_PINS + case E_AXIS: WRITE(E0_MS2_PIN, ms2); break; + #endif + #if HAS_E1_MS_PINS + case (E_AXIS + 1): WRITE(E1_MS2_PIN, ms2); break; + #endif + #if HAS_E2_MS_PINS + case (E_AXIS + 2): WRITE(E2_MS2_PIN, ms2); break; + #endif + #if HAS_E3_MS_PINS + case (E_AXIS + 3): WRITE(E3_MS2_PIN, ms2); break; + #endif + #if HAS_E4_MS_PINS + case (E_AXIS + 4): WRITE(E4_MS2_PIN, ms2); break; + #endif + #if HAS_E5_MS_PINS + case (E_AXIS + 5): WRITE(E5_MS2_PIN, ms2); break; + #endif + #if HAS_E6_MS_PINS + case (E_AXIS + 6): WRITE(E6_MS2_PIN, ms2); break; + #endif + #if HAS_E7_MS_PINS + case (E_AXIS + 7): WRITE(E7_MS2_PIN, ms2); break; + #endif + } + if (ms3 >= 0) switch (driver) { + #if HAS_X_MS_PINS || HAS_X2_MS_PINS + case X_AXIS: + #if HAS_X_MS_PINS && PIN_EXISTS(X_MS3) + WRITE(X_MS3_PIN, ms3); + #endif + #if HAS_X2_MS_PINS && PIN_EXISTS(X2_MS3) + WRITE(X2_MS3_PIN, ms3); + #endif + break; + #endif + #if HAS_Y_MS_PINS || HAS_Y2_MS_PINS + case Y_AXIS: + #if HAS_Y_MS_PINS && PIN_EXISTS(Y_MS3) + WRITE(Y_MS3_PIN, ms3); + #endif + #if HAS_Y2_MS_PINS && PIN_EXISTS(Y2_MS3) + WRITE(Y2_MS3_PIN, ms3); + #endif + break; + #endif + #if HAS_SOME_Z_MS_PINS + case Z_AXIS: + #if HAS_Z_MS_PINS && PIN_EXISTS(Z_MS3) + WRITE(Z_MS3_PIN, ms3); + #endif + #if HAS_Z2_MS_PINS && PIN_EXISTS(Z2_MS3) + WRITE(Z2_MS3_PIN, ms3); + #endif + #if HAS_Z3_MS_PINS && PIN_EXISTS(Z3_MS3) + WRITE(Z3_MS3_PIN, ms3); + #endif + #if HAS_Z4_MS_PINS && PIN_EXISTS(Z4_MS3) + WRITE(Z4_MS3_PIN, ms3); + #endif + break; + #endif + #if HAS_I_MS_PINS && PIN_EXISTS(I_MS3) + case I_AXIS: WRITE(I_MS3_PIN, ms3); break; + #endif + #if HAS_J_MS_PINS && PIN_EXISTS(J_MS3) + case J_AXIS: WRITE(J_MS3_PIN, ms3); break; + #endif + #if HAS_K_MS_PINS && PIN_EXISTS(K_MS3) + case K_AXIS: WRITE(K_MS3_PIN, ms3); break; + #endif + #if HAS_U_MS_PINS && PIN_EXISTS(U_MS3) + case U_AXIS: WRITE(U_MS3_PIN, ms3); break; + #endif + #if HAS_V_MS_PINS && PIN_EXISTS(V_MS3) + case V_AXIS: WRITE(V_MS3_PIN, ms3); break; + #endif + #if HAS_W_MS_PINS && PIN_EXISTS(W_MS3) + case W_AXIS: WRITE(W_MS3_PIN, ms3); break; + #endif + #if HAS_E0_MS_PINS && PIN_EXISTS(E0_MS3) + case E_AXIS: WRITE(E0_MS3_PIN, ms3); break; + #endif + #if HAS_E1_MS_PINS && PIN_EXISTS(E1_MS3) + case (E_AXIS + 1): WRITE(E1_MS3_PIN, ms3); break; + #endif + #if HAS_E2_MS_PINS && PIN_EXISTS(E2_MS3) + case (E_AXIS + 2): WRITE(E2_MS3_PIN, ms3); break; + #endif + #if HAS_E3_MS_PINS && PIN_EXISTS(E3_MS3) + case (E_AXIS + 3): WRITE(E3_MS3_PIN, ms3); break; + #endif + #if HAS_E4_MS_PINS && PIN_EXISTS(E4_MS3) + case (E_AXIS + 4): WRITE(E4_MS3_PIN, ms3); break; + #endif + #if HAS_E5_MS_PINS && PIN_EXISTS(E5_MS3) + case (E_AXIS + 5): WRITE(E5_MS3_PIN, ms3); break; + #endif + #if HAS_E6_MS_PINS && PIN_EXISTS(E6_MS3) + case (E_AXIS + 6): WRITE(E6_MS3_PIN, ms3); break; + #endif + #if HAS_E7_MS_PINS && PIN_EXISTS(E7_MS3) + case (E_AXIS + 7): WRITE(E7_MS3_PIN, ms3); break; + #endif + } + } + + // MS1 MS2 MS3 Stepper Driver Microstepping mode table + #ifndef MICROSTEP1 + #define MICROSTEP1 LOW,LOW,LOW + #endif + #if ENABLED(HEROIC_STEPPER_DRIVERS) + #ifndef MICROSTEP128 + #define MICROSTEP128 LOW,HIGH,LOW + #endif + #else + #ifndef MICROSTEP2 + #define MICROSTEP2 HIGH,LOW,LOW + #endif + #ifndef MICROSTEP4 + #define MICROSTEP4 LOW,HIGH,LOW + #endif + #endif + #ifndef MICROSTEP8 + #define MICROSTEP8 HIGH,HIGH,LOW + #endif + #ifndef MICROSTEP16 + #define MICROSTEP16 HIGH,HIGH,LOW + #endif + + void Stepper::microstep_mode(const uint8_t driver, const uint8_t stepping_mode) { + switch (stepping_mode) { + #ifdef MICROSTEP1 + case 1: microstep_ms(driver, MICROSTEP1); break; + #endif + #ifdef MICROSTEP2 + case 2: microstep_ms(driver, MICROSTEP2); break; + #endif + #ifdef MICROSTEP4 + case 4: microstep_ms(driver, MICROSTEP4); break; + #endif + #ifdef MICROSTEP8 + case 8: microstep_ms(driver, MICROSTEP8); break; + #endif + #ifdef MICROSTEP16 + case 16: microstep_ms(driver, MICROSTEP16); break; + #endif + #ifdef MICROSTEP32 + case 32: microstep_ms(driver, MICROSTEP32); break; + #endif + #ifdef MICROSTEP64 + case 64: microstep_ms(driver, MICROSTEP64); break; + #endif + #ifdef MICROSTEP128 + case 128: microstep_ms(driver, MICROSTEP128); break; + #endif + + default: SERIAL_ERROR_MSG("Microsteps unavailable"); break; + } + } + + void Stepper::microstep_readings() { + #define PIN_CHAR(P) SERIAL_CHAR('0' + READ(P##_PIN)) + #define MS_LINE(A) do{ SERIAL_ECHOPGM(" " STRINGIFY(A) ":"); PIN_CHAR(A##_MS1); PIN_CHAR(A##_MS2); }while(0) + SERIAL_ECHOPGM("MS1|2|3 Pins"); + #if HAS_X_MS_PINS + MS_LINE(X); + #if PIN_EXISTS(X_MS3) + PIN_CHAR(X_MS3); + #endif + #endif + #if HAS_Y_MS_PINS + MS_LINE(Y); + #if PIN_EXISTS(Y_MS3) + PIN_CHAR(Y_MS3); + #endif + #endif + #if HAS_Z_MS_PINS + MS_LINE(Z); + #if PIN_EXISTS(Z_MS3) + PIN_CHAR(Z_MS3); + #endif + #endif + #if HAS_I_MS_PINS + MS_LINE(I); + #if PIN_EXISTS(I_MS3) + PIN_CHAR(I_MS3); + #endif + #endif + #if HAS_J_MS_PINS + MS_LINE(J); + #if PIN_EXISTS(J_MS3) + PIN_CHAR(J_MS3); + #endif + #endif + #if HAS_K_MS_PINS + MS_LINE(K); + #if PIN_EXISTS(K_MS3) + PIN_CHAR(K_MS3); + #endif + #endif + #if HAS_U_MS_PINS + MS_LINE(U); + #if PIN_EXISTS(U_MS3) + PIN_CHAR(U_MS3); + #endif + #endif + #if HAS_V_MS_PINS + MS_LINE(V); + #if PIN_EXISTS(V_MS3) + PIN_CHAR(V_MS3); + #endif + #endif + #if HAS_W_MS_PINS + MS_LINE(W); + #if PIN_EXISTS(W_MS3) + PIN_CHAR(W_MS3); + #endif + #endif + #if HAS_E0_MS_PINS + MS_LINE(E0); + #if PIN_EXISTS(E0_MS3) + PIN_CHAR(E0_MS3); + #endif + #endif + #if HAS_E1_MS_PINS + MS_LINE(E1); + #if PIN_EXISTS(E1_MS3) + PIN_CHAR(E1_MS3); + #endif + #endif + #if HAS_E2_MS_PINS + MS_LINE(E2); + #if PIN_EXISTS(E2_MS3) + PIN_CHAR(E2_MS3); + #endif + #endif + #if HAS_E3_MS_PINS + MS_LINE(E3); + #if PIN_EXISTS(E3_MS3) + PIN_CHAR(E3_MS3); + #endif + #endif + #if HAS_E4_MS_PINS + MS_LINE(E4); + #if PIN_EXISTS(E4_MS3) + PIN_CHAR(E4_MS3); + #endif + #endif + #if HAS_E5_MS_PINS + MS_LINE(E5); + #if PIN_EXISTS(E5_MS3) + PIN_CHAR(E5_MS3); + #endif + #endif + #if HAS_E6_MS_PINS + MS_LINE(E6); + #if PIN_EXISTS(E6_MS3) + PIN_CHAR(E6_MS3); + #endif + #endif + #if HAS_E7_MS_PINS + MS_LINE(E7); + #if PIN_EXISTS(E7_MS3) + PIN_CHAR(E7_MS3); + #endif + #endif + SERIAL_EOL(); + } + +#endif // HAS_MICROSTEPS diff --git a/Marlin/src/pins/sam/pins_PRINTRBOARD_G2.h b/Marlin/src/pins/sam/pins_PRINTRBOARD_G2.h index 0f4db200a3..fb8a1e7c6d 100644 --- a/Marlin/src/pins/sam/pins_PRINTRBOARD_G2.h +++ b/Marlin/src/pins/sam/pins_PRINTRBOARD_G2.h @@ -102,10 +102,6 @@ #define E0_ENABLE_PIN 37 // PB22 // Microstepping mode pins -#define Z_MS1_PIN 52 // PB21 MODE0 MOTOR 1 -#define Z_MS2_PIN 52 // PB21 MODE1 -#define Z_MS3_PIN 65 // PB20 MODE2 - #define X_MS1_PIN 43 // PA20 MODE0 MOTOR 2 #define X_MS2_PIN 43 // PA20 MODE1 #define X_MS3_PIN 42 // PA19 MODE2 @@ -114,6 +110,10 @@ #define Y_MS2_PIN 77 // PA28 MODE1 #define Y_MS3_PIN 76 // PA27 MODE2 +#define Z_MS1_PIN 52 // PB21 MODE0 MOTOR 1 +#define Z_MS2_PIN 52 // PB21 MODE1 +#define Z_MS3_PIN 65 // PB20 MODE2 + #define E0_MS1_PIN 38 // PB11 MODE0 MOTOR 4 #define E0_MS2_PIN 38 // PB11 MODE1 #define E0_MS3_PIN 39 // PB10 MODE2 diff --git a/ini/features.ini b/ini/features.ini index 1cff1a61f4..e51ad0bda3 100644 --- a/ini/features.ini +++ b/ini/features.ini @@ -22,6 +22,7 @@ POSTMORTEM_DEBUGGING = build_src_filter=+ + + + + +HAS_STEPPER_CONTROL = build_src_filter=+ HAS_T(RINAMIC_CONFIG|MC_SPI) = build_src_filter=+ EDITABLE_HOMING_CURRENT = build_src_filter=+ SR_LCD_3W_NL = SailfishLCD=https://github.com/mikeshub/SailfishLCD/archive/6f53c19a8a.zip From f6c891554574e00febec83208951fa52ad8af7b7 Mon Sep 17 00:00:00 2001 From: David Buezas Date: Sun, 20 Apr 2025 07:18:45 +0200 Subject: [PATCH 232/787] =?UTF-8?q?=E2=9C=A8=20SMOOTH=5FLIN=5FADVANCE=20(#?= =?UTF-8?q?27710)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Scott Lahteine --- Marlin/Configuration_adv.h | 18 ++ Marlin/src/feature/bltouch.cpp | 2 +- Marlin/src/gcode/feature/advance/M900.cpp | 50 ++++- Marlin/src/inc/Conditionals-4-adv.h | 5 + Marlin/src/inc/SanityCheck.h | 18 +- Marlin/src/inc/Warnings.cpp | 9 + Marlin/src/lcd/language/language_en.h | 2 + Marlin/src/lcd/menu/menu_advanced.cpp | 28 ++- Marlin/src/lcd/menu/menu_tune.cpp | 12 ++ Marlin/src/module/planner.cpp | 63 ++++-- Marlin/src/module/planner.h | 37 +++- Marlin/src/module/settings.cpp | 44 +++- Marlin/src/module/stepper.cpp | 233 +++++++++++++++++++--- Marlin/src/module/stepper.h | 39 +++- buildroot/tests/LPC1768 | 28 ++- buildroot/tests/LPC1769 | 22 +- 16 files changed, 504 insertions(+), 106 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 73073762f1..9d291f6219 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -2352,6 +2352,24 @@ //#define ADVANCE_K_EXTRA // Add a second linear advance constant, configurable with M900 L. //#define LA_DEBUG // Print debug information to serial during operation. Disable for production use. //#define EXPERIMENTAL_I2S_LA // Allow I2S_STEPPER_STREAM to be used with LA. Performance degrades as the LA step rate reaches ~20kHz. + + //#define SMOOTH_LIN_ADVANCE // Remove limits on acceleration by gradual increase of nozzle pressure + #if ENABLED(SMOOTH_LIN_ADVANCE) + /** + * ADVANCE_TAU is also the time ahead that the smoother needs to look + * into the planner, so the planner needs to have enough blocks loaded. + * For k=0.04 at 10k acceleration and an "Orbiter 2" extruder it can be as low as 0.0075. + * Adjust by lowering the value until you observe the extruder skipping, then raise slightly. + * Higher k and higher XY acceleration may require larger ADVANCE_TAU to avoid skipping steps. + */ + #if ENABLED(DISTINCT_E_FACTORS) + #define ADVANCE_TAU { 0.01 } // (s) Smoothing time to reduce extruder acceleration, per extruder + #else + #define ADVANCE_TAU 0.01 // (s) Smoothing time to reduce extruder acceleration + #endif + #define SMOOTH_LIN_ADV_HZ 5000 // (Hz) How often to update extruder speed + #define INPUT_SHAPING_E_SYNC // Synchronize the extruder-shaped XY axes (to increase precision) + #endif #endif /** diff --git a/Marlin/src/feature/bltouch.cpp b/Marlin/src/feature/bltouch.cpp index 2559547b85..5b498cd474 100644 --- a/Marlin/src/feature/bltouch.cpp +++ b/Marlin/src/feature/bltouch.cpp @@ -48,7 +48,7 @@ bool BLTouch::command(const BLTCommand cmd, const millis_t &ms) { // The previous write should've already delayed to detect the alarm. if (cmd != current) { servo[Z_PROBE_SERVO_NR].move(cmd); - safe_delay(_MAX(ms, (uint32_t)BLTOUCH_DELAY)); // BLTOUCH_DELAY is also the *minimum* delay + safe_delay(_MAX(ms, uint32_t(BLTOUCH_DELAY))); // BLTOUCH_DELAY is also the *minimum* delay } return triggered(); } diff --git a/Marlin/src/gcode/feature/advance/M900.cpp b/Marlin/src/gcode/feature/advance/M900.cpp index e8a16d952f..51a40f934e 100644 --- a/Marlin/src/gcode/feature/advance/M900.cpp +++ b/Marlin/src/gcode/feature/advance/M900.cpp @@ -26,6 +26,7 @@ #include "../../gcode.h" #include "../../../module/planner.h" +#include "../../../module/stepper.h" #if ENABLED(ADVANCE_K_EXTRA) float other_extruder_advance_K[DISTINCT_E]; @@ -62,6 +63,11 @@ void GcodeSuite::M900() { float &kref = planner.extruder_advance_K[E_INDEX_N(tool_index)], newK = kref; const float oldK = newK; + #if ENABLED(SMOOTH_LIN_ADVANCE) + const float oldU = stepper.get_advance_tau(E_INDEX_N(tool_index)); + float newU = oldU; + #endif + #if ENABLED(ADVANCE_K_EXTRA) float &lref = other_extruder_advance_K[E_INDEX_N(tool_index)]; @@ -105,9 +111,22 @@ void GcodeSuite::M900() { #endif - if (newK != oldK) { + #if ENABLED(SMOOTH_LIN_ADVANCE) + if (parser.seenval('U')) { + const float tau = parser.value_float(); + if (WITHIN(tau, 0.0f, 0.5f)) + newU = tau; + else + echo_value_oor('U'); + } + #endif + + if (newK != oldK || TERN0(SMOOTH_LIN_ADVANCE, newU != oldU)) { planner.synchronize(); - kref = newK; + if (newK != oldK) kref = newK; + #if ENABLED(SMOOTH_LIN_ADVANCE) + if (newU != oldU) stepper.set_advance_tau(newU); + #endif } if (!parser.seen_any()) { @@ -124,18 +143,27 @@ void GcodeSuite::M900() { } #endif - #else + #else // !ADVANCE_K_EXTRA SERIAL_ECHO_START(); #if DISTINCT_E < 2 - SERIAL_ECHOLNPGM("Advance K=", planner.extruder_advance_K[0]); + SERIAL_ECHOPGM("Advance K=", planner.extruder_advance_K[0]); + #if ENABLED(SMOOTH_LIN_ADVANCE) + SERIAL_ECHOPGM(" TAU=", stepper.get_advance_tau()); + #endif + SERIAL_EOL(); #else SERIAL_ECHOPGM("Advance K"); EXTRUDER_LOOP() SERIAL_ECHO(C(' '), C('0' + e), C(':'), planner.extruder_advance_K[e]); SERIAL_EOL(); + #if ENABLED(SMOOTH_LIN_ADVANCE) + SERIAL_ECHOPGM("Advance TAU"); + EXTRUDER_LOOP() SERIAL_ECHO(C(' '), C('0' + e), C(':'), stepper.get_advance_tau(e)); + SERIAL_EOL(); + #endif #endif - #endif + #endif // !ADVANCE_K_EXTRA } } @@ -146,11 +174,19 @@ void GcodeSuite::M900_report(const bool forReplay/*=true*/) { report_heading(forReplay, F(STR_LINEAR_ADVANCE)); #if DISTINCT_E < 2 report_echo_start(forReplay); - SERIAL_ECHOLNPGM(" M900 K", planner.extruder_advance_K[0]); + SERIAL_ECHOPGM(" M900 K", planner.extruder_advance_K[0]); + #if ENABLED(SMOOTH_LIN_ADVANCE) + SERIAL_ECHOPGM(" M900 U", stepper.get_advance_tau()); + #endif + SERIAL_EOL(); #else EXTRUDER_LOOP() { report_echo_start(forReplay); - SERIAL_ECHOLNPGM(" M900 T", e, " K", planner.extruder_advance_K[e]); + SERIAL_ECHOPGM(" M900 T", e, " K", planner.extruder_advance_K[e]); + #if ENABLED(SMOOTH_LIN_ADVANCE) + SERIAL_ECHOPGM(" U", stepper.get_advance_tau(e)); + #endif + SERIAL_EOL(); } #endif } diff --git a/Marlin/src/inc/Conditionals-4-adv.h b/Marlin/src/inc/Conditionals-4-adv.h index 109fca6b29..ca096c7661 100644 --- a/Marlin/src/inc/Conditionals-4-adv.h +++ b/Marlin/src/inc/Conditionals-4-adv.h @@ -231,6 +231,7 @@ #undef FWRETRACT #undef LCD_SHOW_E_TOTAL #undef LIN_ADVANCE + #undef SMOOTH_LIN_ADVANCE #undef MANUAL_E_MOVES_RELATIVE #undef PID_EXTRUSION_SCALING #undef SHOW_TEMP_ADC_VALUES @@ -339,6 +340,10 @@ #define HAS_LINEAR_E_JERK 1 #endif +#if ENABLED(LIN_ADVANCE) && DISABLED(SMOOTH_LIN_ADVANCE) + #define HAS_ROUGH_LIN_ADVANCE 1 +#endif + // Some displays can toggle Adaptive Step Smoothing. // The state is saved to EEPROM. // In future this may be added to a G-code such as M205 A. diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index cd3c1cd573..970847ecb5 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -847,7 +847,23 @@ static_assert(COUNT(arm) == LOGICAL_AXES, "AXIS_RELATIVE_MODES must contain " _L #if ENABLED(DIRECT_STEPPING) #error "DIRECT_STEPPING is incompatible with LIN_ADVANCE. (Extrusion is controlled externally by the Step Daemon.)" #endif -#endif + + /** + * Smooth Linear Advance + */ + #if ENABLED(SMOOTH_LIN_ADVANCE) + #ifndef CPU_32_BIT + #error "SMOOTH_LIN_ADVANCE requires a 32-bit CPU." + #elif DISTINCT_E > 1 + #error "SMOOTH_LIN_ADVANCE is not compatible with multiple extruders." + #elif ENABLED(S_CURVE_ACCELERATION) + #error "SMOOTH_LIN_ADVANCE is not compatible with S_CURVE_ACCELERATION." + #elif ENABLED(INPUT_SHAPING_E_SYNC) && NONE(INPUT_SHAPING_X, INPUT_SHAPING_Y) + #error "INPUT_SHAPING_E_SYNC requires INPUT_SHAPING_X or INPUT_SHAPING_Y." + #endif + #endif + +#endif // LIN_ADVANCE /** * Nonlinear Extrusion requirements diff --git a/Marlin/src/inc/Warnings.cpp b/Marlin/src/inc/Warnings.cpp index 119e2205ab..f11eedbe52 100644 --- a/Marlin/src/inc/Warnings.cpp +++ b/Marlin/src/inc/Warnings.cpp @@ -946,3 +946,12 @@ #if LCD_IS_SERIAL_HOST && defined(BOARD_LCD_SERIAL_PORT) && LCD_SERIAL_PORT != BOARD_LCD_SERIAL_PORT && DISABLED(NO_LCD_SERIAL_PORT_WARNING) #warning "LCD_SERIAL_PORT overrides the default (BOARD_LCD_SERIAL_PORT)." #endif + +/** + * Smooth Linear Advance with Mixing Extruder, S-Curve Acceleration + */ +#if ENABLED(SMOOTH_LIN_ADVANCE) + #if ENABLED(MIXING_EXTRUDER) + #warning "SMOOTH_LIN_ADVANCE with MIXING_EXTRUDER is untested. Use with caution." + #endif +#endif diff --git a/Marlin/src/lcd/language/language_en.h b/Marlin/src/lcd/language/language_en.h index d184c0358f..e0c1f53f77 100644 --- a/Marlin/src/lcd/language/language_en.h +++ b/Marlin/src/lcd/language/language_en.h @@ -492,7 +492,9 @@ namespace LanguageNarrow_en { LSTR MSG_MAX_BELT_LEN = _UxGT("Max Belt Len"); LSTR MSG_LINEAR_ADVANCE = _UxGT("Linear Advance"); LSTR MSG_ADVANCE_K = _UxGT("Advance K"); + LSTR MSG_ADVANCE_TAU = _UxGT("Advance Tau"); LSTR MSG_ADVANCE_K_E = _UxGT("Advance K *"); + LSTR MSG_ADVANCE_TAU_E = _UxGT("Advance Tau *"); LSTR MSG_CONTRAST = _UxGT("LCD Contrast"); LSTR MSG_BRIGHTNESS = _UxGT("LCD Brightness"); LSTR MSG_SCREEN_TIMEOUT = _UxGT("LCD Timeout (m)"); diff --git a/Marlin/src/lcd/menu/menu_advanced.cpp b/Marlin/src/lcd/menu/menu_advanced.cpp index 137439c6df..296312bb1f 100644 --- a/Marlin/src/lcd/menu/menu_advanced.cpp +++ b/Marlin/src/lcd/menu/menu_advanced.cpp @@ -122,7 +122,18 @@ void menu_backlash(); EXTRUDER_LOOP() EDIT_ITEM_N(float42_52, e, MSG_ADVANCE_K_E, &planner.extruder_advance_K[e], 0, 10); #endif - #endif + #if ENABLED(SMOOTH_LIN_ADVANCE) + #if DISTINCT_E < 2 + editable.decimal = stepper.get_advance_tau(); + EDIT_ITEM(float54, MSG_ADVANCE_TAU, &editable.decimal, 0.0f, 0.5f, []{ stepper.set_advance_tau(editable.decimal); }); + #else + EXTRUDER_LOOP() { + editable.decimal = stepper.get_advance_tau(e); + EDIT_ITEM_N(float54, e, MSG_ADVANCE_TAU_E, &editable.decimal, 0.0f, 0.5f, []{ stepper.set_advance_tau(editable.decimal, MenuItemBase::itemIndex); }); + } + #endif + #endif + #endif // LIN_ADVANCE #if DISABLED(NO_VOLUMETRICS) EDIT_ITEM(bool, MSG_VOLUMETRIC_ENABLED, &parser.volumetric_enabled, planner.calculate_volumetric_multipliers); @@ -735,13 +746,26 @@ void menu_advanced_settings() { #if HAS_ADV_FILAMENT_MENU SUBMENU(MSG_FILAMENT, menu_advanced_filament); - #elif ENABLED(LIN_ADVANCE) + #endif + + #if ENABLED(LIN_ADVANCE) && DISABLED(HAS_ADV_FILAMENT_MENU) #if DISTINCT_E < 2 EDIT_ITEM(float42_52, MSG_ADVANCE_K, &planner.extruder_advance_K[0], 0, 10); #else EXTRUDER_LOOP() EDIT_ITEM_N(float42_52, e, MSG_ADVANCE_K_E, &planner.extruder_advance_K[e], 0, 10); #endif + #if ENABLED(SMOOTH_LIN_ADVANCE) + #if DISTINCT_E < 2 + editable.decimal = stepper.get_advance_tau(); + EDIT_ITEM(float54, MSG_ADVANCE_TAU, &editable.decimal, 0.0f, 0.5f, []{ stepper.set_advance_tau(editable.decimal); }); + #else + EXTRUDER_LOOP() { + editable.decimal = stepper.get_advance_tau(e); + EDIT_ITEM_N(float54, e, MSG_ADVANCE_TAU_E, &editable.decimal, 0.0f, 0.5f, []{ stepper.set_advance_tau(editable.decimal, MenuItemBase::itemIndex); }); + } + #endif + #endif #endif // M540 S - Abort on endstop hit when SD printing diff --git a/Marlin/src/lcd/menu/menu_tune.cpp b/Marlin/src/lcd/menu/menu_tune.cpp index 1f1571d986..51d877fc5c 100644 --- a/Marlin/src/lcd/menu/menu_tune.cpp +++ b/Marlin/src/lcd/menu/menu_tune.cpp @@ -31,6 +31,7 @@ #include "menu_item.h" #include "../../module/motion.h" #include "../../module/planner.h" +#include "../../module/stepper.h" #include "../../module/temperature.h" #include "../../MarlinCore.h" @@ -220,6 +221,17 @@ void menu_tune() { EXTRUDER_LOOP() EDIT_ITEM_N(float42_52, e, MSG_ADVANCE_K_E, &planner.extruder_advance_K[e], 0, 10); #endif + #if ENABLED(SMOOTH_LIN_ADVANCE) + #if DISTINCT_E < 2 + editable.decimal = stepper.get_advance_tau(); + EDIT_ITEM(float54, MSG_ADVANCE_TAU, &editable.decimal, 0.0f, 0.5f, []{ stepper.set_advance_tau(editable.decimal); }); + #else + EXTRUDER_LOOP() { + editable.decimal = stepper.get_advance_tau(e); + EDIT_ITEM_N(float54, e, MSG_ADVANCE_TAU_E, &editable.decimal, 0.0f, 0.5f, []{ stepper.set_advance_tau(editable.decimal, MenuItemBase::itemIndex); }); + } + #endif + #endif #endif // diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index 881e11f4c0..87cb4cd21b 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -775,6 +775,14 @@ block_t* Planner::get_current_block() { return nullptr; } +block_t* Planner::get_future_block(const uint8_t offset) { + const uint8_t nr_moves = movesplanned(); + if (nr_moves <= offset) return nullptr; + block_t * const block = &block_buffer[block_inc_mod(block_buffer_tail, offset)]; + if (block->flag.recalculate) return nullptr; + return block; +} + /** * Calculate trapezoid parameters, multiplying the entry- and exit-speeds * by the provided factors. If entry_factor is 0 don't change the initial_rate. @@ -840,13 +848,15 @@ void Planner::calculate_trapezoid_for_block(block_t * const block, const_float_t } } - #if ENABLED(S_CURVE_ACCELERATION) + #if ANY(S_CURVE_ACCELERATION, SMOOTH_LIN_ADVANCE) const float rate_factor = inverse_accel * (STEPPER_TIMER_RATE); // Jerk controlled speed requires to express speed versus time, NOT steps uint32_t acceleration_time = rate_factor * float(cruise_rate - initial_rate), - deceleration_time = rate_factor * float(cruise_rate - final_rate), + deceleration_time = rate_factor * float(cruise_rate - final_rate); + #endif + #if ENABLED(S_CURVE_ACCELERATION) // And to offload calculations from the ISR, we also calculate the inverse of those times here - acceleration_time_inverse = get_period_inverse(acceleration_time), + uint32_t acceleration_time_inverse = get_period_inverse(acceleration_time), deceleration_time_inverse = get_period_inverse(deceleration_time); #endif @@ -856,15 +866,20 @@ void Planner::calculate_trapezoid_for_block(block_t * const block, const_float_t block->initial_rate = initial_rate; block->final_rate = final_rate; - #if ENABLED(S_CURVE_ACCELERATION) + #if ANY(S_CURVE_ACCELERATION, SMOOTH_LIN_ADVANCE) block->acceleration_time = acceleration_time; block->deceleration_time = deceleration_time; - block->acceleration_time_inverse = acceleration_time_inverse; - block->deceleration_time_inverse = deceleration_time_inverse; block->cruise_rate = cruise_rate; #endif + #if ENABLED(S_CURVE_ACCELERATION) + block->acceleration_time_inverse = acceleration_time_inverse; + block->deceleration_time_inverse = deceleration_time_inverse; + #endif + #if ENABLED(SMOOTH_LIN_ADVANCE) + block->cruise_time = plateau_steps > 0 ? float(plateau_steps) * float(STEPPER_TIMER_RATE) / float(cruise_rate) : 0; + #endif - #if ENABLED(LIN_ADVANCE) + #if HAS_ROUGH_LIN_ADVANCE if (block->la_advance_rate) { const float comp = extruder_advance_K[E_INDEX_N(block->extruder)] * block->steps.e / block->step_event_count; block->max_adv_steps = cruise_rate * comp; @@ -2409,15 +2424,17 @@ bool Planner::_populate_block( if (e_D_ratio > 3.0f) use_advance_lead = false; else { - // Scale E acceleration so that it will be possible to jump to the advance speed. - const uint32_t max_accel_steps_per_s2 = MAX_E_JERK(extruder) / (extruder_advance_K[E_INDEX_N(extruder)] * e_D_ratio) * steps_per_mm; - if (accel > max_accel_steps_per_s2) { - accel = max_accel_steps_per_s2; - if (ENABLED(LA_DEBUG)) SERIAL_ECHOLNPGM("Acceleration limited."); - } + #if HAS_ROUGH_LIN_ADVANCE + // Scale E acceleration so that it will be possible to jump to the advance speed. + const uint32_t max_accel_steps_per_s2 = MAX_E_JERK(extruder) / (extruder_advance_K[E_INDEX_N(extruder)] * e_D_ratio) * steps_per_mm; + if (accel > max_accel_steps_per_s2) { + accel = max_accel_steps_per_s2; + if (TERN0(LA_DEBUG, DEBUGGING(INFO))) SERIAL_ECHOLNPGM("Acceleration limited."); + } + #endif } } - #endif + #endif // LIN_ADVANCE // Limit acceleration per axis if (block->step_event_count <= acceleration_long_cutoff) { @@ -2443,10 +2460,9 @@ bool Planner::_populate_block( block->acceleration_rate = uint32_t(accel * (float(1UL << 24) / (STEPPER_TIMER_RATE))); #endif - #if ENABLED(LIN_ADVANCE) + #if HAS_ROUGH_LIN_ADVANCE block->la_advance_rate = 0; block->la_scaling = 0; - if (use_advance_lead) { // The Bresenham algorithm will convert this step rate into extruder steps block->la_advance_rate = extruder_advance_K[E_INDEX_N(extruder)] * block->acceleration_steps_per_s2; @@ -2456,12 +2472,14 @@ bool Planner::_populate_block( for (uint32_t dividend = block->steps.e << 1; dividend <= (block->step_event_count >> 2); dividend <<= 1) block->la_scaling++; - #if ENABLED(LA_DEBUG) - if (block->la_advance_rate >> block->la_scaling > 10000) + // Output debugging if the rate gets very high + if (TERN0(LA_DEBUG, DEBUGGING(INFO)) && block->la_advance_rate >> block->la_scaling > 10000) SERIAL_ECHOLNPGM("eISR running at > 10kHz: ", block->la_advance_rate); - #endif } - #endif // LIN_ADVANCE + #elif ENABLED(SMOOTH_LIN_ADVANCE) + block->use_advance_lead = use_advance_lead; + block->e_step_ratio = (block->direction_bits.e ? 1 : -1) * float(block->steps.e) / block->step_event_count; + #endif // Formula for the average speed over a 1 step worth of distance if starting from zero and // accelerating at the current limit. Since we can only change the speed every step this is a @@ -2688,7 +2706,8 @@ bool Planner::_populate_block( } #endif - #if ENABLED(LIN_ADVANCE) + // In the SMOOTH_LIN_ADVANCE case, the extra jerk will be applied by the residual current la_step_rate. + #if HAS_ROUGH_LIN_ADVANCE // Advance affects E_AXIS speed and therefore jerk. Add a speed correction whenever // LA is turned OFF. No correction is applied when LA is turned ON (because it didn't // perform well; it takes more time/effort to push/melt filament than the reverse). @@ -2703,7 +2722,7 @@ bool Planner::_populate_block( // Prepare for next segment. previous_advance_rate = block->la_advance_rate; previous_e_mm_per_step = mm_per_step[E_AXIS_N(extruder)]; - #endif + #endif // HAS_ROUGH_LIN_ADVANCE xyze_float_t speed_diff = current_speed; float vmax_junction; diff --git a/Marlin/src/module/planner.h b/Marlin/src/module/planner.h index e8bacddd9f..a2f91edc81 100644 --- a/Marlin/src/module/planner.h +++ b/Marlin/src/module/planner.h @@ -43,6 +43,11 @@ #define JD_USE_LOOKUP_TABLE #endif +#if ENABLED(SMOOTH_LIN_ADVANCE) + #define SMOOTH_LIN_ADV_EXP_ORDER 5 // Closest to Gaussian smoothing between 3 and 7 + #define SMOOTH_LIN_ADV_INTERVAL (STEPPER_TIMER_RATE / SMOOTH_LIN_ADV_HZ) // Hz +#endif + #include "motion.h" #include "../gcode/queue.h" @@ -240,11 +245,17 @@ typedef struct PlannerBlock { uint32_t accelerate_before, // The index of the step event where cruising starts decelerate_start; // The index of the step event on which to start decelerating - #if ENABLED(S_CURVE_ACCELERATION) + #if ENABLED(SMOOTH_LIN_ADVANCE) + uint32_t cruise_time; // Cruise time in STEP timer counts + float e_step_ratio; + #endif + #if ANY(S_CURVE_ACCELERATION, SMOOTH_LIN_ADVANCE) uint32_t cruise_rate, // The actual cruise rate to use, between end of the acceleration phase and start of deceleration phase acceleration_time, // Acceleration time and deceleration time in STEP timer counts - deceleration_time, - acceleration_time_inverse, // Inverse of acceleration and deceleration periods, expressed as integer. Scale depends on CPU being used + deceleration_time; + #endif + #if ENABLED(S_CURVE_ACCELERATION) + uint32_t acceleration_time_inverse, // Inverse of acceleration and deceleration periods, expressed as integer. Scale depends on CPU being used deceleration_time_inverse; #else uint32_t acceleration_rate; // Acceleration rate in (2^24 steps)/timer_ticks*s @@ -254,10 +265,14 @@ typedef struct PlannerBlock { // Advance extrusion #if ENABLED(LIN_ADVANCE) - uint32_t la_advance_rate; // The rate at which steps are added whilst accelerating - uint8_t la_scaling; // Scale ISR frequency down and step frequency up by 2 ^ la_scaling - uint16_t max_adv_steps, // Max advance steps to get cruising speed pressure - final_adv_steps; // Advance steps for exit speed pressure + #if ENABLED(SMOOTH_LIN_ADVANCE) + bool use_advance_lead; + #else + uint32_t la_advance_rate; // The rate at which steps are added whilst accelerating + uint8_t la_scaling; // Scale ISR frequency down and step frequency up by 2 ^ la_scaling + uint16_t max_adv_steps, // Max advance steps to get cruising speed pressure + final_adv_steps; // Advance steps for exit speed pressure + #endif #endif uint32_t nominal_rate, // The nominal step rate for this block in step_events/sec @@ -1041,6 +1056,14 @@ class Planner { */ static block_t* get_current_block(); + /** + * Get a planned upcoming block from the buffer. + * Return nullptr if the buffer doesn't have the `current + offset` yet. + * + * WARNING: Called from Stepper ISR context! + */ + static block_t* get_future_block(const uint8_t offset); + /** * "Release" the current block so its slot can be reused. * Called when the current block is no longer needed. diff --git a/Marlin/src/module/settings.cpp b/Marlin/src/module/settings.cpp index a6714b3e6a..feb433041e 100644 --- a/Marlin/src/module/settings.cpp +++ b/Marlin/src/module/settings.cpp @@ -500,7 +500,12 @@ typedef struct SettingsDataStruct { // // LIN_ADVANCE // - float planner_extruder_advance_K[DISTINCT_E]; // M900 K planner.extruder_advance_K + #if ENABLED(LIN_ADVANCE) + float planner_extruder_advance_K[DISTINCT_E]; // M900 K planner.extruder_advance_K + #if ENABLED(SMOOTH_LIN_ADVANCE) + float stepper_extruder_advance_tau[DISTINCT_E]; // M900 U stepper.extruder_advance_tau + #endif + #endif // // HAS_MOTOR_CURRENT_PWM @@ -1554,13 +1559,13 @@ void MarlinSettings::postprocess() { // Linear Advance // { - _FIELD_TEST(planner_extruder_advance_K); - #if ENABLED(LIN_ADVANCE) + _FIELD_TEST(planner_extruder_advance_K); EEPROM_WRITE(planner.extruder_advance_K); - #else - dummyf = 0; - for (uint8_t q = DISTINCT_E; q--;) EEPROM_WRITE(dummyf); + #if ENABLED(SMOOTH_LIN_ADVANCE) + _FIELD_TEST(stepper_extruder_advance_tau); + EEPROM_WRITE(stepper.extruder_advance_tau); + #endif #endif } @@ -2633,15 +2638,27 @@ void MarlinSettings::postprocess() { // // Linear Advance // + #if ENABLED(LIN_ADVANCE) { float extruder_advance_K[DISTINCT_E]; _FIELD_TEST(planner_extruder_advance_K); EEPROM_READ(extruder_advance_K); - #if ENABLED(LIN_ADVANCE) - if (!validating) - COPY(planner.extruder_advance_K, extruder_advance_K); + if (!validating) + COPY(planner.extruder_advance_K, extruder_advance_K); + #if ENABLED(SMOOTH_LIN_ADVANCE) + _FIELD_TEST(stepper_extruder_advance_tau); + float tau[DISTINCT_E]; + EEPROM_READ(tau); + if (!validating) { + #if ENABLED(DISTINCT_E_FACTORS) + EXTRUDER_LOOP() stepper.set_advance_tau(tau[e], e); + #else + stepper.set_advance_tau(tau[0]); + #endif + } #endif } + #endif // // Motor Current PWM @@ -3742,6 +3759,15 @@ void MarlinSettings::reset() { #else planner.extruder_advance_K[0] = ADVANCE_K; #endif + #if ENABLED(SMOOTH_LIN_ADVANCE) + #if ENABLED(DISTINCT_E_FACTORS) + constexpr float linAdvanceTau[] = ADVANCE_TAU; + EXTRUDER_LOOP() + stepper.set_advance_tau(linAdvanceTau[_MAX(uint8_t(e), COUNT(linAdvanceTau) - 1)], e); + #else + stepper.set_advance_tau(ADVANCE_TAU); + #endif + #endif #endif // diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp index 1340cd9157..cc042181c6 100644 --- a/Marlin/src/module/stepper.cpp +++ b/Marlin/src/module/stepper.cpp @@ -256,10 +256,15 @@ uint32_t Stepper::advance_divisor = 0, #if ENABLED(LIN_ADVANCE) hal_timer_t Stepper::nextAdvanceISR = LA_ADV_NEVER, Stepper::la_interval = LA_ADV_NEVER; - int32_t Stepper::la_delta_error = 0, + #if HAS_ROUGH_LIN_ADVANCE + int32_t Stepper::la_delta_error = 0, Stepper::la_dividend = 0, Stepper::la_advance_steps = 0; - bool Stepper::la_active = false; + bool Stepper::la_active = false; + #else + uint32_t Stepper::curr_step_rate, + Stepper::curr_timer_tick = 0; + #endif #endif #if ENABLED(NONLINEAR_EXTRUSION) @@ -1521,6 +1526,10 @@ void Stepper::isr() { static hal_timer_t nextMainISR = 0; // Interval until the next main Stepper Pulse phase (0 = Now) + #if ENABLED(SMOOTH_LIN_ADVANCE) + static hal_timer_t smoothLinAdvISR = 0; + #endif + // Program timer compare for the maximum period, so it does NOT // flag an interrupt while this ISR is running - So changes from small // periods to big periods are respected and the timer does not reset to 0 @@ -1594,6 +1603,9 @@ void Stepper::isr() { // ^== Time critical. NOTHING besides pulse generation should be above here!!! if (!nextMainISR) nextMainISR = block_phase_isr(); // Manage acc/deceleration, get next block + #if ENABLED(SMOOTH_LIN_ADVANCE) + if (!smoothLinAdvISR) smoothLinAdvISR = smooth_lin_adv_isr(); // Manage la + #endif #if ENABLED(BABYSTEPPING) if (is_babystep) // Avoid ANY stepping too soon after baby-stepping @@ -1609,6 +1621,7 @@ void Stepper::isr() { TERN_(INPUT_SHAPING_Y, NOMORE(interval, ShapingQueue::peek_y())); // Time until next input shaping echo for Y TERN_(INPUT_SHAPING_Z, NOMORE(interval, ShapingQueue::peek_z())); // Time until next input shaping echo for Z TERN_(LIN_ADVANCE, NOMORE(interval, nextAdvanceISR)); // Come back early for Linear Advance? + TERN_(SMOOTH_LIN_ADVANCE, NOMORE(interval, smoothLinAdvISR)); // Come back early for Linear Advance rate update? TERN_(BABYSTEPPING, NOMORE(interval, nextBabystepISR)); // Come back early for Babystepping? // @@ -1621,6 +1634,7 @@ void Stepper::isr() { nextMainISR -= interval; TERN_(HAS_ZV_SHAPING, ShapingQueue::decrement_delays(interval)); TERN_(LIN_ADVANCE, if (nextAdvanceISR != LA_ADV_NEVER) nextAdvanceISR -= interval); + TERN_(SMOOTH_LIN_ADVANCE, if (smoothLinAdvISR != LA_ADV_NEVER) smoothLinAdvISR -= interval); TERN_(BABYSTEPPING, if (nextBabystepISR != BABYSTEP_NEVER) nextBabystepISR -= interval); } // standard motion control @@ -2000,15 +2014,18 @@ void Stepper::pulse_phase_isr() { #if ANY(HAS_E0_STEP, MIXING_EXTRUDER) PULSE_PREP(E); + #endif - #if ENABLED(LIN_ADVANCE) - if (la_active && step_needed.e) { - // don't actually step here, but do subtract movements steps - // from the linear advance step count - step_needed.e = false; - la_advance_steps--; - } - #endif + #if HAS_ROUGH_LIN_ADVANCE + if (la_active && step_needed.e) { + // don't actually step here, but do subtract movements steps + // from the linear advance step count + step_needed.e = false; + la_advance_steps--; + } + #elif ENABLED(SMOOTH_LIN_ADVANCE) + // Extruder steps are exclusively managed by the LA isr + step_needed.e = false; #endif #if HAS_ZV_SHAPING @@ -2458,7 +2475,7 @@ hal_timer_t Stepper::block_phase_isr() { calc_nonlinear_e(acc_step_rate << oversampling_factor); #endif - #if ENABLED(LIN_ADVANCE) + #if HAS_ROUGH_LIN_ADVANCE if (la_active) { const uint32_t la_step_rate = la_advance_steps < current_block->max_adv_steps ? current_block->la_advance_rate : 0; la_interval = calc_timer_interval((acc_step_rate + la_step_rate) >> current_block->la_scaling); @@ -2487,6 +2504,7 @@ hal_timer_t Stepper::block_phase_isr() { else cutter.apply_power(0); } #endif + TERN_(SMOOTH_LIN_ADVANCE, curr_step_rate = acc_step_rate;) } // Are we in Deceleration phase ? else if (step_events_completed >= decelerate_start) { @@ -2523,7 +2541,7 @@ hal_timer_t Stepper::block_phase_isr() { calc_nonlinear_e(step_rate << oversampling_factor); #endif - #if ENABLED(LIN_ADVANCE) + #if HAS_ROUGH_LIN_ADVANCE if (la_active) { const uint32_t la_step_rate = la_advance_steps > current_block->final_adv_steps ? current_block->la_advance_rate : 0; if (la_step_rate != step_rate) { @@ -2561,7 +2579,7 @@ hal_timer_t Stepper::block_phase_isr() { } } #endif - + TERN_(SMOOTH_LIN_ADVANCE, curr_step_rate = step_rate;) } else { // Must be in cruise phase otherwise @@ -2571,13 +2589,14 @@ hal_timer_t Stepper::block_phase_isr() { ticks_nominal = calc_multistep_timer_interval(current_block->nominal_rate << oversampling_factor); // Prepare for deceleration IF_DISABLED(S_CURVE_ACCELERATION, acc_step_rate = current_block->nominal_rate); + TERN_(SMOOTH_LIN_ADVANCE, curr_step_rate = current_block->nominal_rate;) deceleration_time = ticks_nominal / 2; #if ENABLED(NONLINEAR_EXTRUSION) calc_nonlinear_e(current_block->nominal_rate << oversampling_factor); #endif - #if ENABLED(LIN_ADVANCE) + #if HAS_ROUGH_LIN_ADVANCE if (la_active) la_interval = calc_timer_interval(current_block->nominal_rate >> current_block->la_scaling); #endif @@ -2712,7 +2731,8 @@ hal_timer_t Stepper::block_phase_isr() { step_event_count = current_block->step_event_count << oversampling_factor; // Initialize Bresenham delta errors to 1/2 - delta_error = TERN_(LIN_ADVANCE, la_delta_error =) -int32_t(step_event_count); + delta_error = -int32_t(step_event_count); + TERN_(HAS_ROUGH_LIN_ADVANCE, la_delta_error = delta_error); // Calculate Bresenham dividends and divisors advance_dividend = (current_block->steps << 1).asLong(); @@ -2762,12 +2782,12 @@ hal_timer_t Stepper::block_phase_isr() { E_TERN_(stepper_extruder = current_block->extruder); // Initialize the trapezoid generator from the current block. - #if ENABLED(LIN_ADVANCE) - la_active = (current_block->la_advance_rate != 0); + #if HAS_ROUGH_LIN_ADVANCE #if DISABLED(MIXING_EXTRUDER) && E_STEPPERS > 1 // If the now active extruder wasn't in use during the last move, its pressure is most likely gone. if (stepper_extruder != last_moved_extruder) la_advance_steps = 0; #endif + la_active = (current_block->la_advance_rate != 0); if (la_active) { // Apply LA scaling and discount the effect of frequency scaling la_dividend = (advance_dividend.e << current_block->la_scaling) << oversampling_factor; @@ -2849,10 +2869,14 @@ hal_timer_t Stepper::block_phase_isr() { #endif #if ENABLED(LIN_ADVANCE) - if (la_active) { - const uint32_t la_step_rate = la_advance_steps < current_block->max_adv_steps ? current_block->la_advance_rate : 0; - la_interval = calc_timer_interval((current_block->initial_rate + la_step_rate) >> current_block->la_scaling); - } + #if ENABLED(SMOOTH_LIN_ADVANCE) + curr_timer_tick = 0; + #else + if (la_active) { + const uint32_t la_step_rate = la_advance_steps < current_block->max_adv_steps ? current_block->la_advance_rate : 0; + la_interval = calc_timer_interval((current_block->initial_rate + la_step_rate) >> current_block->la_scaling); + } + #endif #endif } } // !current_block @@ -2863,17 +2887,176 @@ hal_timer_t Stepper::block_phase_isr() { #if ENABLED(LIN_ADVANCE) + #if ENABLED(SMOOTH_LIN_ADVANCE) + + float Stepper::extruder_advance_tau[DISTINCT_E], + Stepper::extruder_advance_tau_ticks[DISTINCT_E], + Stepper::extruder_advance_alpha[DISTINCT_E]; + + void Stepper::set_la_interval(const int32_t rate) { + if (rate == 0) { + la_interval = LA_ADV_NEVER; + } + else { + const bool forward_e = rate > 0; + la_interval = calc_timer_interval(uint32_t(ABS(rate))); + if (forward_e != motor_direction(E_AXIS)) { + last_direction_bits.toggle(E_AXIS); + count_direction.e = -count_direction.e; + DIR_WAIT_BEFORE(); + E_APPLY_DIR(forward_e, false); + TERN_(FT_MOTION, last_set_direction = last_direction_bits); + DIR_WAIT_AFTER(); + } + } + } + + #if ENABLED(INPUT_SHAPING_E_SYNC) + + constexpr uint16_t IS_COMPENSATION_BUFFER_SIZE = uint16_t(float(SMOOTH_LIN_ADV_HZ) / float(SHAPING_MIN_FREQ) / 2.0f + 0.5f); + + typedef struct { + xy_float_t buffer[IS_COMPENSATION_BUFFER_SIZE]; + uint16_t index; + } DelayBuffer; + + DelayBuffer delayBuffer; + + void add_to_buffer(xy_float_t input) { + delayBuffer.buffer[delayBuffer.index++] = input; + if (delayBuffer.index == IS_COMPENSATION_BUFFER_SIZE) + delayBuffer.index = 0; + } + + xy_float_t lookback(shaping_time_t t /* in stepper timer ticks */) { + constexpr float ADV_TICKS_PER_STEPPER_TICKS = float(SMOOTH_LIN_ADV_HZ) / (STEPPER_TIMER_RATE); + uint32_t delay_steps = t * ADV_TICKS_PER_STEPPER_TICKS + 0.5f; // Convert time to steps + uint16_t past_i; + if (delay_steps>= IS_COMPENSATION_BUFFER_SIZE) { + // this means the buffer is too small. TODO: how to inform user? + past_i = delayBuffer.index; + } + else { + past_i = (delayBuffer.index + IS_COMPENSATION_BUFFER_SIZE - delay_steps) % IS_COMPENSATION_BUFFER_SIZE; + } + return delayBuffer.buffer[past_i]; + } + + #endif // INPUT_SHAPING_E_SYNC + + float lookahead(uint32_t t) { + for (uint8_t i = 0; block_t *block = Planner::get_future_block(i); i++) { + if (block->is_sync()) continue; + if (t <= block->acceleration_time) { + if (!block->use_advance_lead) return 0.0f; + uint32_t rate = STEP_MULTIPLY(t, block->acceleration_rate) + block->initial_rate; + NOMORE(rate, block->nominal_rate); + return rate * block->e_step_ratio; + } + t -= block->acceleration_time; + + if (t <= block->cruise_time) { + if (!block->use_advance_lead) return 0.0f; + return block->cruise_rate * block->e_step_ratio; + } + t -= block->cruise_time; + + if (t <= block->deceleration_time) { + if (!block->use_advance_lead) return 0.0f; + uint32_t rate = STEP_MULTIPLY(t, block->acceleration_rate); + if (rate < block->cruise_rate) { + rate = block->cruise_rate - rate; + NOLESS(rate, block->final_rate); + } + else + rate = block->final_rate; + return rate * block->e_step_ratio; + } + t -= block->deceleration_time; + } + return 0.0f; + } + + hal_timer_t Stepper::smooth_lin_adv_isr() { + float target_adv_steps = 0; + if (current_block) { + const uint32_t t = extruder_advance_tau_ticks[0] + curr_timer_tick; + target_adv_steps = lookahead(t) * Planner::extruder_advance_K[0]; + } + else { + curr_step_rate = 0; + } + static float last_target_adv_steps = 0; + constexpr float dt_inv = SMOOTH_LIN_ADV_HZ; + float la_step_rate = (target_adv_steps - last_target_adv_steps) * dt_inv; + last_target_adv_steps = target_adv_steps; + + static float smoothed_vals[SMOOTH_LIN_ADV_EXP_ORDER] = {0}; + for (uint8_t i = 0; i < SMOOTH_LIN_ADV_EXP_ORDER; i++) { + // Approximate gaussian smoothing via higher order exponential smoothing + la_step_rate = extruder_advance_alpha[0] * la_step_rate + (1 - extruder_advance_alpha[0]) * smoothed_vals[i]; + smoothed_vals[i] = la_step_rate; + } + const float planned_step_rate = current_block ? curr_step_rate * current_block->e_step_ratio : 0; + float total_step_rate = la_step_rate + planned_step_rate; + + #if ENABLED(INPUT_SHAPING_E_SYNC) + + xy_float_t pre_shaping_rate = xy_float_t({0, 0}), + first_pulse_rate = xy_float_t({0, 0}); + float unshaped_rate_e = total_step_rate; + if (current_block) { + const float xy_length = TERN0(INPUT_SHAPING_X, current_block->steps.x) + TERN0(INPUT_SHAPING_Y, current_block->steps.y); + if (xy_length > 0) { + unshaped_rate_e = 0; + pre_shaping_rate = xy_float_t({ + TERN0(INPUT_SHAPING_X, total_step_rate * current_block->steps.x / xy_length), + TERN0(INPUT_SHAPING_Y, total_step_rate * current_block->steps.y / xy_length) + }); + first_pulse_rate = xy_float_t({ + TERN0(INPUT_SHAPING_X, pre_shaping_rate.x * Stepper::shaping_x.factor1 / 128.0f), + TERN0(INPUT_SHAPING_Y, pre_shaping_rate.y * Stepper::shaping_y.factor1 / 128.0f) + }); + } + } + const xy_float_t second_pulse_rate = { + TERN0(INPUT_SHAPING_X, lookback(ShapingQueue::get_delay_x()).x * Stepper::shaping_x.factor2 / 128.0f), + TERN0(INPUT_SHAPING_Y, lookback(ShapingQueue::get_delay_y()).y * Stepper::shaping_y.factor2 / 128.0f) + }; + add_to_buffer(pre_shaping_rate); + + const float x = TERN0(INPUT_SHAPING_X, first_pulse_rate.x + second_pulse_rate.x), + y = TERN0(INPUT_SHAPING_Y, first_pulse_rate.y + second_pulse_rate.y); + + total_step_rate = unshaped_rate_e + x + y; + + #endif // INPUT_SHAPING_E_SYNC + + set_la_interval(total_step_rate); + + curr_timer_tick += SMOOTH_LIN_ADV_INTERVAL; + return SMOOTH_LIN_ADV_INTERVAL; + } + #endif // SMOOTH_LIN_ADVANCE + // Timer interrupt for E. LA_steps is set in the main routine void Stepper::advance_isr() { // Apply Bresenham algorithm so that linear advance can piggy back on // the acceleration and speed values calculated in block_phase_isr(). // This helps keep LA in sync with, for example, S_CURVE_ACCELERATION. - la_delta_error += la_dividend; - const bool e_step_needed = la_delta_error >= 0; + #if HAS_ROUGH_LIN_ADVANCE + la_delta_error += la_dividend; + const bool e_step_needed = la_delta_error >= 0; + #else + constexpr bool e_step_needed = true; + #endif + if (e_step_needed) { count_position.e += count_direction.e; - la_advance_steps += count_direction.e; - la_delta_error -= advance_divisor; + #if HAS_ROUGH_LIN_ADVANCE + la_advance_steps += count_direction.e; + la_delta_error -= advance_divisor; + #endif // Set the STEP pulse ON E_STEP_WRITE(TERN(MIXING_EXTRUDER, mixer.get_next_stepper(), stepper_extruder), STEP_STATE_E); diff --git a/Marlin/src/module/stepper.h b/Marlin/src/module/stepper.h index 306b2151b5..83ada9202e 100644 --- a/Marlin/src/module/stepper.h +++ b/Marlin/src/module/stepper.h @@ -241,18 +241,21 @@ constexpr ena_mask_t enable_overlap[] = { static bool dequeue_x() { SHAPING_QUEUE_DEQUEUE(x) } static bool empty_x() { return head_x == tail; } static uint16_t free_count_x() { return _free_count_x; } + static uint16_t get_delay_x() { return delay_x; } #endif #if ENABLED(INPUT_SHAPING_Y) static shaping_time_t peek_y() { return _peek_y; } static bool dequeue_y() { SHAPING_QUEUE_DEQUEUE(y) } static bool empty_y() { return head_y == tail; } static uint16_t free_count_y() { return _free_count_y; } + static uint16_t get_delay_y() { return delay_y; } #endif #if ENABLED(INPUT_SHAPING_Z) static shaping_time_t peek_z() { return _peek_z; } static bool dequeue_z() { SHAPING_QUEUE_DEQUEUE(z) } static bool empty_z() { return head_z == tail; } static uint16_t free_count_z() { return _free_count_z; } + static uint16_t get_delay_z() { return delay_z; } #endif static void purge() { const auto st = shaping_time_t(-1); @@ -292,6 +295,7 @@ constexpr ena_mask_t enable_overlap[] = { class Stepper { friend class Max7219; friend class FTMotion; + friend class MarlinSettings; friend void stepperTask(void *); public: @@ -348,6 +352,16 @@ class Stepper { static constexpr bool adaptive_step_smoothing_enabled = true; #endif + #if ENABLED(SMOOTH_LIN_ADVANCE) + static void set_advance_tau(const_float_t tau, const uint8_t e=E_INDEX_N(active_extruder)) { + extruder_advance_tau[e] = tau; + extruder_advance_tau_ticks[e] = tau * (STEPPER_TIMER_RATE); // i.e., <= STEPPER_TIMER_RATE / 2 + // α=1−exp(−dt/τ) + extruder_advance_alpha[e] = 1.0f - expf(-(SMOOTH_LIN_ADV_INTERVAL) * (SMOOTH_LIN_ADV_EXP_ORDER) / extruder_advance_tau_ticks[e]); + } + static float get_advance_tau(const uint8_t e=E_INDEX_N(active_extruder)) { return extruder_advance_tau[e]; } + #endif + private: static block_t* current_block; // A pointer to the block currently being traced @@ -434,11 +448,20 @@ class Stepper { #if ENABLED(LIN_ADVANCE) static constexpr hal_timer_t LA_ADV_NEVER = HAL_TIMER_TYPE_MAX; static hal_timer_t nextAdvanceISR, - la_interval; // Interval between ISR calls for LA - static int32_t la_delta_error, // Analogue of delta_error.e for E steps in LA ISR - la_dividend, // Analogue of advance_dividend.e for E steps in LA ISR - la_advance_steps; // Count of steps added to increase nozzle pressure - static bool la_active; // Whether linear advance is used on the present segment. + la_interval; // Interval between ISR calls for LA + #if ENABLED(SMOOTH_LIN_ADVANCE) + static uint32_t curr_timer_tick, // Current tick relative to block start + curr_step_rate; // Current motion step rate + static float extruder_advance_tau[DISTINCT_E], // Smoothing time; also the lookahead time of the smoother + extruder_advance_tau_ticks[DISTINCT_E], // Same as extruder_advance_tau but in in stepper timer ticks + extruder_advance_alpha[DISTINCT_E]; // The smoothing factor of each stage of the high-order exponential + // smoothing filter (calculated from tau) + #else + static int32_t la_delta_error, // Analogue of delta_error.e for E steps in LA ISR + la_dividend, // Analogue of advance_dividend.e for E steps in LA ISR + la_advance_steps; // Count of steps added to increase nozzle pressure + static bool la_active; // Whether linear advance is used on the present segment + #endif #endif #if ENABLED(NONLINEAR_EXTRUSION) @@ -504,6 +527,10 @@ class Stepper { #if ENABLED(LIN_ADVANCE) // The Linear advance ISR phase static void advance_isr(); + #if ENABLED(SMOOTH_LIN_ADVANCE) + static void set_la_interval(const int32_t rate); + static hal_timer_t smooth_lin_adv_isr(); + #endif #endif #if ENABLED(BABYSTEPPING) @@ -558,7 +585,7 @@ class Stepper { current_block = nullptr; axis_did_move.reset(); planner.release_current_block(); - TERN_(LIN_ADVANCE, la_interval = nextAdvanceISR = LA_ADV_NEVER); + TERN_(HAS_ROUGH_LIN_ADVANCE, la_interval = nextAdvanceISR = LA_ADV_NEVER); } // Quickly stop all steppers diff --git a/buildroot/tests/LPC1768 b/buildroot/tests/LPC1768 index 3a08af8ae8..cd911a9060 100755 --- a/buildroot/tests/LPC1768 +++ b/buildroot/tests/LPC1768 @@ -77,21 +77,19 @@ opt_set MOTHERBOARD BOARD_BTT_SKR_V1_4 SERIAL_PORT -1 \ Z_STEPPER_ALIGN_ITERATIONS 10 DEFAULT_STEPPER_TIMEOUT_SEC 0 \ SLOWDOWN_DIVISOR 16 SDCARD_CONNECTION ONBOARD BLOCK_BUFFER_SIZE 64 \ CHOPPER_TIMING CHOPPER_DEFAULT_24V MMU_SERIAL_PORT 0 -opt_enable PIDTEMPBED S_CURVE_ACCELERATION \ - USE_PROBE_FOR_Z_HOMING BLTOUCH FILAMENT_RUNOUT_SENSOR \ - AUTO_BED_LEVELING_BILINEAR RESTORE_LEVELING_AFTER_G28 \ - EXTRAPOLATE_BEYOND_GRID LCD_BED_LEVELING MESH_EDIT_MENU Z_SAFE_HOMING \ - EEPROM_SETTINGS EEPROM_AUTO_INIT NOZZLE_PARK_FEATURE SDSUPPORT \ - SPEAKER CR10_STOCKDISPLAY QUICK_HOME BLTOUCH_FORCE_SW_MODE \ - Z_STEPPER_AUTO_ALIGN INPUT_SHAPING_X INPUT_SHAPING_Y SHAPING_MENU \ - ADAPTIVE_STEP_SMOOTHING LCD_INFO_MENU STATUS_MESSAGE_SCROLLING \ - SET_PROGRESS_MANUALLY M73_REPORT SHOW_REMAINING_TIME \ - PRINT_PROGRESS_SHOW_DECIMALS AUTO_REPORT_SD_STATUS USE_BIG_EDIT_FONT \ - BABYSTEPPING BABYSTEP_WITHOUT_HOMING BABYSTEP_ALWAYS_AVAILABLE \ - DOUBLECLICK_FOR_Z_BABYSTEPPING BABYSTEP_DISPLAY_TOTAL LIN_ADVANCE \ - BEZIER_CURVE_SUPPORT EMERGENCY_PARSER ADVANCED_PAUSE_FEATURE \ - TMC_DEBUG HOST_ACTION_COMMANDS HOST_PAUSE_M76 HOST_PROMPT_SUPPORT \ - HOST_STATUS_NOTIFICATIONS MMU_DEBUG +opt_enable PIDTEMPBED FILAMENT_RUNOUT_SENSOR NOZZLE_PARK_FEATURE ADVANCED_PAUSE_FEATURE \ + AUTO_BED_LEVELING_BILINEAR EXTRAPOLATE_BEYOND_GRID RESTORE_LEVELING_AFTER_G28 LCD_BED_LEVELING MESH_EDIT_MENU \ + BLTOUCH BLTOUCH_FORCE_SW_MODE USE_PROBE_FOR_Z_HOMING Z_SAFE_HOMING QUICK_HOME Z_STEPPER_AUTO_ALIGN \ + SDSUPPORT AUTO_REPORT_SD_STATUS \ + EEPROM_SETTINGS EEPROM_AUTO_INIT \ + CR10_STOCKDISPLAY USE_BIG_EDIT_FONT SPEAKER LCD_INFO_MENU STATUS_MESSAGE_SCROLLING \ + INPUT_SHAPING_X INPUT_SHAPING_Y SHAPING_MENU \ + BEZIER_CURVE_SUPPORT \ + LIN_ADVANCE SMOOTH_LIN_ADVANCE INPUT_SHAPING_E_SYNC \ + TMC_DEBUG ADAPTIVE_STEP_SMOOTHING \ + SET_PROGRESS_MANUALLY M73_REPORT SHOW_REMAINING_TIME PRINT_PROGRESS_SHOW_DECIMALS \ + BABYSTEPPING BABYSTEP_WITHOUT_HOMING BABYSTEP_ALWAYS_AVAILABLE DOUBLECLICK_FOR_Z_BABYSTEPPING BABYSTEP_DISPLAY_TOTAL \ + EMERGENCY_PARSER HOST_ACTION_COMMANDS HOST_PAUSE_M76 HOST_PROMPT_SUPPORT HOST_STATUS_NOTIFICATIONS MMU_DEBUG opt_disable Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN FILAMENT_LOAD_UNLOAD_GCODES \ PARK_HEAD_ON_PAUSE exec_test $1 $2 "BigTreeTech SKR 1.4 | MMU2" "$3" diff --git a/buildroot/tests/LPC1769 b/buildroot/tests/LPC1769 index f29bbb5656..5356d3e186 100755 --- a/buildroot/tests/LPC1769 +++ b/buildroot/tests/LPC1769 @@ -81,20 +81,20 @@ opt_set MOTHERBOARD BOARD_BTT_SKR_V1_4_TURBO SERIAL_PORT -1 \ SLOWDOWN_DIVISOR 16 SDCARD_CONNECTION ONBOARD BLOCK_BUFFER_SIZE 64 \ CHOPPER_TIMING CHOPPER_DEFAULT_24V MMU_SERIAL_PORT 0 \ Z_MIN_ENDSTOP_HIT_STATE HIGH -opt_enable PIDTEMPBED S_CURVE_ACCELERATION \ - USE_PROBE_FOR_Z_HOMING BLTOUCH FILAMENT_RUNOUT_SENSOR \ - AUTO_BED_LEVELING_BILINEAR RESTORE_LEVELING_AFTER_G28 \ - EXTRAPOLATE_BEYOND_GRID LCD_BED_LEVELING MESH_EDIT_MENU Z_SAFE_HOMING \ - EEPROM_SETTINGS EEPROM_AUTO_INIT NOZZLE_PARK_FEATURE SDSUPPORT \ - SPEAKER CR10_STOCKDISPLAY QUICK_HOME BLTOUCH_FORCE_SW_MODE \ - Z_STEPPER_AUTO_ALIGN INPUT_SHAPING_X INPUT_SHAPING_Y SHAPING_MENU \ - ADAPTIVE_STEP_SMOOTHING LCD_INFO_MENU STATUS_MESSAGE_SCROLLING \ +opt_enable PIDTEMPBED \ + FILAMENT_RUNOUT_SENSOR NOZZLE_PARK_FEATURE ADVANCED_PAUSE_FEATURE \ + BLTOUCH BLTOUCH_FORCE_SW_MODE USE_PROBE_FOR_Z_HOMING Z_SAFE_HOMING QUICK_HOME Z_STEPPER_AUTO_ALIGN \ + AUTO_BED_LEVELING_BILINEAR EXTRAPOLATE_BEYOND_GRID RESTORE_LEVELING_AFTER_G28 LCD_BED_LEVELING MESH_EDIT_MENU \ + EEPROM_SETTINGS EEPROM_AUTO_INIT \ + SDSUPPORT CR10_STOCKDISPLAY SPEAKER LCD_INFO_MENU STATUS_MESSAGE_SCROLLING \ + INPUT_SHAPING_X INPUT_SHAPING_Y SHAPING_MENU \ + BEZIER_CURVE_SUPPORT LIN_ADVANCE \ + TMC_DEBUG S_CURVE_ACCELERATION ADAPTIVE_STEP_SMOOTHING \ SET_PROGRESS_MANUALLY M73_REPORT SHOW_REMAINING_TIME \ PRINT_PROGRESS_SHOW_DECIMALS AUTO_REPORT_SD_STATUS USE_BIG_EDIT_FONT \ BABYSTEPPING BABYSTEP_WITHOUT_HOMING BABYSTEP_ALWAYS_AVAILABLE \ - DOUBLECLICK_FOR_Z_BABYSTEPPING BABYSTEP_DISPLAY_TOTAL LIN_ADVANCE \ - BEZIER_CURVE_SUPPORT EMERGENCY_PARSER ADVANCED_PAUSE_FEATURE \ - TMC_DEBUG HOST_ACTION_COMMANDS HOST_PAUSE_M76 HOST_PROMPT_SUPPORT HOST_STATUS_NOTIFICATIONS \ + DOUBLECLICK_FOR_Z_BABYSTEPPING BABYSTEP_DISPLAY_TOTAL \ + EMERGENCY_PARSER HOST_ACTION_COMMANDS HOST_PAUSE_M76 HOST_PROMPT_SUPPORT HOST_STATUS_NOTIFICATIONS \ MMU3_SPOOL_JOIN_CONSUMES_ALL_FILAMENT MMU_MENUS MMU_DEBUG opt_disable Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN FILAMENT_LOAD_UNLOAD_GCODES PARK_HEAD_ON_PAUSE exec_test $1 $2 "BigTreeTech SKR 1.4 Turbo | MMU3" "$3" From 4b32be9df074df23ee084869af8a3ed3bd07c9f5 Mon Sep 17 00:00:00 2001 From: Keith Bennett <13375512+thisiskeithb@users.noreply.github.com> Date: Sun, 20 Apr 2025 09:04:48 -0700 Subject: [PATCH 233/787] =?UTF-8?q?=F0=9F=94=A7=20Malyan=20M300=20/=20Mono?= =?UTF-8?q?price=20Mini=20alternate=20orientation=20(#27808)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/pins/stm32f0/pins_MALYAN_M300.h | 44 ++++++++++++++++------ 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/Marlin/src/pins/stm32f0/pins_MALYAN_M300.h b/Marlin/src/pins/stm32f0/pins_MALYAN_M300.h index 5bc8c5f74b..0a524e4952 100644 --- a/Marlin/src/pins/stm32f0/pins_MALYAN_M300.h +++ b/Marlin/src/pins/stm32f0/pins_MALYAN_M300.h @@ -46,9 +46,15 @@ // // Limit Switches // -#define X_STOP_PIN PC13 -#define Y_STOP_PIN PC14 -#define Z_STOP_PIN PC15 +#if ENABLED(M300_ROTATE_TOWERS) + #define X_STOP_PIN PC14 + #define Y_STOP_PIN PC15 + #define Z_STOP_PIN PC13 +#else + #define X_STOP_PIN PC13 + #define Y_STOP_PIN PC14 + #define Z_STOP_PIN PC15 +#endif #ifndef Z_MIN_PROBE_PIN #define Z_MIN_PROBE_PIN PB7 @@ -57,17 +63,31 @@ // // Steppers // -#define X_STEP_PIN PB14 -#define X_DIR_PIN PB13 -#define X_ENABLE_PIN PB10 +#if ENABLED(M300_ROTATE_TOWERS) + #define X_STEP_PIN PB12 + #define X_DIR_PIN PB11 + #define X_ENABLE_PIN PB10 -#define Y_STEP_PIN PB12 -#define Y_DIR_PIN PB11 -#define Y_ENABLE_PIN PB10 + #define Y_STEP_PIN PB2 + #define Y_DIR_PIN PB1 + #define Y_ENABLE_PIN PB10 -#define Z_STEP_PIN PB2 -#define Z_DIR_PIN PB1 -#define Z_ENABLE_PIN PB10 + #define Z_STEP_PIN PB14 + #define Z_DIR_PIN PB13 + #define Z_ENABLE_PIN PB10 +#else + #define X_STEP_PIN PB14 + #define X_DIR_PIN PB13 + #define X_ENABLE_PIN PB10 + + #define Y_STEP_PIN PB12 + #define Y_DIR_PIN PB11 + #define Y_ENABLE_PIN PB10 + + #define Z_STEP_PIN PB2 + #define Z_DIR_PIN PB1 + #define Z_ENABLE_PIN PB10 +#endif #define E0_STEP_PIN PA7 #define E0_DIR_PIN PA6 From d3687d933ca029626865d8465ef5ea728a262296 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sun, 20 Apr 2025 11:27:15 -0500 Subject: [PATCH 234/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Add?= =?UTF-8?q?=20stepper/control.cpp=20(2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/inc/Conditionals-5-post.h | 2 +- Marlin/src/module/settings.cpp | 2 +- Marlin/src/module/stepper.cpp | 12 ---- Marlin/src/module/stepper/control.cpp | 87 +++++++++++++++------------ 4 files changed, 51 insertions(+), 52 deletions(-) diff --git a/Marlin/src/inc/Conditionals-5-post.h b/Marlin/src/inc/Conditionals-5-post.h index 920031dcdb..fd06285bca 100644 --- a/Marlin/src/inc/Conditionals-5-post.h +++ b/Marlin/src/inc/Conditionals-5-post.h @@ -3012,7 +3012,7 @@ #undef MICROSTEP_MODES #endif -#if MB(PRINTRBOARD_G2) || ANY(HAS_MOTOR_CURRENT_SPI, HAS_MOTOR_CURRENT_PWM, HAS_MICROSTEPS) +#if ANY(HAS_MOTOR_CURRENT_SPI, HAS_MOTOR_CURRENT_PWM, HAS_MICROSTEPS) #define HAS_STEPPER_CONTROL 1 #endif diff --git a/Marlin/src/module/settings.cpp b/Marlin/src/module/settings.cpp index feb433041e..8c99c54323 100644 --- a/Marlin/src/module/settings.cpp +++ b/Marlin/src/module/settings.cpp @@ -508,7 +508,7 @@ typedef struct SettingsDataStruct { #endif // - // HAS_MOTOR_CURRENT_PWM + // Stepper Motors Current // #ifndef MOTOR_CURRENT_COUNT #if HAS_MOTOR_CURRENT_PWM diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp index cc042181c6..1d02620e6f 100644 --- a/Marlin/src/module/stepper.cpp +++ b/Marlin/src/module/stepper.cpp @@ -120,10 +120,6 @@ Stepper stepper; // Singleton #include "../feature/dac/dac_dac084s085.h" #endif -#if HAS_MOTOR_CURRENT_SPI - #include -#endif - #if ENABLED(MIXING_EXTRUDER) #include "../feature/mixing.h" #endif @@ -158,14 +154,6 @@ Stepper stepper; // Singleton bool Stepper::separate_multi_axis = false; #endif -#if HAS_MOTOR_CURRENT_SPI || HAS_MOTOR_CURRENT_PWM - bool Stepper::initialized; // = false - uint32_t Stepper::motor_current_setting[MOTOR_CURRENT_COUNT]; // Initialized by settings.load - #if HAS_MOTOR_CURRENT_SPI - constexpr uint32_t Stepper::digipot_count[]; - #endif -#endif - stepper_flags_t Stepper::axis_enabled; // {0} // private: diff --git a/Marlin/src/module/stepper/control.cpp b/Marlin/src/module/stepper/control.cpp index 0d523c8ed5..4d4b6b351f 100644 --- a/Marlin/src/module/stepper/control.cpp +++ b/Marlin/src/module/stepper/control.cpp @@ -30,14 +30,24 @@ #if MB(PRINTRBOARD_G2) #include HAL_PATH(../.., fastio/G2_PWM.h) +#elif HAS_MOTOR_CURRENT_SPI || HAS_MOTOR_CURRENT_PWM + #define HAS_NON_G2_MOTOR_CURRENT 1 +#endif + +#if HAS_MOTOR_CURRENT_PWM || HAS_NON_G2_MOTOR_CURRENT + bool Stepper::initialized; // = false + uint32_t Stepper::motor_current_setting[MOTOR_CURRENT_COUNT]; // Initialized by settings.load #endif /** - * Software-controlled Stepper Motor Current + * SPI-controlled Stepper Motor Current */ #if HAS_MOTOR_CURRENT_SPI + #include + constexpr uint32_t Stepper::digipot_count[]; + // From Arduino DigitalPotControl example void Stepper::set_digipot_value_spi(const int16_t address, const int16_t value) { WRITE(DIGIPOTSS_PIN, LOW); // Take the SS pin low to select the chip @@ -47,8 +57,36 @@ //delay(10); } + #if HAS_NON_G2_MOTOR_CURRENT + + void Stepper::set_digipot_current(const uint8_t driver, const int16_t current) { + if (WITHIN(driver, 0, COUNT(motor_current_setting) - 1)) + motor_current_setting[driver] = current; // update motor_current_setting + + if (!initialized) return; + + //SERIAL_ECHOLNPGM("Digipotss current ", current); + + const uint8_t digipot_ch[] = DIGIPOT_CHANNELS; + set_digipot_value_spi(digipot_ch[driver], current); + } + + void Stepper::digipot_init() { + SPI.begin(); + SET_OUTPUT(DIGIPOTSS_PIN); + + for (uint8_t i = 0; i < COUNT(motor_current_setting); ++i) + set_digipot_current(i, motor_current_setting[i]); + } + + #endif // HAS_NON_G2_MOTOR_CURRENT + #endif // HAS_MOTOR_CURRENT_SPI +/** + * PWM-controlled Stepper Motor Current + */ + #if HAS_MOTOR_CURRENT_PWM void Stepper::refresh_motor_power() { @@ -70,28 +108,13 @@ } } -#endif // HAS_MOTOR_CURRENT_PWM + #if HAS_NON_G2_MOTOR_CURRENT -/** - * PWM-controlled Stepper Motor Current - */ + void Stepper::set_digipot_current(const uint8_t driver, const int16_t current) { + if (WITHIN(driver, 0, COUNT(motor_current_setting) - 1)) + motor_current_setting[driver] = current; // update motor_current_setting -#if !MB(PRINTRBOARD_G2) && (HAS_MOTOR_CURRENT_SPI || HAS_MOTOR_CURRENT_PWM) - - void Stepper::set_digipot_current(const uint8_t driver, const int16_t current) { - if (WITHIN(driver, 0, COUNT(motor_current_setting) - 1)) - motor_current_setting[driver] = current; // update motor_current_setting - - if (!initialized) return; - - #if HAS_MOTOR_CURRENT_SPI - - //SERIAL_ECHOLNPGM("Digipotss current ", current); - - const uint8_t digipot_ch[] = DIGIPOT_CHANNELS; - set_digipot_value_spi(digipot_ch[driver], current); - - #elif HAS_MOTOR_CURRENT_PWM + if (!initialized) return; #define _WRITE_CURRENT_PWM(P) hal.set_pwm_duty(pin_t(MOTOR_CURRENT_PWM_## P ##_PIN), 255L * current / (MOTOR_CURRENT_PWM_RANGE)) switch (driver) { @@ -141,21 +164,9 @@ #endif break; } - #endif - } - - void Stepper::digipot_init() { - - #if HAS_MOTOR_CURRENT_SPI - - SPI.begin(); - SET_OUTPUT(DIGIPOTSS_PIN); - - for (uint8_t i = 0; i < COUNT(motor_current_setting); ++i) - set_digipot_current(i, motor_current_setting[i]); - - #elif HAS_MOTOR_CURRENT_PWM + } + void Stepper::digipot_init() { #ifdef __SAM3X8E__ #define _RESET_CURRENT_PWM_FREQ(P) NOOP #else @@ -204,11 +215,11 @@ #endif refresh_motor_power(); + } - #endif - } + #endif // HAS_NON_G2_MOTOR_CURRENT -#endif +#endif // HAS_MOTOR_CURRENT_PWM /** * Software-controlled Microstepping with digital pins From b23f86f83f6ff5f2e8fcedc4203ca081cbc58596 Mon Sep 17 00:00:00 2001 From: B Date: Sun, 20 Apr 2025 10:12:02 -0700 Subject: [PATCH 235/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20GD3?= =?UTF-8?q?2=20fast=20write=20non-bool=20(#27806)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/HAL/GD32_MFL/fastio.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Marlin/src/HAL/GD32_MFL/fastio.h b/Marlin/src/HAL/GD32_MFL/fastio.h index 8185be73a4..35bd2b1ef7 100644 --- a/Marlin/src/HAL/GD32_MFL/fastio.h +++ b/Marlin/src/HAL/GD32_MFL/fastio.h @@ -27,9 +27,12 @@ #include #include -static inline void fast_write_pin_wrapper(pin_size_t IO, bool V) { - if (V) gpio::fast_set_pin(getPortFromPin(IO), getPinInPort(IO)); - else gpio::fast_clear_pin(getPortFromPin(IO), getPinInPort(IO)); +template +static inline void fast_write_pin_wrapper(pin_size_t IO, T V) { + auto port = getPortFromPin(IO); + auto pin = getPinInPort(IO); + if (static_cast(V)) gpio::fast_set_pin(port, pin); + else gpio::fast_clear_pin(port, pin); } static inline bool fast_read_pin_wrapper(pin_size_t IO) { From d434729da6ea38295fed76a23603767439b22e06 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sun, 20 Apr 2025 19:25:12 -0500 Subject: [PATCH 236/787] =?UTF-8?q?=F0=9F=90=9B=F0=9F=94=A7=20Move=20extra?= =?UTF-8?q?=20volume=20flags?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/inc/Conditionals-2-LCD.h | 6 ------ Marlin/src/inc/Conditionals-4-adv.h | 10 ++++++++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Marlin/src/inc/Conditionals-2-LCD.h b/Marlin/src/inc/Conditionals-2-LCD.h index 633cd2beb6..2bf663b6f0 100644 --- a/Marlin/src/inc/Conditionals-2-LCD.h +++ b/Marlin/src/inc/Conditionals-2-LCD.h @@ -36,12 +36,6 @@ #if ENABLED(SDSUPPORT) #define HAS_MEDIA 1 #endif -#if ENABLED(MULTI_VOLUME) - #define HAS_MULTI_VOLUME 1 -#endif -#if ENABLED(USB_FLASH_DRIVE_SUPPORT) - #define HAS_USB_FLASH_DRIVE 1 -#endif // // Serial Port Info diff --git a/Marlin/src/inc/Conditionals-4-adv.h b/Marlin/src/inc/Conditionals-4-adv.h index ca096c7661..3b01077931 100644 --- a/Marlin/src/inc/Conditionals-4-adv.h +++ b/Marlin/src/inc/Conditionals-4-adv.h @@ -1246,8 +1246,14 @@ #define HOMING_BUMP_MM { 0, 0, 0 } #endif -#if HAS_USB_FLASH_DRIVE && NONE(USE_OTG_USB_HOST, USE_UHS3_USB) - #define USE_UHS2_USB +#if ENABLED(MULTI_VOLUME) + #define HAS_MULTI_VOLUME 1 +#endif +#if ENABLED(USB_FLASH_DRIVE_SUPPORT) + #define HAS_USB_FLASH_DRIVE 1 + #if NONE(USE_OTG_USB_HOST, USE_UHS3_USB) + #define USE_UHS2_USB + #endif #endif /** From 1e009c2aa5f3ca5c7d5671f28dec333b9a2f3686 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Mon, 21 Apr 2025 00:32:59 +0000 Subject: [PATCH 237/787] [cron] Bump distribution date (2025-04-21) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 85663d4899..50361ebc03 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-04-20" +//#define STRING_DISTRIBUTION_DATE "2025-04-21" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index f46988c11b..2462ecd50c 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-04-20" + #define STRING_DISTRIBUTION_DATE "2025-04-21" #endif /** From 24928f93bac5694daf00827316419cd224781fb0 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Mon, 21 Apr 2025 19:59:41 -0500 Subject: [PATCH 238/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Fas?= =?UTF-8?q?tIO=20AT90USB=20pins=2046-47?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/HAL/AVR/fastio/fastio_AT90USB.h | 12 ++++++------ Marlin/src/HAL/AVR/pinsDebug.h | 8 ++++---- Marlin/src/gcode/config/M43.cpp | 20 ++++++++++---------- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/Marlin/src/HAL/AVR/fastio/fastio_AT90USB.h b/Marlin/src/HAL/AVR/fastio/fastio_AT90USB.h index 2119d168ab..a9af519ff3 100644 --- a/Marlin/src/HAL/AVR/fastio/fastio_AT90USB.h +++ b/Marlin/src/HAL/AVR/fastio/fastio_AT90USB.h @@ -363,8 +363,11 @@ #define AIO7_PWM 0 #define AIO7_DDR DDRF -//-- Begin not supported by Teensyduino -//-- don't use Arduino functions on these pins pinMode/digitalWrite/etc +//-- 46-47 are not supported by Teensyduino +//-- Don't use Arduino functions (pinMode, digitalWrite, etc.) on these pins +#define PIN_E2 46 +#define PIN_E3 47 + #define DIO46_PIN PINE2 #define DIO46_RPORT PINE #define DIO46_WPORT PORTE @@ -377,10 +380,7 @@ #define DIO47_PWM 0 #define DIO47_DDR DDRE -#define TEENSY_E2 46 -#define TEENSY_E3 47 - -//-- end not supported by Teensyduino +//-- #undef PA0 #define PA0_PIN PINA0 diff --git a/Marlin/src/HAL/AVR/pinsDebug.h b/Marlin/src/HAL/AVR/pinsDebug.h index e9bc09a4bf..c833964a29 100644 --- a/Marlin/src/HAL/AVR/pinsDebug.h +++ b/Marlin/src/HAL/AVR/pinsDebug.h @@ -377,16 +377,16 @@ void printPinPort(const pin_t pin) { // print port number uint8_t x; SERIAL_ECHOPGM(" Port: "); #if AVR_AT90USB1286_FAMILY - x = (pin == 46 || pin == 47) ? 'E' : digitalPinToPort_DEBUG(pin) + 64; + x = (pin == PIN_E2 || pin == PIN_E3) ? 'E' : 'A' + digitalPinToPort_DEBUG(pin) - 1; #else - x = digitalPinToPort_DEBUG(pin) + 64; + x = 'A' + digitalPinToPort_DEBUG(pin) - 1; #endif SERIAL_CHAR(x); #if AVR_AT90USB1286_FAMILY - if (pin == 46) + if (pin == PIN_E2) x = '2'; - else if (pin == 47) + else if (pin == PIN_E3) x = '3'; else { uint8_t temp = digitalPinToBitMask_DEBUG(pin); diff --git a/Marlin/src/gcode/config/M43.cpp b/Marlin/src/gcode/config/M43.cpp index 893607792a..a515acb241 100644 --- a/Marlin/src/gcode/config/M43.cpp +++ b/Marlin/src/gcode/config/M43.cpp @@ -79,20 +79,20 @@ inline void toggle_pins() { #endif ); #if AVR_AT90USB1286_FAMILY // Teensy IDEs don't know about these pins so must use FASTIO - if (pin == TEENSY_E2) { - SET_OUTPUT(TEENSY_E2); + if (pin == PIN_E2) { + SET_OUTPUT(PIN_E2); for (int16_t j = 0; j < repeat; j++) { - WRITE(TEENSY_E2, LOW); safe_delay(wait); - WRITE(TEENSY_E2, HIGH); safe_delay(wait); - WRITE(TEENSY_E2, LOW); safe_delay(wait); + WRITE(PIN_E2, LOW); safe_delay(wait); + WRITE(PIN_E2, HIGH); safe_delay(wait); + WRITE(PIN_E2, LOW); safe_delay(wait); } } - else if (pin == TEENSY_E3) { - SET_OUTPUT(TEENSY_E3); + else if (pin == PIN_E3) { + SET_OUTPUT(PIN_E3); for (int16_t j = 0; j < repeat; j++) { - WRITE(TEENSY_E3, LOW); safe_delay(wait); - WRITE(TEENSY_E3, HIGH); safe_delay(wait); - WRITE(TEENSY_E3, LOW); safe_delay(wait); + WRITE(PIN_E3, LOW); safe_delay(wait); + WRITE(PIN_E3, HIGH); safe_delay(wait); + WRITE(PIN_E3, LOW); safe_delay(wait); } } else From db3c5dd877fb41e2cd03ca3ff02c50e4f2bfcbbd Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Tue, 22 Apr 2025 06:09:47 +0000 Subject: [PATCH 239/787] [cron] Bump distribution date (2025-04-22) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 50361ebc03..59bbef9fda 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-04-21" +//#define STRING_DISTRIBUTION_DATE "2025-04-22" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 2462ecd50c..82956a1451 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-04-21" + #define STRING_DISTRIBUTION_DATE "2025-04-22" #endif /** From 9a901941aa118e88dcbbf3177e7d54495f34d909 Mon Sep 17 00:00:00 2001 From: InsanityAutomation <38436470+InsanityAutomation@users.noreply.github.com> Date: Tue, 22 Apr 2025 13:01:14 -0400 Subject: [PATCH 240/787] =?UTF-8?q?=F0=9F=90=9B=20Watchdog=20Reset=20PIO?= =?UTF-8?q?=20on=20DUE=20to=20prevent=20hang=20(#27803)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Scott Lahteine --- Marlin/src/HAL/DUE/HAL.cpp | 23 ++++++++------ Marlin/src/pins/pins.h | 30 +++++++++---------- .../PlatformIO/boards/marlin_archim.json | 2 +- ini/due.ini | 10 ++----- 4 files changed, 33 insertions(+), 32 deletions(-) diff --git a/Marlin/src/HAL/DUE/HAL.cpp b/Marlin/src/HAL/DUE/HAL.cpp index d1db9148c4..9b3cf1a516 100644 --- a/Marlin/src/HAL/DUE/HAL.cpp +++ b/Marlin/src/HAL/DUE/HAL.cpp @@ -102,6 +102,10 @@ void watchdogSetup() { #if ENABLED(USE_WATCHDOG) + #ifndef WATCHDOG_PIO_RESET + #define WATCHDOG_PIO_RESET + #endif + // 4 seconds timeout uint32_t timeout = TERN(WATCHDOG_DURATION_8S, 8000, 4000); @@ -115,15 +119,16 @@ void watchdogSetup() { timeout = 0xFFF; // We want to enable the watchdog with the specified timeout - uint32_t value = - WDT_MR_WDV(timeout) | // With the specified timeout - WDT_MR_WDD(timeout) | // and no invalid write window - #if !(SAMV70 || SAMV71 || SAME70 || SAMS70) - WDT_MR_WDRPROC | // WDT fault resets processor only - We want - // to keep PIO controller state - #endif - WDT_MR_WDDBGHLT | // WDT stops in debug state. - WDT_MR_WDIDLEHLT; // WDT stops in idle state. + uint32_t value = (0 + | WDT_MR_WDV(timeout) // With the specified timeout + | WDT_MR_WDD(timeout) // and no invalid write window + #if NONE(WATCHDOG_PIO_RESET, SAMV70, SAMV71, SAME70, SAMS70) + | WDT_MR_WDRPROC // WDT fault resets processor only with this flag. + // Omit to also reset the PIO controller. + #endif + | WDT_MR_WDDBGHLT // WDT stops in debug state. + | WDT_MR_WDIDLEHLT // WDT stops in idle state. + ); #if ENABLED(WATCHDOG_RESET_MANUAL) // We enable the watchdog timer, but only for the interrupt. diff --git a/Marlin/src/pins/pins.h b/Marlin/src/pins/pins.h index dcb8415de8..8c974cce48 100644 --- a/Marlin/src/pins/pins.h +++ b/Marlin/src/pins/pins.h @@ -516,33 +516,33 @@ // #elif MB(DUE3DOM) - #include "sam/pins_DUE3DOM.h" // SAM3X8E env:DUE env:DUE_USB env:DUE_debug + #include "sam/pins_DUE3DOM.h" // SAM3X8E env:DUE env:DUE_USB #elif MB(DUE3DOM_MINI) - #include "sam/pins_DUE3DOM_MINI.h" // SAM3X8E env:DUE env:DUE_USB env:DUE_debug + #include "sam/pins_DUE3DOM_MINI.h" // SAM3X8E env:DUE env:DUE_USB #elif MB(RADDS) - #include "sam/pins_RADDS.h" // SAM3X8E env:DUE env:DUE_USB env:DUE_debug + #include "sam/pins_RADDS.h" // SAM3X8E env:DUE env:DUE_USB #elif MB(RAMPS_FD_V1) - #include "sam/pins_RAMPS_FD_V1.h" // SAM3X8E env:DUE env:DUE_USB env:DUE_debug + #include "sam/pins_RAMPS_FD_V1.h" // SAM3X8E env:DUE env:DUE_USB #elif MB(RAMPS_FD_V2) - #include "sam/pins_RAMPS_FD_V2.h" // SAM3X8E env:DUE env:DUE_USB env:DUE_debug + #include "sam/pins_RAMPS_FD_V2.h" // SAM3X8E env:DUE env:DUE_USB #elif MB(RAMPS_SMART_EFB, RAMPS_SMART_EEB, RAMPS_SMART_EFF, RAMPS_SMART_EEF, RAMPS_SMART_SF) - #include "sam/pins_RAMPS_SMART.h" // SAM3X8E env:DUE env:DUE_USB env:DUE_debug + #include "sam/pins_RAMPS_SMART.h" // SAM3X8E env:DUE env:DUE_USB #elif MB(RAMPS_DUO_EFB, RAMPS_DUO_EEB, RAMPS_DUO_EFF, RAMPS_DUO_EEF, RAMPS_DUO_SF) - #include "sam/pins_RAMPS_DUO.h" // SAM3X8E env:DUE env:DUE_USB env:DUE_debug + #include "sam/pins_RAMPS_DUO.h" // SAM3X8E env:DUE env:DUE_USB #elif MB(RAMPS4DUE_EFB, RAMPS4DUE_EEB, RAMPS4DUE_EFF, RAMPS4DUE_EEF, RAMPS4DUE_SF) - #include "sam/pins_RAMPS4DUE.h" // SAM3X8E env:DUE env:DUE_USB env:DUE_debug + #include "sam/pins_RAMPS4DUE.h" // SAM3X8E env:DUE env:DUE_USB #elif MB(RURAMPS4D_11) - #include "sam/pins_RURAMPS4D_11.h" // SAM3X8E env:DUE env:DUE_USB env:DUE_debug + #include "sam/pins_RURAMPS4D_11.h" // SAM3X8E env:DUE env:DUE_USB #elif MB(RURAMPS4D_13) - #include "sam/pins_RURAMPS4D_13.h" // SAM3X8E env:DUE env:DUE_USB env:DUE_debug + #include "sam/pins_RURAMPS4D_13.h" // SAM3X8E env:DUE env:DUE_USB #elif MB(ULTRATRONICS_PRO) - #include "sam/pins_ULTRATRONICS_PRO.h" // SAM3X8E env:DUE env:DUE_debug + #include "sam/pins_ULTRATRONICS_PRO.h" // SAM3X8E env:DUE #elif MB(ARCHIM1) - #include "sam/pins_ARCHIM1.h" // SAM3X8E env:DUE_archim env:DUE_archim_debug + #include "sam/pins_ARCHIM1.h" // SAM3X8E env:DUE_archim #elif MB(ARCHIM2) - #include "sam/pins_ARCHIM2.h" // SAM3X8E env:DUE_archim env:DUE_archim_debug + #include "sam/pins_ARCHIM2.h" // SAM3X8E env:DUE_archim #elif MB(ALLIGATOR) - #include "sam/pins_ALLIGATOR_R2.h" // SAM3X8E env:DUE env:DUE_debug + #include "sam/pins_ALLIGATOR_R2.h" // SAM3X8E env:DUE #elif MB(CNCONTROLS_15D) #include "sam/pins_CNCONTROLS_15D.h" // SAM3X8E env:DUE env:DUE_USB #elif MB(KRATOS32) @@ -555,7 +555,7 @@ #elif MB(PRINTRBOARD_G2) #include "sam/pins_PRINTRBOARD_G2.h" // SAM3X8C env:DUE_USB #elif MB(ADSK) - #include "sam/pins_ADSK.h" // SAM3X8C env:DUE env:DUE_debug + #include "sam/pins_ADSK.h" // SAM3X8C env:DUE // // STM32 ARM Cortex-M0+ diff --git a/buildroot/share/PlatformIO/boards/marlin_archim.json b/buildroot/share/PlatformIO/boards/marlin_archim.json index 6d78c1f195..ee2ebd62ad 100644 --- a/buildroot/share/PlatformIO/boards/marlin_archim.json +++ b/buildroot/share/PlatformIO/boards/marlin_archim.json @@ -2,7 +2,7 @@ "build": { "core": "arduino", "cpu": "cortex-m3", - "extra_flags": "-D__SAM3X8E__ -DARDUINO_ARCH_SAM -DARDUINO_SAM_DUE", + "extra_flags": "-D__SAM3X8E__ -DARDUINO_SAM_DUE -DARDUINO_SAM_ARCHIM", "f_cpu": "84000000L", "hwids": [ [ diff --git a/ini/due.ini b/ini/due.ini index c1e2375d7c..7e4017e257 100644 --- a/ini/due.ini +++ b/ini/due.ini @@ -19,6 +19,7 @@ platform = atmelsam board = due build_src_filter = ${common.default_src_filter} + + +build_flags = -DWATCHDOG_PIO_RESET [env:DUE_USB] extends = env:DUE @@ -27,14 +28,9 @@ board = dueUSB # # Archim SAM # -[common_DUE_archim] +[env:DUE_archim] extends = env:DUE board = marlin_archim -build_flags = ${common.build_flags} - -DARDUINO_SAM_ARCHIM -DARDUINO_ARCH_SAM -D__SAM3X8E__ -DUSBCON board_build.variants_dir = buildroot/share/PlatformIO/variants/ extra_scripts = ${common.extra_scripts} - Marlin/src/HAL/DUE/upload_extra_script.py - -[env:DUE_archim] -extends = common_DUE_archim + Marlin/src/HAL/DUE/upload_extra_script.py From 28a1355f293d568e6f1ca70a0b63153bb1d5664b Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 22 Apr 2025 15:12:13 -0500 Subject: [PATCH 241/787] =?UTF-8?q?=F0=9F=8C=90=20Fix=20extra=20MSG=5FATTA?= =?UTF-8?q?CH=5FUSB=5FMEDIA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/lcd/language/language_ru.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Marlin/src/lcd/language/language_ru.h b/Marlin/src/lcd/language/language_ru.h index 991fd638ef..42e1656a8b 100644 --- a/Marlin/src/lcd/language/language_ru.h +++ b/Marlin/src/lcd/language/language_ru.h @@ -437,7 +437,7 @@ namespace LanguageNarrow_ru { LSTR MSG_FILAMENTUNLOAD_ALL = _UxGT("Выгрузить всё"); #if HAS_MULTI_VOLUME LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Установить SD карту"); - LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Установить флешка"); + LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Монтировать USB"); // Установить флешка #else LSTR MSG_ATTACH_MEDIA = _UxGT("Установить SD карту"); #endif @@ -766,7 +766,6 @@ namespace LanguageNarrow_ru { LSTR MSG_SINGLENOZZLE_WIPE_RETRACT = _UxGT("Вытирание при откате"); LSTR MSG_PARK_FAILED = _UxGT("Не удалось запарковать"); LSTR MSG_FILAMENTUNLOAD = _UxGT("Выгрузить филамент"); - LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Монтировать USB"); LSTR MSG_BLTOUCH_SPEED_MODE = _UxGT("Высокая скорость"); LSTR MSG_MANUAL_PENUP = _UxGT("Поднять перо"); LSTR MSG_MANUAL_PENDOWN = _UxGT("Опустить перо"); From 4b419eefd2b35bd08df928481053ca45a3bf992d Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 22 Apr 2025 17:41:59 -0500 Subject: [PATCH 242/787] =?UTF-8?q?=F0=9F=94=A5=20DEFAULT=5FVOLUME?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/Configuration_adv.h | 1 - 1 file changed, 1 deletion(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 9d291f6219..b1ad8d9629 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -1960,7 +1960,6 @@ #if ENABLED(MULTI_VOLUME) #define VOLUME_SD_ONBOARD #define VOLUME_USB_FLASH_DRIVE - #define DEFAULT_VOLUME SV_SD_ONBOARD #define DEFAULT_SHARED_VOLUME SV_USB_FLASH_DRIVE #endif From 21dadce958f993b1e33e94a7e160f2926ecd2177 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Wed, 23 Apr 2025 00:30:30 +0000 Subject: [PATCH 243/787] [cron] Bump distribution date (2025-04-23) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 59bbef9fda..e9c1d9ba1b 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-04-22" +//#define STRING_DISTRIBUTION_DATE "2025-04-23" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 82956a1451..d06c53dd5e 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-04-22" + #define STRING_DISTRIBUTION_DATE "2025-04-23" #endif /** From efd875766a7e443e2078d70c44c05b3947316c3b Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 22 Apr 2025 19:10:27 -0500 Subject: [PATCH 244/787] =?UTF-8?q?=F0=9F=9A=B8=20"Inverted"=20text=20on?= =?UTF-8?q?=20GLCD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/lcd/tft/themes/theme_ANET_BLACK.h | 1 + Marlin/src/lcd/tft/themes/theme_BLUE_MARLIN.h | 5 ++++- Marlin/src/lcd/tft/themes/theme_default.h | 3 +++ Marlin/src/lcd/tft/ui_common.cpp | 8 +++++--- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/Marlin/src/lcd/tft/themes/theme_ANET_BLACK.h b/Marlin/src/lcd/tft/themes/theme_ANET_BLACK.h index d6a7bab671..67db585435 100644 --- a/Marlin/src/lcd/tft/themes/theme_ANET_BLACK.h +++ b/Marlin/src/lcd/tft/themes/theme_ANET_BLACK.h @@ -47,6 +47,7 @@ #define COLOR_SD_DISABLED COLOR_CONTROL_DISABLED #define COLOR_MENU_TEXT COLOR_WHITE #define COLOR_MENU_STATIC_TEXT COLOR_WHITE +#define COLOR_MENU_INVERT_TEXT COLOR_YELLOW #define COLOR_MENU_BACK_TEXT COLOR_YELLOW #define COLOR_MENU_EDIT_TEXT COLOR_LIME2 #define COLOR_MENU_VALUE_FONT COLOR_ORANGE2 diff --git a/Marlin/src/lcd/tft/themes/theme_BLUE_MARLIN.h b/Marlin/src/lcd/tft/themes/theme_BLUE_MARLIN.h index 7414a7f250..bbc3b6671f 100644 --- a/Marlin/src/lcd/tft/themes/theme_BLUE_MARLIN.h +++ b/Marlin/src/lcd/tft/themes/theme_BLUE_MARLIN.h @@ -106,9 +106,12 @@ #ifndef COLOR_MENU_TEXT #define COLOR_MENU_TEXT COLOR_YELLOW #endif -#ifndef COLOR_MENU_TEXT +#ifndef COLOR_MENU_STATIC_TEXT #define COLOR_MENU_STATIC_TEXT COLOR_SILVER #endif +#ifndef COLOR_MENU_INVERT_TEXT + #define COLOR_MENU_INVERT_TEXT COLOR_WHITE +#endif #ifndef COLOR_MENU_BACK_TEXT #define COLOR_MENU_BACK_TEXT COLOR_CYAN #endif diff --git a/Marlin/src/lcd/tft/themes/theme_default.h b/Marlin/src/lcd/tft/themes/theme_default.h index 17790c7557..6b7e789216 100644 --- a/Marlin/src/lcd/tft/themes/theme_default.h +++ b/Marlin/src/lcd/tft/themes/theme_default.h @@ -107,6 +107,9 @@ #ifndef COLOR_MENU_STATIC_TEXT #define COLOR_MENU_STATIC_TEXT COLOR_SILVER #endif +#ifndef COLOR_MENU_INVERT_TEXT + #define COLOR_MENU_INVERT_TEXT COLOR_WHITE +#endif #ifndef COLOR_MENU_BACK_TEXT #define COLOR_MENU_BACK_TEXT COLOR_WHITE #endif diff --git a/Marlin/src/lcd/tft/ui_common.cpp b/Marlin/src/lcd/tft/ui_common.cpp index 6d59e0ce8b..b16b3e80a0 100644 --- a/Marlin/src/lcd/tft/ui_common.cpp +++ b/Marlin/src/lcd/tft/ui_common.cpp @@ -390,10 +390,12 @@ void MenuItem_static::draw(const uint8_t row, FSTR_P const ftpl, const uint8_t s else tft_string.set(); + const uint16_t color = (style & SS_INVERT) ? COLOR_MENU_INVERT_TEXT : COLOR_MENU_STATIC_TEXT; + const bool center = bool(style & SS_CENTER), full = bool(style & SS_FULL); if (!full || !vstr) { if (vstr) tft_string.add(vstr); - tft.add_text(center ? tft_string.center(TFT_WIDTH) : 0, MENU_TEXT_Y, COLOR_MENU_STATIC_TEXT, tft_string); + tft.add_text(center ? tft_string.center(TFT_WIDTH) : 0, MENU_TEXT_Y, color, tft_string); return; } @@ -401,12 +403,12 @@ void MenuItem_static::draw(const uint8_t row, FSTR_P const ftpl, const uint8_t s if (*vstr == ':') { tft_string.add(':'); vstr++; } // Left-justified label - tft.add_text(0, MENU_TEXT_Y, COLOR_MENU_STATIC_TEXT, tft_string); + tft.add_text(0, MENU_TEXT_Y, color, tft_string); // Right-justified value, after spaces while (*vstr == ' ') vstr++; tft_string.set(vstr); - tft.add_text(TFT_WIDTH - 1 - tft_string.width(), MENU_TEXT_Y, COLOR_MENU_STATIC_TEXT, tft_string); + tft.add_text(TFT_WIDTH - 1 - tft_string.width(), MENU_TEXT_Y, color, tft_string); } #if HAS_MEDIA From 3696cc351313dce38213630435c3e45753391223 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 22 Apr 2025 19:11:30 -0500 Subject: [PATCH 245/787] =?UTF-8?q?=F0=9F=9A=B8=20Clear=20alert=20on=20men?= =?UTF-8?q?u=20click?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/lcd/menu/menu.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Marlin/src/lcd/menu/menu.cpp b/Marlin/src/lcd/menu/menu.cpp index 96e6f6d073..6e22dfa23e 100644 --- a/Marlin/src/lcd/menu/menu.cpp +++ b/Marlin/src/lcd/menu/menu.cpp @@ -203,6 +203,15 @@ void MarlinUI::goto_screen(screenFunc_t screen, const uint16_t encoder/*=0*/, co } #endif + // + // Clear alerts when exiting the Status Screen to the Main Menu + // + + if (currentScreen == status_screen && screen == menu_main) { + reset_alert_level(); + reset_status(); + } + // // Go to the new screen // From 7ee745b2da37b04cbd30ca01538acc37021efe09 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Wed, 23 Apr 2025 12:57:30 -0500 Subject: [PATCH 246/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20TFT?= =?UTF-8?q?=20GLCD=20"panel=5Fdetected"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/lcd/TFTGLCD/marlinui_TFTGLCD.cpp | 96 ++++++++++----------- 1 file changed, 46 insertions(+), 50 deletions(-) diff --git a/Marlin/src/lcd/TFTGLCD/marlinui_TFTGLCD.cpp b/Marlin/src/lcd/TFTGLCD/marlinui_TFTGLCD.cpp index 6a80044a34..6766820cfd 100644 --- a/Marlin/src/lcd/TFTGLCD/marlinui_TFTGLCD.cpp +++ b/Marlin/src/lcd/TFTGLCD/marlinui_TFTGLCD.cpp @@ -135,7 +135,7 @@ static unsigned char framebuffer[FBSIZE]; static unsigned char *fb; static uint8_t cour_line; static uint8_t picBits, ledBits, hotBits; -static uint8_t PanelDetected = 0; +static bool panel_detected = false; // Different platforms use different SPI methods #if ANY(__AVR__, TARGET_LPC1768, __STM32F1__, ARDUINO_ARCH_SAM, __SAMD51__, __MK20DX256__, __MK64FX512__) @@ -169,13 +169,13 @@ void TFTGLCD::clear_buffer() { // Clear panel's screen void TFTGLCD::clr_screen() { - if (!PanelDetected) return; + if (!panel_detected) return; #if ENABLED(TFTGLCD_PANEL_SPI) WRITE(TFTGLCD_CS, LOW); SPI_SEND_ONE(CLR_SCREEN); WRITE(TFTGLCD_CS, HIGH); #else - Wire.beginTransmission((uint8_t)LCD_I2C_ADDRESS); //set I2C device address + Wire.beginTransmission(uint8_t(LCD_I2C_ADDRESS)); //set I2C device address Wire.write(CLR_SCREEN); Wire.endTransmission(); //transmit data #endif @@ -199,7 +199,7 @@ void TFTGLCD::print(const char *line) { // For menu void TFTGLCD::print_line() { - if (!PanelDetected) return; + if (!panel_detected) return; #if ENABLED(TFTGLCD_PANEL_SPI) WRITE(TFTGLCD_CS, LOW); SPI_SEND_ONE(LCD_PUT); @@ -207,7 +207,7 @@ void TFTGLCD::print_line() { SPI_SEND_SOME(framebuffer, LCD_WIDTH, cour_line * LCD_WIDTH); WRITE(TFTGLCD_CS, HIGH); #else - Wire.beginTransmission((uint8_t)LCD_I2C_ADDRESS); //set I2C device address + Wire.beginTransmission(uint8_t(LCD_I2C_ADDRESS)); //set I2C device address Wire.write(LCD_PUT); Wire.write(cour_line); Wire.write(&framebuffer[cour_line * LCD_WIDTH], LCD_WIDTH); //transfer 1 line to txBuffer @@ -217,7 +217,7 @@ void TFTGLCD::print_line() { } void TFTGLCD::print_screen() { - if (!PanelDetected) return; + if (!panel_detected) return; framebuffer[FBSIZE - 2] = picBits & PIC_MASK; framebuffer[FBSIZE - 1] = ledBits; #if ENABLED(TFTGLCD_PANEL_SPI) @@ -229,18 +229,18 @@ void TFTGLCD::print_screen() { #else uint8_t r; // Send framebuffer to panel by line - Wire.beginTransmission((uint8_t)LCD_I2C_ADDRESS); + Wire.beginTransmission(uint8_t(LCD_I2C_ADDRESS)); // First line Wire.write(LCD_WRITE); Wire.write(&framebuffer[0], LCD_WIDTH); Wire.endTransmission(); for (r = 1; r < (LCD_HEIGHT - 1); r++) { - Wire.beginTransmission((uint8_t)LCD_I2C_ADDRESS); + Wire.beginTransmission(uint8_t(LCD_I2C_ADDRESS)); Wire.write(&framebuffer[r * LCD_WIDTH], LCD_WIDTH); Wire.endTransmission(); } // Last line - Wire.beginTransmission((uint8_t)LCD_I2C_ADDRESS); + Wire.beginTransmission(uint8_t(LCD_I2C_ADDRESS)); Wire.write(&framebuffer[r * LCD_WIDTH], LCD_WIDTH); Wire.write(&framebuffer[FBSIZE - 2], 2); Wire.endTransmission(); @@ -248,14 +248,14 @@ void TFTGLCD::print_screen() { } void TFTGLCD::setContrast(uint16_t contrast) { - if (!PanelDetected) return; + if (!panel_detected) return; #if ENABLED(TFTGLCD_PANEL_SPI) WRITE(TFTGLCD_CS, LOW); SPI_SEND_ONE(CONTRAST); SPI_SEND_ONE((uint8_t)contrast); WRITE(TFTGLCD_CS, HIGH); #else - Wire.beginTransmission((uint8_t)LCD_I2C_ADDRESS); + Wire.beginTransmission(uint8_t(LCD_I2C_ADDRESS)); Wire.write(CONTRAST); Wire.write((uint8_t)contrast); Wire.endTransmission(); @@ -266,7 +266,7 @@ extern volatile int8_t encoderDiff; // Read buttons and encoder states uint8_t MarlinUI::read_slow_buttons() { - if (!PanelDetected) return 0; + if (!panel_detected) return 0; #if ENABLED(TFTGLCD_PANEL_SPI) uint8_t b = 0; WRITE(TFTGLCD_CS, LOW); @@ -283,13 +283,13 @@ uint8_t MarlinUI::read_slow_buttons() { WRITE(TFTGLCD_CS, HIGH); return b; #else - Wire.beginTransmission((uint8_t)LCD_I2C_ADDRESS); + Wire.beginTransmission(uint8_t(LCD_I2C_ADDRESS)); Wire.write(READ_ENCODER); Wire.endTransmission(); #ifdef __AVR__ - Wire.requestFrom((uint8_t)LCD_I2C_ADDRESS, 2, 0, 0, 1); + Wire.requestFrom(uint8_t(LCD_I2C_ADDRESS), 2, 0, 0, 1); #elif defined(STM32F1) - Wire.requestFrom((uint8_t)LCD_I2C_ADDRESS, (uint8_t)2); + Wire.requestFrom(uint8_t(LCD_I2C_ADDRESS), uint8_t(2)); #elif ANY(STM32F4xx, TARGET_LPC1768) Wire.requestFrom(LCD_I2C_ADDRESS, 2); #endif @@ -300,7 +300,7 @@ uint8_t MarlinUI::read_slow_buttons() { // Duration in ms, freq in Hz void MarlinUI::buzz(const long duration, const uint16_t freq/*=0*/) { - if (!PanelDetected) return; + if (!panel_detected) return; if (!sound_on) return; #if ENABLED(TFTGLCD_PANEL_SPI) WRITE(TFTGLCD_CS, LOW); @@ -309,20 +309,19 @@ void MarlinUI::buzz(const long duration, const uint16_t freq/*=0*/) { SPI_SEND_TWO(freq); WRITE(TFTGLCD_CS, HIGH); #else - Wire.beginTransmission((uint8_t)LCD_I2C_ADDRESS); + Wire.beginTransmission(uint8_t(LCD_I2C_ADDRESS)); Wire.write(BUZZER); - Wire.write((uint8_t)(duration >> 8)); - Wire.write((uint8_t)duration); - Wire.write((uint8_t)(freq >> 8)); - Wire.write((uint8_t)freq); + Wire.write(uint8_t(duration >> 8)); + Wire.write(uint8_t(duration)); + Wire.write(uint8_t(freq >> 8)); + Wire.write(uint8_t(freq)); Wire.endTransmission(); #endif } void MarlinUI::init_lcd() { - uint8_t t; lcd.clear_buffer(); - t = 0; + uint8_t t = 0; #if ENABLED(TFTGLCD_PANEL_SPI) // SPI speed must be less 10MHz SET_OUTPUT(TFTGLCD_CS); @@ -335,43 +334,40 @@ void MarlinUI::init_lcd() { #ifdef TARGET_LPC1768 Wire.begin(); //init twi/I2C #else - Wire.begin((uint8_t)LCD_I2C_ADDRESS); //init twi/I2C + Wire.begin(uint8_t(LCD_I2C_ADDRESS)); //init twi/I2C #endif - Wire.beginTransmission((uint8_t)LCD_I2C_ADDRESS); - Wire.write((uint8_t)GET_LCD_ROW); // put command to buffer + Wire.beginTransmission(uint8_t(LCD_I2C_ADDRESS)); + Wire.write(uint8_t(GET_LCD_ROW)); // put command to buffer Wire.endTransmission(); // send buffer #ifdef __AVR__ - Wire.requestFrom((uint8_t)LCD_I2C_ADDRESS, 1, 0, 0, 1); + Wire.requestFrom(uint8_t(LCD_I2C_ADDRESS), 1, 0, 0, 1); #elif ANY(STM32F1, STM32F4xx, TARGET_LPC1768) Wire.requestFrom(LCD_I2C_ADDRESS, 1); #endif t = (uint8_t)Wire.read(); #endif - if (t == LCD_HEIGHT) { - PanelDetected = 1; + panel_detected = (t == LCD_HEIGHT); + + if (panel_detected) { #if ENABLED(TFTGLCD_PANEL_SPI) SPI_SEND_ONE(INIT_SCREEN); SPI_SEND_ONE(Marlin); WRITE(TFTGLCD_CS, HIGH); #else - Wire.beginTransmission((uint8_t)LCD_I2C_ADDRESS); - Wire.write((uint8_t)INIT_SCREEN); + Wire.beginTransmission(uint8_t(LCD_I2C_ADDRESS)); + Wire.write(uint8_t(INIT_SCREEN)); Wire.write(Marlin); Wire.endTransmission(); #endif } - else - PanelDetected = 0; safe_delay(100); } -bool MarlinUI::detected() { - return PanelDetected; -} +bool MarlinUI::detected() { return panel_detected; } void MarlinUI::clear_lcd() { - if (!PanelDetected) return; + if (!panel_detected) return; lcd.clr_screen(); lcd.clear_buffer(); } @@ -395,7 +391,7 @@ static void center_text(FSTR_P const fstart, const uint8_t y) { #if ENABLED(SHOW_BOOTSCREEN) void MarlinUI::show_bootscreen() { - if (!PanelDetected) return; + if (!panel_detected) return; // // Show the Marlin logo, splash line1, and splash line 2 // @@ -418,7 +414,7 @@ static void center_text(FSTR_P const fstart, const uint8_t y) { #endif // SHOW_BOOTSCREEN void MarlinUI::draw_kill_screen() { - if (!PanelDetected) return; + if (!panel_detected) return; lcd.clear_buffer(); lcd_moveto(0, 3); lcd.write(COLOR_ERROR); lcd_moveto((LCD_WIDTH - status_message.glyphs()) / 2 + 1, 3); @@ -655,7 +651,7 @@ FORCE_INLINE void _draw_axis_value(const AxisEnum axis, const char *value, const #if ENABLED(LCD_PROGRESS_BAR) void MarlinUI::draw_progress_bar(const uint8_t percent) { - if (!PanelDetected) return; + if (!panel_detected) return; if (fb == &framebuffer[0] + LCD_WIDTH * 2) { // For status screen lcd.write('%'); lcd.write(percent); } @@ -672,7 +668,7 @@ FORCE_INLINE void _draw_axis_value(const AxisEnum axis, const char *value, const #endif // LCD_PROGRESS_BAR void MarlinUI::draw_status_message(const bool blink) { - if (!PanelDetected) return; + if (!panel_detected) return; lcd_moveto(0, 3); #if ALL(FILAMENT_LCD_DISPLAY, HAS_MEDIA) @@ -812,7 +808,7 @@ Equal to 24x10 text LCD */ void MarlinUI::draw_status_screen() { - if (!PanelDetected) return; + if (!panel_detected) return; const bool blink = get_blink(); @@ -959,7 +955,7 @@ void MarlinUI::draw_status_screen() { #if ENABLED(ADVANCED_PAUSE_FEATURE) void MarlinUI::draw_hotend_status(const uint8_t row, const uint8_t extruder) { - if (!PanelDetected) return; + if (!panel_detected) return; lcd_moveto((LCD_WIDTH - 14) / 2, row + 1); lcd.write(LCD_STR_THERMOMETER[0]); lcd_put_u8str(F(" E")); lcd.write('1' + extruder); lcd.write(' '); lcd.print(i16tostr3rj(thermalManager.wholeDegHotend(extruder))); lcd.write(LCD_STR_DEGREE[0]); lcd.write('/'); @@ -971,7 +967,7 @@ void MarlinUI::draw_status_screen() { // Draw a static item with no left-right margin required. Centered by default. void MenuItem_static::draw(const uint8_t row, FSTR_P const ftpl, const uint8_t style/*=SS_DEFAULT*/, const char *vstr/*=nullptr*/) { - if (!PanelDetected) return; + if (!panel_detected) return; lcd_moveto(0, row); uint8_t n = LCD_WIDTH; @@ -1019,7 +1015,7 @@ void MarlinUI::draw_status_screen() { // Draw a generic menu item with pre_char (if selected) and post_char void MenuItemBase::_draw(const bool sel, const uint8_t row, FSTR_P const ftpl, const char pre_char, const char post_char) { - if (!PanelDetected) return; + if (!panel_detected) return; lcd_moveto(0, row); lcd.write(sel ? pre_char : ' '); uint8_t n = LCD_WIDTH - 2; @@ -1031,7 +1027,7 @@ void MarlinUI::draw_status_screen() { // Draw a menu item with a (potentially) editable value void MenuEditItemBase::draw(const bool sel, const uint8_t row, FSTR_P const ftpl, const char * const inStr, const bool pgm) { - if (!PanelDetected) return; + if (!panel_detected) return; const uint8_t vlen = inStr ? (pgm ? utf8_strlen_P(inStr) : utf8_strlen(inStr)) : 0; lcd_moveto(0, row); lcd.write(sel ? LCD_STR_ARROW_RIGHT[0] : ' '); @@ -1048,7 +1044,7 @@ void MarlinUI::draw_status_screen() { // Low-level draw_edit_screen can be used to draw an edit screen from anyplace // This line moves to the last line of the screen for UBL plot screen on the panel side void MenuEditItemBase::draw_edit_screen(FSTR_P const fstr, const char * const value/*=nullptr*/) { - if (!PanelDetected) return; + if (!panel_detected) return; ui.encoder_direction_normal(); const uint8_t y = TERN0(AUTO_BED_LEVELING_UBL, ui.external_control) ? LCD_HEIGHT - 1 : MIDDLE_Y; lcd_moveto(0, y); @@ -1066,7 +1062,7 @@ void MarlinUI::draw_status_screen() { // The Select Screen presents a prompt and two "buttons" void MenuItem_confirm::draw_select_screen(FSTR_P const yes, FSTR_P const no, const bool yesno, FSTR_P const fpre, const char * const string, FSTR_P const fsuf) { - if (!PanelDetected) return; + if (!panel_detected) return; ui.draw_select_screen_prompt(fpre, string, fsuf); lcd.write(COLOR_EDIT); if (no) { @@ -1083,7 +1079,7 @@ void MarlinUI::draw_status_screen() { #if HAS_MEDIA void MenuItem_sdbase::draw(const bool sel, const uint8_t row, FSTR_P const, CardReader &theCard, const bool isDir) { - if (!PanelDetected) return; + if (!panel_detected) return; lcd_moveto(0, row); lcd.write(sel ? LCD_STR_ARROW_RIGHT[0] : ' '); uint8_t n = LCD_WIDTH - 2; @@ -1116,7 +1112,7 @@ void MarlinUI::draw_status_screen() { * |____________________| */ void MarlinUI::ubl_plot(const uint8_t x_plot, const uint8_t y_plot) { - if (!PanelDetected) return; + if (!panel_detected) return; #define _LCD_W_POS 12 From 3df75188f3b4bdff9463bbf16eebfae84c2b8733 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Wed, 23 Apr 2025 12:57:53 -0500 Subject: [PATCH 247/787] =?UTF-8?q?=F0=9F=9A=B8=20Fix=20TFT=20GLCD=20"Sele?= =?UTF-8?q?ct=20from=20Media"=20glitch?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/lcd/marlinui.cpp | 2 +- Marlin/src/lcd/menu/menu.h | 1 + Marlin/src/lcd/menu/menu_media.cpp | 45 +++++++++++++++++------------- 3 files changed, 27 insertions(+), 21 deletions(-) diff --git a/Marlin/src/lcd/marlinui.cpp b/Marlin/src/lcd/marlinui.cpp index 384bf65211..7f78d21bf3 100644 --- a/Marlin/src/lcd/marlinui.cpp +++ b/Marlin/src/lcd/marlinui.cpp @@ -1114,7 +1114,7 @@ void MarlinUI::init() { #if MARLINUI_SCROLL_NAME // If scrolling of long file names is enabled and we are in the sd card menu, // cause a refresh to occur until all the text has scrolled into view. - if (currentScreen == menu_media && filename_scroll_max && !lcd_status_update_delay--) { + if (currentScreen == menu_media_filelist && filename_scroll_max && !lcd_status_update_delay--) { lcd_status_update_delay = ++filename_scroll_pos >= filename_scroll_max ? 12 : 4; // Long delay at end and start if (filename_scroll_pos > filename_scroll_max) filename_scroll_pos = 0; refresh(LCDVIEW_REDRAW_NOW); diff --git a/Marlin/src/lcd/menu/menu.h b/Marlin/src/lcd/menu/menu.h index 92a2d506f5..80a84af1ba 100644 --- a/Marlin/src/lcd/menu/menu.h +++ b/Marlin/src/lcd/menu/menu.h @@ -211,6 +211,7 @@ void menu_main(); void menu_move(); #if HAS_MEDIA + void menu_media_filelist(); void menu_media(); #endif diff --git a/Marlin/src/lcd/menu/menu_media.cpp b/Marlin/src/lcd/menu/menu_media.cpp index fe00bf3710..8633551672 100644 --- a/Marlin/src/lcd/menu/menu_media.cpp +++ b/Marlin/src/lcd/menu/menu_media.cpp @@ -45,7 +45,7 @@ void lcd_sd_updir() { void MarlinUI::reselect_last_file() { if (sd_encoder_position == 0xFFFF) return; - goto_screen(menu_media, sd_encoder_position, sd_top_line, sd_items); + goto_screen(menu_media_filelist, sd_encoder_position, sd_top_line, sd_items); sd_encoder_position = 0xFFFF; defer_status_screen(); } @@ -101,6 +101,29 @@ class MenuItem_sdfolder : public MenuItem_sdbase { } }; +#if HAS_MULTI_VOLUME + void menu_media_select() { + START_MENU(); + BACK_ITEM_F(TERN1(BROWSE_MEDIA_ON_INSERT, screen_history_depth) ? GET_TEXT_F(MSG_MAIN_MENU) : GET_TEXT_F(MSG_BACK)); + #if ENABLED(VOLUME_SD_ONBOARD) + ACTION_ITEM(MSG_SD_CARD, []{ card.changeMedia(&card.media_driver_sdcard); card.mount(); ui.goto_screen(menu_media_filelist); }); + #endif + #if ENABLED(VOLUME_USB_FLASH_DRIVE) + ACTION_ITEM(MSG_USB_DISK, []{ card.changeMedia(&card.media_driver_usbFlash); card.mount(); ui.goto_screen(menu_media_filelist); }); + #endif + END_MENU(); + } +#endif + +/** + * "Select From Media" menu item. Depending on single or multiple drives: + * - menu_media_filelist - List files on the current media + * - menu_media_select - Select one of the attached drives, then go to the file list + */ +void menu_media() { + ui.goto_screen(TERN(HAS_MULTI_VOLUME, menu_media_select, menu_media_filelist)); +} + void menu_media_filelist() { ui.encoder_direction_menus(); @@ -113,7 +136,7 @@ void menu_media_filelist() { START_MENU(); #if HAS_MULTI_VOLUME - ACTION_ITEM(MSG_BACK, []{ ui.goto_screen(menu_media); }); + ACTION_ITEM(MSG_BACK, []{ ui.goto_screen(menu_media_select); }); #else BACK_ITEM_F(TERN1(BROWSE_MEDIA_ON_INSERT, screen_history_depth) ? GET_TEXT_F(MSG_MAIN_MENU) : GET_TEXT_F(MSG_BACK)); #endif @@ -141,22 +164,4 @@ void menu_media_filelist() { END_MENU(); } -#if HAS_MULTI_VOLUME - void menu_media_select() { - START_MENU(); - BACK_ITEM_F(TERN1(BROWSE_MEDIA_ON_INSERT, screen_history_depth) ? GET_TEXT_F(MSG_MAIN_MENU) : GET_TEXT_F(MSG_BACK)); - #if ENABLED(VOLUME_SD_ONBOARD) - ACTION_ITEM(MSG_SD_CARD, []{ card.changeMedia(&card.media_driver_sdcard); card.mount(); ui.goto_screen(menu_media_filelist); }); - #endif - #if ENABLED(VOLUME_USB_FLASH_DRIVE) - ACTION_ITEM(MSG_USB_DISK, []{ card.changeMedia(&card.media_driver_usbFlash); card.mount(); ui.goto_screen(menu_media_filelist); }); - #endif - END_MENU(); - } -#endif - -void menu_media() { - TERN(HAS_MULTI_VOLUME, menu_media_select, menu_media_filelist)(); -} - #endif // HAS_MARLINUI_MENU && HAS_MEDIA From ef9cec9e40ec055e811dbc83ee3991e59a58cecb Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Wed, 23 Apr 2025 13:43:15 -0500 Subject: [PATCH 248/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Fas?= =?UTF-8?q?tIO=20AT90USB=20pins=2046-47=20(2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit also lang --- Marlin/src/pins/pinsDebug.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Marlin/src/pins/pinsDebug.h b/Marlin/src/pins/pinsDebug.h index 94da51ccc2..f897343ffc 100644 --- a/Marlin/src/pins/pinsDebug.h +++ b/Marlin/src/pins/pinsDebug.h @@ -191,14 +191,14 @@ inline void printPinStateExt(const pin_t pin, const bool ignore, const bool exte auto alt_pin_echo = [](const pin_t &pin) { #if AVR_AT90USB1286_FAMILY // Use FastIO for pins Teensy doesn't expose - if (pin == 46) { - printPinIOState(IS_OUTPUT(46)); - printPinState(READ(46)); + if (pin == PIN_E2) { + printPinIOState(IS_OUTPUT(PIN_E2)); + printPinState(READ(PIN_E2)); return false; } - else if (pin == 47) { - printPinIOState(IS_OUTPUT(47)); - printPinState(READ(47)); + else if (pin == PIN_E3) { + printPinIOState(IS_OUTPUT(PIN_E3)); + printPinState(READ(PIN_E3)); return false; } #endif From e3a28afd5100c3bcd430db992e8a446ef4f40956 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Wed, 23 Apr 2025 15:08:57 -0500 Subject: [PATCH 249/787] =?UTF-8?q?=F0=9F=A9=B9=20Fix=20AboutScreen::onTou?= =?UTF-8?q?chEnd=20warning?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/lcd/extui/ftdi_eve_touch_ui/generic/about_screen.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/about_screen.cpp b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/about_screen.cpp index 065f89adef..eac6e646e6 100644 --- a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/about_screen.cpp +++ b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/about_screen.cpp @@ -92,16 +92,17 @@ void AboutScreen::onRedraw(draw_mode_t) { } bool AboutScreen::onTouchEnd(uint8_t tag) { - switch(tag) { + switch (tag) { default: return false; #if ALL(PRINTCOUNTER, FTDI_STATISTICS_SCREEN) case 1: GOTO_SCREEN(StatisticsScreen); break; #endif - case 2: GOTO_PREVIOUS(); return true; + case 2: GOTO_PREVIOUS(); break; #if ALL(TOUCH_UI_DEVELOPER_MENU, FTDI_DEVELOPER_MENU) case 3: GOTO_SCREEN(DeveloperMenu); break; #endif } + return true; } #endif // EXTENSIBLE_UI From 1e6326e85f9846e0db7c5cd23b39d86f97165af4 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Wed, 23 Apr 2025 11:22:20 -0500 Subject: [PATCH 250/787] =?UTF-8?q?=F0=9F=8C=90=20Language=20for=20SD=20/?= =?UTF-8?q?=20USB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/lcd/language/language_an.h | 13 ++-- Marlin/src/lcd/language/language_bg.h | 13 ++-- Marlin/src/lcd/language/language_ca.h | 13 ++-- Marlin/src/lcd/language/language_cz.h | 12 ++-- Marlin/src/lcd/language/language_da.h | 2 + Marlin/src/lcd/language/language_de.h | 13 ++-- Marlin/src/lcd/language/language_el.h | 13 ++-- Marlin/src/lcd/language/language_el_gr.h | 13 ++-- Marlin/src/lcd/language/language_en.h | 73 +++++++++++++++------- Marlin/src/lcd/language/language_es.h | 21 ++++--- Marlin/src/lcd/language/language_eu.h | 13 ++-- Marlin/src/lcd/language/language_fi.h | 2 +- Marlin/src/lcd/language/language_fr.h | 13 ++-- Marlin/src/lcd/language/language_fr_na.h | 13 ++-- Marlin/src/lcd/language/language_gl.h | 21 ++++--- Marlin/src/lcd/language/language_hr.h | 13 ++-- Marlin/src/lcd/language/language_hu.h | 13 ++-- Marlin/src/lcd/language/language_it.h | 21 ++++--- Marlin/src/lcd/language/language_jp_kana.h | 13 ++-- Marlin/src/lcd/language/language_ko_KR.h | 2 +- Marlin/src/lcd/language/language_nl.h | 13 ++-- Marlin/src/lcd/language/language_pl.h | 13 ++-- Marlin/src/lcd/language/language_pt.h | 11 ++-- Marlin/src/lcd/language/language_pt_br.h | 13 ++-- Marlin/src/lcd/language/language_ro.h | 13 ++-- Marlin/src/lcd/language/language_ru.h | 13 ++-- Marlin/src/lcd/language/language_sk.h | 13 ++-- Marlin/src/lcd/language/language_sv.h | 13 ++-- Marlin/src/lcd/language/language_tr.h | 13 ++-- Marlin/src/lcd/language/language_uk.h | 13 ++-- Marlin/src/lcd/language/language_vi.h | 36 +++++------ Marlin/src/lcd/language/language_zh_CN.h | 13 ++-- Marlin/src/lcd/language/language_zh_TW.h | 13 ++-- Marlin/src/lcd/menu/menu_main.cpp | 8 +-- 34 files changed, 260 insertions(+), 248 deletions(-) diff --git a/Marlin/src/lcd/language/language_an.h b/Marlin/src/lcd/language/language_an.h index 095a3440aa..c5230db098 100644 --- a/Marlin/src/lcd/language/language_an.h +++ b/Marlin/src/lcd/language/language_an.h @@ -42,7 +42,6 @@ namespace LanguageNarrow_an { LSTR MSG_MEDIA_REMOVED = _UxGT("Tarcheta sacada"); LSTR MSG_LCD_ENDSTOPS = _UxGT("Endstops"); // Max length 8 characters LSTR MSG_MAIN_MENU = _UxGT("Menu prencipal"); - LSTR MSG_RUN_AUTO_FILES = _UxGT("Inicio automatico"); LSTR MSG_DISABLE_STEPPERS = _UxGT("Amortar motors"); LSTR MSG_HOMING = _UxGT("Orichen"); LSTR MSG_AUTO_HOME = _UxGT("Levar a l'orichen"); @@ -155,13 +154,13 @@ namespace LanguageNarrow_an { LSTR MSG_AUTORETRACT = _UxGT("Retraccion auto."); LSTR MSG_FILAMENTCHANGE = _UxGT("Cambear filamento"); LSTR MSG_FILAMENTCHANGE_E = _UxGT("Cambear filamento *"); - #if HAS_MULTI_VOLUME - LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Encetan. SD"); - LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Encetan. USB"); - #else - LSTR MSG_ATTACH_MEDIA = _UxGT("Encetan. SD"); - #endif + + LSTR MSG_ATTACH_MEDIA = _UxGT("Encetan. media"); + LSTR MSG_ATTACH_SD = _UxGT("Encetan. SD"); + LSTR MSG_ATTACH_USB = _UxGT("Encetan. USB"); LSTR MSG_CHANGE_MEDIA = _UxGT("Cambiar tarcheta"); + LSTR MSG_RUN_AUTOFILES = _UxGT("Inicio automatico"); + LSTR MSG_ZPROBE_OUT = _UxGT("Sonda Z fuera"); LSTR MSG_BLTOUCH_RESET = _UxGT("Reset BLTouch"); LSTR MSG_ZPROBE_XOFFSET = _UxGT("Desfase X"); diff --git a/Marlin/src/lcd/language/language_bg.h b/Marlin/src/lcd/language/language_bg.h index 4eef867826..4f278c4bcf 100644 --- a/Marlin/src/lcd/language/language_bg.h +++ b/Marlin/src/lcd/language/language_bg.h @@ -40,7 +40,6 @@ namespace LanguageNarrow_bg { LSTR MSG_MEDIA_INSERTED = _UxGT("Картата е поставена"); LSTR MSG_MEDIA_REMOVED = _UxGT("Картата е извадена"); LSTR MSG_MAIN_MENU = _UxGT("Меню"); - LSTR MSG_RUN_AUTO_FILES = _UxGT("Автостарт"); LSTR MSG_DISABLE_STEPPERS = _UxGT("Изкл. двигатели"); LSTR MSG_AUTO_HOME = _UxGT("Паркиране"); LSTR MSG_SET_HOME_OFFSETS = _UxGT("Задай Начало"); @@ -139,13 +138,13 @@ namespace LanguageNarrow_bg { LSTR MSG_AUTORETRACT = _UxGT("Автоoткат"); LSTR MSG_FILAMENTCHANGE = _UxGT("Смяна нишка"); LSTR MSG_FILAMENTCHANGE_E = _UxGT("Смяна нишка *"); - #if HAS_MULTI_VOLUME - LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Иниц. SD-Карта"); - LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Иниц. USB-Карта"); - #else - LSTR MSG_ATTACH_MEDIA = _UxGT("Иниц. SD-Карта"); - #endif + + LSTR MSG_ATTACH_MEDIA = _UxGT("Иниц. SD-Карта"); + LSTR MSG_ATTACH_SD = _UxGT("Иниц. SD-Карта"); + LSTR MSG_ATTACH_USB = _UxGT("Иниц. USB-Карта"); LSTR MSG_CHANGE_MEDIA = _UxGT("Смяна SD-Карта"); + LSTR MSG_RUN_AUTOFILES = _UxGT("Автостарт"); + LSTR MSG_ZPROBE_OUT = _UxGT("Z-сондата е извадена"); LSTR MSG_ZPROBE_XOFFSET = _UxGT("X Отстояние"); LSTR MSG_ZPROBE_YOFFSET = _UxGT("Y Отстояние"); diff --git a/Marlin/src/lcd/language/language_ca.h b/Marlin/src/lcd/language/language_ca.h index fa74f255aa..be12c69df4 100644 --- a/Marlin/src/lcd/language/language_ca.h +++ b/Marlin/src/lcd/language/language_ca.h @@ -38,7 +38,6 @@ namespace LanguageNarrow_ca { LSTR MSG_MEDIA_REMOVED = _UxGT("Targeta extreta."); LSTR MSG_LCD_ENDSTOPS = _UxGT("Endstops"); LSTR MSG_MAIN_MENU = _UxGT("Menú principal"); - LSTR MSG_RUN_AUTO_FILES = _UxGT("Inici automatic"); LSTR MSG_DISABLE_STEPPERS = _UxGT("Desactiva motors"); LSTR MSG_DEBUG_MENU = _UxGT("Menu de depuracio"); LSTR MSG_PROGRESS_BAR_TEST = _UxGT("Test barra progres"); @@ -145,13 +144,13 @@ namespace LanguageNarrow_ca { LSTR MSG_AUTORETRACT = _UxGT("Auto retraccio"); LSTR MSG_FILAMENTCHANGE = _UxGT("Canvia filament"); LSTR MSG_FILAMENTCHANGE_E = _UxGT("Canvia filament *"); - #if HAS_MULTI_VOLUME - LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Inicialitza SD"); - LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Inicialitza USB"); - #else - LSTR MSG_ATTACH_MEDIA = _UxGT("Inicialitza SD"); - #endif + + LSTR MSG_ATTACH_MEDIA = _UxGT("Inicialitza SD"); + LSTR MSG_ATTACH_SD = _UxGT("Inicialitza SD"); + LSTR MSG_ATTACH_USB = _UxGT("Inicialitza USB"); LSTR MSG_CHANGE_MEDIA = _UxGT("Canvia SD"); + LSTR MSG_RUN_AUTOFILES = _UxGT("Inici automatic"); + LSTR MSG_ZPROBE_OUT = _UxGT("Sonda Z fora"); LSTR MSG_BLTOUCH_RESET = _UxGT("Reinicia BLTouch"); LSTR MSG_HOME_FIRST = _UxGT("Home %s primer"); diff --git a/Marlin/src/lcd/language/language_cz.h b/Marlin/src/lcd/language/language_cz.h index 9a01466227..ac23bc8daf 100644 --- a/Marlin/src/lcd/language/language_cz.h +++ b/Marlin/src/lcd/language/language_cz.h @@ -57,7 +57,6 @@ namespace LanguageNarrow_cz { LSTR MSG_MAIN_MENU = _UxGT("Hlavní nabídka"); LSTR MSG_ADVANCED_SETTINGS = _UxGT("Další nastavení"); LSTR MSG_CONFIGURATION = _UxGT("Konfigurace"); - LSTR MSG_RUN_AUTO_FILES = _UxGT("Autostart"); LSTR MSG_DISABLE_STEPPERS = _UxGT("Uvolnit motory"); LSTR MSG_DEBUG_MENU = _UxGT("Nabídka ladění"); LSTR MSG_PROGRESS_BAR_TEST = _UxGT("Test uk. průběhu"); @@ -359,14 +358,13 @@ namespace LanguageNarrow_cz { LSTR MSG_FILAMENTUNLOAD_E = _UxGT("Vysunout filament *"); LSTR MSG_FILAMENTUNLOAD_ALL = _UxGT("Vysunout vše"); - #if HAS_MULTI_VOLUME - LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Načíst SD"); - LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Načíst USB"); - #else - LSTR MSG_ATTACH_MEDIA = _UxGT("Načíst SD"); - #endif + LSTR MSG_ATTACH_MEDIA = _UxGT("Načíst médium"); + LSTR MSG_ATTACH_SD = _UxGT("Načíst SD"); + LSTR MSG_ATTACH_USB = _UxGT("Načíst USB"); LSTR MSG_CHANGE_MEDIA = _UxGT("Vyměnit médium"); LSTR MSG_RELEASE_MEDIA = _UxGT("Vysunout médium"); + LSTR MSG_RUN_AUTOFILES = _UxGT("Autostart"); + LSTR MSG_ZPROBE_OUT = _UxGT("Sonda Z mimo podl"); LSTR MSG_SKEW_FACTOR = _UxGT("Faktor zkosení"); LSTR MSG_BLTOUCH = _UxGT("BLTouch"); diff --git a/Marlin/src/lcd/language/language_da.h b/Marlin/src/lcd/language/language_da.h index 35083aa01f..0a286d1751 100644 --- a/Marlin/src/lcd/language/language_da.h +++ b/Marlin/src/lcd/language/language_da.h @@ -133,7 +133,9 @@ namespace LanguageNarrow_da { LSTR MSG_AUTORETRACT = _UxGT("Auto-Retract"); LSTR MSG_FILAMENTCHANGE = _UxGT("Skift filament"); LSTR MSG_FILAMENTCHANGE_E = _UxGT("Skift filament *"); + LSTR MSG_CHANGE_MEDIA = _UxGT("Skift SD kort"); + LSTR MSG_ZPROBE_OUT = _UxGT("Probe udenfor plade"); LSTR MSG_BLTOUCH_SELFTEST = _UxGT("BLTouch Selv-Test"); LSTR MSG_HOME_FIRST = _UxGT("Home %s først"); diff --git a/Marlin/src/lcd/language/language_de.h b/Marlin/src/lcd/language/language_de.h index 23730d321a..e681317fb8 100644 --- a/Marlin/src/lcd/language/language_de.h +++ b/Marlin/src/lcd/language/language_de.h @@ -55,7 +55,6 @@ namespace LanguageNarrow_de { LSTR MSG_MAIN_MENU = _UxGT("Hauptmenü"); LSTR MSG_ADVANCED_SETTINGS = _UxGT("Erw. Einstellungen"); LSTR MSG_CONFIGURATION = _UxGT("Konfiguration"); - LSTR MSG_RUN_AUTO_FILES = _UxGT("Autostart"); LSTR MSG_DISABLE_STEPPERS = _UxGT("Motoren deaktivieren"); // M84 :: Max length 19 characters LSTR MSG_DEBUG_MENU = _UxGT("Debug-Menü"); LSTR MSG_PROGRESS_BAR_TEST = _UxGT("Statusbalken-Test"); @@ -493,14 +492,14 @@ namespace LanguageNarrow_de { LSTR MSG_FILAMENTUNLOAD = _UxGT("Filament entladen"); LSTR MSG_FILAMENTUNLOAD_E = _UxGT("Filament entladen *"); LSTR MSG_FILAMENTUNLOAD_ALL = _UxGT("Alles entladen"); - #if HAS_MULTI_VOLUME - LSTR MSG_ATTACH_SD_MEDIA = _UxGT("SD initial."); - LSTR MSG_ATTACH_USB_MEDIA = _UxGT("USB initial."); - #else - LSTR MSG_ATTACH_MEDIA = _UxGT("SD initial."); - #endif + + LSTR MSG_ATTACH_MEDIA = _UxGT("SD initial."); + LSTR MSG_ATTACH_SD = _UxGT("SD initial."); + LSTR MSG_ATTACH_USB = _UxGT("USB initial."); LSTR MSG_CHANGE_MEDIA = _UxGT("Medium getauscht"); // SD-card changed by user. For machines with no autocarddetect. Both send "M21" LSTR MSG_RELEASE_MEDIA = _UxGT("Medium freigeben"); // if Marlin gets confused - M22 + LSTR MSG_RUN_AUTOFILES = _UxGT("Autostart"); + LSTR MSG_ZPROBE_OUT = _UxGT("Z-Sonde außerhalb"); LSTR MSG_SKEW_FACTOR = _UxGT("Korrekturfaktor"); LSTR MSG_BLTOUCH = _UxGT("BLTouch"); diff --git a/Marlin/src/lcd/language/language_el.h b/Marlin/src/lcd/language/language_el.h index 85de0f0751..0d3d355cb0 100644 --- a/Marlin/src/lcd/language/language_el.h +++ b/Marlin/src/lcd/language/language_el.h @@ -52,7 +52,6 @@ namespace LanguageNarrow_el { LSTR MSG_MEDIA_USB_FAILED = _UxGT("Αποτυχία εκκίνησης USB"); LSTR MSG_MEDIA_INIT_FAIL = _UxGT("Αποτυχία αρχικοποίησης SD"); LSTR MSG_MAIN_MENU = _UxGT("Αρχική Οθόνη"); - LSTR MSG_RUN_AUTO_FILES = _UxGT("Αυτόματη εκκίνηση"); LSTR MSG_DISABLE_STEPPERS = _UxGT("Απενεργοποίηση μοτέρ"); LSTR MSG_AUTO_HOME = _UxGT("Αυτόμ. επαναφορά XYZ"); LSTR MSG_AUTO_HOME_X = _UxGT("Επαναφορά X"); @@ -180,13 +179,13 @@ namespace LanguageNarrow_el { LSTR MSG_AUTORETRACT = _UxGT("Αυτόματη ανάσυρση"); LSTR MSG_FILAMENTCHANGE = _UxGT("Αλλαγή νήματος"); LSTR MSG_FILAMENTCHANGE_E = _UxGT("Αλλαγή νήματος *"); - #if HAS_MULTI_VOLUME - LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Προετοιμασία SD"); - LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Προετοιμασία USB"); - #else - LSTR MSG_ATTACH_MEDIA = _UxGT("Προετοιμασία SD"); - #endif + + LSTR MSG_ATTACH_MEDIA = _UxGT("Προετοιμασία SD"); + LSTR MSG_ATTACH_SD = _UxGT("Προετοιμασία SD"); + LSTR MSG_ATTACH_USB = _UxGT("Προετοιμασία USB"); LSTR MSG_CHANGE_MEDIA = _UxGT("Αλλαγή κάρτας SD"); + LSTR MSG_RUN_AUTOFILES = _UxGT("Αυτόματη εκκίνηση"); + LSTR MSG_ZPROBE_OUT = _UxGT("Διερεύνηση Z εκτός Επ.Εκτύπωσης"); // SHORTEN LSTR MSG_YX_UNHOMED = _UxGT("Επαναφορά Χ/Υ πρώτα"); LSTR MSG_XYZ_UNHOMED = _UxGT("Επαναφορά ΧΥZ πρώτα"); diff --git a/Marlin/src/lcd/language/language_el_gr.h b/Marlin/src/lcd/language/language_el_gr.h index 65b2da5ee3..3e2cb0ec07 100644 --- a/Marlin/src/lcd/language/language_el_gr.h +++ b/Marlin/src/lcd/language/language_el_gr.h @@ -41,7 +41,6 @@ namespace LanguageNarrow_el_gr { LSTR MSG_MEDIA_REMOVED = _UxGT("Αφαίρεση κάρτας"); LSTR MSG_LCD_ENDSTOPS = _UxGT("Endstops"); // Max length 8 characters LSTR MSG_MAIN_MENU = _UxGT("Βασική Οθόνη"); - LSTR MSG_RUN_AUTO_FILES = _UxGT("Αυτόματη εκκίνηση"); LSTR MSG_DISABLE_STEPPERS = _UxGT("Απενεργοποίηση βηματιστή"); LSTR MSG_AUTO_HOME = _UxGT("Αυτομ. επαναφορά στο αρχικό σημείο"); LSTR MSG_AUTO_HOME_X = _UxGT("Αρχικό σημείο X"); @@ -170,13 +169,13 @@ namespace LanguageNarrow_el_gr { LSTR MSG_AUTORETRACT = _UxGT("Αυτόματη ανάσυρση"); LSTR MSG_FILAMENTCHANGE = _UxGT("Αλλαγή νήματος"); LSTR MSG_FILAMENTCHANGE_E = _UxGT("Αλλαγή νήματος *"); - #if HAS_MULTI_VOLUME - LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Προετοιμασία SD"); - LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Προετοιμασία USB"); - #else - LSTR MSG_ATTACH_MEDIA = _UxGT("Προετοιμασία SD"); - #endif + + LSTR MSG_ATTACH_MEDIA = _UxGT("Προετοιμασία SD"); + LSTR MSG_ATTACH_SD = _UxGT("Προετοιμασία SD"); + LSTR MSG_ATTACH_USB = _UxGT("Προετοιμασία USB"); LSTR MSG_CHANGE_MEDIA = _UxGT("Αλλαγή κάρτας SD"); + LSTR MSG_RUN_AUTOFILES = _UxGT("Αυτόματη εκκίνηση"); + LSTR MSG_ZPROBE_OUT = _UxGT("Διερεύνηση Z εκτός κλίνης"); LSTR MSG_YX_UNHOMED = _UxGT("Επαναφορά Χ/Υ πριν από Z"); LSTR MSG_XYZ_UNHOMED = _UxGT("Επαναφορά ΧΥZ πρώτα"); diff --git a/Marlin/src/lcd/language/language_en.h b/Marlin/src/lcd/language/language_en.h index e0c1f53f77..d23e638a78 100644 --- a/Marlin/src/lcd/language/language_en.h +++ b/Marlin/src/lcd/language/language_en.h @@ -42,7 +42,13 @@ #endif #undef en -#define MEDIA_TYPE_EN "Media" +#if HAS_SDCARD && !HAS_USB_FLASH_DRIVE + #define MEDIA_TYPE_EN "SD Card" +#elif HAS_USB_FLASH_DRIVE + #define MEDIA_TYPE_EN "USB Drive" +#else + #define MEDIA_TYPE_EN "Media" +#endif #ifndef PREHEAT_1_LABEL #define PREHEAT_1_LABEL "" @@ -76,23 +82,32 @@ namespace LanguageNarrow_en { LSTR MSG_LOW = _UxGT("LOW"); LSTR MSG_BACK = _UxGT("Back"); LSTR MSG_ERROR = _UxGT("Error"); + LSTR MSG_MEDIA_ABORTING = _UxGT("Aborting..."); LSTR MSG_MEDIA_INSERTED = MEDIA_TYPE_EN _UxGT(" Inserted"); + LSTR MSG_MEDIA_INSERTED_SD = _UxGT("SD Card Inserted"); + LSTR MSG_MEDIA_INSERTED_USB = _UxGT("USB Drive Inserted"); LSTR MSG_MEDIA_REMOVED = MEDIA_TYPE_EN _UxGT(" Removed"); + LSTR MSG_MEDIA_REMOVED_SD = _UxGT("SD Card Removed"); + LSTR MSG_MEDIA_REMOVED_USB = _UxGT("USB Drive Removed"); LSTR MSG_MEDIA_WAITING = _UxGT("Waiting for ") MEDIA_TYPE_EN; + LSTR MSG_MEDIA_WAITING_SD = _UxGT("Waiting for SD Card"); + LSTR MSG_MEDIA_WAITING_USB = _UxGT("Waiting for USB Drive"); LSTR MSG_MEDIA_INIT_FAIL = MEDIA_TYPE_EN _UxGT(" Init Fail"); + LSTR MSG_MEDIA_INIT_FAIL_SD = _UxGT("SD Card Init Fail"); + LSTR MSG_MEDIA_INIT_FAIL_USB = _UxGT("USB Drive Init Fail"); LSTR MSG_MEDIA_READ_ERROR = MEDIA_TYPE_EN _UxGT(" read error"); LSTR MSG_MEDIA_USB_REMOVED = _UxGT("USB device removed"); LSTR MSG_MEDIA_USB_FAILED = _UxGT("USB start failed"); LSTR MSG_MEDIA_SORT = _UxGT("Sort ") MEDIA_TYPE_EN; LSTR MSG_MEDIA_UPDATE = MEDIA_TYPE_EN _UxGT(" Update"); + LSTR MSG_KILL_SUBCALL_OVERFLOW = _UxGT("Subcall Overflow"); LSTR MSG_LCD_ENDSTOPS = _UxGT("Endstops"); // Max length 8 characters LSTR MSG_LCD_SOFT_ENDSTOPS = _UxGT("Soft Endstops"); LSTR MSG_MAIN_MENU = _UxGT("Main Menu"); LSTR MSG_ADVANCED_SETTINGS = _UxGT("Advanced Settings"); LSTR MSG_CONFIGURATION = _UxGT("Configuration"); - LSTR MSG_RUN_AUTO_FILES = _UxGT("Run Auto Files"); LSTR MSG_DISABLE_STEPPERS = _UxGT("Disable Steppers"); LSTR MSG_DEBUG_MENU = _UxGT("Debug Menu"); LSTR MSG_PROGRESS_BAR_TEST = _UxGT("Progress Bar Test"); @@ -613,14 +628,20 @@ namespace LanguageNarrow_en { LSTR MSG_FILAMENTUNLOAD = _UxGT("Unload Filament"); LSTR MSG_FILAMENTUNLOAD_E = _UxGT("Unload * Filament"); LSTR MSG_FILAMENTUNLOAD_ALL = _UxGT("Unload All"); - #if HAS_MULTI_VOLUME - LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Attach SD Card"); - LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Attach USB Drive"); - #else - LSTR MSG_ATTACH_MEDIA = _UxGT("Attach ") MEDIA_TYPE_EN; - #endif - LSTR MSG_CHANGE_MEDIA = _UxGT("Change ") MEDIA_TYPE_EN; + + LSTR MSG_ATTACH_MEDIA = _UxGT("Attach ") MEDIA_TYPE_EN; + LSTR MSG_ATTACH_SD = _UxGT("Attach SD Card"); + LSTR MSG_ATTACH_USB = _UxGT("Attach USB Drive"); LSTR MSG_RELEASE_MEDIA = _UxGT("Release ") MEDIA_TYPE_EN; + LSTR MSG_RELEASE_SD = _UxGT("Release SD Card"); + LSTR MSG_RELEASE_USB = _UxGT("Release USB Drive"); + LSTR MSG_CHANGE_MEDIA = _UxGT("Refresh ") MEDIA_TYPE_EN; + LSTR MSG_CHANGE_SD = _UxGT("Select SD Card"); + LSTR MSG_CHANGE_USB = _UxGT("Select USB Drive"); + LSTR MSG_RUN_AUTOFILES = _UxGT("Run Autofiles"); + LSTR MSG_RUN_AUTOFILES_SD = _UxGT("Run SD Autofiles"); + LSTR MSG_RUN_AUTOFILES_USB = _UxGT("Run USB Autofiles"); + LSTR MSG_ZPROBE_OUT = _UxGT("Z Probe Past Bed"); LSTR MSG_SKEW_FACTOR = _UxGT("Skew Factor"); LSTR MSG_BLTOUCH = _UxGT("BLTouch"); @@ -665,6 +686,7 @@ namespace LanguageNarrow_en { LSTR MSG_BABYSTEP_N = _UxGT("Babystep @"); LSTR MSG_BABYSTEP_TOTAL = _UxGT("Total"); LSTR MSG_ENDSTOP_ABORT = _UxGT("Endstop Abort"); + LSTR MSG_ERR_HEATING_FAILED = _UxGT("Heating Failed"); LSTR MSG_ERR_REDUNDANT_TEMP = _UxGT("Err: REDUNDANT TEMP"); LSTR MSG_ERR_THERMAL_RUNAWAY = _UxGT("THERMAL RUNAWAY"); @@ -686,6 +708,7 @@ namespace LanguageNarrow_en { LSTR MSG_CHAMBER_HEATING = _UxGT("Chamber Heating..."); LSTR MSG_CHAMBER_COOLING = _UxGT("Chamber Cooling..."); LSTR MSG_LASER_COOLING = _UxGT("Laser Cooling..."); + LSTR MSG_DELTA_CALIBRATE = _UxGT("Delta Calibration"); LSTR MSG_DELTA_CALIBRATION_IN_PROGRESS = _UxGT("Delta Calibration in progress"); LSTR MSG_DELTA_CALIBRATE_X = _UxGT("Calibrate X"); @@ -697,14 +720,9 @@ namespace LanguageNarrow_en { LSTR MSG_DELTA_DIAG_ROD = _UxGT("Diag Rod"); LSTR MSG_DELTA_HEIGHT = _UxGT("Height"); LSTR MSG_DELTA_RADIUS = _UxGT("Radius"); + LSTR MSG_INFO_MENU = _UxGT("About Printer"); LSTR MSG_INFO_PRINTER_MENU = _UxGT("Printer Info"); - LSTR MSG_3POINT_LEVELING = _UxGT("3-Point Leveling"); - LSTR MSG_LINEAR_LEVELING = _UxGT("Linear Leveling"); - LSTR MSG_BILINEAR_LEVELING = _UxGT("Bilinear Leveling"); - LSTR MSG_UBL_LEVELING = _UxGT("Unified Bed Leveling"); - LSTR MSG_MESH_LEVELING = _UxGT("Mesh Leveling"); - LSTR MSG_MESH_DONE = _UxGT("Mesh probing done"); LSTR MSG_INFO_PRINTER_STATS_MENU = _UxGT("Printer Stats"); LSTR MSG_INFO_STATS_MENU = _UxGT("Stats"); LSTR MSG_RESET_STATS = _UxGT("Reset Print Stats?"); @@ -715,6 +733,22 @@ namespace LanguageNarrow_en { LSTR MSG_INFO_PROTOCOL = _UxGT("Protocol"); LSTR MSG_INFO_RUNAWAY_OFF = _UxGT("Runaway Watch: OFF"); LSTR MSG_INFO_RUNAWAY_ON = _UxGT("Runaway Watch: ON"); + LSTR MSG_INFO_PRINT_COUNT = _UxGT("Prints"); + LSTR MSG_INFO_PRINT_TIME = _UxGT("Total"); + LSTR MSG_INFO_PRINT_LONGEST = _UxGT("Longest"); + LSTR MSG_INFO_PRINT_FILAMENT = _UxGT("Extruded"); + LSTR MSG_INFO_COMPLETED_PRINTS = _UxGT("Completed"); + LSTR MSG_INFO_MIN_TEMP = _UxGT("Min Temp"); + LSTR MSG_INFO_MAX_TEMP = _UxGT("Max Temp"); + LSTR MSG_INFO_PSU = _UxGT("PSU"); + + LSTR MSG_3POINT_LEVELING = _UxGT("3-Point Leveling"); + LSTR MSG_LINEAR_LEVELING = _UxGT("Linear Leveling"); + LSTR MSG_BILINEAR_LEVELING = _UxGT("Bilinear Leveling"); + LSTR MSG_UBL_LEVELING = _UxGT("Unified Bed Leveling"); + LSTR MSG_MESH_LEVELING = _UxGT("Mesh Leveling"); + LSTR MSG_MESH_DONE = _UxGT("Mesh probing done"); + LSTR MSG_HOTEND_IDLE_TIMEOUT = _UxGT("Hotend Idle Timeout"); LSTR MSG_BED_IDLE_TIMEOUT = _UxGT("Bed Idle Timeout"); LSTR MSG_HOTEND_IDLE_DISABLE = _UxGT("Disable Timeout"); @@ -726,15 +760,6 @@ namespace LanguageNarrow_en { LSTR MSG_CASE_LIGHT_BRIGHTNESS = _UxGT("Light Brightness"); LSTR MSG_KILL_EXPECTED_PRINTER = _UxGT("INCORRECT PRINTER"); - LSTR MSG_INFO_PRINT_COUNT = _UxGT("Prints"); - LSTR MSG_INFO_PRINT_TIME = _UxGT("Total"); - LSTR MSG_INFO_PRINT_LONGEST = _UxGT("Longest"); - LSTR MSG_INFO_PRINT_FILAMENT = _UxGT("Extruded"); - LSTR MSG_INFO_COMPLETED_PRINTS = _UxGT("Completed"); - LSTR MSG_INFO_MIN_TEMP = _UxGT("Min Temp"); - LSTR MSG_INFO_MAX_TEMP = _UxGT("Max Temp"); - LSTR MSG_INFO_PSU = _UxGT("PSU"); - LSTR MSG_DRIVE_STRENGTH = _UxGT("Drive Strength"); LSTR MSG_DAC_PERCENT_N = _UxGT("@ Driver %"); LSTR MSG_ERROR_TMC = _UxGT("TMC CONNECTION ERROR"); diff --git a/Marlin/src/lcd/language/language_es.h b/Marlin/src/lcd/language/language_es.h index 058b550f67..d1e4babf2b 100644 --- a/Marlin/src/lcd/language/language_es.h +++ b/Marlin/src/lcd/language/language_es.h @@ -28,7 +28,13 @@ * See also https://marlinfw.org/docs/development/lcd_language.html */ -#define MEDIA_TYPE_ES "SD/FD" +#if HAS_SDCARD && !HAS_USB_FLASH_DRIVE + #define MEDIA_TYPE_ES "SD" +#elif HAS_USB_FLASH_DRIVE + #define MEDIA_TYPE_ES "USB" +#else + #define MEDIA_TYPE_ES "SD/FD" +#endif namespace LanguageNarrow_es { using namespace Language_en; // Inherit undefined strings from English @@ -54,7 +60,6 @@ namespace LanguageNarrow_es { LSTR MSG_MAIN_MENU = _UxGT("Menú principal"); LSTR MSG_ADVANCED_SETTINGS = _UxGT("Ajustes avanzados"); LSTR MSG_CONFIGURATION = _UxGT("Configuración"); - LSTR MSG_RUN_AUTO_FILES = _UxGT("Inicio automático"); LSTR MSG_DISABLE_STEPPERS = _UxGT("Apagar motores"); LSTR MSG_DEBUG_MENU = _UxGT("Menú depuración"); LSTR MSG_PROGRESS_BAR_TEST = _UxGT("Prob. barra progreso"); @@ -368,14 +373,14 @@ namespace LanguageNarrow_es { LSTR MSG_FILAMENTUNLOAD = _UxGT("Descargar filamento"); LSTR MSG_FILAMENTUNLOAD_E = _UxGT("Descargar fil. *"); LSTR MSG_FILAMENTUNLOAD_ALL = _UxGT("Descargar todo"); - #if HAS_MULTI_VOLUME - LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Iniciar SD"); - LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Iniciar USB"); - #else - LSTR MSG_ATTACH_MEDIA = _UxGT("Iniciar ") MEDIA_TYPE_ES; - #endif + + LSTR MSG_ATTACH_MEDIA = _UxGT("Iniciar ") MEDIA_TYPE_ES; + LSTR MSG_ATTACH_SD = _UxGT("Iniciar SD"); + LSTR MSG_ATTACH_USB = _UxGT("Iniciar USB"); LSTR MSG_CHANGE_MEDIA = _UxGT("Cambiar ") MEDIA_TYPE_ES; LSTR MSG_RELEASE_MEDIA = _UxGT("Lanzar ") MEDIA_TYPE_ES; + LSTR MSG_RUN_AUTOFILES = _UxGT("Inicio automático"); + LSTR MSG_ZPROBE_OUT = _UxGT("Sonda Z fuera cama"); LSTR MSG_SKEW_FACTOR = _UxGT("Factor de desviación"); LSTR MSG_BLTOUCH = _UxGT("BLTouch"); diff --git a/Marlin/src/lcd/language/language_eu.h b/Marlin/src/lcd/language/language_eu.h index 561de0b8e6..52612a8081 100644 --- a/Marlin/src/lcd/language/language_eu.h +++ b/Marlin/src/lcd/language/language_eu.h @@ -42,7 +42,6 @@ namespace LanguageNarrow_eu { LSTR MSG_MEDIA_INSERTED = _UxGT("Txartela sartuta"); LSTR MSG_MEDIA_REMOVED = _UxGT("Txartela kenduta"); LSTR MSG_MAIN_MENU = _UxGT("Menu nagusia"); - LSTR MSG_RUN_AUTO_FILES = _UxGT("Auto hasiera"); LSTR MSG_DISABLE_STEPPERS = _UxGT("Itzali motoreak"); LSTR MSG_DEBUG_MENU = _UxGT("Arazketa Menua"); LSTR MSG_PROGRESS_BAR_TEST = _UxGT("Prog. Barra Proba"); @@ -219,13 +218,13 @@ namespace LanguageNarrow_eu { LSTR MSG_FILAMENTUNLOAD = _UxGT("Harizpia deskargatu"); LSTR MSG_FILAMENTUNLOAD_E = _UxGT("Harizpia deskargatu *"); LSTR MSG_FILAMENTUNLOAD_ALL = _UxGT("Erabat deskargatu"); - #if HAS_MULTI_VOLUME - LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Hasieratu SD-a"); - LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Hasieratu USB-a"); - #else - LSTR MSG_ATTACH_MEDIA = _UxGT("Hasieratu SD-a"); - #endif + + LSTR MSG_ATTACH_MEDIA = _UxGT("Hasieratu SD-a"); + LSTR MSG_ATTACH_SD = _UxGT("Hasieratu SD-a"); + LSTR MSG_ATTACH_USB = _UxGT("Hasieratu USB-a"); LSTR MSG_CHANGE_MEDIA = _UxGT("Aldatu txartela"); + LSTR MSG_RUN_AUTOFILES = _UxGT("Auto hasiera"); + LSTR MSG_ZPROBE_OUT = _UxGT("Z zunda kanpora"); LSTR MSG_SKEW_FACTOR = _UxGT("Okertze faktorea"); LSTR MSG_BLTOUCH = _UxGT("BLTouch"); diff --git a/Marlin/src/lcd/language/language_fi.h b/Marlin/src/lcd/language/language_fi.h index 7b3f0f6082..d70c67208c 100644 --- a/Marlin/src/lcd/language/language_fi.h +++ b/Marlin/src/lcd/language/language_fi.h @@ -40,7 +40,7 @@ namespace LanguageNarrow_fi { LSTR MSG_MEDIA_INSERTED = _UxGT("Kortti asetettu"); LSTR MSG_MEDIA_REMOVED = _UxGT("Kortti poistettu"); LSTR MSG_MAIN_MENU = _UxGT("Palaa"); - LSTR MSG_RUN_AUTO_FILES = _UxGT("Automaatti"); + LSTR MSG_RUN_AUTOFILES = _UxGT("Automaatti"); LSTR MSG_DISABLE_STEPPERS = _UxGT("Vapauta moottorit"); LSTR MSG_AUTO_HOME = _UxGT("Aja referenssiin"); diff --git a/Marlin/src/lcd/language/language_fr.h b/Marlin/src/lcd/language/language_fr.h index 13bee9fbb8..6d9fd3b4f4 100644 --- a/Marlin/src/lcd/language/language_fr.h +++ b/Marlin/src/lcd/language/language_fr.h @@ -52,7 +52,6 @@ namespace LanguageNarrow_fr { LSTR MSG_MAIN_MENU = _UxGT("Menu principal"); LSTR MSG_ADVANCED_SETTINGS = _UxGT("Config. avancée"); LSTR MSG_CONFIGURATION = _UxGT("Configuration"); - LSTR MSG_RUN_AUTO_FILES = _UxGT("Exéc. auto.gcode"); LSTR MSG_DISABLE_STEPPERS = _UxGT("Arrêter moteurs"); LSTR MSG_DEBUG_MENU = _UxGT("Menu debug"); LSTR MSG_PROGRESS_BAR_TEST = _UxGT("Test barre progress."); @@ -392,14 +391,14 @@ namespace LanguageNarrow_fr { LSTR MSG_FILAMENTUNLOAD = _UxGT("Retrait filament"); LSTR MSG_FILAMENTUNLOAD_E = _UxGT("Retrait filament *"); LSTR MSG_FILAMENTUNLOAD_ALL = _UxGT("Retirer tout"); - #if HAS_MULTI_VOLUME - LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Charger le SD"); - LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Charger le USB"); - #else - LSTR MSG_ATTACH_MEDIA = _UxGT("Charger le SD"); - #endif + + LSTR MSG_ATTACH_MEDIA = _UxGT("Charger le SD"); + LSTR MSG_ATTACH_SD = _UxGT("Charger le SD"); + LSTR MSG_ATTACH_USB = _UxGT("Charger le USB"); LSTR MSG_CHANGE_MEDIA = _UxGT("Actualiser média"); LSTR MSG_RELEASE_MEDIA = _UxGT("Retirer le média"); + LSTR MSG_RUN_AUTOFILES = _UxGT("Exéc. auto.gcode"); + LSTR MSG_ZPROBE_OUT = _UxGT("Sonde Z hors lit"); LSTR MSG_SKEW_FACTOR = _UxGT("Facteur écart"); LSTR MSG_BLTOUCH = _UxGT("BLTouch"); diff --git a/Marlin/src/lcd/language/language_fr_na.h b/Marlin/src/lcd/language/language_fr_na.h index a3da3082de..07f2b86499 100644 --- a/Marlin/src/lcd/language/language_fr_na.h +++ b/Marlin/src/lcd/language/language_fr_na.h @@ -52,7 +52,6 @@ namespace LanguageNarrow_fr_na { LSTR MSG_MAIN_MENU = _UxGT("Menu principal"); LSTR MSG_ADVANCED_SETTINGS = _UxGT("Config. avancee"); LSTR MSG_CONFIGURATION = _UxGT("Configuration"); - LSTR MSG_RUN_AUTO_FILES = _UxGT("Exec. auto.gcode"); LSTR MSG_DISABLE_STEPPERS = _UxGT("Arreter moteurs"); LSTR MSG_DEBUG_MENU = _UxGT("Menu debug"); LSTR MSG_PROGRESS_BAR_TEST = _UxGT("Test barre progress."); @@ -392,14 +391,14 @@ namespace LanguageNarrow_fr_na { LSTR MSG_FILAMENTUNLOAD = _UxGT("Retrait filament"); LSTR MSG_FILAMENTUNLOAD_E = _UxGT("Retrait filament *"); LSTR MSG_FILAMENTUNLOAD_ALL = _UxGT("Retirer tout"); - #if HAS_MULTI_VOLUME - LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Charger le SD"); - LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Charger le USB"); - #else - LSTR MSG_ATTACH_MEDIA = _UxGT("Charger le SD"); - #endif + + LSTR MSG_ATTACH_MEDIA = _UxGT("Charger le SD"); + LSTR MSG_ATTACH_SD = _UxGT("Charger le SD"); + LSTR MSG_ATTACH_USB = _UxGT("Charger le USB"); LSTR MSG_CHANGE_MEDIA = _UxGT("Actualiser media"); LSTR MSG_RELEASE_MEDIA = _UxGT("Retirer le media"); + LSTR MSG_RUN_AUTOFILES = _UxGT("Exec. auto.gcode"); + LSTR MSG_ZPROBE_OUT = _UxGT("Sonde Z hors lit"); LSTR MSG_SKEW_FACTOR = _UxGT("Facteur ecart"); LSTR MSG_BLTOUCH = _UxGT("BLTouch"); diff --git a/Marlin/src/lcd/language/language_gl.h b/Marlin/src/lcd/language/language_gl.h index 3287ae2676..6dd699f1bd 100644 --- a/Marlin/src/lcd/language/language_gl.h +++ b/Marlin/src/lcd/language/language_gl.h @@ -30,7 +30,13 @@ #define DISPLAY_CHARSET_ISO10646_1 -#define MEDIA_TYPE_GL "SD/FD" +#if HAS_SDCARD && !HAS_USB_FLASH_DRIVE + #define MEDIA_TYPE_GL "SD" +#elif HAS_USB_FLASH_DRIVE + #define MEDIA_TYPE_GL "FD" +#else + #define MEDIA_TYPE_GL "SD/FD" +#endif namespace LanguageNarrow_gl { using namespace Language_en; // Inherit undefined strings from English @@ -55,7 +61,6 @@ namespace LanguageNarrow_gl { LSTR MSG_MAIN_MENU = _UxGT("Menú principal"); LSTR MSG_ADVANCED_SETTINGS = _UxGT("Axustes avanzados"); LSTR MSG_CONFIGURATION = _UxGT("Configuración"); - LSTR MSG_RUN_AUTO_FILES = _UxGT("Autoarranque"); LSTR MSG_DISABLE_STEPPERS = _UxGT("Apagar motores"); LSTR MSG_DEBUG_MENU = _UxGT("Menú depuración"); LSTR MSG_PROGRESS_BAR_TEST = _UxGT("Test barra progreso"); @@ -383,14 +388,14 @@ namespace LanguageNarrow_gl { LSTR MSG_FILAMENTUNLOAD = _UxGT("Descargar Filamento"); LSTR MSG_FILAMENTUNLOAD_E = _UxGT("Descargar Filamento *"); LSTR MSG_FILAMENTUNLOAD_ALL = _UxGT("Descargar Todo"); - #if HAS_MULTI_VOLUME - LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Iniciar SD"); - LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Iniciar USB"); - #else - LSTR MSG_ATTACH_MEDIA = _UxGT("Iniciar ") MEDIA_TYPE_GL; - #endif + + LSTR MSG_ATTACH_MEDIA = _UxGT("Iniciar ") MEDIA_TYPE_GL; + LSTR MSG_ATTACH_SD = _UxGT("Iniciar SD"); + LSTR MSG_ATTACH_USB = _UxGT("Iniciar USB"); LSTR MSG_CHANGE_MEDIA = _UxGT("Cambiar ") MEDIA_TYPE_GL; LSTR MSG_RELEASE_MEDIA = _UxGT("Lanzar ") MEDIA_TYPE_GL; + LSTR MSG_RUN_AUTOFILES = _UxGT("Autoarranque"); + LSTR MSG_ZPROBE_OUT = _UxGT("Sonda-Z fóra Cama"); LSTR MSG_SKEW_FACTOR = _UxGT("Factor de Desviación"); LSTR MSG_BLTOUCH = _UxGT("BLTouch"); diff --git a/Marlin/src/lcd/language/language_hr.h b/Marlin/src/lcd/language/language_hr.h index 5f60b000e3..a75dcff846 100644 --- a/Marlin/src/lcd/language/language_hr.h +++ b/Marlin/src/lcd/language/language_hr.h @@ -41,7 +41,6 @@ namespace LanguageNarrow_hr { LSTR MSG_MEDIA_REMOVED = _UxGT("SD kartica uklonjena"); LSTR MSG_LCD_ENDSTOPS = _UxGT("Endstops"); // Max length 8 characters LSTR MSG_MAIN_MENU = _UxGT("Main"); - LSTR MSG_RUN_AUTO_FILES = _UxGT("Auto pokretanje"); LSTR MSG_DISABLE_STEPPERS = _UxGT("Ugasi steppere"); LSTR MSG_AUTO_HOME = _UxGT("Automatski homing"); LSTR MSG_AUTO_HOME_X = _UxGT("Home-aj X"); @@ -117,13 +116,13 @@ namespace LanguageNarrow_hr { LSTR MSG_STOPPED = _UxGT("ZAUSTAVLJEN. "); LSTR MSG_FILAMENTCHANGE = _UxGT("Promijeni filament"); LSTR MSG_FILAMENTCHANGE_E = _UxGT("Promijeni filament *"); - #if HAS_MULTI_VOLUME - LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Init. SD karticu"); - LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Init. USB pogon"); - #else - LSTR MSG_ATTACH_MEDIA = _UxGT("Init. SD karticu"); - #endif + + LSTR MSG_ATTACH_MEDIA = _UxGT("Init. SD karticu"); + LSTR MSG_ATTACH_SD = _UxGT("Init. SD karticu"); + LSTR MSG_ATTACH_USB = _UxGT("Init. USB pogon"); LSTR MSG_CHANGE_MEDIA = _UxGT("Promijeni SD karticu"); + LSTR MSG_RUN_AUTOFILES = _UxGT("Auto pokretanje"); + LSTR MSG_ERR_HEATING_FAILED = _UxGT("Grijanje neuspješno"); LSTR MSG_HEATING = _UxGT("Grijanje..."); LSTR MSG_BED_HEATING = _UxGT("Grijanje Bed-a..."); diff --git a/Marlin/src/lcd/language/language_hu.h b/Marlin/src/lcd/language/language_hu.h index a626aa2209..3159b79827 100644 --- a/Marlin/src/lcd/language/language_hu.h +++ b/Marlin/src/lcd/language/language_hu.h @@ -57,7 +57,6 @@ namespace LanguageNarrow_hu { LSTR MSG_MAIN_MENU = _UxGT(""); LSTR MSG_ADVANCED_SETTINGS = _UxGT("További beállítások"); LSTR MSG_CONFIGURATION = _UxGT("Konfiguráció"); - LSTR MSG_RUN_AUTO_FILES = _UxGT("Fájl auto. futtatás"); LSTR MSG_DISABLE_STEPPERS = _UxGT("Motorok kikapcsolása"); LSTR MSG_DEBUG_MENU = _UxGT("Hiba Menü"); LSTR MSG_PROGRESS_BAR_TEST = _UxGT("Haladás sáv teszt"); @@ -431,14 +430,14 @@ namespace LanguageNarrow_hu { LSTR MSG_FILAMENTUNLOAD = _UxGT("Szál eltávolítás"); LSTR MSG_FILAMENTUNLOAD_E = _UxGT("Szál eltávolítás *"); LSTR MSG_FILAMENTUNLOAD_ALL = _UxGT("Mindet eltávolít"); - #if HAS_MULTI_VOLUME - LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Tároló SD"); - LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Tároló USB"); - #else - LSTR MSG_ATTACH_MEDIA = _UxGT("Tároló SD"); - #endif + + LSTR MSG_ATTACH_MEDIA = _UxGT("Tároló SD"); + LSTR MSG_ATTACH_SD = _UxGT("Tároló SD"); + LSTR MSG_ATTACH_USB = _UxGT("Tároló USB"); LSTR MSG_CHANGE_MEDIA = _UxGT("Tároló csere"); LSTR MSG_RELEASE_MEDIA = _UxGT("Tároló Kiadása"); + LSTR MSG_RUN_AUTOFILES = _UxGT("Fájl auto. futtatás"); + LSTR MSG_ZPROBE_OUT = _UxGT("Z szonda tálcán kivül"); LSTR MSG_SKEW_FACTOR = _UxGT("Ferdeség faktor"); LSTR MSG_BLTOUCH = _UxGT("BLTouch"); diff --git a/Marlin/src/lcd/language/language_it.h b/Marlin/src/lcd/language/language_it.h index c1b5366332..424bcd8367 100644 --- a/Marlin/src/lcd/language/language_it.h +++ b/Marlin/src/lcd/language/language_it.h @@ -38,7 +38,13 @@ #define DISPLAY_CHARSET_ISO10646_1 -#define MEDIA_TYPE_IT "Media" +#if HAS_SDCARD && !HAS_USB_FLASH_DRIVE + #define MEDIA_TYPE_IT "SD" +#elif HAS_USB_FLASH_DRIVE + #define MEDIA_TYPE_IT "USB" +#else + #define MEDIA_TYPE_IT "Media" +#endif namespace LanguageNarrow_it { using namespace Language_en; // Inherit undefined strings from English @@ -69,7 +75,6 @@ namespace LanguageNarrow_it { LSTR MSG_MAIN_MENU = _UxGT("Menu principale"); LSTR MSG_ADVANCED_SETTINGS = _UxGT("Impostaz. avanzate"); LSTR MSG_CONFIGURATION = _UxGT("Configurazione"); - LSTR MSG_RUN_AUTO_FILES = _UxGT("Esegui files auto"); LSTR MSG_DISABLE_STEPPERS = _UxGT("Disabilita motori"); LSTR MSG_DEBUG_MENU = _UxGT("Menu di debug"); LSTR MSG_PROGRESS_BAR_TEST = _UxGT("Test barra avanzam."); @@ -581,14 +586,14 @@ namespace LanguageNarrow_it { LSTR MSG_FILAMENTUNLOAD = _UxGT("Rimuovi filamento"); LSTR MSG_FILAMENTUNLOAD_E = _UxGT("Rimuovi filam. *"); LSTR MSG_FILAMENTUNLOAD_ALL = _UxGT("Rimuovi tutto"); - #if HAS_MULTI_VOLUME - LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Collega scheda SD"); - LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Collega penna USB"); - #else - LSTR MSG_ATTACH_MEDIA = _UxGT("Collega ") MEDIA_TYPE_IT; - #endif + + LSTR MSG_ATTACH_MEDIA = _UxGT("Collega ") MEDIA_TYPE_IT; + LSTR MSG_ATTACH_SD = _UxGT("Collega scheda SD"); + LSTR MSG_ATTACH_USB = _UxGT("Collega penna USB"); LSTR MSG_CHANGE_MEDIA = _UxGT("Cambia ") MEDIA_TYPE_IT; LSTR MSG_RELEASE_MEDIA = _UxGT("Rilascia ") MEDIA_TYPE_IT; + LSTR MSG_RUN_AUTOFILES = _UxGT("Esegui files auto"); + LSTR MSG_ZPROBE_OUT = _UxGT("Z probe fuori piatto"); LSTR MSG_SKEW_FACTOR = _UxGT("Fattore distorsione"); LSTR MSG_BLTOUCH = _UxGT("BLTouch"); diff --git a/Marlin/src/lcd/language/language_jp_kana.h b/Marlin/src/lcd/language/language_jp_kana.h index ae88b1d968..37c9aa043e 100644 --- a/Marlin/src/lcd/language/language_jp_kana.h +++ b/Marlin/src/lcd/language/language_jp_kana.h @@ -47,7 +47,6 @@ namespace LanguageNarrow_jp_kana { LSTR MSG_RELEASE_MEDIA = _UxGT("メディアノトリダシ"); LSTR MSG_LCD_ENDSTOPS = _UxGT("エンドストップ"); // "Endstops" // Max length 8 characters LSTR MSG_MAIN_MENU = _UxGT("メイン"); // "Main" - LSTR MSG_RUN_AUTO_FILES = _UxGT("ジドウカイシ"); // "Autostart" LSTR MSG_DISABLE_STEPPERS = _UxGT("モーターデンゲン オフ"); // "Disable steppers" LSTR MSG_DEBUG_MENU = _UxGT("デバッグメニュー"); // "Debug Menu" LSTR MSG_PROGRESS_BAR_TEST = _UxGT("プログレスバー テスト"); // "Progress Bar Test" @@ -168,13 +167,13 @@ namespace LanguageNarrow_jp_kana { LSTR MSG_CONTROL_RETRACT_RECOVERF = _UxGT("ホショウソクド mm/s"); // "Unretract V" LSTR MSG_AUTORETRACT = _UxGT("ジドウヒキコミ"); // "Auto-Retract" LSTR MSG_FILAMENTCHANGE = _UxGT("フィラメントコウカン"); // "Change filament" - #if HAS_MULTI_VOLUME - LSTR MSG_ATTACH_SD_MEDIA = _UxGT("SDカードをマウントする"); // "Attach SD Card" - LSTR MSG_ATTACH_USB_MEDIA = _UxGT("USBメモリをマウントする"); // "Attach USB Drive" - #else - LSTR MSG_ATTACH_MEDIA = _UxGT("SDカードをマウントする"); // "Attach SD Card" - #endif + + LSTR MSG_ATTACH_MEDIA = _UxGT("SDカードをマウントする"); // "Attach SD Card" + LSTR MSG_ATTACH_SD = _UxGT("SDカードをマウントする"); // "Attach SD Card" + LSTR MSG_ATTACH_USB = _UxGT("USBメモリをマウントする"); // "Attach USB Drive" LSTR MSG_CHANGE_MEDIA = _UxGT("メディアコウカン"); // "Change SD card" + LSTR MSG_RUN_AUTOFILES = _UxGT("ジドウカイシ"); // "Autostart" + LSTR MSG_ZPROBE_OUT = _UxGT("Zプローブ ベッドガイ"); // "Z probe out. bed" LSTR MSG_BLTOUCH_SELFTEST = _UxGT("BLTouch ジコシンダン"); // "BLTouch Self-Test" LSTR MSG_BLTOUCH_RESET = _UxGT("BLTouch リセット"); // "Reset BLTouch" diff --git a/Marlin/src/lcd/language/language_ko_KR.h b/Marlin/src/lcd/language/language_ko_KR.h index d5410cadf5..4ecaab5394 100644 --- a/Marlin/src/lcd/language/language_ko_KR.h +++ b/Marlin/src/lcd/language/language_ko_KR.h @@ -42,7 +42,7 @@ namespace LanguageNarrow_ko_KR { LSTR MSG_MAIN_MENU = _UxGT("뒤로"); LSTR MSG_ADVANCED_SETTINGS = _UxGT("고급 설정"); LSTR MSG_CONFIGURATION = _UxGT("설정"); - LSTR MSG_RUN_AUTO_FILES = _UxGT("자동 시작"); + LSTR MSG_RUN_AUTOFILES = _UxGT("자동 시작"); LSTR MSG_DISABLE_STEPPERS = _UxGT("모터 정지"); LSTR MSG_DEBUG_MENU = _UxGT("디버깅 메뉴"); LSTR MSG_PROGRESS_BAR_TEST = _UxGT("프로그레스바 테스트"); diff --git a/Marlin/src/lcd/language/language_nl.h b/Marlin/src/lcd/language/language_nl.h index e99417a2dc..bb4c7e00b2 100644 --- a/Marlin/src/lcd/language/language_nl.h +++ b/Marlin/src/lcd/language/language_nl.h @@ -43,7 +43,6 @@ namespace LanguageNarrow_nl { LSTR MSG_MEDIA_REMOVED = _UxGT("Kaart verwijderd"); LSTR MSG_LCD_ENDSTOPS = _UxGT("Endstops"); // Max length 8 characters LSTR MSG_MAIN_MENU = _UxGT("Hoofdmenu"); - LSTR MSG_RUN_AUTO_FILES = _UxGT("Autostart"); LSTR MSG_DISABLE_STEPPERS = _UxGT("Motoren uit"); LSTR MSG_DEBUG_MENU = _UxGT("Debug Menu"); // accepted English terms LSTR MSG_PROGRESS_BAR_TEST = _UxGT("Vooruitgang Test"); @@ -146,13 +145,13 @@ namespace LanguageNarrow_nl { LSTR MSG_AUTORETRACT = _UxGT("Auto-Retract"); LSTR MSG_FILAMENTCHANGE = _UxGT("Verv. Filament"); LSTR MSG_FILAMENTCHANGE_E = _UxGT("Verv. Filament *"); - #if HAS_MULTI_VOLUME - LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Init. SD kaart"); - LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Init. USB stick"); - #else - LSTR MSG_ATTACH_MEDIA = _UxGT("Init. SD kaart"); - #endif + + LSTR MSG_ATTACH_MEDIA = _UxGT("Init. SD kaart"); + LSTR MSG_ATTACH_SD = _UxGT("Init. SD kaart"); + LSTR MSG_ATTACH_USB = _UxGT("Init. USB stick"); LSTR MSG_CHANGE_MEDIA = _UxGT("Verv. SD Kaart"); + LSTR MSG_RUN_AUTOFILES = _UxGT("Autostart"); + LSTR MSG_ZPROBE_OUT = _UxGT("Z probe uit. bed"); LSTR MSG_BLTOUCH_SELFTEST = _UxGT("BLTouch Zelf-Test"); LSTR MSG_BLTOUCH_RESET = _UxGT("Reset BLTouch"); diff --git a/Marlin/src/lcd/language/language_pl.h b/Marlin/src/lcd/language/language_pl.h index 07573bb2d8..7c7297d184 100644 --- a/Marlin/src/lcd/language/language_pl.h +++ b/Marlin/src/lcd/language/language_pl.h @@ -61,7 +61,6 @@ namespace LanguageNarrow_pl { LSTR MSG_MAIN_MENU = _UxGT("Menu główne"); LSTR MSG_ADVANCED_SETTINGS = _UxGT("Ustawienie zaawansowane"); LSTR MSG_CONFIGURATION = _UxGT("Konfiguracja"); - LSTR MSG_RUN_AUTO_FILES = _UxGT("Autostart"); LSTR MSG_DISABLE_STEPPERS = _UxGT("Wyłącz silniki"); LSTR MSG_DEBUG_MENU = _UxGT("Menu Debugowania"); LSTR MSG_PROGRESS_BAR_TEST = _UxGT("Testowy pasek postępu"); @@ -358,14 +357,14 @@ namespace LanguageNarrow_pl { LSTR MSG_FILAMENTUNLOAD = _UxGT("Wysuń Filament"); LSTR MSG_FILAMENTUNLOAD_E = _UxGT("Wysuń Filament *"); LSTR MSG_FILAMENTUNLOAD_ALL = _UxGT("Wysuń wszystkie"); - #if HAS_MULTI_VOLUME - LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Inicjal. karty SD"); - LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Inicjal. dysk flash"); - #else - LSTR MSG_ATTACH_MEDIA = _UxGT("Inicjal. karty SD"); - #endif + + LSTR MSG_ATTACH_MEDIA = _UxGT("Inicjal. karty SD"); + LSTR MSG_ATTACH_SD = _UxGT("Inicjal. karty SD"); + LSTR MSG_ATTACH_USB = _UxGT("Inicjal. dysk flash"); LSTR MSG_CHANGE_MEDIA = _UxGT("Zmiana karty SD"); LSTR MSG_RELEASE_MEDIA = _UxGT("Zwolnienie karty"); + LSTR MSG_RUN_AUTOFILES = _UxGT("Autostart"); + LSTR MSG_ZPROBE_OUT = _UxGT("Sonda Z za stołem"); LSTR MSG_SKEW_FACTOR = _UxGT("Współczynik skrzywienia"); LSTR MSG_BLTOUCH_SELFTEST = _UxGT("BLTouch Self-Test"); diff --git a/Marlin/src/lcd/language/language_pt.h b/Marlin/src/lcd/language/language_pt.h index 62799fc9a5..229211b4f2 100644 --- a/Marlin/src/lcd/language/language_pt.h +++ b/Marlin/src/lcd/language/language_pt.h @@ -142,13 +142,12 @@ namespace LanguageNarrow_pt { LSTR MSG_AUTORETRACT = _UxGT(" Auto-Retract"); LSTR MSG_FILAMENTCHANGE = _UxGT("Trocar filamento"); LSTR MSG_FILAMENTCHANGE_E = _UxGT("Trocar filamento *"); - #if HAS_MULTI_VOLUME - LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Inici. cartão SD"); - LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Inici. flash USB"); - #else - LSTR MSG_ATTACH_MEDIA = _UxGT("Inici. cartão SD"); - #endif + + LSTR MSG_ATTACH_MEDIA = _UxGT("Inici. cartão SD"); + LSTR MSG_ATTACH_SD = _UxGT("Inici. cartão SD"); + LSTR MSG_ATTACH_USB = _UxGT("Inici. flash USB"); LSTR MSG_CHANGE_MEDIA = _UxGT("Trocar cartão SD"); + LSTR MSG_ZPROBE_OUT = _UxGT("Sensor fora/base"); LSTR MSG_ZPROBE_XOFFSET = _UxGT("Desvio X"); LSTR MSG_ZPROBE_YOFFSET = _UxGT("Desvio Y"); diff --git a/Marlin/src/lcd/language/language_pt_br.h b/Marlin/src/lcd/language/language_pt_br.h index 8d5a608d00..80a8d95bdb 100644 --- a/Marlin/src/lcd/language/language_pt_br.h +++ b/Marlin/src/lcd/language/language_pt_br.h @@ -50,7 +50,6 @@ namespace LanguageNarrow_pt_br { LSTR MSG_MAIN_MENU = _UxGT("Menu principal"); LSTR MSG_ADVANCED_SETTINGS = _UxGT("Config. Avançada"); LSTR MSG_CONFIGURATION = _UxGT("Configuração"); - LSTR MSG_RUN_AUTO_FILES = _UxGT("Início automático"); LSTR MSG_DISABLE_STEPPERS = _UxGT("Desabilit. motores"); LSTR MSG_DEBUG_MENU = _UxGT("Menu Debug"); LSTR MSG_PROGRESS_BAR_TEST = _UxGT("Testar Barra Progres"); @@ -321,14 +320,14 @@ namespace LanguageNarrow_pt_br { LSTR MSG_FILAMENTUNLOAD = _UxGT("Descarreg. Filamento"); LSTR MSG_FILAMENTUNLOAD_E = _UxGT("Descarreg. Filamento *"); LSTR MSG_FILAMENTUNLOAD_ALL = _UxGT("Descarregar Todos"); - #if HAS_MULTI_VOLUME - LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Iniciar cartão SD"); - LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Iniciar flash USB"); - #else - LSTR MSG_ATTACH_MEDIA = _UxGT("Iniciar cartão SD"); - #endif + + LSTR MSG_ATTACH_MEDIA = _UxGT("Iniciar cartão SD"); + LSTR MSG_ATTACH_SD = _UxGT("Iniciar cartão SD"); + LSTR MSG_ATTACH_USB = _UxGT("Iniciar flash USB"); LSTR MSG_CHANGE_MEDIA = _UxGT("Trocar SD"); LSTR MSG_RELEASE_MEDIA = _UxGT("Liberar SD"); + LSTR MSG_RUN_AUTOFILES = _UxGT("Início automático"); + LSTR MSG_ZPROBE_OUT = _UxGT("Sonda fora da mesa"); LSTR MSG_SKEW_FACTOR = _UxGT("Fator de Cisalho"); LSTR MSG_BLTOUCH = _UxGT("BLTouch"); diff --git a/Marlin/src/lcd/language/language_ro.h b/Marlin/src/lcd/language/language_ro.h index 0b263a4ea6..7337862909 100644 --- a/Marlin/src/lcd/language/language_ro.h +++ b/Marlin/src/lcd/language/language_ro.h @@ -52,7 +52,6 @@ namespace LanguageNarrow_ro { LSTR MSG_MAIN_MENU = _UxGT("Principal"); LSTR MSG_ADVANCED_SETTINGS = _UxGT("Setari Avansate"); LSTR MSG_CONFIGURATION = _UxGT("Configurare"); - LSTR MSG_RUN_AUTO_FILES = _UxGT("Autostart"); LSTR MSG_DISABLE_STEPPERS = _UxGT("Dezactivare Motoare"); LSTR MSG_DEBUG_MENU = _UxGT("Meniu Debug"); LSTR MSG_PROGRESS_BAR_TEST = _UxGT("Test Bara Progres"); @@ -388,14 +387,14 @@ namespace LanguageNarrow_ro { LSTR MSG_FILAMENTUNLOAD = _UxGT("Scoatere Filament"); LSTR MSG_FILAMENTUNLOAD_E = _UxGT("Scoatere Filament *"); LSTR MSG_FILAMENTUNLOAD_ALL = _UxGT("Scoate Tot"); - #if HAS_MULTI_VOLUME - LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Atasare card SD"); - LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Atasare FD USB"); - #else - LSTR MSG_ATTACH_MEDIA = _UxGT("Atasare card SD"); - #endif + + LSTR MSG_ATTACH_MEDIA = _UxGT("Atasare card SD"); + LSTR MSG_ATTACH_SD = _UxGT("Atasare card SD"); + LSTR MSG_ATTACH_USB = _UxGT("Atasare FD USB"); LSTR MSG_CHANGE_MEDIA = _UxGT("Inlocuire Media"); LSTR MSG_RELEASE_MEDIA = _UxGT("Eliberare Media"); + LSTR MSG_RUN_AUTOFILES = _UxGT("Autostart"); + LSTR MSG_ZPROBE_OUT = _UxGT("Z Probe Past Bed"); LSTR MSG_SKEW_FACTOR = _UxGT("Skew Factor"); LSTR MSG_BLTOUCH = _UxGT("BLTouch"); diff --git a/Marlin/src/lcd/language/language_ru.h b/Marlin/src/lcd/language/language_ru.h index 42e1656a8b..40b3a03d3d 100644 --- a/Marlin/src/lcd/language/language_ru.h +++ b/Marlin/src/lcd/language/language_ru.h @@ -53,7 +53,6 @@ namespace LanguageNarrow_ru { LSTR MSG_LCD_ENDSTOPS = _UxGT("Концевик"); // Max length 8 characters LSTR MSG_MAIN_MENU = _UxGT("Главное меню"); LSTR MSG_CONFIGURATION = _UxGT("Конфигурация"); - LSTR MSG_RUN_AUTO_FILES = _UxGT("Автостарт"); LSTR MSG_DISABLE_STEPPERS = _UxGT("Выключить двигатели"); LSTR MSG_DEBUG_MENU = _UxGT("Меню отладки"); LSTR MSG_PROGRESS_BAR_TEST = _UxGT("Тест индикатора"); @@ -435,14 +434,14 @@ namespace LanguageNarrow_ru { LSTR MSG_FILAMENTLOAD_E = _UxGT("Подать филамент *"); LSTR MSG_FILAMENTUNLOAD_E = _UxGT("Убрать филамент *"); LSTR MSG_FILAMENTUNLOAD_ALL = _UxGT("Выгрузить всё"); - #if HAS_MULTI_VOLUME - LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Установить SD карту"); - LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Монтировать USB"); // Установить флешка - #else - LSTR MSG_ATTACH_MEDIA = _UxGT("Установить SD карту"); - #endif + + LSTR MSG_ATTACH_MEDIA = _UxGT("Установить SD карту"); + LSTR MSG_ATTACH_SD = _UxGT("Установить SD карту"); + LSTR MSG_ATTACH_USB = _UxGT("Монтировать USB"); // Установить флешка LSTR MSG_CHANGE_MEDIA = _UxGT("Сменить SD карту"); LSTR MSG_RELEASE_MEDIA = _UxGT("Освободить SD карту"); + LSTR MSG_RUN_AUTOFILES = _UxGT("Автостарт"); + LSTR MSG_ZPROBE_OUT = _UxGT("Z-зонд вне стола"); LSTR MSG_SKEW_FACTOR = _UxGT("Фактор перекоса"); LSTR MSG_BLTOUCH = _UxGT("Z-зонд BLTouch"); diff --git a/Marlin/src/lcd/language/language_sk.h b/Marlin/src/lcd/language/language_sk.h index 782f42f118..7a8c228d84 100644 --- a/Marlin/src/lcd/language/language_sk.h +++ b/Marlin/src/lcd/language/language_sk.h @@ -68,7 +68,6 @@ namespace LanguageNarrow_sk { LSTR MSG_MAIN_MENU = _UxGT("Hlavná ponuka"); LSTR MSG_ADVANCED_SETTINGS = _UxGT("Pokročilé nastav."); LSTR MSG_CONFIGURATION = _UxGT("Konfigurácia"); - LSTR MSG_RUN_AUTO_FILES = _UxGT("Auto-štart"); LSTR MSG_DISABLE_STEPPERS = _UxGT("Uvolniť motory"); LSTR MSG_DEBUG_MENU = _UxGT("Ponuka ladenia"); LSTR MSG_PROGRESS_BAR_TEST = _UxGT("Test uk. priebehu"); @@ -533,14 +532,14 @@ namespace LanguageNarrow_sk { LSTR MSG_FILAMENTUNLOAD = _UxGT("Vysunúť filament"); LSTR MSG_FILAMENTUNLOAD_E = _UxGT("Vysunúť filament *"); LSTR MSG_FILAMENTUNLOAD_ALL = _UxGT("Vysunúť všetko"); - #if HAS_MULTI_VOLUME - LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Načítať SD kartu"); - LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Načítať USB disk"); - #else - LSTR MSG_ATTACH_MEDIA = _UxGT("Načítať SD kartu"); - #endif + + LSTR MSG_ATTACH_MEDIA = _UxGT("Načítať SD kartu"); + LSTR MSG_ATTACH_SD = _UxGT("Načítať SD kartu"); + LSTR MSG_ATTACH_USB = _UxGT("Načítať USB disk"); LSTR MSG_CHANGE_MEDIA = _UxGT("Vymeniť kartu"); LSTR MSG_RELEASE_MEDIA = _UxGT("Odpojiť kartu"); + LSTR MSG_RUN_AUTOFILES = _UxGT("Auto-štart"); + LSTR MSG_ZPROBE_OUT = _UxGT("Sonda Z mimo podl."); LSTR MSG_SKEW_FACTOR = _UxGT("Faktor skosenia"); LSTR MSG_BLTOUCH = _UxGT("BLTouch"); diff --git a/Marlin/src/lcd/language/language_sv.h b/Marlin/src/lcd/language/language_sv.h index 356a253b6e..e2e408391c 100644 --- a/Marlin/src/lcd/language/language_sv.h +++ b/Marlin/src/lcd/language/language_sv.h @@ -54,7 +54,6 @@ namespace LanguageNarrow_sv { LSTR MSG_MAIN_MENU = _UxGT("Huvud"); LSTR MSG_ADVANCED_SETTINGS = _UxGT("Advancerade inställningar"); LSTR MSG_CONFIGURATION = _UxGT("Konfiguration"); - LSTR MSG_RUN_AUTO_FILES = _UxGT("Autostarta Filer"); LSTR MSG_DISABLE_STEPPERS = _UxGT("Inaktivera Stegare"); LSTR MSG_DEBUG_MENU = _UxGT("Debug Meny"); LSTR MSG_PROGRESS_BAR_TEST = _UxGT("Framstegsindikator Test"); @@ -417,14 +416,14 @@ namespace LanguageNarrow_sv { LSTR MSG_FILAMENTUNLOAD = _UxGT("Lossa Tråd"); LSTR MSG_FILAMENTUNLOAD_E = _UxGT("Lossa *"); LSTR MSG_FILAMENTUNLOAD_ALL = _UxGT("Lossa All"); - #if HAS_MULTI_VOLUME - LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Bifoga SD-kort"); - LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Bifoga USB-minne"); - #else - LSTR MSG_ATTACH_MEDIA = _UxGT("Bifoga SD-kort"); - #endif + + LSTR MSG_ATTACH_MEDIA = _UxGT("Bifoga SD-kort"); + LSTR MSG_ATTACH_SD = _UxGT("Bifoga SD-kort"); + LSTR MSG_ATTACH_USB = _UxGT("Bifoga USB-minne"); LSTR MSG_CHANGE_MEDIA = _UxGT("Byt Media"); LSTR MSG_RELEASE_MEDIA = _UxGT("Släpp Media"); + LSTR MSG_RUN_AUTOFILES = _UxGT("Autostarta Filer"); + LSTR MSG_ZPROBE_OUT = _UxGT("Z Sond Utanför Bädd"); LSTR MSG_SKEW_FACTOR = _UxGT("Skev Faktor"); LSTR MSG_BLTOUCH = _UxGT("BLTouch"); diff --git a/Marlin/src/lcd/language/language_tr.h b/Marlin/src/lcd/language/language_tr.h index 947f094fa6..36fe4188fa 100644 --- a/Marlin/src/lcd/language/language_tr.h +++ b/Marlin/src/lcd/language/language_tr.h @@ -68,7 +68,6 @@ namespace LanguageNarrow_tr { LSTR MSG_MAIN_MENU = _UxGT("Ana"); LSTR MSG_ADVANCED_SETTINGS = _UxGT("Gelişmiş Ayarlar"); LSTR MSG_CONFIGURATION = _UxGT("Yapılandırma"); - LSTR MSG_RUN_AUTO_FILES = _UxGT("Oto. Başlat"); LSTR MSG_DISABLE_STEPPERS = _UxGT("Motorları Durdur"); LSTR MSG_DEBUG_MENU = _UxGT("Hata Ayıklama"); LSTR MSG_PROGRESS_BAR_TEST = _UxGT("Durum Çubuğu Testi"); @@ -550,14 +549,14 @@ namespace LanguageNarrow_tr { LSTR MSG_FILAMENTUNLOAD = _UxGT("Filaman Çıkart"); LSTR MSG_FILAMENTUNLOAD_E = _UxGT("Filaman Çıkart *"); LSTR MSG_FILAMENTUNLOAD_ALL = _UxGT("Tümünü Çıkart"); - #if HAS_MULTI_VOLUME - LSTR MSG_ATTACH_SD_MEDIA = _UxGT("SD Kartı takın"); - LSTR MSG_ATTACH_USB_MEDIA = _UxGT("USB Sürücüyü takın"); - #else - LSTR MSG_ATTACH_MEDIA = _UxGT("Medyayı Ekle"); - #endif + + LSTR MSG_ATTACH_MEDIA = _UxGT("Medyayı Ekle"); + LSTR MSG_ATTACH_SD = _UxGT("SD Kartı takın"); + LSTR MSG_ATTACH_USB = _UxGT("USB Sürücüyü takın"); LSTR MSG_CHANGE_MEDIA = _UxGT("Medyayı Değiştir"); LSTR MSG_RELEASE_MEDIA = _UxGT("Medyayı Çıkart"); + LSTR MSG_RUN_AUTOFILES = _UxGT("Oto. Başlat"); + LSTR MSG_ZPROBE_OUT = _UxGT("Z Prob Tablayı Geçti"); LSTR MSG_SKEW_FACTOR = _UxGT("Çarpıklık Faktörü"); LSTR MSG_BLTOUCH = _UxGT("BLTouch"); diff --git a/Marlin/src/lcd/language/language_uk.h b/Marlin/src/lcd/language/language_uk.h index c061b9ad02..4d323d6ba7 100644 --- a/Marlin/src/lcd/language/language_uk.h +++ b/Marlin/src/lcd/language/language_uk.h @@ -54,7 +54,6 @@ namespace LanguageNarrow_uk { LSTR MSG_MAIN_MENU = _UxGT("Основне меню"); LSTR MSG_ADVANCED_SETTINGS = _UxGT("Інші налаштування"); LSTR MSG_CONFIGURATION = _UxGT("Конфігурація"); - LSTR MSG_RUN_AUTO_FILES = _UxGT("Автостарт"); LSTR MSG_DISABLE_STEPPERS = _UxGT("Вимкнути двигуни"); LSTR MSG_DEBUG_MENU = _UxGT("Меню Debug"); LSTR MSG_PROGRESS_BAR_TEST = _UxGT("Тест лінії прогр."); @@ -445,14 +444,14 @@ namespace LanguageNarrow_uk { LSTR MSG_FILAMENTUNLOAD = _UxGT("Видалити пруток"); LSTR MSG_FILAMENTUNLOAD_E = _UxGT("Видалити пруток *"); LSTR MSG_FILAMENTUNLOAD_ALL = _UxGT("Видалити все"); - #if HAS_MULTI_VOLUME - LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Вставити SD-картку"); - LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Вставити USB флешка"); - #else - LSTR MSG_ATTACH_MEDIA = _UxGT("Вставити SD-картку"); - #endif + + LSTR MSG_ATTACH_MEDIA = _UxGT("Вставити SD-картку"); + LSTR MSG_ATTACH_SD = _UxGT("Вставити SD-картку"); + LSTR MSG_ATTACH_USB = _UxGT("Вставити USB флешка"); LSTR MSG_CHANGE_MEDIA = _UxGT("Заміна SD-картки"); LSTR MSG_RELEASE_MEDIA = _UxGT("Видаліть SD-картку"); + LSTR MSG_RUN_AUTOFILES = _UxGT("Автостарт"); + LSTR MSG_ZPROBE_OUT = _UxGT("Z-Зонд поза столом"); LSTR MSG_SKEW_FACTOR = _UxGT("Фактор нахилу"); LSTR MSG_BLTOUCH = _UxGT("BLTouch"); diff --git a/Marlin/src/lcd/language/language_vi.h b/Marlin/src/lcd/language/language_vi.h index fb158e306b..f7f5545bcb 100644 --- a/Marlin/src/lcd/language/language_vi.h +++ b/Marlin/src/lcd/language/language_vi.h @@ -47,7 +47,6 @@ namespace LanguageNarrow_vi { LSTR MSG_MAIN_MENU = _UxGT("Chính"); // Main LSTR MSG_ADVANCED_SETTINGS = _UxGT("Thiết lập cấp cao"); // Advanced Settings LSTR MSG_CONFIGURATION = _UxGT("Cấu hình"); // Configuration - LSTR MSG_RUN_AUTO_FILES = _UxGT("Khởi chạy tự động"); // Autostart LSTR MSG_DISABLE_STEPPERS = _UxGT("Tắt động cơ bước"); // Disable steppers LSTR MSG_DEBUG_MENU = _UxGT("Menu gỡ lỗi"); // Debug Menu LSTR MSG_PROGRESS_BAR_TEST = _UxGT("Kiểm tra tiến độ"); // Progress bar test @@ -309,14 +308,14 @@ namespace LanguageNarrow_vi { LSTR MSG_FILAMENTUNLOAD = _UxGT("Dỡ dây nhựa"); // Unload filament LSTR MSG_FILAMENTUNLOAD_E = _UxGT("Dỡ dây nhựa *"); // Unload filament LSTR MSG_FILAMENTUNLOAD_ALL = _UxGT("Dỡ tất cả"); // Unload All - #if HAS_MULTI_VOLUME - LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Khởi tạo thẻ SD"); // Attach SD Card - LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Khởi tạo thanh USB"); // Attach USB Drive - #else - LSTR MSG_ATTACH_MEDIA = _UxGT("Khởi tạo phương tiện"); // Attach media - #endif + + LSTR MSG_ATTACH_MEDIA = _UxGT("Khởi tạo phương tiện"); // Attach media + LSTR MSG_ATTACH_SD = _UxGT("Khởi tạo thẻ SD"); // Attach SD Card + LSTR MSG_ATTACH_USB = _UxGT("Khởi tạo thanh USB"); // Attach USB Drive LSTR MSG_CHANGE_MEDIA = _UxGT("Thay phương tiện"); // Change midea LSTR MSG_RELEASE_MEDIA = _UxGT("Phát hành phương tiện"); + LSTR MSG_RUN_AUTOFILES = _UxGT("Khởi chạy tự động"); // Autostart + LSTR MSG_ZPROBE_OUT = _UxGT("Đầu Dò Z qua bàn"); // Z Probe past bed LSTR MSG_SKEW_FACTOR = _UxGT("Hệ số nghiêng"); // Skew Factor LSTR MSG_BLTOUCH = _UxGT("BLTOUCH"); // BLTouch @@ -373,19 +372,11 @@ namespace LanguageNarrow_vi { LSTR MSG_INFO_PROTOCOL = _UxGT("Giao Thức"); // Protocol LSTR MSG_CASE_LIGHT = _UxGT("Đèn Khuông"); // Case light LSTR MSG_CASE_LIGHT_BRIGHTNESS = _UxGT("Độ Sáng"); // Light Brightness - #if LCD_WIDTH >= 20 || HAS_DWIN_E3V2 - LSTR MSG_INFO_PRINT_COUNT = _UxGT("Số In"); // Print Count - LSTR MSG_INFO_COMPLETED_PRINTS = _UxGT("Đã hoàn thành"); - LSTR MSG_INFO_PRINT_TIME = _UxGT("Tổng số thời gian in"); // Total print time - LSTR MSG_INFO_PRINT_LONGEST = _UxGT("Thời gian việc lâu nhất"); // Longest job time - LSTR MSG_INFO_PRINT_FILAMENT = _UxGT("Tổng số đùn"); // Extruded total - #else - LSTR MSG_INFO_PRINT_COUNT = _UxGT("In"); // Prints - LSTR MSG_INFO_COMPLETED_PRINTS = _UxGT("Đã hoàn thành"); // Completed - LSTR MSG_INFO_PRINT_TIME = _UxGT("Tổng số"); // Total - LSTR MSG_INFO_PRINT_LONGEST = _UxGT("Dài nhất"); // Longest - LSTR MSG_INFO_PRINT_FILAMENT = _UxGT("Đã ép đùn"); - #endif + LSTR MSG_INFO_PRINT_COUNT = _UxGT("In"); // Prints + LSTR MSG_INFO_COMPLETED_PRINTS = _UxGT("Đã hoàn thành"); // Completed + LSTR MSG_INFO_PRINT_TIME = _UxGT("Tổng số"); // Total + LSTR MSG_INFO_PRINT_LONGEST = _UxGT("Dài nhất"); // Longest + LSTR MSG_INFO_PRINT_FILAMENT = _UxGT("Đã ép đùn"); LSTR MSG_INFO_MIN_TEMP = _UxGT("Nhiệt độ tối thiểu"); // Min Temp LSTR MSG_INFO_MAX_TEMP = _UxGT("Nhiệt độ tối đa"); // Max temp LSTR MSG_INFO_PSU = _UxGT("Bộ nguồn"); // PSU @@ -446,6 +437,11 @@ namespace LanguageNarrow_vi { namespace LanguageWide_vi { using namespace LanguageNarrow_vi; #if LCD_WIDTH >= 20 || HAS_DWIN_E3V2 + LSTR MSG_INFO_PRINT_COUNT = _UxGT("Số In"); // Print Count + LSTR MSG_INFO_COMPLETED_PRINTS = _UxGT("Đã hoàn thành"); + LSTR MSG_INFO_PRINT_TIME = _UxGT("Tổng số thời gian in"); // Total print time + LSTR MSG_INFO_PRINT_LONGEST = _UxGT("Thời gian việc lâu nhất"); // Longest job time + LSTR MSG_INFO_PRINT_FILAMENT = _UxGT("Tổng số đùn"); // Extruded total #endif } diff --git a/Marlin/src/lcd/language/language_zh_CN.h b/Marlin/src/lcd/language/language_zh_CN.h index 680ff8c9b0..01f9f53d0c 100644 --- a/Marlin/src/lcd/language/language_zh_CN.h +++ b/Marlin/src/lcd/language/language_zh_CN.h @@ -54,7 +54,6 @@ namespace LanguageNarrow_zh_CN { LSTR MSG_MAIN_MENU = _UxGT("主菜单"); // "Main" LSTR MSG_ADVANCED_SETTINGS = _UxGT("高级设置"); LSTR MSG_CONFIGURATION = _UxGT("配置"); - LSTR MSG_RUN_AUTO_FILES = _UxGT("自动开始"); // "Autostart" LSTR MSG_DISABLE_STEPPERS = _UxGT("关闭步进电机"); // "Disable steppers" LSTR MSG_DEBUG_MENU = _UxGT("调试菜单"); // "Debug Menu" LSTR MSG_PROGRESS_BAR_TEST = _UxGT("进度条测试"); // "Progress Bar Test" @@ -398,14 +397,14 @@ namespace LanguageNarrow_zh_CN { LSTR MSG_FILAMENTUNLOAD = _UxGT("卸载丝料"); // "Unload filament" LSTR MSG_FILAMENTUNLOAD_E = _UxGT("卸载丝料 *"); // "Unload filament" LSTR MSG_FILAMENTUNLOAD_ALL = _UxGT("卸载全部"); // "Unload All" - #if HAS_MULTI_VOLUME - LSTR MSG_ATTACH_SD_MEDIA = _UxGT("挂载存储卡"); // "Attach SD Card" - LSTR MSG_ATTACH_USB_MEDIA = _UxGT("挂载U盘"); // "Attach USB Drive" - #else - LSTR MSG_ATTACH_MEDIA = _UxGT("挂载存储卡"); // "Attach SD Card" - #endif + + LSTR MSG_ATTACH_MEDIA = _UxGT("挂载存储卡"); // "Attach SD Card" + LSTR MSG_ATTACH_SD = _UxGT("挂载存储卡"); // "Attach SD Card" + LSTR MSG_ATTACH_USB = _UxGT("挂载U盘"); // "Attach USB Drive" LSTR MSG_CHANGE_MEDIA = _UxGT("更换存储卡"); // "Change SD card" LSTR MSG_RELEASE_MEDIA = _UxGT("释放存储卡"); + LSTR MSG_RUN_AUTOFILES = _UxGT("自动开始"); // "Autostart" + LSTR MSG_ZPROBE_OUT = _UxGT("Z探针在热床之外"); // "Z probe out. bed" Z probe is not within the physical limits LSTR MSG_SKEW_FACTOR = _UxGT("偏斜因数"); // "Skew Factor" LSTR MSG_BLTOUCH = _UxGT("BLTouch"); // "BLTouch" diff --git a/Marlin/src/lcd/language/language_zh_TW.h b/Marlin/src/lcd/language/language_zh_TW.h index 63e386a06f..7321252de7 100644 --- a/Marlin/src/lcd/language/language_zh_TW.h +++ b/Marlin/src/lcd/language/language_zh_TW.h @@ -49,7 +49,6 @@ namespace LanguageNarrow_zh_TW { LSTR MSG_MAIN_MENU = _UxGT("主選單"); // "Main" LSTR MSG_ADVANCED_SETTINGS = _UxGT("進階設置"); // "Advanced Settings" LSTR MSG_CONFIGURATION = _UxGT("設置"); //Configuration - LSTR MSG_RUN_AUTO_FILES = _UxGT("自動開始"); // "Autostart" LSTR MSG_DISABLE_STEPPERS = _UxGT("關閉步進馬達"); // "Disable steppers" LSTR MSG_DEBUG_MENU = _UxGT("除錯選單"); // "Debug Menu" LSTR MSG_PROGRESS_BAR_TEST = _UxGT("進度條測試"); // "Progress Bar Test" @@ -350,14 +349,14 @@ namespace LanguageNarrow_zh_TW { LSTR MSG_FILAMENTUNLOAD = _UxGT("卸載絲料"); // "Unload filament" LSTR MSG_FILAMENTUNLOAD_E = _UxGT("卸載絲料 *"); // "Unload filament" LSTR MSG_FILAMENTUNLOAD_ALL = _UxGT("卸載全部"); // "Unload All" - #if HAS_MULTI_VOLUME - LSTR MSG_ATTACH_SD_MEDIA = _UxGT("挂载記憶卡"); // "Attach SD Card" - LSTR MSG_ATTACH_USB_MEDIA = _UxGT("挂载隨身碟"); // "Attach USB Drive" - #else - LSTR MSG_ATTACH_MEDIA = _UxGT("連接記憶卡"); // "Attach Media" - #endif + + LSTR MSG_ATTACH_MEDIA = _UxGT("連接記憶卡"); // "Attach Media" + LSTR MSG_ATTACH_SD = _UxGT("挂载記憶卡"); // "Attach SD Card" + LSTR MSG_ATTACH_USB = _UxGT("挂载隨身碟"); // "Attach USB Drive" LSTR MSG_CHANGE_MEDIA = _UxGT("更換記憶卡"); // "Change SD card" LSTR MSG_RELEASE_MEDIA = _UxGT("釋放媒體"); // "Release Media" + LSTR MSG_RUN_AUTOFILES = _UxGT("自動開始"); // "Autostart" + LSTR MSG_ZPROBE_OUT = _UxGT("Z探針在熱床之外"); // "Z probe out. bed" Z probe is not within the physical limits LSTR MSG_SKEW_FACTOR = _UxGT("偏斜因數"); // "Skew Factor" diff --git a/Marlin/src/lcd/menu/menu_main.cpp b/Marlin/src/lcd/menu/menu_main.cpp index 9509c72cc5..7e2d458e41 100644 --- a/Marlin/src/lcd/menu/menu_main.cpp +++ b/Marlin/src/lcd/menu/menu_main.cpp @@ -253,13 +253,13 @@ void menu_main() { if (card_detected) { if (!card_open) { #if ENABLED(MENU_ADDAUTOSTART) - ACTION_ITEM(MSG_RUN_AUTO_FILES, card.autofile_begin); // Run Auto Files + ACTION_ITEM(MSG_RUN_AUTOFILES, card.autofile_begin); // Run Auto Files #endif #if HAS_SD_DETECT GCODES_ITEM(MSG_CHANGE_MEDIA, F("M21" TERN_(HAS_MULTI_VOLUME, "S"))); // M21 Change Media #if HAS_MULTI_VOLUME - GCODES_ITEM(MSG_ATTACH_USB_MEDIA, F("M21U")); // M21 Attach USB Media + GCODES_ITEM(MSG_ATTACH_USB, F("M21U")); // M21 Attach USB Media #endif #else // - or - ACTION_ITEM(MSG_RELEASE_MEDIA, []{ // M22 Release Media @@ -279,8 +279,8 @@ void menu_main() { ACTION_ITEM(MSG_NO_MEDIA, nullptr); // "No Media" #else #if HAS_MULTI_VOLUME - GCODES_ITEM(MSG_ATTACH_SD_MEDIA, F("M21S")); // M21S Attach SD Card - GCODES_ITEM(MSG_ATTACH_USB_MEDIA, F("M21U")); // M21U Attach USB Media + GCODES_ITEM(MSG_ATTACH_SD, F("M21S")); // M21S Attach SD Card + GCODES_ITEM(MSG_ATTACH_USB, F("M21U")); // M21U Attach USB Media #else GCODES_ITEM(MSG_ATTACH_MEDIA, F("M21")); // M21 Attach Media #endif From 62f2b8fc176887071e9a07152420f28fe54fceef Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Thu, 24 Apr 2025 00:30:48 +0000 Subject: [PATCH 251/787] [cron] Bump distribution date (2025-04-24) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index e9c1d9ba1b..e8a64a95f0 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-04-23" +//#define STRING_DISTRIBUTION_DATE "2025-04-24" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index d06c53dd5e..8a91fbdb71 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-04-23" + #define STRING_DISTRIBUTION_DATE "2025-04-24" #endif /** From d16667838fdbdf793840ee5ac8b977746af6055d Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Wed, 23 Apr 2025 18:37:03 -0500 Subject: [PATCH 252/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Cla?= =?UTF-8?q?rify=20some=20SD=20/=20FD=20build=20flags?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/gcode/sd/M21_M22.cpp | 4 +- Marlin/src/inc/Conditionals-4-adv.h | 11 +- Marlin/src/inc/Conditionals-5-post.h | 2 + Marlin/src/inc/SanityCheck.h | 2 +- .../lcd/extui/mks_ui/draw_media_select.cpp | 4 +- .../extui/mks_ui/tft_lvgl_configuration.cpp | 15 +- Marlin/src/lcd/marlinui.cpp | 2 +- Marlin/src/lcd/menu/menu.h | 2 +- Marlin/src/lcd/menu/menu_media.cpp | 18 +-- Marlin/src/sd/cardreader.cpp | 24 ++-- Marlin/src/sd/cardreader.h | 112 ++++++++++----- .../sd/usb_flashdrive/Sd2Card_FlashDrive.cpp | 130 +++++++++--------- 12 files changed, 190 insertions(+), 136 deletions(-) diff --git a/Marlin/src/gcode/sd/M21_M22.cpp b/Marlin/src/gcode/sd/M21_M22.cpp index f561229b17..672dc80f00 100644 --- a/Marlin/src/gcode/sd/M21_M22.cpp +++ b/Marlin/src/gcode/sd/M21_M22.cpp @@ -38,9 +38,9 @@ void GcodeSuite::M21() { #if HAS_MULTI_VOLUME const int8_t vol = parser.intval('P', -1); if (vol == 0 || parser.seen_test('S')) // "S" for SD Card - card.changeMedia(&card.media_driver_sdcard); + card.selectMediaSDCard(); else if (vol == 1 || parser.seen_test('U')) // "U" for USB - card.changeMedia(&card.media_driver_usbFlash); + card.selectMediaFlashDrive(); #endif card.mount(); } diff --git a/Marlin/src/inc/Conditionals-4-adv.h b/Marlin/src/inc/Conditionals-4-adv.h index 3b01077931..a9427c3605 100644 --- a/Marlin/src/inc/Conditionals-4-adv.h +++ b/Marlin/src/inc/Conditionals-4-adv.h @@ -1248,10 +1248,17 @@ #if ENABLED(MULTI_VOLUME) #define HAS_MULTI_VOLUME 1 + #define SV_SD_ONBOARD 101 + #define SV_USB_FLASH_DRIVE 102 + #define _VOLUME_ID(N) _CAT(SV_, N) + #define SHARED_VOLUME_IS(N) (DEFAULT_SHARED_VOLUME == _VOLUME_ID(N)) +#else + #define SHARED_VOLUME_IS(...) 0 #endif -#if ENABLED(USB_FLASH_DRIVE_SUPPORT) + +#if ANY(USB_FLASH_DRIVE_SUPPORT, VOLUME_USB_FLASH_DRIVE) #define HAS_USB_FLASH_DRIVE 1 - #if NONE(USE_OTG_USB_HOST, USE_UHS3_USB) + #if NONE(USE_OTG_USB_HOST, USE_UHS2_USB, USE_UHS3_USB) #define USE_UHS2_USB #endif #endif diff --git a/Marlin/src/inc/Conditionals-5-post.h b/Marlin/src/inc/Conditionals-5-post.h index fd06285bca..ae9074ec89 100644 --- a/Marlin/src/inc/Conditionals-5-post.h +++ b/Marlin/src/inc/Conditionals-5-post.h @@ -550,7 +550,9 @@ #endif #endif + // Tests indicating a single or multi-volume SD Card #if !HAS_USB_FLASH_DRIVE || ALL(HAS_MULTI_VOLUME, VOLUME_SD_ONBOARD) + #define HAS_SDCARD 1 #if ENABLED(ONBOARD_SDIO) #define NEED_SD2CARD_SDIO 1 #else diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index 970847ecb5..3182d93e92 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -3943,7 +3943,7 @@ static_assert(_PLUS_TEST(3), "DEFAULT_MAX_ACCELERATION values must be positive." #if HAS_USB_FLASH_DRIVE && DISABLED(USE_OTG_USB_HOST) && !PINS_EXIST(USB_CS, USB_INTR) #error "USB_CS_PIN and USB_INTR_PIN (or USE_OTG_USB_HOST) are required for USB_FLASH_DRIVE_SUPPORT." -#elif ENABLED(USE_OTG_USB_HOST) && !defined(HAS_OTG_USB_HOST_SUPPORT) +#elif ENABLED(USE_OTG_USB_HOST) && DISABLED(HAS_OTG_USB_HOST_SUPPORT) #error "The current board does not support USE_OTG_USB_HOST." #endif diff --git a/Marlin/src/lcd/extui/mks_ui/draw_media_select.cpp b/Marlin/src/lcd/extui/mks_ui/draw_media_select.cpp index 25a9238705..a327f2f33e 100644 --- a/Marlin/src/lcd/extui/mks_ui/draw_media_select.cpp +++ b/Marlin/src/lcd/extui/mks_ui/draw_media_select.cpp @@ -46,8 +46,8 @@ static void event_handler(lv_obj_t *obj, lv_event_t event) { if (event != LV_EVENT_RELEASED) return; lv_clear_media_select(); switch (obj->mks_obj_id) { - case ID_T_USB_DISK: card.changeMedia(&card.media_driver_usbFlash); break; - case ID_T_SD_DISK: card.changeMedia(&card.media_driver_sdcard); break; + case ID_T_USB_DISK: card.selectMediaFlashDrive(); break; + case ID_T_SD_DISK: card.selectMediaSDCard(); break; case ID_T_RETURN: TERN_(MKS_TEST, current_disp_ui = 1); lv_draw_ready_print(); diff --git a/Marlin/src/lcd/extui/mks_ui/tft_lvgl_configuration.cpp b/Marlin/src/lcd/extui/mks_ui/tft_lvgl_configuration.cpp index 7a56cf371f..e138449181 100644 --- a/Marlin/src/lcd/extui/mks_ui/tft_lvgl_configuration.cpp +++ b/Marlin/src/lcd/extui/mks_ui/tft_lvgl_configuration.cpp @@ -135,18 +135,19 @@ void tft_lvgl_init() { hal.watchdog_refresh(); // LVGL init takes time #if HAS_USB_FLASH_DRIVE - uint16_t usb_flash_loop = 1000; #if HAS_MULTI_VOLUME && !HAS_SD_HOST_DRIVE if (IS_SD_INSERTED()) - card.changeMedia(&card.media_driver_sdcard); + card.selectMediaSDCard(); else - card.changeMedia(&card.media_driver_usbFlash); + card.selectMediaFlashDrive(); #endif - do { - card.media_driver_usbFlash.idle(); + // Wait up to two seconds for USB Drive to mount + for (uint16_t usb_flash_loop = 500; --usb_flash_loop;) { hal.watchdog_refresh(); - delay(2); - } while (!card.media_driver_usbFlash.isInserted() && usb_flash_loop--); + card.media_driver_usbFlash.idle(); + delay(4); + if (card.media_driver_usbFlash.isInserted()) break; + } card.mount(); #elif HAS_LOGO_IN_FLASH delay(1000); diff --git a/Marlin/src/lcd/marlinui.cpp b/Marlin/src/lcd/marlinui.cpp index 7f78d21bf3..1726c67930 100644 --- a/Marlin/src/lcd/marlinui.cpp +++ b/Marlin/src/lcd/marlinui.cpp @@ -1114,7 +1114,7 @@ void MarlinUI::init() { #if MARLINUI_SCROLL_NAME // If scrolling of long file names is enabled and we are in the sd card menu, // cause a refresh to occur until all the text has scrolled into view. - if (currentScreen == menu_media_filelist && filename_scroll_max && !lcd_status_update_delay--) { + if (currentScreen == menu_file_selector && filename_scroll_max && !lcd_status_update_delay--) { lcd_status_update_delay = ++filename_scroll_pos >= filename_scroll_max ? 12 : 4; // Long delay at end and start if (filename_scroll_pos > filename_scroll_max) filename_scroll_pos = 0; refresh(LCDVIEW_REDRAW_NOW); diff --git a/Marlin/src/lcd/menu/menu.h b/Marlin/src/lcd/menu/menu.h index 80a84af1ba..b7861655e2 100644 --- a/Marlin/src/lcd/menu/menu.h +++ b/Marlin/src/lcd/menu/menu.h @@ -211,7 +211,7 @@ void menu_main(); void menu_move(); #if HAS_MEDIA - void menu_media_filelist(); + void menu_file_selector(); void menu_media(); #endif diff --git a/Marlin/src/lcd/menu/menu_media.cpp b/Marlin/src/lcd/menu/menu_media.cpp index 8633551672..8747685fe5 100644 --- a/Marlin/src/lcd/menu/menu_media.cpp +++ b/Marlin/src/lcd/menu/menu_media.cpp @@ -45,7 +45,7 @@ void lcd_sd_updir() { void MarlinUI::reselect_last_file() { if (sd_encoder_position == 0xFFFF) return; - goto_screen(menu_media_filelist, sd_encoder_position, sd_top_line, sd_items); + goto_screen(menu_file_selector, sd_encoder_position, sd_top_line, sd_items); sd_encoder_position = 0xFFFF; defer_status_screen(); } @@ -105,11 +105,11 @@ class MenuItem_sdfolder : public MenuItem_sdbase { void menu_media_select() { START_MENU(); BACK_ITEM_F(TERN1(BROWSE_MEDIA_ON_INSERT, screen_history_depth) ? GET_TEXT_F(MSG_MAIN_MENU) : GET_TEXT_F(MSG_BACK)); - #if ENABLED(VOLUME_SD_ONBOARD) - ACTION_ITEM(MSG_SD_CARD, []{ card.changeMedia(&card.media_driver_sdcard); card.mount(); ui.goto_screen(menu_media_filelist); }); + #if HAS_SDCARD + ACTION_ITEM(MSG_SD_CARD, []{ card.selectMediaSDCard(); card.mount(); ui.goto_screen(menu_file_selector); }); #endif - #if ENABLED(VOLUME_USB_FLASH_DRIVE) - ACTION_ITEM(MSG_USB_DISK, []{ card.changeMedia(&card.media_driver_usbFlash); card.mount(); ui.goto_screen(menu_media_filelist); }); + #if HAS_USB_FLASH_DRIVE + ACTION_ITEM(MSG_USB_DISK, []{ card.selectMediaFlashDrive(); card.mount(); ui.goto_screen(menu_file_selector); }); #endif END_MENU(); } @@ -117,14 +117,14 @@ class MenuItem_sdfolder : public MenuItem_sdbase { /** * "Select From Media" menu item. Depending on single or multiple drives: - * - menu_media_filelist - List files on the current media - * - menu_media_select - Select one of the attached drives, then go to the file list + * - menu_file_selector - List files on the current media + * - menu_media_select - Select one of the attached drives, then go to the file list */ void menu_media() { - ui.goto_screen(TERN(HAS_MULTI_VOLUME, menu_media_select, menu_media_filelist)); + ui.goto_screen(TERN(HAS_MULTI_VOLUME, menu_media_select, menu_file_selector)); } -void menu_media_filelist() { +void menu_file_selector() { ui.encoder_direction_menus(); #if HAS_MARLINUI_U8GLIB diff --git a/Marlin/src/sd/cardreader.cpp b/Marlin/src/sd/cardreader.cpp index 647e071c72..cd20f921db 100644 --- a/Marlin/src/sd/cardreader.cpp +++ b/Marlin/src/sd/cardreader.cpp @@ -28,6 +28,10 @@ #if HAS_MEDIA +#if HAS_MULTI_VOLUME && !SHARED_VOLUME_IS(SD_ONBOARD) && !SHARED_VOLUME_IS(USB_FLASH_DRIVE) + #error "DEFAULT_SHARED_VOLUME must be either SV_SD_ONBOARD or SV_USB_FLASH_DRIVE." +#endif + //#define DEBUG_CARDREADER #include "cardreader.h" @@ -132,12 +136,12 @@ int16_t CardReader::nrItems = -1; #endif // SDCARD_SORT_ALPHA -#if HAS_USB_FLASH_DRIVE - DiskIODriver_USBFlash CardReader::media_driver_usbFlash; +#if HAS_SDCARD + CardReader::sdcard_driver_t CardReader::media_driver_sdcard; #endif -#if NEED_SD2CARD_SDIO || NEED_SD2CARD_SPI - CardReader::sdcard_driver_t CardReader::media_driver_sdcard; +#if HAS_USB_FLASH_DRIVE + DiskIODriver_USBFlash CardReader::media_driver_usbFlash; #endif DiskIODriver* CardReader::driver = nullptr; @@ -153,13 +157,11 @@ MediaFile CardReader::file; uint32_t CardReader::filesize, CardReader::sdpos; CardReader::CardReader() { - changeMedia(& - #if HAS_USB_FLASH_DRIVE && !SHARED_VOLUME_IS(SD_ONBOARD) - media_driver_usbFlash - #else - media_driver_sdcard - #endif - ); + #if HAS_USB_FLASH_DRIVE && !SHARED_VOLUME_IS(SD_ONBOARD) + selectMediaFlashDrive(); + #else + selectMediaSDCard(); + #endif #if ENABLED(SDCARD_SORT_ALPHA) sort_count = 0; diff --git a/Marlin/src/sd/cardreader.h b/Marlin/src/sd/cardreader.h index eeead4e490..7dfe7e344f 100644 --- a/Marlin/src/sd/cardreader.h +++ b/Marlin/src/sd/cardreader.h @@ -60,18 +60,6 @@ extern const char M23_STR[], M24_STR[]; #include "Sd2Card.h" #endif -#if HAS_MULTI_VOLUME - #define SV_SD_ONBOARD 1 - #define SV_USB_FLASH_DRIVE 2 - #define _VOLUME_ID(N) _CAT(SV_, N) - #define SHARED_VOLUME_IS(N) (DEFAULT_SHARED_VOLUME == _VOLUME_ID(N)) - #if !SHARED_VOLUME_IS(SD_ONBOARD) && !SHARED_VOLUME_IS(USB_FLASH_DRIVE) - #error "DEFAULT_SHARED_VOLUME must be either SD_ONBOARD or USB_FLASH_DRIVE." - #endif -#else - #define SHARED_VOLUME_IS(...) 0 -#endif - typedef struct { bool saving:1, // Receiving a G-code file or logging commands during a print logging:1, // Log enqueued commands to the open file. See GCodeQueue::advance() @@ -114,15 +102,76 @@ public: CardReader(); + /** + * Media Selection - Only one drive may be active at a time, + * so switching drives (currently) returns to the root folder. + * TODO: Save the last-used path for each device and cd on mount. + */ static void changeMedia(DiskIODriver *_driver) { driver = _driver; } - static MediaFile getroot() { return root; } + static DiskIODriver* diskIODriver() { return driver; } + #if HAS_SDCARD + typedef TERN(NEED_SD2CARD_SDIO, DiskIODriver_SDIO, DiskIODriver_SPI_SD) sdcard_driver_t; + static sdcard_driver_t media_driver_sdcard; + #endif + + #if HAS_USB_FLASH_DRIVE + static DiskIODriver_USBFlash media_driver_usbFlash; + #endif + + static void selectMediaSDCard() { + #if HAS_SDCARD + changeMedia(&media_driver_sdcard); + #endif + } + + static void selectMediaFlashDrive() { + #if HAS_USB_FLASH_DRIVE + changeMedia(&media_driver_usbFlash); + #endif + } + + static bool isSDCardSelected() { + return TERN0(HAS_SDCARD, TERN1(HAS_MULTI_VOLUME, driver == &media_driver_sdcard)); + } + static bool isFlashDriveSelected() { + return TERN0(HAS_USB_FLASH_DRIVE, TERN1(HAS_MULTI_VOLUME, driver == &media_driver_usbFlash)); + } + static bool isMediaSelected() { + return isSDCardSelected() || isFlashDriveSelected(); + } + + /** + * Media Detection - Inserted, Mounted, Job Running, Job Paused, etc. + * + * Marlin 2.1.x supports up to two drives, either an SD Card or USB-FD + * Onboard SD may have SPI or SDIO interface. USB FD may use MSC. + */ + + // No card detect line? Assume the card is inserted. + static bool isSDCardInserted() { + return ( + #if HAS_SD_DETECT + READ(SD_DETECT_PIN) == SD_DETECT_STATE + #else + ENABLED(HAS_SDCARD) + #endif + ); + } + + // Use the isInserted state from the driver + static bool isFlashDriveInserted() { return TERN0(HAS_USB_FLASH_DRIVE, DiskIODriver_USBFlash::isInserted()); } + + // NOTE: If the SD Card has no DETECT line this always returns true + static bool isInserted() { return isFlashDriveInserted() || isSDCardInserted(); } + + // Mount and release physical media static void mount(); static void release(); static bool isMounted() { return flag.mounted; } - // Handle media insert/remove + // Handle media insert/remove (including mounting on boot-up) static void manage_media(); // SD Card Logging @@ -142,6 +191,9 @@ public: static bool selectNewestFile(); #endif + // The root directory of the current mounted drive + static MediaFile getroot() { return root; } + // Basic file ops static void openFileRead(const char * const path, const uint8_t subcall=0); static void openFileWrite(const char * const path); @@ -232,7 +284,7 @@ public: // Current Working Dir - Set by cd, cdup, cdroot, and diveToFile(true, ...) static char* getWorkDirName() { workDir.getDosName(filename); return filename; } - static MediaFile& getWorkDir() { return workDir.isOpen() ? workDir : root; } + static MediaFile& getWorkDir() { return workDir.isOpen() ? workDir : root; } // Print File stats static uint32_t getFileSize() { return filesize; } @@ -246,9 +298,6 @@ public: static int16_t write(void *buf, uint16_t nbyte) { return file.isOpen() ? file.write(buf, nbyte) : -1; } static void setIndex(const uint32_t index) { file.seekSet((sdpos = index)); } - // TODO: rename to diskIODriver() - static DiskIODriver* diskIODriver() { return driver; } - #if ENABLED(AUTO_REPORT_SD_STATUS) // // SD Auto Reporting @@ -257,17 +306,17 @@ public: static AutoReporter auto_reporter; #endif - #if SHARED_VOLUME_IS(USB_FLASH_DRIVE) || HAS_USB_FLASH_DRIVE - #define HAS_USB_FLASH_DRIVE 1 - static DiskIODriver_USBFlash media_driver_usbFlash; - #endif - - #if NEED_SD2CARD_SDIO || NEED_SD2CARD_SPI - typedef TERN(NEED_SD2CARD_SDIO, DiskIODriver_SDIO, DiskIODriver_SPI_SD) sdcard_driver_t; - static sdcard_driver_t media_driver_sdcard; - #endif - private: + // + // Driver, volume, and temporary file + // + static DiskIODriver *driver; + static MarlinVolume volume; + + static MediaFile file; + static uint32_t filesize, // Total size of the current file, in bytes + sdpos; // Index most recently read (one behind file.getPos) + // // Working directory and parents // @@ -330,13 +379,6 @@ private: #endif // SDCARD_SORT_ALPHA - static DiskIODriver *driver; - static MarlinVolume volume; - static MediaFile file; - - static uint32_t filesize, // Total size of the current file, in bytes - sdpos; // Index most recently read (one behind file.getPos) - // // Procedure calls to other files // diff --git a/Marlin/src/sd/usb_flashdrive/Sd2Card_FlashDrive.cpp b/Marlin/src/sd/usb_flashdrive/Sd2Card_FlashDrive.cpp index 455ba6ba0a..2ae38c64c0 100644 --- a/Marlin/src/sd/usb_flashdrive/Sd2Card_FlashDrive.cpp +++ b/Marlin/src/sd/usb_flashdrive/Sd2Card_FlashDrive.cpp @@ -179,82 +179,82 @@ void DiskIODriver_USBFlash::idle() { } #endif - static millis_t next_state_ms = millis(); + static millis_t next_state_ms = 0; #define GOTO_STATE_AFTER_DELAY(STATE, DELAY) do{ state = STATE; next_state_ms = millis() + DELAY; }while(0) - if (ELAPSED(millis(), next_state_ms)) { - GOTO_STATE_AFTER_DELAY(state, 250); // Default delay + if (PENDING(millis(), next_state_ms)) return; - switch (state) { + GOTO_STATE_AFTER_DELAY(state, 250); // Default delay - case UNINITIALIZED: - #ifndef MANUAL_USB_STARTUP - GOTO_STATE_AFTER_DELAY( DO_STARTUP, USB_STARTUP_DELAY ); + switch (state) { + + case UNINITIALIZED: + #ifndef MANUAL_USB_STARTUP + GOTO_STATE_AFTER_DELAY( DO_STARTUP, USB_STARTUP_DELAY ); + #endif + break; + + case DO_STARTUP: usbStartup(); break; + + case WAIT_FOR_DEVICE: + if (task_state == UHS_STATE(RUNNING)) { + #if USB_DEBUG >= 1 + SERIAL_ECHOLNPGM("USB device inserted"); #endif - break; + GOTO_STATE_AFTER_DELAY( WAIT_FOR_LUN, 250 ); + } + break; - case DO_STARTUP: usbStartup(); break; + case WAIT_FOR_LUN: + /* USB device is inserted, but if it is an SD card, + * adapter it may not have an SD card in it yet. */ + if (bulk.LUNIsGood(0)) { + #if USB_DEBUG >= 1 + SERIAL_ECHOLNPGM("LUN is good"); + #endif + GOTO_STATE_AFTER_DELAY( MEDIA_READY, 100 ); + } + else { + #ifdef USB_HOST_MANUAL_POLL + // Make sure we catch disconnect events + usb.busprobe(); + usb.VBUS_changed(); + #endif + #if USB_DEBUG >= 1 + SERIAL_ECHOLNPGM("Waiting for media"); + #endif + LCD_MESSAGE(MSG_MEDIA_WAITING); + GOTO_STATE_AFTER_DELAY(state, 2000); + } + break; - case WAIT_FOR_DEVICE: - if (task_state == UHS_STATE(RUNNING)) { - #if USB_DEBUG >= 1 - SERIAL_ECHOLNPGM("USB device inserted"); - #endif - GOTO_STATE_AFTER_DELAY( WAIT_FOR_LUN, 250 ); - } - break; + case MEDIA_READY: break; + case MEDIA_ERROR: break; + } - case WAIT_FOR_LUN: - /* USB device is inserted, but if it is an SD card, - * adapter it may not have an SD card in it yet. */ - if (bulk.LUNIsGood(0)) { - #if USB_DEBUG >= 1 - SERIAL_ECHOLNPGM("LUN is good"); - #endif - GOTO_STATE_AFTER_DELAY( MEDIA_READY, 100 ); - } - else { - #ifdef USB_HOST_MANUAL_POLL - // Make sure we catch disconnect events - usb.busprobe(); - usb.VBUS_changed(); - #endif - #if USB_DEBUG >= 1 - SERIAL_ECHOLNPGM("Waiting for media"); - #endif - LCD_MESSAGE(MSG_MEDIA_WAITING); - GOTO_STATE_AFTER_DELAY(state, 2000); - } - break; + if (state > WAIT_FOR_DEVICE && task_state != UHS_STATE(RUNNING)) { + // Handle device removal events + #if USB_DEBUG >= 1 + SERIAL_ECHOLNPGM("USB device removed"); + #endif + if (state != MEDIA_READY) + LCD_MESSAGE(MSG_MEDIA_USB_REMOVED); + GOTO_STATE_AFTER_DELAY(WAIT_FOR_DEVICE, 0); + } - case MEDIA_READY: break; - case MEDIA_ERROR: break; - } + else if (state > WAIT_FOR_LUN && !bulk.LUNIsGood(0)) { + // Handle media removal events + #if USB_DEBUG >= 1 + SERIAL_ECHOLNPGM("Media removed"); + #endif + LCD_MESSAGE(MSG_MEDIA_REMOVED); + GOTO_STATE_AFTER_DELAY(WAIT_FOR_DEVICE, 0); + } - if (state > WAIT_FOR_DEVICE && task_state != UHS_STATE(RUNNING)) { - // Handle device removal events - #if USB_DEBUG >= 1 - SERIAL_ECHOLNPGM("USB device removed"); - #endif - if (state != MEDIA_READY) - LCD_MESSAGE(MSG_MEDIA_USB_REMOVED); - GOTO_STATE_AFTER_DELAY(WAIT_FOR_DEVICE, 0); - } - - else if (state > WAIT_FOR_LUN && !bulk.LUNIsGood(0)) { - // Handle media removal events - #if USB_DEBUG >= 1 - SERIAL_ECHOLNPGM("Media removed"); - #endif - LCD_MESSAGE(MSG_MEDIA_REMOVED); - GOTO_STATE_AFTER_DELAY(WAIT_FOR_DEVICE, 0); - } - - else if (task_state == UHS_STATE(ERROR)) { - LCD_MESSAGE(MSG_MEDIA_READ_ERROR); - GOTO_STATE_AFTER_DELAY(MEDIA_ERROR, 0); - } + else if (task_state == UHS_STATE(ERROR)) { + LCD_MESSAGE(MSG_MEDIA_READ_ERROR); + GOTO_STATE_AFTER_DELAY(MEDIA_ERROR, 0); } } From 5c0e8d594d343d4e38f6d2254916077e0f3a3c7d Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Mon, 21 Apr 2025 20:00:49 -0500 Subject: [PATCH 253/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Stu?= =?UTF-8?q?b=20CardReader,=20proper=20methods?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/HAL/DUE/usb/sd_mmc_spi_mem.cpp | 2 +- Marlin/src/HAL/LPC1768/HAL.cpp | 4 +- Marlin/src/HAL/STM32F1/HAL.cpp | 2 +- Marlin/src/MarlinCore.cpp | 12 +++-- Marlin/src/feature/mmu3/mmu3.cpp | 2 +- Marlin/src/feature/pause.cpp | 2 +- Marlin/src/feature/powerloss.cpp | 8 ++-- Marlin/src/gcode/feature/pause/M125.cpp | 2 +- Marlin/src/gcode/gcode.cpp | 2 +- Marlin/src/gcode/lcd/M73.cpp | 2 +- Marlin/src/gcode/queue.cpp | 2 +- Marlin/src/gcode/sd/M21_M22.cpp | 2 +- Marlin/src/gcode/sd/M24_M25.cpp | 2 +- Marlin/src/gcode/sd/M32.cpp | 2 +- Marlin/src/gcode/sd/M524.cpp | 2 +- Marlin/src/gcode/stats/M75-M78.cpp | 2 +- Marlin/src/lcd/HD44780/marlinui_HD44780.cpp | 2 +- Marlin/src/lcd/TFTGLCD/marlinui_TFTGLCD.cpp | 2 +- Marlin/src/lcd/e3v2/jyersui/dwin.cpp | 2 +- Marlin/src/lcd/e3v2/proui/dwin.cpp | 6 +-- .../generic/about_screen.cpp | 6 +-- Marlin/src/lcd/extui/mks_ui/draw_ui.cpp | 13 ----- Marlin/src/lcd/extui/mks_ui/draw_ui.h | 1 - .../lcd/extui/mks_ui/printer_operation.cpp | 2 +- .../extui/mks_ui/tft_lvgl_configuration.cpp | 2 +- Marlin/src/lcd/extui/ui_api.cpp | 7 +-- Marlin/src/lcd/marlinui.cpp | 6 +-- Marlin/src/lcd/sovol_rts/sovol_rts.cpp | 10 ++-- Marlin/src/module/temperature.cpp | 2 +- Marlin/src/sd/cardreader.cpp | 32 ++++++------- Marlin/src/sd/cardreader.h | 48 ++++++++----------- 31 files changed, 85 insertions(+), 106 deletions(-) diff --git a/Marlin/src/HAL/DUE/usb/sd_mmc_spi_mem.cpp b/Marlin/src/HAL/DUE/usb/sd_mmc_spi_mem.cpp index cf6739c5bd..ff6ff4859b 100644 --- a/Marlin/src/HAL/DUE/usb/sd_mmc_spi_mem.cpp +++ b/Marlin/src/HAL/DUE/usb/sd_mmc_spi_mem.cpp @@ -19,7 +19,7 @@ void sd_mmc_spi_mem_init() { } inline bool media_ready() { - return IS_SD_MOUNTED() && IS_SD_INSERTED() && !IS_SD_FILE_OPEN() && !IS_SD_PRINTING(); + return card.isMounted() && card.isInserted() && !card.isFileOpen() && !card.isStillPrinting(); } bool sd_mmc_spi_unload(bool) { return true; } diff --git a/Marlin/src/HAL/LPC1768/HAL.cpp b/Marlin/src/HAL/LPC1768/HAL.cpp index 55658acb76..6e4357777d 100644 --- a/Marlin/src/HAL/LPC1768/HAL.cpp +++ b/Marlin/src/HAL/LPC1768/HAL.cpp @@ -175,11 +175,11 @@ void MarlinHAL::idletask() { #if HAS_SHARED_MEDIA // If Marlin is using the SD card we need to lock it to prevent access from // a PC via USB. - // Other HALs use IS_SD_PRINTING() and IS_SD_FILE_OPEN() to check for access but + // Other HALs use card.isStillPrinting() and card.isFileOpen() to check for access but // this will not reliably detect delete operations. To be safe we will lock // the disk if Marlin has it mounted. Unfortunately there is currently no way // to unmount the disk from the LCD menu. - // if (IS_SD_PRINTING() || IS_SD_FILE_OPEN()) + // if (card.isStillPrinting() || card.isFileOpen()) if (card.isMounted()) MSC_Aquire_Lock(); else diff --git a/Marlin/src/HAL/STM32F1/HAL.cpp b/Marlin/src/HAL/STM32F1/HAL.cpp index e6cbb9fc06..d5f4ade79d 100644 --- a/Marlin/src/HAL/STM32F1/HAL.cpp +++ b/Marlin/src/HAL/STM32F1/HAL.cpp @@ -264,7 +264,7 @@ void MarlinHAL::idletask() { /** * When Marlin is using the SD card it should be locked to prevent it being * accessed from a PC over USB. - * Other HALs use (IS_SD_PRINTING() || IS_SD_FILE_OPEN()) to check for access + * Other HALs use (card.isStillPrinting() || card.isFileOpen()) to check for access * but this won't reliably detect other file operations. To be safe we just lock * the drive whenever Marlin has it mounted. LCDs should include an Unmount * command so drives can be released as needed. diff --git a/Marlin/src/MarlinCore.cpp b/Marlin/src/MarlinCore.cpp index f2b2589ee6..05355ddccb 100644 --- a/Marlin/src/MarlinCore.cpp +++ b/Marlin/src/MarlinCore.cpp @@ -269,6 +269,10 @@ #include "feature/rs485.h" #endif +#if !HAS_MEDIA + CardReader card; // Stub instance with "no media" methods +#endif + PGMSTR(M112_KILL_STR, "M112 Shutdown"); #if ENABLED(CONFIGURABLE_MACHINE_NAME) @@ -339,7 +343,7 @@ bool printer_busy() { /** * A Print Job exists when the timer is running or SD is printing */ -bool printJobOngoing() { return print_job_timer.isRunning() || IS_SD_PRINTING(); } +bool printJobOngoing() { return print_job_timer.isRunning() || card.isStillPrinting(); } /** * Printing is active when a job is underway but not paused @@ -350,7 +354,7 @@ bool printingIsActive() { return !did_pause_print && printJobOngoing(); } * Printing is paused according to SD or host indicators */ bool printingIsPaused() { - return did_pause_print || print_job_timer.isPaused() || IS_SD_PAUSED(); + return did_pause_print || print_job_timer.isPaused() || card.isPaused(); } void startOrResumeJob() { @@ -509,7 +513,7 @@ inline void manage_inactivity(const bool no_stepper_sleep=false) { // Handle a standalone HOME button constexpr millis_t HOME_DEBOUNCE_DELAY = 1000UL; static millis_t next_home_key_ms; // = 0 - if (!IS_SD_PRINTING() && !READ(HOME_PIN)) { // HOME_PIN goes LOW when pressed + if (!card.isStillPrinting() && !READ(HOME_PIN)) { // HOME_PIN goes LOW when pressed if (ELAPSED(ms, next_home_key_ms)) { next_home_key_ms = ms + HOME_DEBOUNCE_DELAY; LCD_MESSAGE(MSG_AUTO_HOME); @@ -804,7 +808,7 @@ void idle(const bool no_stepper_sleep/*=false*/) { // Handle Power-Loss Recovery #if ENABLED(POWER_LOSS_RECOVERY) && PIN_EXISTS(POWER_LOSS) - if (IS_SD_PRINTING()) recovery.outage(); + if (card.isStillPrinting()) recovery.outage(); #endif // Run StallGuard endstop checks diff --git a/Marlin/src/feature/mmu3/mmu3.cpp b/Marlin/src/feature/mmu3/mmu3.cpp index b4d4c76afc..27a1dc05c9 100644 --- a/Marlin/src/feature/mmu3/mmu3.cpp +++ b/Marlin/src/feature/mmu3/mmu3.cpp @@ -456,7 +456,7 @@ namespace MMU3 { if (slot != extruder) { if ( //findaDetectsFilament() - //!IS_SD_PRINTING() && !usb_timer.running() + //!card.isStillPrinting() && !usb_timer.running() !marlin_printingIsActive() ) { // If Tcodes are used manually through the serial diff --git a/Marlin/src/feature/pause.cpp b/Marlin/src/feature/pause.cpp index fbb78ccbf9..bd86133771 100644 --- a/Marlin/src/feature/pause.cpp +++ b/Marlin/src/feature/pause.cpp @@ -439,7 +439,7 @@ bool pause_print(const_float_t retract, const xyz_pos_t &park_point, const bool // Pause the print job and timer #if HAS_MEDIA - const bool was_sd_printing = IS_SD_PRINTING(); + const bool was_sd_printing = card.isStillPrinting(); if (was_sd_printing) { card.pauseSDPrint(); ++did_pause_print; // Indicate SD pause also diff --git a/Marlin/src/feature/powerloss.cpp b/Marlin/src/feature/powerloss.cpp index 3cd96e1155..27f3e44ca5 100644 --- a/Marlin/src/feature/powerloss.cpp +++ b/Marlin/src/feature/powerloss.cpp @@ -117,7 +117,7 @@ void PrintJobRecovery::enable(const bool onoff) { void PrintJobRecovery::changed() { if (!enabled) purge(); - else if (IS_SD_PRINTING()) + else if (card.isStillPrinting()) save(true); TERN_(EXTENSIBLE_UI, ExtUI::onSetPowerLoss(enabled)); } @@ -174,7 +174,7 @@ void PrintJobRecovery::prepare() { */ void PrintJobRecovery::save(const bool force/*=false*/, const float zraise/*=POWER_LOSS_ZRAISE*/, const bool raised/*=false*/) { - // We don't check IS_SD_PRINTING here so a save may occur during a pause + // We don't check isStillPrinting here so a save may occur during a pause #if SAVE_INFO_INTERVAL_MS > 0 static millis_t next_save_ms; // = 0 @@ -202,7 +202,7 @@ void PrintJobRecovery::save(const bool force/*=false*/, const float zraise/*=POW // Set Head and Foot to matching non-zero values if (!++info.valid_head) ++info.valid_head; // non-zero in sequence - //if (!IS_SD_PRINTING()) info.valid_head = 0; + //if (!card.isStillPrinting()) info.valid_head = 0; info.valid_foot = info.valid_head; // Machine state @@ -326,7 +326,7 @@ void PrintJobRecovery::save(const bool force/*=false*/, const float zraise/*=POW // Save the current position, distance that Z was (or should be) raised, // and a flag whether the raise was already done here. - if (IS_SD_PRINTING()) save(true, zraise, ENABLED(BACKUP_POWER_SUPPLY)); + if (card.isStillPrinting()) save(true, zraise, ENABLED(BACKUP_POWER_SUPPLY)); // Tell the LCD about the outage, even though it is about to die TERN_(EXTENSIBLE_UI, ExtUI::onPowerLoss()); diff --git a/Marlin/src/gcode/feature/pause/M125.cpp b/Marlin/src/gcode/feature/pause/M125.cpp index 71fa7c7b4d..75611760f1 100644 --- a/Marlin/src/gcode/feature/pause/M125.cpp +++ b/Marlin/src/gcode/feature/pause/M125.cpp @@ -88,7 +88,7 @@ void GcodeSuite::M125() { park_point += hotend_offset[active_extruder]; #endif - const bool sd_printing = IS_SD_PRINTING(); + const bool sd_printing = card.isStillPrinting(); ui.pause_show_message(PAUSE_MESSAGE_PARKING, PAUSE_MODE_PAUSE_PRINT); diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp index 6dfc54d99e..469ab134d3 100644 --- a/Marlin/src/gcode/gcode.cpp +++ b/Marlin/src/gcode/gcode.cpp @@ -196,7 +196,7 @@ void GcodeSuite::get_destination_from_command() { #if ENABLED(POWER_LOSS_RECOVERY) && !PIN_EXISTS(POWER_LOSS) // Only update power loss recovery on moves with E - if (recovery.enabled && IS_SD_PRINTING() && seen.e && (seen.x || seen.y)) + if (recovery.enabled && card.isStillPrinting() && seen.e && (seen.x || seen.y)) recovery.save(); #endif diff --git a/Marlin/src/gcode/lcd/M73.cpp b/Marlin/src/gcode/lcd/M73.cpp index 6f74476240..5d9b3bd107 100644 --- a/Marlin/src/gcode/lcd/M73.cpp +++ b/Marlin/src/gcode/lcd/M73.cpp @@ -62,7 +62,7 @@ void GcodeSuite::M73() { #endif #if ENABLED(M73_REPORT) - if (TERN1(M73_REPORT_SD_ONLY, IS_SD_PRINTING())) { + if (TERN1(M73_REPORT_SD_ONLY, card.isStillPrinting())) { SERIAL_ECHO_START(); SERIAL_ECHOPGM(" M73"); #if ENABLED(SET_PROGRESS_PERCENT) diff --git a/Marlin/src/gcode/queue.cpp b/Marlin/src/gcode/queue.cpp index 657bfab08b..7fa55b70e8 100644 --- a/Marlin/src/gcode/queue.cpp +++ b/Marlin/src/gcode/queue.cpp @@ -570,7 +570,7 @@ void GCodeQueue::get_serial_commands() { static uint8_t sd_input_state = PS_NORMAL; // Get commands if there are more in the file - if (!IS_SD_FETCHING()) return; + if (!card.isStillFetching()) return; int sd_count = 0; while (!ring_buffer.full() && !card.eof()) { diff --git a/Marlin/src/gcode/sd/M21_M22.cpp b/Marlin/src/gcode/sd/M21_M22.cpp index 672dc80f00..eb1594fbaf 100644 --- a/Marlin/src/gcode/sd/M21_M22.cpp +++ b/Marlin/src/gcode/sd/M21_M22.cpp @@ -49,7 +49,7 @@ void GcodeSuite::M21() { * M22: Release SD Card */ void GcodeSuite::M22() { - if (!IS_SD_PRINTING()) card.release(); + if (!card.isStillPrinting()) card.release(); } #endif // HAS_MEDIA diff --git a/Marlin/src/gcode/sd/M24_M25.cpp b/Marlin/src/gcode/sd/M24_M25.cpp index 7bf1ab74d5..f4ad7c7dab 100644 --- a/Marlin/src/gcode/sd/M24_M25.cpp +++ b/Marlin/src/gcode/sd/M24_M25.cpp @@ -101,7 +101,7 @@ void GcodeSuite::M25() { #else // Set initial pause flag to prevent more commands from landing in the queue while we try to pause - if (IS_SD_PRINTING()) card.pauseSDPrint(); + if (card.isStillPrinting()) card.pauseSDPrint(); #if ENABLED(POWER_LOSS_RECOVERY) && DISABLED(DGUS_LCD_UI_MKS) if (recovery.enabled) recovery.save(true); diff --git a/Marlin/src/gcode/sd/M32.cpp b/Marlin/src/gcode/sd/M32.cpp index 3baa552e6e..552a75cdf4 100644 --- a/Marlin/src/gcode/sd/M32.cpp +++ b/Marlin/src/gcode/sd/M32.cpp @@ -40,7 +40,7 @@ * M32 S60 !PATH/TO/FILE.GCO# ; Start FILE.GCO at byte 60 */ void GcodeSuite::M32() { - if (IS_SD_PRINTING()) planner.synchronize(); + if (card.isStillPrinting()) planner.synchronize(); if (card.isMounted()) { const uint8_t call_procedure = parser.boolval('P'); diff --git a/Marlin/src/gcode/sd/M524.cpp b/Marlin/src/gcode/sd/M524.cpp index 61185b7e0b..d72aa0ac35 100644 --- a/Marlin/src/gcode/sd/M524.cpp +++ b/Marlin/src/gcode/sd/M524.cpp @@ -42,7 +42,7 @@ void GcodeSuite::M524() { #else - if (IS_SD_PRINTING()) + if (card.isStillPrinting()) card.abortFilePrintSoon(); else if (card.isMounted()) card.closefile(); diff --git a/Marlin/src/gcode/stats/M75-M78.cpp b/Marlin/src/gcode/stats/M75-M78.cpp index 8ab94577ef..4e1b1aff9d 100644 --- a/Marlin/src/gcode/stats/M75-M78.cpp +++ b/Marlin/src/gcode/stats/M75-M78.cpp @@ -43,7 +43,7 @@ void GcodeSuite::M75() { startOrResumeJob(); // ... ExtUI::onPrintTimerStarted() #if ENABLED(DWIN_LCD_PROUI) // TODO: Remove if M75 is never used - if (!IS_SD_PRINTING()) dwinPrintHeader(parser.has_string() ? parser.string_arg : GET_TEXT(MSG_HOST_START_PRINT)); + if (!card.isStillPrinting()) dwinPrintHeader(parser.has_string() ? parser.string_arg : GET_TEXT(MSG_HOST_START_PRINT)); #endif } diff --git a/Marlin/src/lcd/HD44780/marlinui_HD44780.cpp b/Marlin/src/lcd/HD44780/marlinui_HD44780.cpp index a0145d6165..265f62ab88 100644 --- a/Marlin/src/lcd/HD44780/marlinui_HD44780.cpp +++ b/Marlin/src/lcd/HD44780/marlinui_HD44780.cpp @@ -841,7 +841,7 @@ void MarlinUI::draw_status_message(const bool blink) { const uint8_t progress = get_progress_percent(); if (progress) { lcd_moveto(pc, pr); - lcd_put_u8str(F(TERN(IS_SD_PRINTING, "SD", "P:"))); + lcd_put_u8str(card.isStillPrinting() ? F("SD") : F("P:")); lcd_put_u8str(TERN(PRINT_PROGRESS_SHOW_DECIMALS, permyriadtostr4(get_progress_permyriad()), ui8tostr3rj(progress))); lcd_put_u8str(F("%")); } diff --git a/Marlin/src/lcd/TFTGLCD/marlinui_TFTGLCD.cpp b/Marlin/src/lcd/TFTGLCD/marlinui_TFTGLCD.cpp index 6766820cfd..4ac012ba93 100644 --- a/Marlin/src/lcd/TFTGLCD/marlinui_TFTGLCD.cpp +++ b/Marlin/src/lcd/TFTGLCD/marlinui_TFTGLCD.cpp @@ -603,7 +603,7 @@ FORCE_INLINE void _draw_axis_value(const AxisEnum axis, const char *value, const const uint8_t progress = ui.get_progress_percent(); if (progress) { lcd_moveto(0, 2); - lcd_put_u8str(F(TERN(IS_SD_PRINTING, "SD", "P:"))); + lcd_put_u8str(card.isStillPrinting() ? F("SD") : F("P:")); lcd.print(TERN(PRINT_PROGRESS_SHOW_DECIMALS, permyriadtostr4(ui.get_progress_permyriad()), ui8tostr3rj(progress))); lcd.write('%'); } diff --git a/Marlin/src/lcd/e3v2/jyersui/dwin.cpp b/Marlin/src/lcd/e3v2/jyersui/dwin.cpp index d582b96ed7..aa087cefc4 100644 --- a/Marlin/src/lcd/e3v2/jyersui/dwin.cpp +++ b/Marlin/src/lcd/e3v2/jyersui/dwin.cpp @@ -4653,7 +4653,7 @@ void JyersDWIN::popupControl() { #if ENABLED(PARK_HEAD_ON_PAUSE) popupHandler(Popup_Home, true); #if HAS_MEDIA - if (IS_SD_PRINTING()) card.pauseSDPrint(); + if (card.isStillPrinting()) card.pauseSDPrint(); #endif planner.synchronize(); queue.inject(F("M125")); diff --git a/Marlin/src/lcd/e3v2/proui/dwin.cpp b/Marlin/src/lcd/e3v2/proui/dwin.cpp index 7428a4b254..b1df0234b0 100644 --- a/Marlin/src/lcd/e3v2/proui/dwin.cpp +++ b/Marlin/src/lcd/e3v2/proui/dwin.cpp @@ -294,9 +294,9 @@ MenuItem *fanSpeedItem = nullptr; MenuItem *mMeshMoveZItem = nullptr; MenuItem *editZValueItem = nullptr; -bool isPrinting() { return printingIsActive() || printingIsPaused(); } -bool sdPrinting() { return isPrinting() && IS_SD_FILE_OPEN(); } -bool hostPrinting() { return isPrinting() && !IS_SD_FILE_OPEN(); } +bool isPrinting() { return printingIsActive() || printingIsPaused(); } +bool sdPrinting() { return isPrinting() && card.isStillPrinting(); } +bool hostPrinting() { return isPrinting() && !card.isStillPrinting(); } #define DWIN_LANGUAGE_EEPROM_ADDRESS 0x01 // Between 0x01 and 0x63 (EEPROM_OFFSET-1) // BL24CXX::check() uses 0x00 diff --git a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/about_screen.cpp b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/about_screen.cpp index eac6e646e6..366151959b 100644 --- a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/about_screen.cpp +++ b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/about_screen.cpp @@ -62,11 +62,11 @@ void AboutScreen::onRedraw(draw_mode_t) { #ifdef LULZBOT_LCD_MACHINE_NAME cmd.tag(3); draw_text_box(cmd, BTN_POS(1,7), BTN_SIZE(4,3), F( - "Firmware:" + "Firmware:" ), OPT_CENTER, font_xlarge); draw_text_box(cmd, BTN_POS(1,10), BTN_SIZE(4,2), F( - "" LULZBOT_M115_EXTRUDER_TYPE "" + "" LULZBOT_M115_EXTRUDER_TYPE "" ), OPT_CENTER, font_xlarge); #endif @@ -77,7 +77,7 @@ void AboutScreen::onRedraw(draw_mode_t) { #endif draw_text_box(cmd, BTN_POS(1,19), BTN_SIZE(4,3), F( - "Version:" + "Version:" ), OPT_CENTER, font_xlarge); draw_text_box(cmd, BTN_POS(1,22), BTN_SIZE(4,2), F( diff --git a/Marlin/src/lcd/extui/mks_ui/draw_ui.cpp b/Marlin/src/lcd/extui/mks_ui/draw_ui.cpp index 92cc17f8cc..2e66db2c86 100644 --- a/Marlin/src/lcd/extui/mks_ui/draw_ui.cpp +++ b/Marlin/src/lcd/extui/mks_ui/draw_ui.cpp @@ -1332,19 +1332,6 @@ void lv_screen_menu_item_onoff_update(lv_obj_t *btn, const bool curValue) { lv_label_set_text((lv_obj_t*)btn->child_ll.head, curValue ? machine_menu.enable : machine_menu.disable); } -#if HAS_MEDIA - - void sd_detection() { - static bool last_sd_status; - const bool sd_status = IS_SD_INSERTED(); - if (sd_status != last_sd_status) { - last_sd_status = sd_status; - if (sd_status) card.mount(); else card.release(); - } - } - -#endif - void lv_ex_line(lv_obj_t *line, lv_point_t *points) { // Copy the previous line and apply the new style lv_line_set_points(line, points, 2); // Set the points diff --git a/Marlin/src/lcd/extui/mks_ui/draw_ui.h b/Marlin/src/lcd/extui/mks_ui/draw_ui.h index 10b8dcee28..33a0764d2c 100644 --- a/Marlin/src/lcd/extui/mks_ui/draw_ui.h +++ b/Marlin/src/lcd/extui/mks_ui/draw_ui.h @@ -468,7 +468,6 @@ void GUI_RefreshPage(); void clear_cur_ui(); void draw_return_ui(); void goto_previous_ui(); -void sd_detection(); void gCfg_to_spiFlah(); void print_time_count(); diff --git a/Marlin/src/lcd/extui/mks_ui/printer_operation.cpp b/Marlin/src/lcd/extui/mks_ui/printer_operation.cpp index dc47cdb357..9999aa4843 100644 --- a/Marlin/src/lcd/extui/mks_ui/printer_operation.cpp +++ b/Marlin/src/lcd/extui/mks_ui/printer_operation.cpp @@ -88,7 +88,7 @@ void printer_state_polling() { } if (uiCfg.print_state == RESUMING) { - if (IS_SD_PAUSED()) { + if (card.isPaused()) { if (gCfgItems.pausePosX != (float)-1 && gCfgItems.pausePosY != (float)-1) { sprintf_P(public_buf_m, PSTR("G1 X%s Y%s"), dtostrf(uiCfg.current_x_position_bak, 1, 1, str_1), dtostrf(uiCfg.current_y_position_bak, 1, 1, str_1)); gcode.process_subcommands_now(public_buf_m); diff --git a/Marlin/src/lcd/extui/mks_ui/tft_lvgl_configuration.cpp b/Marlin/src/lcd/extui/mks_ui/tft_lvgl_configuration.cpp index e138449181..729d8bc4b2 100644 --- a/Marlin/src/lcd/extui/mks_ui/tft_lvgl_configuration.cpp +++ b/Marlin/src/lcd/extui/mks_ui/tft_lvgl_configuration.cpp @@ -136,7 +136,7 @@ void tft_lvgl_init() { #if HAS_USB_FLASH_DRIVE #if HAS_MULTI_VOLUME && !HAS_SD_HOST_DRIVE - if (IS_SD_INSERTED()) + if (card.isSDCardInserted()) card.selectMediaSDCard(); else card.selectMediaFlashDrive(); diff --git a/Marlin/src/lcd/extui/ui_api.cpp b/Marlin/src/lcd/extui/ui_api.cpp index b88df6ee9d..7763bac05a 100644 --- a/Marlin/src/lcd/extui/ui_api.cpp +++ b/Marlin/src/lcd/extui/ui_api.cpp @@ -1064,11 +1064,8 @@ namespace ExtUI { TERN(HAS_MEDIA, card.openAndPrintFile(filename), UNUSED(filename)); } - bool isPrintingFromMediaPaused() { - return IS_SD_PAUSED(); - } - - bool isPrintingFromMedia() { return IS_SD_PRINTING() || IS_SD_PAUSED(); } + bool isPrintingFromMedia() { return card.isStillPrinting() || card.isPaused(); } + bool isPrintingFromMediaPaused() { return card.isPaused(); } bool isPrinting() { return commandsInQueue() || isPrintingFromMedia() || printJobOngoing() || printingIsPaused(); diff --git a/Marlin/src/lcd/marlinui.cpp b/Marlin/src/lcd/marlinui.cpp index 1726c67930..8b7e64dda8 100644 --- a/Marlin/src/lcd/marlinui.cpp +++ b/Marlin/src/lcd/marlinui.cpp @@ -1540,7 +1540,7 @@ uint8_t expand_u8str_P(char * const outstr, PGM_P const ptpl, const int8_t ind, if (printingIsPaused()) msg = GET_TEXT_F(MSG_PRINT_PAUSED); #if HAS_MEDIA - else if (IS_SD_PRINTING()) + else if (card.isStillPrinting()) return set_status_no_expire(card.longest_filename()); #endif else if (print_job_timer.isRunning()) @@ -1743,7 +1743,7 @@ uint8_t expand_u8str_P(char * const outstr, PGM_P const ptpl, const int8_t ind, void MarlinUI::abort_print() { #if HAS_MEDIA wait_for_heatup = wait_for_user = false; - if (IS_SD_PRINTING()) + if (card.isStillPrinting()) card.abortFilePrintSoon(); else if (card.isMounted()) card.closefile(); @@ -1810,7 +1810,7 @@ uint8_t expand_u8str_P(char * const outstr, PGM_P const ptpl, const int8_t ind, void MarlinUI::resume_print() { reset_status(); TERN_(PARK_HEAD_ON_PAUSE, wait_for_heatup = wait_for_user = false); - TERN_(HAS_MEDIA, if (IS_SD_PAUSED()) queue.inject_P(M24_STR)); + TERN_(HAS_MEDIA, if (card.isPaused()) queue.inject_P(M24_STR)); #ifdef ACTION_ON_RESUME hostui.resume(); #endif diff --git a/Marlin/src/lcd/sovol_rts/sovol_rts.cpp b/Marlin/src/lcd/sovol_rts/sovol_rts.cpp index dcd5d9b384..bea95be96a 100644 --- a/Marlin/src/lcd/sovol_rts/sovol_rts.cpp +++ b/Marlin/src/lcd/sovol_rts/sovol_rts.cpp @@ -171,7 +171,7 @@ void RTS::sdCardInit() { // Clear the file name displayed in the print interface sendData(0, PRINT_FILE_TEXT_VP + j); } - lcd_sd_status = IS_SD_INSERTED(); + lcd_sd_status = card.isInserted(); } else { // Clean all filename Icons @@ -186,7 +186,7 @@ bool RTS::sdDetected() { static bool state = false, stable = false, was_present = false; static millis_t stable_ms = 0; - const bool present = IS_SD_INSERTED(); + const bool present = card.isInserted(); if (present != was_present) stable = false; else if (!stable) { @@ -1485,7 +1485,7 @@ void RTS::handleData() { sendData(cardRec.display_filename[cardRec.recordcount], PRINT_FILE_TEXT_VP); // Represents to update file list - if (update_sd && lcd_sd_status && IS_SD_INSERTED()) { + if (update_sd && lcd_sd_status && card.isInserted()) { for (uint16_t i = 0; i < cardRec.Filesum; i++) { delay(3); sendData(cardRec.display_filename[i], cardRec.addr[i]); @@ -1654,8 +1654,8 @@ void RTS_Update() { // Check the status of card rts.sdCardUpdate(); - sd_printing = IS_SD_PRINTING(); - card_insert_st = IS_SD_INSERTED(); + sd_printing = card.isStillPrinting(); + card_insert_st = card.isInserted(); if (!card_insert_st && sd_printing) { rts.gotoPage(ID_MediaFail_L, ID_MediaFail_D); diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index 5c9f122067..0ef0a2f961 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -4772,7 +4772,7 @@ void Temperature::isr() { dwin_heat_time = elapsed.value; #elif ENABLED(SOVOL_SV06_RTS) update_time_value = RTS_UPDATE_VALUE; - if (IS_SD_PRINTING()) rts.refreshTime(); + if (card.isStillPrinting()) rts.refreshTime(); rts.start_print_flag = false; #else ui.reset_status(); diff --git a/Marlin/src/sd/cardreader.cpp b/Marlin/src/sd/cardreader.cpp index cd20f921db..9b0a37913a 100644 --- a/Marlin/src/sd/cardreader.cpp +++ b/Marlin/src/sd/cardreader.cpp @@ -146,7 +146,7 @@ int16_t CardReader::nrItems = -1; DiskIODriver* CardReader::driver = nullptr; MarlinVolume CardReader::volume; -MediaFile CardReader::file; +MediaFile CardReader::myfile; #if HAS_MEDIA_SUBCALLS uint8_t CardReader::file_subcall_ctr; @@ -463,9 +463,9 @@ void CardReader::ls(const uint8_t lsflags/*=0*/) { // Echo the DOS 8.3 filename (and long filename, if any) // void CardReader::printSelectedFilename() { - if (file.isOpen()) { + if (myfile.isOpen()) { char dosFilename[FILENAME_LENGTH]; - file.getDosName(dosFilename); + myfile.getDosName(dosFilename); SERIAL_ECHO(dosFilename); #if ENABLED(LONG_FILENAME_HOST_SUPPORT) selectFileByName(dosFilename); @@ -517,7 +517,7 @@ void CardReader::mount() { */ void CardReader::manage_media() { static uint8_t prev_stat = 2; // At boot we don't know if media is present or not - uint8_t stat = uint8_t(IS_SD_INSERTED()); + uint8_t stat = uint8_t(isInserted()); if (stat == prev_stat) return; // Already checked and still no change? DEBUG_SECTION(cmm, "CardReader::manage_media()", true); @@ -626,7 +626,7 @@ void CardReader::endFilePrintNow(TERN_(SD_RESORT, const bool re_sort/*=false*/)) TERN_(ADVANCED_PAUSE_FEATURE, did_pause_print = 0); TERN_(DWIN_CREALITY_LCD, hmiFlag.print_finish = flag.sdprinting); flag.abort_sd_printing = false; - if (isFileOpen()) file.close(); + if (isFileOpen()) myfile.close(); TERN_(SD_RESORT, if (re_sort) presort()); } @@ -661,7 +661,7 @@ void CardReader::getAbsFilenameInCWD(char *dst) { appendAtom(workDirParents[i]); if (cnt < MAXPATHNAMELENGTH - (FILENAME_LENGTH) - 1) { // Leave room for filename and nul - appendAtom(file); + appendAtom(myfile); --dst; } *dst = '\0'; @@ -738,8 +738,8 @@ void CardReader::openFileRead(const char * const path, const uint8_t subcall_typ const char * const fname = diveToFile(true, diveDir, path); if (!fname) return openFailed(path); - if (file.open(diveDir, fname, O_READ)) { - filesize = file.fileSize(); + if (myfile.open(diveDir, fname, O_READ)) { + filesize = myfile.fileSize(); sdpos = 0; { // Don't remove this block, as the PORT_REDIRECT is a RAII @@ -778,7 +778,7 @@ void CardReader::openFileWrite(const char * const path) { if (!fname) return openFailed(path); #if DISABLED(SDCARD_READONLY) - if (file.open(diveDir, fname, O_CREAT | O_APPEND | O_WRITE | O_TRUNC)) { + if (myfile.open(diveDir, fname, O_CREAT | O_APPEND | O_WRITE | O_TRUNC)) { flag.saving = true; selectFileByName(fname); TERN_(EMERGENCY_PARSER, emergency_parser.disable()); @@ -832,7 +832,7 @@ void CardReader::removeFile(const char * const name) { #if ENABLED(SDCARD_READONLY) SERIAL_ECHOLNPGM("Deletion failed (read-only), File: ", fname, "."); #else - if (file.remove(itsDirPtr, fname)) { + if (myfile.remove(itsDirPtr, fname)) { SERIAL_ECHOLNPGM("File deleted:", fname); sdpos = 0; TERN_(SDCARD_SORT_ALPHA, presort()); @@ -866,7 +866,7 @@ void CardReader::write_command(char * const buf) { *npos = nullptr, *end = buf + strlen(buf) - 1; - file.writeError = false; + myfile.writeError = false; if ((npos = strchr(buf, 'N'))) { begin = strchr(npos, ' ') + 1; end = strchr(npos, '*') - 1; @@ -874,9 +874,9 @@ void CardReader::write_command(char * const buf) { end[1] = '\r'; end[2] = '\n'; end[3] = '\0'; - file.write(begin); + myfile.write(begin); - if (file.writeError) SERIAL_ERROR_MSG(STR_SD_ERR_WRITE_TO_FILE); + if (myfile.writeError) SERIAL_ERROR_MSG(STR_SD_ERR_WRITE_TO_FILE); } #if DISABLED(NO_SD_AUTOSTART) @@ -1001,8 +1001,8 @@ void CardReader::write_command(char * const buf) { // Close the working file. // void CardReader::closefile(const bool store_location/*=false*/) { - file.sync(); - file.close(); + myfile.sync(); + myfile.close(); flag.saving = flag.logging = false; sdpos = 0; @@ -1441,7 +1441,7 @@ int16_t CardReader::get_num_items() { // Return from procedure or close out the Print Job. // void CardReader::fileHasFinished() { - file.close(); + myfile.close(); #if HAS_MEDIA_SUBCALLS if (file_subcall_ctr > 0) { // Resume calling file after closing procedure diff --git a/Marlin/src/sd/cardreader.h b/Marlin/src/sd/cardreader.h index 7dfe7e344f..1fa23ececf 100644 --- a/Marlin/src/sd/cardreader.h +++ b/Marlin/src/sd/cardreader.h @@ -230,6 +230,7 @@ public: static void pauseSDPrint() { flag.sdprinting = false; } static bool isPrinting() { return flag.sdprinting; } static bool isStillPrinting() { return flag.sdprinting && !flag.abort_sd_printing; } + static bool isStillFetching() { return isStillPrinting() && !flag.sdprintdone; } static bool isPaused() { return isFileOpen() && !isPrinting(); } #if HAS_PRINT_PROGRESS_PERMYRIAD static uint16_t permyriadDone() { @@ -289,14 +290,14 @@ public: // Print File stats static uint32_t getFileSize() { return filesize; } static uint32_t getIndex() { return sdpos; } - static bool isFileOpen() { return isMounted() && file.isOpen(); } + static bool isFileOpen() { return isMounted() && myfile.isOpen(); } static bool eof() { return getIndex() >= getFileSize(); } // File data operations - static int16_t get() { int16_t out = (int16_t)file.read(); sdpos = file.curPosition(); return out; } - static int16_t read(void *buf, uint16_t nbyte) { return file.isOpen() ? file.read(buf, nbyte) : -1; } - static int16_t write(void *buf, uint16_t nbyte) { return file.isOpen() ? file.write(buf, nbyte) : -1; } - static void setIndex(const uint32_t index) { file.seekSet((sdpos = index)); } + static int16_t get() { int16_t out = (int16_t)myfile.read(); sdpos = myfile.curPosition(); return out; } + static int16_t read(void *buf, uint16_t nbyte) { return myfile.isOpen() ? myfile.read(buf, nbyte) : -1; } + static int16_t write(void *buf, uint16_t nbyte) { return myfile.isOpen() ? myfile.write(buf, nbyte) : -1; } + static void setIndex(const uint32_t index) { myfile.seekSet((sdpos = index)); } #if ENABLED(AUTO_REPORT_SD_STATUS) // @@ -313,7 +314,7 @@ private: static DiskIODriver *driver; static MarlinVolume volume; - static MediaFile file; + static MediaFile myfile; static uint32_t filesize, // Total size of the current file, in bytes sdpos; // Index most recently read (one behind file.getPos) @@ -405,31 +406,22 @@ private: #endif }; -#if HAS_USB_FLASH_DRIVE - #define IS_SD_INSERTED() DiskIODriver_USBFlash::isInserted() -#elif HAS_SD_DETECT - #define IS_SD_INSERTED() (READ(SD_DETECT_PIN) == SD_DETECT_STATE) -#else - // No card detect line? Assume the card is inserted. - #define IS_SD_INSERTED() true -#endif - -#define IS_SD_MOUNTED() card.isMounted() -#define IS_SD_PRINTING() card.isStillPrinting() -#define IS_SD_FETCHING() (!card.flag.sdprintdone && card.isStillPrinting()) -#define IS_SD_PAUSED() card.isPaused() -#define IS_SD_FILE_OPEN() card.isFileOpen() - -extern CardReader card; - #else // !HAS_MEDIA -#define IS_SD_MOUNTED() false -#define IS_SD_PRINTING() false -#define IS_SD_FETCHING() false -#define IS_SD_PAUSED() false -#define IS_SD_FILE_OPEN() false +class CardReader { +public: + static constexpr bool isFlashDriveInserted() { return false; } + static constexpr bool isSDCardInserted() { return false; } + static constexpr bool isInserted() { return false; } + static constexpr bool isMounted() { return false; } + static constexpr bool isStillPrinting() { return false; } + static constexpr bool isStillFetching() { return false; } + static constexpr bool isPaused() { return false; } + static constexpr bool isFileOpen() { return false; } +}; #define LONG_FILENAME_LENGTH 0 #endif // !HAS_MEDIA + +extern CardReader card; From 06ef78dd19a3741f2bd2050ea34995701fad4575 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 22 Apr 2025 22:30:14 -0500 Subject: [PATCH 254/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Spe?= =?UTF-8?q?cific=20SD=20/=20FD=20methods?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/MarlinCore.cpp | 3 --- .../cocoa_press/status_screen.cpp | 6 +++-- .../generic/status_screen.cpp | 6 +++-- Marlin/src/lcd/extui/ui_api.cpp | 4 +++- Marlin/src/lcd/extui/ui_api.h | 3 +++ Marlin/src/lcd/language/language_en.h | 2 +- Marlin/src/lcd/language/language_es.h | 2 +- Marlin/src/lcd/language/language_gl.h | 2 +- Marlin/src/lcd/language/language_it.h | 2 +- Marlin/src/lcd/marlinui.cpp | 7 +++++- Marlin/src/sd/cardreader.cpp | 13 +++++++++- Marlin/src/sd/cardreader.h | 24 +++++++++++++++---- .../sd/usb_flashdrive/Sd2Card_FlashDrive.cpp | 2 +- 13 files changed, 57 insertions(+), 19 deletions(-) diff --git a/Marlin/src/MarlinCore.cpp b/Marlin/src/MarlinCore.cpp index 05355ddccb..de6677fc9a 100644 --- a/Marlin/src/MarlinCore.cpp +++ b/Marlin/src/MarlinCore.cpp @@ -820,9 +820,6 @@ void idle(const bool no_stepper_sleep/*=false*/) { // Handle SD Card insert / remove TERN_(HAS_MEDIA, card.manage_media()); - // Handle USB Flash Drive insert / remove - TERN_(HAS_USB_FLASH_DRIVE, card.diskIODriver()->idle()); - // Announce Host Keepalive state (if any) TERN_(HOST_KEEPALIVE_FEATURE, gcode.host_keepalive()); diff --git a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/status_screen.cpp b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/status_screen.cpp index 1a7ccd8be5..65ac4551b9 100644 --- a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/status_screen.cpp +++ b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/status_screen.cpp @@ -432,8 +432,10 @@ void StatusScreen::onIdle() { } void StatusScreen::onMediaMounted() { - if (AT_SCREEN(StatusScreen)) - setStatusMessage(GET_TEXT_F(MSG_MEDIA_INSERTED)); + if (!AT_SCREEN(StatusScreen)) return; + setStatusMessage(ExtUI::isMediaMountedSD() ? GET_TEXT_F(MSG_MEDIA_INSERTED_SD) : + ExtUI::isMediaMountedUSB() ? GET_TEXT_F(MSG_MEDIA_INSERTED_USB) : + GET_TEXT_F(MSG_MEDIA_INSERTED)); } void StatusScreen::onMediaRemoved() { diff --git a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/status_screen.cpp b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/status_screen.cpp index 420758ca88..7b9e8f9f34 100644 --- a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/status_screen.cpp +++ b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/status_screen.cpp @@ -588,8 +588,10 @@ bool StatusScreen::onTouchEnd(uint8_t tag) { } void StatusScreen::onMediaMounted() { - if (AT_SCREEN(StatusScreen)) - setStatusMessage(GET_TEXT_F(MSG_MEDIA_INSERTED)); + if (!AT_SCREEN(StatusScreen)) return; + setStatusMessage(ExtUI::isMediaMountedSD() ? GET_TEXT_F(MSG_MEDIA_INSERTED_SD) : + ExtUI::isMediaMountedUSB() ? GET_TEXT_F(MSG_MEDIA_INSERTED_USB) : + GET_TEXT_F(MSG_MEDIA_INSERTED)); } void StatusScreen::onMediaRemoved() { diff --git a/Marlin/src/lcd/extui/ui_api.cpp b/Marlin/src/lcd/extui/ui_api.cpp index 7763bac05a..b3f4c39c24 100644 --- a/Marlin/src/lcd/extui/ui_api.cpp +++ b/Marlin/src/lcd/extui/ui_api.cpp @@ -1079,7 +1079,9 @@ namespace ExtUI { return isPrintingFromMedia() || printJobOngoing(); } - bool isMediaMounted() { return TERN0(HAS_MEDIA, card.isMounted()); } + bool isMediaMounted() { return card.isMounted(); } + bool isMediaMountedSD() { return card.isSDCardMounted(); } + bool isMediaMountedUSB() { return card.isFlashDriveMounted(); } // Pause/Resume/Stop are implemented in MarlinUI void pausePrint() { ui.pause_print(); } diff --git a/Marlin/src/lcd/extui/ui_api.h b/Marlin/src/lcd/extui/ui_api.h index 5e781706bc..7796a4e49f 100644 --- a/Marlin/src/lcd/extui/ui_api.h +++ b/Marlin/src/lcd/extui/ui_api.h @@ -464,6 +464,9 @@ namespace ExtUI { * Use these to operate on files */ bool isMediaMounted(); + bool isMediaMountedSD(); + bool isMediaMountedUSB(); + bool isPrintingFromMediaPaused(); bool isPrintingFromMedia(); bool isPrinting(); diff --git a/Marlin/src/lcd/language/language_en.h b/Marlin/src/lcd/language/language_en.h index d23e638a78..7ea17d5bb3 100644 --- a/Marlin/src/lcd/language/language_en.h +++ b/Marlin/src/lcd/language/language_en.h @@ -44,7 +44,7 @@ #if HAS_SDCARD && !HAS_USB_FLASH_DRIVE #define MEDIA_TYPE_EN "SD Card" -#elif HAS_USB_FLASH_DRIVE +#elif HAS_USB_FLASH_DRIVE && !HAS_SDCARD #define MEDIA_TYPE_EN "USB Drive" #else #define MEDIA_TYPE_EN "Media" diff --git a/Marlin/src/lcd/language/language_es.h b/Marlin/src/lcd/language/language_es.h index d1e4babf2b..a92efd5389 100644 --- a/Marlin/src/lcd/language/language_es.h +++ b/Marlin/src/lcd/language/language_es.h @@ -30,7 +30,7 @@ #if HAS_SDCARD && !HAS_USB_FLASH_DRIVE #define MEDIA_TYPE_ES "SD" -#elif HAS_USB_FLASH_DRIVE +#elif HAS_USB_FLASH_DRIVE && !HAS_SDCARD #define MEDIA_TYPE_ES "USB" #else #define MEDIA_TYPE_ES "SD/FD" diff --git a/Marlin/src/lcd/language/language_gl.h b/Marlin/src/lcd/language/language_gl.h index 6dd699f1bd..3b7620de90 100644 --- a/Marlin/src/lcd/language/language_gl.h +++ b/Marlin/src/lcd/language/language_gl.h @@ -32,7 +32,7 @@ #if HAS_SDCARD && !HAS_USB_FLASH_DRIVE #define MEDIA_TYPE_GL "SD" -#elif HAS_USB_FLASH_DRIVE +#elif HAS_USB_FLASH_DRIVE && !HAS_SDCARD #define MEDIA_TYPE_GL "FD" #else #define MEDIA_TYPE_GL "SD/FD" diff --git a/Marlin/src/lcd/language/language_it.h b/Marlin/src/lcd/language/language_it.h index 424bcd8367..4bcde87859 100644 --- a/Marlin/src/lcd/language/language_it.h +++ b/Marlin/src/lcd/language/language_it.h @@ -40,7 +40,7 @@ #if HAS_SDCARD && !HAS_USB_FLASH_DRIVE #define MEDIA_TYPE_IT "SD" -#elif HAS_USB_FLASH_DRIVE +#elif HAS_USB_FLASH_DRIVE && !HAS_SDCARD #define MEDIA_TYPE_IT "USB" #else #define MEDIA_TYPE_IT "Media" diff --git a/Marlin/src/lcd/marlinui.cpp b/Marlin/src/lcd/marlinui.cpp index 8b7e64dda8..f6b1b60c7d 100644 --- a/Marlin/src/lcd/marlinui.cpp +++ b/Marlin/src/lcd/marlinui.cpp @@ -1907,7 +1907,12 @@ uint8_t expand_u8str_P(char * const outstr, PGM_P const ptpl, const int8_t ind, quick_feedback(); goto_screen(MEDIA_MENU_GATEWAY); #else - LCD_MESSAGE(MSG_MEDIA_INSERTED); + if (card.isSDCardSelected()) + LCD_MESSAGE(MSG_MEDIA_INSERTED_SD); + else if (card.isFlashDriveSelected()) + LCD_MESSAGE(MSG_MEDIA_INSERTED_USB); + else + LCD_MESSAGE(MSG_MEDIA_INSERTED); #endif } else { // Media Removed diff --git a/Marlin/src/sd/cardreader.cpp b/Marlin/src/sd/cardreader.cpp index 9b0a37913a..21bc6e780a 100644 --- a/Marlin/src/sd/cardreader.cpp +++ b/Marlin/src/sd/cardreader.cpp @@ -501,7 +501,14 @@ void CardReader::mount() { cdroot(); else { #if ANY(HAS_SD_DETECT, HAS_USB_FLASH_DRIVE) - if (marlin_state != MarlinState::MF_INITIALIZING) LCD_ALERTMESSAGE(MSG_MEDIA_INIT_FAIL); + if (marlin_state != MarlinState::MF_INITIALIZING) { + if (isSDCardSelected()) + LCD_ALERTMESSAGE(MSG_MEDIA_INIT_FAIL_SD); + else if (isFlashDriveSelected()) + LCD_ALERTMESSAGE(MSG_MEDIA_INIT_FAIL_USB); + else + LCD_ALERTMESSAGE(MSG_MEDIA_INIT_FAIL); + } #endif } @@ -516,6 +523,10 @@ void CardReader::mount() { * Handle SD card events */ void CardReader::manage_media() { + #if HAS_USB_FLASH_DRIVE // Wrap for optimal non-virtual? + driver->idle(); // Handle device tasks (e.g., USB Drive insert / remove) + #endif + static uint8_t prev_stat = 2; // At boot we don't know if media is present or not uint8_t stat = uint8_t(isInserted()); if (stat == prev_stat) return; // Already checked and still no change? diff --git a/Marlin/src/sd/cardreader.h b/Marlin/src/sd/cardreader.h index 1fa23ececf..1a8843da58 100644 --- a/Marlin/src/sd/cardreader.h +++ b/Marlin/src/sd/cardreader.h @@ -143,10 +143,11 @@ public: } /** - * Media Detection - Inserted, Mounted, Job Running, Job Paused, etc. + * Media Detection - Inserted and Mounted Media * - * Marlin 2.1.x supports up to two drives, either an SD Card or USB-FD - * Onboard SD may have SPI or SDIO interface. USB FD may use MSC. + * Marlin 2.1.x supports up to two drives, either an SD Card or USB-FD. + * SD Card may have SPI or SDIO interface. + * SDIO / USB drives may be shared via MSC when not in use by Marlin. */ // No card detect line? Assume the card is inserted. @@ -169,8 +170,16 @@ public: // Mount and release physical media static void mount(); static void release(); + static bool isMounted() { return flag.mounted; } + static bool isSDCardMounted() { + return isMounted() && isSDCardSelected(); + } + static bool isFlashDriveMounted() { + return isMounted() && isFlashDriveSelected(); + } + // Handle media insert/remove (including mounting on boot-up) static void manage_media(); @@ -410,10 +419,17 @@ private: class CardReader { public: - static constexpr bool isFlashDriveInserted() { return false; } + static constexpr bool isSDCardSelected() { return false; } + static constexpr bool isFlashDriveSelected() { return false; } + static constexpr bool isSDCardInserted() { return false; } + static constexpr bool isFlashDriveInserted() { return false; } static constexpr bool isInserted() { return false; } + + static constexpr bool isSDCardMounted() { return false; } + static constexpr bool isFlashDriveMounted() { return false; } static constexpr bool isMounted() { return false; } + static constexpr bool isStillPrinting() { return false; } static constexpr bool isStillFetching() { return false; } static constexpr bool isPaused() { return false; } diff --git a/Marlin/src/sd/usb_flashdrive/Sd2Card_FlashDrive.cpp b/Marlin/src/sd/usb_flashdrive/Sd2Card_FlashDrive.cpp index 2ae38c64c0..e6e6f30ae6 100644 --- a/Marlin/src/sd/usb_flashdrive/Sd2Card_FlashDrive.cpp +++ b/Marlin/src/sd/usb_flashdrive/Sd2Card_FlashDrive.cpp @@ -30,7 +30,7 @@ * 3 - perform block range checking * 4 - print each block access */ -#define USB_DEBUG 1 +#define USB_DEBUG TERN(MARLIN_DEV_MODE, 1, 0) #define USB_STARTUP_DELAY 0 // uncomment to get 'printf' console debugging. NOT FOR UNO! From 1383a4e413307a458b6fb95c4a92563b04f1c93e Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Wed, 23 Apr 2025 22:04:42 -0500 Subject: [PATCH 255/787] =?UTF-8?q?=F0=9F=94=A7=20Allow=20SMOOTH=5FLIN=5FA?= =?UTF-8?q?DVANCE=20with=20DISTINCT=5FE=5FFACTORS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/inc/SanityCheck.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index 3182d93e92..074cfe0dcb 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -854,8 +854,6 @@ static_assert(COUNT(arm) == LOGICAL_AXES, "AXIS_RELATIVE_MODES must contain " _L #if ENABLED(SMOOTH_LIN_ADVANCE) #ifndef CPU_32_BIT #error "SMOOTH_LIN_ADVANCE requires a 32-bit CPU." - #elif DISTINCT_E > 1 - #error "SMOOTH_LIN_ADVANCE is not compatible with multiple extruders." #elif ENABLED(S_CURVE_ACCELERATION) #error "SMOOTH_LIN_ADVANCE is not compatible with S_CURVE_ACCELERATION." #elif ENABLED(INPUT_SHAPING_E_SYNC) && NONE(INPUT_SHAPING_X, INPUT_SHAPING_Y) From ad71b81b0c78cd62fbfe98814b0110956adeda5b Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Fri, 25 Apr 2025 00:31:00 +0000 Subject: [PATCH 256/787] [cron] Bump distribution date (2025-04-25) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index e8a64a95f0..c96f304a03 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-04-24" +//#define STRING_DISTRIBUTION_DATE "2025-04-25" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 8a91fbdb71..43e63deb20 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-04-24" + #define STRING_DISTRIBUTION_DATE "2025-04-25" #endif /** From e0d8ea57a8261160f040431016db5f827e7a47c6 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Fri, 25 Apr 2025 21:54:53 -0500 Subject: [PATCH 257/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Gro?= =?UTF-8?q?up=20HAL/*/eeprom=20code?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/HAL/DUE/{ => eeprom}/eeprom_flash.cpp | 6 +++--- Marlin/src/HAL/DUE/{ => eeprom}/eeprom_wired.cpp | 6 +++--- .../src/HAL/GD32_MFL/{ => eeprom}/eeprom_bl24cxx.cpp | 8 ++++---- Marlin/src/HAL/GD32_MFL/{ => eeprom}/eeprom_if_iic.cpp | 8 ++++---- Marlin/src/HAL/GD32_MFL/{ => eeprom}/eeprom_wired.cpp | 8 ++++---- Marlin/src/HAL/HC32/{ => eeprom}/eeprom_bl24cxx.cpp | 6 +++--- Marlin/src/HAL/HC32/{ => eeprom}/eeprom_if_iic.cpp | 6 +++--- Marlin/src/HAL/HC32/{ => eeprom}/eeprom_sdcard.cpp | 6 +++--- Marlin/src/HAL/HC32/{ => eeprom}/eeprom_wired.cpp | 6 +++--- Marlin/src/HAL/LPC1768/{ => eeprom}/eeprom_flash.cpp | 4 ++-- Marlin/src/HAL/LPC1768/{ => eeprom}/eeprom_sdcard.cpp | 4 ++-- Marlin/src/HAL/LPC1768/{ => eeprom}/eeprom_wired.cpp | 6 +++--- Marlin/src/HAL/RP2040/{ => eeprom}/eeprom_flash.cpp | 6 +++--- Marlin/src/HAL/RP2040/{ => eeprom}/eeprom_wired.cpp | 8 ++++---- Marlin/src/HAL/SAMD21/{ => eeprom}/QSPIFlash.cpp | 2 +- Marlin/src/HAL/SAMD21/{ => eeprom}/QSPIFlash.h | 0 Marlin/src/HAL/SAMD21/{ => eeprom}/eeprom_flash.cpp | 4 ++-- Marlin/src/HAL/SAMD21/{ => eeprom}/eeprom_qspi.cpp | 4 ++-- Marlin/src/HAL/SAMD21/{ => eeprom}/eeprom_wired.cpp | 6 +++--- Marlin/src/HAL/SAMD51/{ => eeprom}/QSPIFlash.cpp | 2 +- Marlin/src/HAL/SAMD51/{ => eeprom}/QSPIFlash.h | 0 Marlin/src/HAL/SAMD51/{ => eeprom}/eeprom_flash.cpp | 4 ++-- Marlin/src/HAL/SAMD51/{ => eeprom}/eeprom_qspi.cpp | 4 ++-- Marlin/src/HAL/SAMD51/{ => eeprom}/eeprom_wired.cpp | 6 +++--- Marlin/src/HAL/STM32/{ => eeprom}/eeprom_bl24cxx.cpp | 8 ++++---- Marlin/src/HAL/STM32/{ => eeprom}/eeprom_flash.cpp | 10 +++++----- Marlin/src/HAL/STM32/{ => eeprom}/eeprom_if_iic.cpp | 8 ++++---- Marlin/src/HAL/STM32/{ => eeprom}/eeprom_sdcard.cpp | 8 ++++---- Marlin/src/HAL/STM32/{ => eeprom}/eeprom_sram.cpp | 8 ++++---- Marlin/src/HAL/STM32/{ => eeprom}/eeprom_wired.cpp | 8 ++++---- Marlin/src/HAL/STM32F1/{ => eeprom}/eeprom_bl24cxx.cpp | 6 +++--- Marlin/src/HAL/STM32F1/{ => eeprom}/eeprom_flash.cpp | 4 ++-- Marlin/src/HAL/STM32F1/{ => eeprom}/eeprom_if_iic.cpp | 6 +++--- Marlin/src/HAL/STM32F1/{ => eeprom}/eeprom_sdcard.cpp | 6 +++--- Marlin/src/HAL/STM32F1/{ => eeprom}/eeprom_wired.cpp | 6 +++--- platformio.ini | 1 + 36 files changed, 100 insertions(+), 99 deletions(-) rename Marlin/src/HAL/DUE/{ => eeprom}/eeprom_flash.cpp (99%) rename Marlin/src/HAL/DUE/{ => eeprom}/eeprom_wired.cpp (95%) rename Marlin/src/HAL/GD32_MFL/{ => eeprom}/eeprom_bl24cxx.cpp (94%) rename Marlin/src/HAL/GD32_MFL/{ => eeprom}/eeprom_if_iic.cpp (91%) rename Marlin/src/HAL/GD32_MFL/{ => eeprom}/eeprom_wired.cpp (94%) rename Marlin/src/HAL/HC32/{ => eeprom}/eeprom_bl24cxx.cpp (95%) rename Marlin/src/HAL/HC32/{ => eeprom}/eeprom_if_iic.cpp (92%) rename Marlin/src/HAL/HC32/{ => eeprom}/eeprom_sdcard.cpp (96%) rename Marlin/src/HAL/HC32/{ => eeprom}/eeprom_wired.cpp (95%) rename Marlin/src/HAL/LPC1768/{ => eeprom}/eeprom_flash.cpp (98%) rename Marlin/src/HAL/LPC1768/{ => eeprom}/eeprom_sdcard.cpp (98%) rename Marlin/src/HAL/LPC1768/{ => eeprom}/eeprom_wired.cpp (95%) rename Marlin/src/HAL/RP2040/{ => eeprom}/eeprom_flash.cpp (95%) rename Marlin/src/HAL/RP2040/{ => eeprom}/eeprom_wired.cpp (94%) rename Marlin/src/HAL/SAMD21/{ => eeprom}/QSPIFlash.cpp (98%) rename Marlin/src/HAL/SAMD21/{ => eeprom}/QSPIFlash.h (100%) rename Marlin/src/HAL/SAMD21/{ => eeprom}/eeprom_flash.cpp (98%) rename Marlin/src/HAL/SAMD21/{ => eeprom}/eeprom_qspi.cpp (96%) rename Marlin/src/HAL/SAMD21/{ => eeprom}/eeprom_wired.cpp (95%) rename Marlin/src/HAL/SAMD51/{ => eeprom}/QSPIFlash.cpp (98%) rename Marlin/src/HAL/SAMD51/{ => eeprom}/QSPIFlash.h (100%) rename Marlin/src/HAL/SAMD51/{ => eeprom}/eeprom_flash.cpp (97%) rename Marlin/src/HAL/SAMD51/{ => eeprom}/eeprom_qspi.cpp (96%) rename Marlin/src/HAL/SAMD51/{ => eeprom}/eeprom_wired.cpp (95%) rename Marlin/src/HAL/STM32/{ => eeprom}/eeprom_bl24cxx.cpp (94%) rename Marlin/src/HAL/STM32/{ => eeprom}/eeprom_flash.cpp (98%) rename Marlin/src/HAL/STM32/{ => eeprom}/eeprom_if_iic.cpp (91%) rename Marlin/src/HAL/STM32/{ => eeprom}/eeprom_sdcard.cpp (94%) rename Marlin/src/HAL/STM32/{ => eeprom}/eeprom_sram.cpp (93%) rename Marlin/src/HAL/STM32/{ => eeprom}/eeprom_wired.cpp (94%) rename Marlin/src/HAL/STM32F1/{ => eeprom}/eeprom_bl24cxx.cpp (95%) rename Marlin/src/HAL/STM32F1/{ => eeprom}/eeprom_flash.cpp (98%) rename Marlin/src/HAL/STM32F1/{ => eeprom}/eeprom_if_iic.cpp (93%) rename Marlin/src/HAL/STM32F1/{ => eeprom}/eeprom_sdcard.cpp (96%) rename Marlin/src/HAL/STM32F1/{ => eeprom}/eeprom_wired.cpp (95%) diff --git a/Marlin/src/HAL/DUE/eeprom_flash.cpp b/Marlin/src/HAL/DUE/eeprom/eeprom_flash.cpp similarity index 99% rename from Marlin/src/HAL/DUE/eeprom_flash.cpp rename to Marlin/src/HAL/DUE/eeprom/eeprom_flash.cpp index 55206a0f9d..b33d15e106 100644 --- a/Marlin/src/HAL/DUE/eeprom_flash.cpp +++ b/Marlin/src/HAL/DUE/eeprom/eeprom_flash.cpp @@ -21,7 +21,7 @@ */ #ifdef ARDUINO_ARCH_SAM -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(FLASH_EEPROM_EMULATION) @@ -132,7 +132,7 @@ static uint8_t buffer[256] = {0}, // The RAM buffer to accumulate writes curGroup = 0xFF; // Current FLASH group #define DEBUG_OUT ENABLED(EE_EMU_DEBUG) -#include "../../core/debug_out.h" +#include "../../../core/debug_out.h" static void ee_Dump(const int page, const void *data) { @@ -953,7 +953,7 @@ static void ee_Init() { /* PersistentStore -----------------------------------------------------------*/ -#include "../shared/eeprom_api.h" +#include "../../shared/eeprom_api.h" #ifndef MARLIN_EEPROM_SIZE #define MARLIN_EEPROM_SIZE 0x1000 // 4KB diff --git a/Marlin/src/HAL/DUE/eeprom_wired.cpp b/Marlin/src/HAL/DUE/eeprom/eeprom_wired.cpp similarity index 95% rename from Marlin/src/HAL/DUE/eeprom_wired.cpp rename to Marlin/src/HAL/DUE/eeprom/eeprom_wired.cpp index 84338ccb4b..cf9233816c 100644 --- a/Marlin/src/HAL/DUE/eeprom_wired.cpp +++ b/Marlin/src/HAL/DUE/eeprom/eeprom_wired.cpp @@ -21,7 +21,7 @@ */ #ifdef ARDUINO_ARCH_SAM -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if USE_WIRED_EEPROM @@ -30,8 +30,8 @@ * with simple implementations supplied by Marlin. */ -#include "../shared/eeprom_if.h" -#include "../shared/eeprom_api.h" +#include "../../shared/eeprom_if.h" +#include "../../shared/eeprom_api.h" #ifndef MARLIN_EEPROM_SIZE #error "MARLIN_EEPROM_SIZE is required for I2C / SPI EEPROM." diff --git a/Marlin/src/HAL/GD32_MFL/eeprom_bl24cxx.cpp b/Marlin/src/HAL/GD32_MFL/eeprom/eeprom_bl24cxx.cpp similarity index 94% rename from Marlin/src/HAL/GD32_MFL/eeprom_bl24cxx.cpp rename to Marlin/src/HAL/GD32_MFL/eeprom/eeprom_bl24cxx.cpp index 2d3329c7f6..9c44933fe3 100644 --- a/Marlin/src/HAL/GD32_MFL/eeprom_bl24cxx.cpp +++ b/Marlin/src/HAL/GD32_MFL/eeprom/eeprom_bl24cxx.cpp @@ -25,16 +25,16 @@ * with simple implementations supplied by Marlin. */ -#include "../platforms.h" +#include "../../platforms.h" #ifdef ARDUINO_ARCH_MFL -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(IIC_BL24CXX_EEPROM) -#include "../shared/eeprom_if.h" -#include "../shared/eeprom_api.h" +#include "../../shared/eeprom_if.h" +#include "../../shared/eeprom_api.h" #ifndef MARLIN_EEPROM_SIZE #error "MARLIN_EEPROM_SIZE is required for IIC_BL24CXX_EEPROM." diff --git a/Marlin/src/HAL/GD32_MFL/eeprom_if_iic.cpp b/Marlin/src/HAL/GD32_MFL/eeprom/eeprom_if_iic.cpp similarity index 91% rename from Marlin/src/HAL/GD32_MFL/eeprom_if_iic.cpp rename to Marlin/src/HAL/GD32_MFL/eeprom/eeprom_if_iic.cpp index 96eebea122..ea563f742c 100644 --- a/Marlin/src/HAL/GD32_MFL/eeprom_if_iic.cpp +++ b/Marlin/src/HAL/GD32_MFL/eeprom/eeprom_if_iic.cpp @@ -25,16 +25,16 @@ * Enable USE_SHARED_EEPROM if not supplied by the framework. */ -#include "../platforms.h" +#include "../../platforms.h" #ifdef ARDUINO_ARCH_MFL -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(IIC_BL24CXX_EEPROM) -#include "../../libs/BL24CXX.h" -#include "../shared/eeprom_if.h" +#include "../../../libs/BL24CXX.h" +#include "../../shared/eeprom_if.h" void eeprom_init() { BL24CXX::init(); diff --git a/Marlin/src/HAL/GD32_MFL/eeprom_wired.cpp b/Marlin/src/HAL/GD32_MFL/eeprom/eeprom_wired.cpp similarity index 94% rename from Marlin/src/HAL/GD32_MFL/eeprom_wired.cpp rename to Marlin/src/HAL/GD32_MFL/eeprom/eeprom_wired.cpp index 58a6f85e7f..8860e53a62 100644 --- a/Marlin/src/HAL/GD32_MFL/eeprom_wired.cpp +++ b/Marlin/src/HAL/GD32_MFL/eeprom/eeprom_wired.cpp @@ -19,11 +19,11 @@ * along with this program. If not, see . * */ -#include "../platforms.h" +#include "../../platforms.h" #ifdef ARDUINO_ARCH_MFL -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if USE_WIRED_EEPROM @@ -32,8 +32,8 @@ * with simple implementations supplied by Marlin. */ -#include "../shared/eeprom_if.h" -#include "../shared/eeprom_api.h" +#include "../../shared/eeprom_if.h" +#include "../../shared/eeprom_api.h" #ifndef MARLIN_EEPROM_SIZE #define MARLIN_EEPROM_SIZE size_t(E2END + 1) diff --git a/Marlin/src/HAL/HC32/eeprom_bl24cxx.cpp b/Marlin/src/HAL/HC32/eeprom/eeprom_bl24cxx.cpp similarity index 95% rename from Marlin/src/HAL/HC32/eeprom_bl24cxx.cpp rename to Marlin/src/HAL/HC32/eeprom/eeprom_bl24cxx.cpp index 59da99b3f5..a53a7c4062 100644 --- a/Marlin/src/HAL/HC32/eeprom_bl24cxx.cpp +++ b/Marlin/src/HAL/HC32/eeprom/eeprom_bl24cxx.cpp @@ -26,12 +26,12 @@ */ #ifdef ARDUINO_ARCH_HC32 -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(IIC_BL24CXX_EEPROM) -#include "../shared/eeprom_api.h" -#include "../shared/eeprom_if.h" +#include "../../shared/eeprom_api.h" +#include "../../shared/eeprom_if.h" #ifndef MARLIN_EEPROM_SIZE #error "MARLIN_EEPROM_SIZE is required for IIC_BL24CXX_EEPROM." diff --git a/Marlin/src/HAL/HC32/eeprom_if_iic.cpp b/Marlin/src/HAL/HC32/eeprom/eeprom_if_iic.cpp similarity index 92% rename from Marlin/src/HAL/HC32/eeprom_if_iic.cpp rename to Marlin/src/HAL/HC32/eeprom/eeprom_if_iic.cpp index 02b1d3fd54..85d21a972a 100644 --- a/Marlin/src/HAL/HC32/eeprom_if_iic.cpp +++ b/Marlin/src/HAL/HC32/eeprom/eeprom_if_iic.cpp @@ -26,12 +26,12 @@ */ #ifdef ARDUINO_ARCH_HC32 -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(IIC_BL24CXX_EEPROM) -#include "../../libs/BL24CXX.h" -#include "../shared/eeprom_if.h" +#include "../../../libs/BL24CXX.h" +#include "../../shared/eeprom_if.h" void eeprom_init() { BL24CXX::init(); diff --git a/Marlin/src/HAL/HC32/eeprom_sdcard.cpp b/Marlin/src/HAL/HC32/eeprom/eeprom_sdcard.cpp similarity index 96% rename from Marlin/src/HAL/HC32/eeprom_sdcard.cpp rename to Marlin/src/HAL/HC32/eeprom/eeprom_sdcard.cpp index 601e86dd30..45f3b01cf7 100644 --- a/Marlin/src/HAL/HC32/eeprom_sdcard.cpp +++ b/Marlin/src/HAL/HC32/eeprom/eeprom_sdcard.cpp @@ -25,12 +25,12 @@ */ #ifdef ARDUINO_ARCH_HC32 -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(SDCARD_EEPROM_EMULATION) -#include "../shared/eeprom_api.h" -#include "../../sd/cardreader.h" +#include "../../shared/eeprom_api.h" +#include "../../../sd/cardreader.h" #define EEPROM_FILENAME "eeprom.dat" diff --git a/Marlin/src/HAL/HC32/eeprom_wired.cpp b/Marlin/src/HAL/HC32/eeprom/eeprom_wired.cpp similarity index 95% rename from Marlin/src/HAL/HC32/eeprom_wired.cpp rename to Marlin/src/HAL/HC32/eeprom/eeprom_wired.cpp index aea5fc87db..997180bd98 100644 --- a/Marlin/src/HAL/HC32/eeprom_wired.cpp +++ b/Marlin/src/HAL/HC32/eeprom/eeprom_wired.cpp @@ -21,7 +21,7 @@ */ #ifdef ARDUINO_ARCH_HC32 -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if USE_WIRED_EEPROM @@ -32,8 +32,8 @@ * with simple implementations supplied by Marlin. */ -#include "../shared/eeprom_if.h" -#include "../shared/eeprom_api.h" +#include "../../shared/eeprom_if.h" +#include "../../shared/eeprom_api.h" #ifndef MARLIN_EEPROM_SIZE #error "MARLIN_EEPROM_SIZE is required for I2C / SPI EEPROM." diff --git a/Marlin/src/HAL/LPC1768/eeprom_flash.cpp b/Marlin/src/HAL/LPC1768/eeprom/eeprom_flash.cpp similarity index 98% rename from Marlin/src/HAL/LPC1768/eeprom_flash.cpp rename to Marlin/src/HAL/LPC1768/eeprom/eeprom_flash.cpp index 9f873d5774..3610f433eb 100644 --- a/Marlin/src/HAL/LPC1768/eeprom_flash.cpp +++ b/Marlin/src/HAL/LPC1768/eeprom/eeprom_flash.cpp @@ -36,11 +36,11 @@ * 16Kb I/O buffers (intended to hold DMA USB and Ethernet data, but currently * unused). */ -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(FLASH_EEPROM_EMULATION) -#include "../shared/eeprom_api.h" +#include "../../shared/eeprom_api.h" extern "C" { #include diff --git a/Marlin/src/HAL/LPC1768/eeprom_sdcard.cpp b/Marlin/src/HAL/LPC1768/eeprom/eeprom_sdcard.cpp similarity index 98% rename from Marlin/src/HAL/LPC1768/eeprom_sdcard.cpp rename to Marlin/src/HAL/LPC1768/eeprom/eeprom_sdcard.cpp index 30ecb01a09..3500f3e7cf 100644 --- a/Marlin/src/HAL/LPC1768/eeprom_sdcard.cpp +++ b/Marlin/src/HAL/LPC1768/eeprom/eeprom_sdcard.cpp @@ -26,13 +26,13 @@ #ifdef TARGET_LPC1768 -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(SDCARD_EEPROM_EMULATION) //#define DEBUG_SD_EEPROM_EMULATION -#include "../shared/eeprom_api.h" +#include "../../shared/eeprom_api.h" #include #include diff --git a/Marlin/src/HAL/LPC1768/eeprom_wired.cpp b/Marlin/src/HAL/LPC1768/eeprom/eeprom_wired.cpp similarity index 95% rename from Marlin/src/HAL/LPC1768/eeprom_wired.cpp rename to Marlin/src/HAL/LPC1768/eeprom/eeprom_wired.cpp index 3230e29afc..6a5d90bd02 100644 --- a/Marlin/src/HAL/LPC1768/eeprom_wired.cpp +++ b/Marlin/src/HAL/LPC1768/eeprom/eeprom_wired.cpp @@ -21,7 +21,7 @@ */ #ifdef TARGET_LPC1768 -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if USE_WIRED_EEPROM @@ -30,8 +30,8 @@ * with implementations supplied by the framework. */ -#include "../shared/eeprom_if.h" -#include "../shared/eeprom_api.h" +#include "../../shared/eeprom_if.h" +#include "../../shared/eeprom_api.h" #ifndef MARLIN_EEPROM_SIZE #define MARLIN_EEPROM_SIZE 0x8000 // 32K diff --git a/Marlin/src/HAL/RP2040/eeprom_flash.cpp b/Marlin/src/HAL/RP2040/eeprom/eeprom_flash.cpp similarity index 95% rename from Marlin/src/HAL/RP2040/eeprom_flash.cpp rename to Marlin/src/HAL/RP2040/eeprom/eeprom_flash.cpp index 5b1131ed43..89e882d77b 100644 --- a/Marlin/src/HAL/RP2040/eeprom_flash.cpp +++ b/Marlin/src/HAL/RP2040/eeprom/eeprom_flash.cpp @@ -19,15 +19,15 @@ * along with this program. If not, see . * */ -#include "../platforms.h" +#include "../../platforms.h" #ifdef __PLAT_RP2040__ -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(FLASH_EEPROM_EMULATION) -#include "../shared/eeprom_api.h" +#include "../../shared/eeprom_api.h" // NOTE: The Bigtreetech SKR Pico has an onboard W25Q16 flash module diff --git a/Marlin/src/HAL/RP2040/eeprom_wired.cpp b/Marlin/src/HAL/RP2040/eeprom/eeprom_wired.cpp similarity index 94% rename from Marlin/src/HAL/RP2040/eeprom_wired.cpp rename to Marlin/src/HAL/RP2040/eeprom/eeprom_wired.cpp index 974f6f8dc1..7a5ca86c4c 100644 --- a/Marlin/src/HAL/RP2040/eeprom_wired.cpp +++ b/Marlin/src/HAL/RP2040/eeprom/eeprom_wired.cpp @@ -19,11 +19,11 @@ * along with this program. If not, see . * */ -#include "../platforms.h" +#include "../../platforms.h" #ifdef __PLAT_RP2040__ -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if USE_WIRED_EEPROM @@ -32,8 +32,8 @@ * with simple implementations supplied by Marlin. */ -#include "../shared/eeprom_if.h" -#include "../shared/eeprom_api.h" +#include "../../shared/eeprom_if.h" +#include "../../shared/eeprom_api.h" #ifndef MARLIN_EEPROM_SIZE #define MARLIN_EEPROM_SIZE size_t(E2END + 1) diff --git a/Marlin/src/HAL/SAMD21/QSPIFlash.cpp b/Marlin/src/HAL/SAMD21/eeprom/QSPIFlash.cpp similarity index 98% rename from Marlin/src/HAL/SAMD21/QSPIFlash.cpp rename to Marlin/src/HAL/SAMD21/eeprom/QSPIFlash.cpp index fa54c62071..2a93226a6f 100644 --- a/Marlin/src/HAL/SAMD21/QSPIFlash.cpp +++ b/Marlin/src/HAL/SAMD21/eeprom/QSPIFlash.cpp @@ -24,7 +24,7 @@ * SAMD21 HAL developed by Bart Meijer (brupje) * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) */ -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(QSPI_EEPROM) diff --git a/Marlin/src/HAL/SAMD21/QSPIFlash.h b/Marlin/src/HAL/SAMD21/eeprom/QSPIFlash.h similarity index 100% rename from Marlin/src/HAL/SAMD21/QSPIFlash.h rename to Marlin/src/HAL/SAMD21/eeprom/QSPIFlash.h diff --git a/Marlin/src/HAL/SAMD21/eeprom_flash.cpp b/Marlin/src/HAL/SAMD21/eeprom/eeprom_flash.cpp similarity index 98% rename from Marlin/src/HAL/SAMD21/eeprom_flash.cpp rename to Marlin/src/HAL/SAMD21/eeprom/eeprom_flash.cpp index 66329bff19..1c190495de 100644 --- a/Marlin/src/HAL/SAMD21/eeprom_flash.cpp +++ b/Marlin/src/HAL/SAMD21/eeprom/eeprom_flash.cpp @@ -26,7 +26,7 @@ */ #ifdef __SAMD21__ -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(FLASH_EEPROM_EMULATION) @@ -35,7 +35,7 @@ /* reserve flash memory */ static const uint8_t flashdata[TOTAL_FLASH_SIZE] __attribute__((__aligned__(256))) { }; \ -#include "../shared/eeprom_api.h" +#include "../../shared/eeprom_api.h" size_t PersistentStore::capacity() { return MARLIN_EEPROM_SIZE - eeprom_exclude_size; } diff --git a/Marlin/src/HAL/SAMD21/eeprom_qspi.cpp b/Marlin/src/HAL/SAMD21/eeprom/eeprom_qspi.cpp similarity index 96% rename from Marlin/src/HAL/SAMD21/eeprom_qspi.cpp rename to Marlin/src/HAL/SAMD21/eeprom/eeprom_qspi.cpp index 12977a178c..8bd1bd3539 100644 --- a/Marlin/src/HAL/SAMD21/eeprom_qspi.cpp +++ b/Marlin/src/HAL/SAMD21/eeprom/eeprom_qspi.cpp @@ -26,13 +26,13 @@ */ #ifdef __SAMD21__ -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(QSPI_EEPROM) #error "QSPI_EEPROM emulation Not implemented on SAMD21" -#include "../shared/eeprom_api.h" +#include "../../shared/eeprom_api.h" #include "QSPIFlash.h" diff --git a/Marlin/src/HAL/SAMD21/eeprom_wired.cpp b/Marlin/src/HAL/SAMD21/eeprom/eeprom_wired.cpp similarity index 95% rename from Marlin/src/HAL/SAMD21/eeprom_wired.cpp rename to Marlin/src/HAL/SAMD21/eeprom/eeprom_wired.cpp index da0eb1b0c8..82c701ebb1 100644 --- a/Marlin/src/HAL/SAMD21/eeprom_wired.cpp +++ b/Marlin/src/HAL/SAMD21/eeprom/eeprom_wired.cpp @@ -26,7 +26,7 @@ */ #ifdef __SAMD21__ -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if USE_WIRED_EEPROM @@ -36,8 +36,8 @@ * with simple implementations supplied by Marlin. */ -#include "../shared/eeprom_if.h" -#include "../shared/eeprom_api.h" +#include "../../shared/eeprom_if.h" +#include "../../shared/eeprom_api.h" #ifndef MARLIN_EEPROM_SIZE #error "MARLIN_EEPROM_SIZE is required for I2C / SPI EEPROM." diff --git a/Marlin/src/HAL/SAMD51/QSPIFlash.cpp b/Marlin/src/HAL/SAMD51/eeprom/QSPIFlash.cpp similarity index 98% rename from Marlin/src/HAL/SAMD51/QSPIFlash.cpp rename to Marlin/src/HAL/SAMD51/eeprom/QSPIFlash.cpp index fc21a1ad8c..191da1f30c 100644 --- a/Marlin/src/HAL/SAMD51/QSPIFlash.cpp +++ b/Marlin/src/HAL/SAMD51/eeprom/QSPIFlash.cpp @@ -20,7 +20,7 @@ * */ -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(QSPI_EEPROM) diff --git a/Marlin/src/HAL/SAMD51/QSPIFlash.h b/Marlin/src/HAL/SAMD51/eeprom/QSPIFlash.h similarity index 100% rename from Marlin/src/HAL/SAMD51/QSPIFlash.h rename to Marlin/src/HAL/SAMD51/eeprom/QSPIFlash.h diff --git a/Marlin/src/HAL/SAMD51/eeprom_flash.cpp b/Marlin/src/HAL/SAMD51/eeprom/eeprom_flash.cpp similarity index 97% rename from Marlin/src/HAL/SAMD51/eeprom_flash.cpp rename to Marlin/src/HAL/SAMD51/eeprom/eeprom_flash.cpp index 7d5518956c..2387a0f99e 100644 --- a/Marlin/src/HAL/SAMD51/eeprom_flash.cpp +++ b/Marlin/src/HAL/SAMD51/eeprom/eeprom_flash.cpp @@ -25,11 +25,11 @@ */ #ifdef __SAMD51__ -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(FLASH_EEPROM_EMULATION) -#include "../shared/eeprom_api.h" +#include "../../shared/eeprom_api.h" #define NVMCTRL_CMD(c) do{ \ SYNC(!NVMCTRL->STATUS.bit.READY); \ diff --git a/Marlin/src/HAL/SAMD51/eeprom_qspi.cpp b/Marlin/src/HAL/SAMD51/eeprom/eeprom_qspi.cpp similarity index 96% rename from Marlin/src/HAL/SAMD51/eeprom_qspi.cpp rename to Marlin/src/HAL/SAMD51/eeprom/eeprom_qspi.cpp index a39e4c4fa3..e829c28e26 100644 --- a/Marlin/src/HAL/SAMD51/eeprom_qspi.cpp +++ b/Marlin/src/HAL/SAMD51/eeprom/eeprom_qspi.cpp @@ -25,11 +25,11 @@ */ #ifdef __SAMD51__ -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(QSPI_EEPROM) -#include "../shared/eeprom_api.h" +#include "../../shared/eeprom_api.h" #include "QSPIFlash.h" diff --git a/Marlin/src/HAL/SAMD51/eeprom_wired.cpp b/Marlin/src/HAL/SAMD51/eeprom/eeprom_wired.cpp similarity index 95% rename from Marlin/src/HAL/SAMD51/eeprom_wired.cpp rename to Marlin/src/HAL/SAMD51/eeprom/eeprom_wired.cpp index 00a739a587..fc1eb09a0c 100644 --- a/Marlin/src/HAL/SAMD51/eeprom_wired.cpp +++ b/Marlin/src/HAL/SAMD51/eeprom/eeprom_wired.cpp @@ -25,7 +25,7 @@ */ #ifdef __SAMD51__ -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if USE_WIRED_EEPROM @@ -34,8 +34,8 @@ * with simple implementations supplied by Marlin. */ -#include "../shared/eeprom_if.h" -#include "../shared/eeprom_api.h" +#include "../../shared/eeprom_if.h" +#include "../../shared/eeprom_api.h" #ifndef MARLIN_EEPROM_SIZE #error "MARLIN_EEPROM_SIZE is required for I2C / SPI EEPROM." diff --git a/Marlin/src/HAL/STM32/eeprom_bl24cxx.cpp b/Marlin/src/HAL/STM32/eeprom/eeprom_bl24cxx.cpp similarity index 94% rename from Marlin/src/HAL/STM32/eeprom_bl24cxx.cpp rename to Marlin/src/HAL/STM32/eeprom/eeprom_bl24cxx.cpp index 3e0bb58dad..8240f15d3a 100644 --- a/Marlin/src/HAL/STM32/eeprom_bl24cxx.cpp +++ b/Marlin/src/HAL/STM32/eeprom/eeprom_bl24cxx.cpp @@ -20,7 +20,7 @@ * */ -#include "../platforms.h" +#include "../../platforms.h" #ifdef HAL_STM32 @@ -29,12 +29,12 @@ * with simple implementations supplied by Marlin. */ -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(IIC_BL24CXX_EEPROM) -#include "../shared/eeprom_if.h" -#include "../shared/eeprom_api.h" +#include "../../shared/eeprom_if.h" +#include "../../shared/eeprom_api.h" // // PersistentStore diff --git a/Marlin/src/HAL/STM32/eeprom_flash.cpp b/Marlin/src/HAL/STM32/eeprom/eeprom_flash.cpp similarity index 98% rename from Marlin/src/HAL/STM32/eeprom_flash.cpp rename to Marlin/src/HAL/STM32/eeprom/eeprom_flash.cpp index 14e6e4d854..9f1e49a4f6 100644 --- a/Marlin/src/HAL/STM32/eeprom_flash.cpp +++ b/Marlin/src/HAL/STM32/eeprom/eeprom_flash.cpp @@ -19,15 +19,15 @@ * along with this program. If not, see . * */ -#include "../platforms.h" +#include "../../platforms.h" #ifdef HAL_STM32 -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(FLASH_EEPROM_EMULATION) -#include "../shared/eeprom_api.h" +#include "../../shared/eeprom_api.h" // Better: "utility/stm32_eeprom.h", but only after updating stm32duino to 2.0.0 // Use EEPROM.h for compatibility, for now. @@ -50,10 +50,10 @@ #if ENABLED(FLASH_EEPROM_LEVELING) - #include "stm32_def.h" + #include #define DEBUG_OUT ENABLED(EEPROM_CHITCHAT) - #include "../../core/debug_out.h" + #include "../../../core/debug_out.h" #ifndef MARLIN_EEPROM_SIZE #define MARLIN_EEPROM_SIZE 0x1000 // 4KB diff --git a/Marlin/src/HAL/STM32/eeprom_if_iic.cpp b/Marlin/src/HAL/STM32/eeprom/eeprom_if_iic.cpp similarity index 91% rename from Marlin/src/HAL/STM32/eeprom_if_iic.cpp rename to Marlin/src/HAL/STM32/eeprom/eeprom_if_iic.cpp index ad8712c0c0..9cabdd681b 100644 --- a/Marlin/src/HAL/STM32/eeprom_if_iic.cpp +++ b/Marlin/src/HAL/STM32/eeprom/eeprom_if_iic.cpp @@ -20,7 +20,7 @@ * */ -#include "../platforms.h" +#include "../../platforms.h" #ifdef HAL_STM32 @@ -29,12 +29,12 @@ * Enable USE_SHARED_EEPROM if not supplied by the framework. */ -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(IIC_BL24CXX_EEPROM) -#include "../../libs/BL24CXX.h" -#include "../shared/eeprom_if.h" +#include "../../../libs/BL24CXX.h" +#include "../../shared/eeprom_if.h" void eeprom_init() { BL24CXX::init(); } diff --git a/Marlin/src/HAL/STM32/eeprom_sdcard.cpp b/Marlin/src/HAL/STM32/eeprom/eeprom_sdcard.cpp similarity index 94% rename from Marlin/src/HAL/STM32/eeprom_sdcard.cpp rename to Marlin/src/HAL/STM32/eeprom/eeprom_sdcard.cpp index 071d0bac00..bcc76df813 100644 --- a/Marlin/src/HAL/STM32/eeprom_sdcard.cpp +++ b/Marlin/src/HAL/STM32/eeprom/eeprom_sdcard.cpp @@ -20,7 +20,7 @@ * */ -#include "../platforms.h" +#include "../../platforms.h" #ifdef HAL_STM32 @@ -28,12 +28,12 @@ * Implementation of EEPROM settings in SD Card */ -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(SDCARD_EEPROM_EMULATION) -#include "../shared/eeprom_api.h" -#include "../../sd/cardreader.h" +#include "../../shared/eeprom_api.h" +#include "../../../sd/cardreader.h" #define EEPROM_FILENAME "eeprom.dat" diff --git a/Marlin/src/HAL/STM32/eeprom_sram.cpp b/Marlin/src/HAL/STM32/eeprom/eeprom_sram.cpp similarity index 93% rename from Marlin/src/HAL/STM32/eeprom_sram.cpp rename to Marlin/src/HAL/STM32/eeprom/eeprom_sram.cpp index 58a67f1759..a9d62ec29c 100644 --- a/Marlin/src/HAL/STM32/eeprom_sram.cpp +++ b/Marlin/src/HAL/STM32/eeprom/eeprom_sram.cpp @@ -19,16 +19,16 @@ * along with this program. If not, see . * */ -#include "../platforms.h" +#include "../../platforms.h" #ifdef HAL_STM32 -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(SRAM_EEPROM_EMULATION) -#include "../shared/eeprom_if.h" -#include "../shared/eeprom_api.h" +#include "../../shared/eeprom_if.h" +#include "../../shared/eeprom_api.h" #ifndef MARLIN_EEPROM_SIZE #define MARLIN_EEPROM_SIZE 0x1000 // 4KB diff --git a/Marlin/src/HAL/STM32/eeprom_wired.cpp b/Marlin/src/HAL/STM32/eeprom/eeprom_wired.cpp similarity index 94% rename from Marlin/src/HAL/STM32/eeprom_wired.cpp rename to Marlin/src/HAL/STM32/eeprom/eeprom_wired.cpp index 5440030bd4..fa45e6c40d 100644 --- a/Marlin/src/HAL/STM32/eeprom_wired.cpp +++ b/Marlin/src/HAL/STM32/eeprom/eeprom_wired.cpp @@ -19,11 +19,11 @@ * along with this program. If not, see . * */ -#include "../platforms.h" +#include "../../platforms.h" #ifdef HAL_STM32 -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if USE_WIRED_EEPROM @@ -32,8 +32,8 @@ * with simple implementations supplied by Marlin. */ -#include "../shared/eeprom_if.h" -#include "../shared/eeprom_api.h" +#include "../../shared/eeprom_if.h" +#include "../../shared/eeprom_api.h" #ifndef MARLIN_EEPROM_SIZE #define MARLIN_EEPROM_SIZE size_t(E2END + 1) diff --git a/Marlin/src/HAL/STM32F1/eeprom_bl24cxx.cpp b/Marlin/src/HAL/STM32F1/eeprom/eeprom_bl24cxx.cpp similarity index 95% rename from Marlin/src/HAL/STM32F1/eeprom_bl24cxx.cpp rename to Marlin/src/HAL/STM32F1/eeprom/eeprom_bl24cxx.cpp index 1252e77b0b..9e96a741bf 100644 --- a/Marlin/src/HAL/STM32F1/eeprom_bl24cxx.cpp +++ b/Marlin/src/HAL/STM32F1/eeprom/eeprom_bl24cxx.cpp @@ -26,12 +26,12 @@ * with simple implementations supplied by Marlin. */ -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(IIC_BL24CXX_EEPROM) -#include "../shared/eeprom_if.h" -#include "../shared/eeprom_api.h" +#include "../../shared/eeprom_if.h" +#include "../../shared/eeprom_api.h" // // PersistentStore diff --git a/Marlin/src/HAL/STM32F1/eeprom_flash.cpp b/Marlin/src/HAL/STM32F1/eeprom/eeprom_flash.cpp similarity index 98% rename from Marlin/src/HAL/STM32F1/eeprom_flash.cpp rename to Marlin/src/HAL/STM32F1/eeprom/eeprom_flash.cpp index 50d9cfc4f4..485bc4f1ba 100644 --- a/Marlin/src/HAL/STM32F1/eeprom_flash.cpp +++ b/Marlin/src/HAL/STM32F1/eeprom/eeprom_flash.cpp @@ -28,11 +28,11 @@ #ifdef __STM32F1__ -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(FLASH_EEPROM_EMULATION) -#include "../shared/eeprom_api.h" +#include "../../shared/eeprom_api.h" #include #include diff --git a/Marlin/src/HAL/STM32F1/eeprom_if_iic.cpp b/Marlin/src/HAL/STM32F1/eeprom/eeprom_if_iic.cpp similarity index 93% rename from Marlin/src/HAL/STM32F1/eeprom_if_iic.cpp rename to Marlin/src/HAL/STM32F1/eeprom/eeprom_if_iic.cpp index 78b7af0b04..e1d5e06b68 100644 --- a/Marlin/src/HAL/STM32F1/eeprom_if_iic.cpp +++ b/Marlin/src/HAL/STM32F1/eeprom/eeprom_if_iic.cpp @@ -27,12 +27,12 @@ #ifdef __STM32F1__ -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(IIC_BL24CXX_EEPROM) -#include "../../libs/BL24CXX.h" -#include "../shared/eeprom_if.h" +#include "../../../libs/BL24CXX.h" +#include "../../shared/eeprom_if.h" void eeprom_init() { BL24CXX::init(); } diff --git a/Marlin/src/HAL/STM32F1/eeprom_sdcard.cpp b/Marlin/src/HAL/STM32F1/eeprom/eeprom_sdcard.cpp similarity index 96% rename from Marlin/src/HAL/STM32F1/eeprom_sdcard.cpp rename to Marlin/src/HAL/STM32F1/eeprom/eeprom_sdcard.cpp index 6b72193422..4d28ce8e0a 100644 --- a/Marlin/src/HAL/STM32F1/eeprom_sdcard.cpp +++ b/Marlin/src/HAL/STM32F1/eeprom/eeprom_sdcard.cpp @@ -27,12 +27,12 @@ #ifdef __STM32F1__ -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(SDCARD_EEPROM_EMULATION) -#include "../shared/eeprom_api.h" -#include "../../sd/cardreader.h" +#include "../../shared/eeprom_api.h" +#include "../../../sd/cardreader.h" #define EEPROM_FILENAME "eeprom.dat" diff --git a/Marlin/src/HAL/STM32F1/eeprom_wired.cpp b/Marlin/src/HAL/STM32F1/eeprom/eeprom_wired.cpp similarity index 95% rename from Marlin/src/HAL/STM32F1/eeprom_wired.cpp rename to Marlin/src/HAL/STM32F1/eeprom/eeprom_wired.cpp index bfb7718094..a1464ab983 100644 --- a/Marlin/src/HAL/STM32F1/eeprom_wired.cpp +++ b/Marlin/src/HAL/STM32F1/eeprom/eeprom_wired.cpp @@ -26,12 +26,12 @@ #ifdef __STM32F1__ -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if USE_WIRED_EEPROM -#include "../shared/eeprom_if.h" -#include "../shared/eeprom_api.h" +#include "../../shared/eeprom_if.h" +#include "../../shared/eeprom_api.h" #ifndef MARLIN_EEPROM_SIZE #error "MARLIN_EEPROM_SIZE is required for I2C / SPI EEPROM." diff --git a/platformio.ini b/platformio.ini index d69fdc6cea..4d03696b5a 100644 --- a/platformio.ini +++ b/platformio.ini @@ -78,6 +78,7 @@ default_src_filter = + - - - - - + - - - - From f60bc278fa14abc7d7fabf79a8ac9335a1a764b4 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sat, 26 Apr 2025 17:21:41 -0500 Subject: [PATCH 258/787] =?UTF-8?q?=F0=9F=A9=B9=20Misc.=20HAL,=20flag=20fi?= =?UTF-8?q?xes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/HAL/DUE/usb/sd_mmc_spi_mem.cpp | 11 ++++++----- Marlin/src/HAL/LPC1768/HAL.cpp | 9 ++------- Marlin/src/HAL/LPC1768/eeprom/eeprom_sdcard.cpp | 2 +- Marlin/src/HAL/RP2040/HAL.cpp | 2 +- Marlin/src/HAL/STM32/HAL.cpp | 2 +- Marlin/src/HAL/STM32/usb_serial.cpp | 4 ++-- Marlin/src/HAL/STM32F1/HAL.cpp | 3 ++- Marlin/src/sd/usb_flashdrive/lib-uhs2/usbhost.cpp | 2 +- ini/stm32f1-maple.ini | 2 +- ini/stm32f1.ini | 9 +++++---- 10 files changed, 22 insertions(+), 24 deletions(-) diff --git a/Marlin/src/HAL/DUE/usb/sd_mmc_spi_mem.cpp b/Marlin/src/HAL/DUE/usb/sd_mmc_spi_mem.cpp index ff6ff4859b..74cfd9b39b 100644 --- a/Marlin/src/HAL/DUE/usb/sd_mmc_spi_mem.cpp +++ b/Marlin/src/HAL/DUE/usb/sd_mmc_spi_mem.cpp @@ -29,11 +29,10 @@ bool sd_mmc_spi_wr_protect() { return false; } bool sd_mmc_spi_removal() { return !media_ready(); } Ctrl_status sd_mmc_spi_test_unit_ready() { - #ifdef DISABLE_DUE_SD_MMC + #if ENABLED(DISABLE_DUE_SD_MMC) return CTRL_NO_PRESENT; #endif - if (sd_mmc_spi_removal()) return CTRL_NO_PRESENT; - return CTRL_GOOD; + return sd_mmc_spi_removal() ? CTRL_NO_PRESENT : CTRL_GOOD; } // NOTE: This function is defined as returning the address of the last block @@ -58,9 +57,10 @@ uint8_t sector_buf[SD_MMC_BLOCK_SIZE]; // #define DEBUG_MMC Ctrl_status sd_mmc_spi_usb_read_10(uint32_t addr, uint16_t nb_sector) { - #ifdef DISABLE_DUE_SD_MMC + #if ENABLED(DISABLE_DUE_SD_MMC) return CTRL_NO_PRESENT; #endif + if (sd_mmc_spi_removal()) return CTRL_NO_PRESENT; #ifdef DEBUG_MMC @@ -97,9 +97,10 @@ Ctrl_status sd_mmc_spi_usb_read_10(uint32_t addr, uint16_t nb_sector) { } Ctrl_status sd_mmc_spi_usb_write_10(uint32_t addr, uint16_t nb_sector) { - #ifdef DISABLE_DUE_SD_MMC + #if ENABLED(DISABLE_DUE_SD_MMC) return CTRL_NO_PRESENT; #endif + if (sd_mmc_spi_removal()) return CTRL_NO_PRESENT; #ifdef DEBUG_MMC diff --git a/Marlin/src/HAL/LPC1768/HAL.cpp b/Marlin/src/HAL/LPC1768/HAL.cpp index 6e4357777d..4b0e255f37 100644 --- a/Marlin/src/HAL/LPC1768/HAL.cpp +++ b/Marlin/src/HAL/LPC1768/HAL.cpp @@ -173,13 +173,8 @@ void MarlinHAL::init() { // HAL idle task void MarlinHAL::idletask() { #if HAS_SHARED_MEDIA - // If Marlin is using the SD card we need to lock it to prevent access from - // a PC via USB. - // Other HALs use card.isStillPrinting() and card.isFileOpen() to check for access but - // this will not reliably detect delete operations. To be safe we will lock - // the disk if Marlin has it mounted. Unfortunately there is currently no way - // to unmount the disk from the LCD menu. - // if (card.isStillPrinting() || card.isFileOpen()) + // When Marlin is using the SD Card it must be locked to prevent PC access via USB. + // For maximum safety we lock the disk if Marlin has it mounted for any reason. if (card.isMounted()) MSC_Aquire_Lock(); else diff --git a/Marlin/src/HAL/LPC1768/eeprom/eeprom_sdcard.cpp b/Marlin/src/HAL/LPC1768/eeprom/eeprom_sdcard.cpp index 3500f3e7cf..5bf2d353b6 100644 --- a/Marlin/src/HAL/LPC1768/eeprom/eeprom_sdcard.cpp +++ b/Marlin/src/HAL/LPC1768/eeprom/eeprom_sdcard.cpp @@ -52,7 +52,6 @@ bool eeprom_file_open = false; size_t PersistentStore::capacity() { return MARLIN_EEPROM_SIZE - eeprom_exclude_size; } bool PersistentStore::access_start() { - const char eeprom_erase_value = 0xFF; MSC_Aquire_Lock(); if (f_mount(&fat_fs, "", 1)) { MSC_Release_Lock(); @@ -65,6 +64,7 @@ bool PersistentStore::access_start() { UINT bytes_written; FSIZE_t file_size = f_size(&eeprom_file); f_lseek(&eeprom_file, file_size); + const char eeprom_erase_value = 0xFF; while (file_size < capacity() && res == FR_OK) { res = f_write(&eeprom_file, &eeprom_erase_value, 1, &bytes_written); file_size++; diff --git a/Marlin/src/HAL/RP2040/HAL.cpp b/Marlin/src/HAL/RP2040/HAL.cpp index ceaf540452..6e35fac938 100644 --- a/Marlin/src/HAL/RP2040/HAL.cpp +++ b/Marlin/src/HAL/RP2040/HAL.cpp @@ -77,7 +77,7 @@ void MarlinHAL::init() { HAL_timer_init(); - #if ENABLED(EMERGENCY_PARSER) && USBD_USE_CDC + #if ALL(EMERGENCY_PARSER, USBD_USE_CDC) USB_Hook_init(); #endif diff --git a/Marlin/src/HAL/STM32/HAL.cpp b/Marlin/src/HAL/STM32/HAL.cpp index 6bebaa24f0..a44c333096 100644 --- a/Marlin/src/HAL/STM32/HAL.cpp +++ b/Marlin/src/HAL/STM32/HAL.cpp @@ -87,7 +87,7 @@ void MarlinHAL::init() { SetTimerInterruptPriorities(); - #if ENABLED(EMERGENCY_PARSER) && (USBD_USE_CDC || USBD_USE_CDC_MSC) + #if ENABLED(EMERGENCY_PARSER) && ANY(USBD_USE_CDC, USBD_USE_CDC_MSC) USB_Hook_init(); #endif diff --git a/Marlin/src/HAL/STM32/usb_serial.cpp b/Marlin/src/HAL/STM32/usb_serial.cpp index 0b2372f3a7..1ca8b19976 100644 --- a/Marlin/src/HAL/STM32/usb_serial.cpp +++ b/Marlin/src/HAL/STM32/usb_serial.cpp @@ -26,7 +26,7 @@ #include "../../inc/MarlinConfigPre.h" -#if ENABLED(EMERGENCY_PARSER) && (USBD_USE_CDC || USBD_USE_CDC_MSC) +#if ENABLED(EMERGENCY_PARSER) && ANY(USBD_USE_CDC, USBD_USE_CDC_MSC) #include "usb_serial.h" #include "../../feature/e_parser.h" @@ -56,5 +56,5 @@ void USB_Hook_init() { USBD_CDC_fops.Receive = USBD_CDC_Receive_hook; } -#endif // EMERGENCY_PARSER && USBD_USE_CDC +#endif // EMERGENCY_PARSER && (USBD_USE_CDC || USBD_USE_CDC_MSC) #endif // HAL_STM32 diff --git a/Marlin/src/HAL/STM32F1/HAL.cpp b/Marlin/src/HAL/STM32F1/HAL.cpp index d5f4ade79d..4072e55652 100644 --- a/Marlin/src/HAL/STM32F1/HAL.cpp +++ b/Marlin/src/HAL/STM32F1/HAL.cpp @@ -65,7 +65,8 @@ uint16_t adc_results[ADC_COUNT]; emergency_parser.update(MSerial0.emergency_state, buf[i + total - len]); } #endif -#endif + +#endif // SERIAL_USB && !HAS_SD_HOST_DRIVE // ------------------------ // Watchdog Timer diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs2/usbhost.cpp b/Marlin/src/sd/usb_flashdrive/lib-uhs2/usbhost.cpp index fd3849d1ed..6f3d44dd7f 100644 --- a/Marlin/src/sd/usb_flashdrive/lib-uhs2/usbhost.cpp +++ b/Marlin/src/sd/usb_flashdrive/lib-uhs2/usbhost.cpp @@ -109,7 +109,7 @@ bool MAX3421e::start() { // Initialize pins and SPI bus SET_OUTPUT(USB_CS_PIN); - SET_INPUT_PULLUP(USB_INTR_PIN); + SET_INPUT_PULLUP(USB_INTR_PIN); // Active LOW ncs(); spiBegin(); diff --git a/ini/stm32f1-maple.ini b/ini/stm32f1-maple.ini index 0e77ff8dfa..ddd75549c8 100644 --- a/ini/stm32f1-maple.ini +++ b/ini/stm32f1-maple.ini @@ -219,7 +219,7 @@ board_build.address = 0x08010000 board_build.rename = project.bin board_build.ldscript = STM32F103VE_longer.ld build_flags = ${STM32F1_maple.build_flags} - -DMCU_STM32F103VE -DSTM32F1xx -USERIAL_USB -DU20 -DTS_V12 + -DMCU_STM32F103VE -DSTM32F1xx -DSERIAL_USB -DU20 -DTS_V12 build_unflags = ${STM32F1_maple.build_unflags} -DCONFIG_MAPLE_MINI_NO_DISABLE_DEBUG=1 -DERROR_LED_PORT=GPIOE -DERROR_LED_PIN=6 diff --git a/ini/stm32f1.ini b/ini/stm32f1.ini index ed60983a23..58b33afaaf 100644 --- a/ini/stm32f1.ini +++ b/ini/stm32f1.ini @@ -64,13 +64,14 @@ board_build.offset = 0x7000 board_upload.offset_address = 0x08007000 [USBD_CDC_MSC] -build_flags = -DUSE_USB_FS -DUSBD_USE_CDC_MSC -DUSBD_IRQ_PRIO=5 -DUSBD_IRQ_SUBPRIO=6 +build_flags = -DUSE_USB_FS -DUSBD_USE_CDC_MSC -DUSBD_IRQ_PRIO=5 -DUSBD_IRQ_SUBPRIO=6 +build_unflags = -DUSBD_USE_CDC [env:STM32F103RC_btt_USB] extends = env:STM32F103RC_btt platform_packages = ${stm_flash_drive.platform_packages} build_flags = ${env:STM32F103RC_btt.build_flags} ${USBD_CDC_MSC.build_flags} -build_unflags = ${env:STM32F103RC_btt.build_unflags} -DUSBD_USE_CDC +build_unflags = ${env:STM32F103RC_btt.build_unflags} ${USBD_CDC_MSC.build_unflags} # # Panda Pi V2.9 - Standalone (STM32F103RC) @@ -227,7 +228,7 @@ upload_protocol = jlink extends = env:STM32F103RE_btt platform_packages = ${stm_flash_drive.platform_packages} build_flags = ${env:STM32F103RE_btt.build_flags} ${USBD_CDC_MSC.build_flags} -build_unflags = ${env:STM32F103RE_btt.build_unflags} -DUSBD_USE_CDC +build_unflags = ${env:STM32F103RE_btt.build_unflags} ${USBD_CDC_MSC.build_unflags} # # ZNP Robin Nano V1.2 @@ -473,7 +474,7 @@ board_upload.maximum_size = 237568 extra_scripts = ${stm32_variant.extra_scripts} build_flags = ${stm32_variant.build_flags} ${USBD_CDC_MSC.build_flags} -DSS_TIMER=4 -DTIMER_SERVO=TIM5 -build_unflags = ${stm32_variant.build_unflags} -DUSBD_USE_CDC +build_unflags = ${stm32_variant.build_unflags} ${USBD_CDC_MSC.build_unflags} [env:STM32F103RC_ZM3E2_USB] extends = ZONESTAR_ZM3E From 75d60b77bac5300e38725c0aae6f788b70ef085b Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Sun, 27 Apr 2025 00:37:52 +0000 Subject: [PATCH 259/787] [cron] Bump distribution date (2025-04-27) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index c96f304a03..d48398ed22 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-04-25" +//#define STRING_DISTRIBUTION_DATE "2025-04-27" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 43e63deb20..f3a12580c9 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-04-25" + #define STRING_DISTRIBUTION_DATE "2025-04-27" #endif /** From 4d8f82df328016c1b325520d9af10d25e3a86aee Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sun, 27 Apr 2025 15:02:58 -0500 Subject: [PATCH 260/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Org?= =?UTF-8?q?anize=20some=20HAL=20code?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/HAL/AVR/HAL.h | 2 +- Marlin/src/HAL/DUE/usb/ctrl_access.c | 4 ++-- Marlin/src/HAL/ESP32/HAL.cpp | 10 ++++------ Marlin/src/HAL/ESP32/HAL.h | 8 +++----- Marlin/src/HAL/ESP32/u8g_esp32_spi.cpp | 2 +- Marlin/src/HAL/ESP32/{ => wifi}/WebSocketSerial.cpp | 2 +- Marlin/src/HAL/ESP32/{ => wifi}/WebSocketSerial.h | 4 ++-- Marlin/src/HAL/ESP32/{ => wifi}/ota.cpp | 2 +- Marlin/src/HAL/ESP32/{ => wifi}/ota.h | 0 Marlin/src/HAL/ESP32/{ => wifi}/spiffs.cpp | 4 ++-- Marlin/src/HAL/ESP32/{ => wifi}/spiffs.h | 0 Marlin/src/HAL/ESP32/{ => wifi}/web.cpp | 4 ++-- Marlin/src/HAL/ESP32/{ => wifi}/web.h | 0 Marlin/src/HAL/ESP32/{ => wifi}/wifi.cpp | 4 ++-- Marlin/src/HAL/ESP32/{ => wifi}/wifi.h | 0 Marlin/src/HAL/GD32_MFL/{ => sd}/SDCard.cpp | 6 +++--- Marlin/src/HAL/GD32_MFL/{ => sd}/SDCard.h | 4 ++-- Marlin/src/HAL/GD32_MFL/{ => sd}/sdio.cpp | 6 ++---- Marlin/src/HAL/GD32_MFL/{ => sd}/sdio.h | 0 Marlin/src/HAL/HAL.h | 2 +- Marlin/src/HAL/LINUX/HAL.h | 2 +- Marlin/src/HAL/LINUX/arduino.cpp | 2 -- Marlin/src/HAL/LINUX/include/Arduino.h | 1 - Marlin/src/HAL/NATIVE_SIM/HAL.h | 2 +- Marlin/src/HAL/RP2040/HAL.cpp | 2 +- Marlin/src/HAL/RP2040/HAL.h | 2 +- Marlin/src/HAL/STM32/HAL.cpp | 6 +++--- Marlin/src/HAL/STM32/HAL.h | 8 ++------ Marlin/src/HAL/STM32/{ => sd}/msc_sd.cpp | 11 +++++------ Marlin/src/HAL/STM32/{ => sd}/msc_sd.h | 0 Marlin/src/HAL/STM32/{ => sd}/usb_host.cpp | 9 ++++----- Marlin/src/HAL/STM32/{ => sd}/usb_host.h | 0 Marlin/src/HAL/STM32F1/HAL.cpp | 2 +- Marlin/src/HAL/STM32F1/HAL.h | 2 +- Marlin/src/HAL/STM32F1/{ => sd}/msc_sd.cpp | 9 +++++---- Marlin/src/HAL/STM32F1/{ => sd}/msc_sd.h | 4 ++-- Marlin/src/HAL/STM32F1/{ => sd}/onboard_sd.cpp | 6 +++--- Marlin/src/HAL/STM32F1/{ => sd}/onboard_sd.h | 0 Marlin/src/HAL/STM32F1/{ => sd}/sdio.cpp | 6 +++--- Marlin/src/HAL/STM32F1/{ => sd}/sdio.h | 2 +- Marlin/src/HAL/shared/math_32bit.h | 1 + Marlin/src/inc/MarlinConfig.h | 1 - Marlin/src/inc/MarlinConfigPre-6-type.h | 1 - Marlin/src/sd/usb_flashdrive/Sd2Card_FlashDrive.cpp | 6 +++--- Marlin/src/sd/usb_flashdrive/lib-uhs2/Usb.cpp | 4 ++-- Marlin/src/sd/usb_flashdrive/lib-uhs2/masstorage.cpp | 4 ++-- Marlin/src/sd/usb_flashdrive/lib-uhs2/message.cpp | 4 ++-- Marlin/src/sd/usb_flashdrive/lib-uhs2/parsetools.cpp | 4 ++-- Marlin/src/sd/usb_flashdrive/lib-uhs2/usbhost.cpp | 4 ++-- 49 files changed, 77 insertions(+), 92 deletions(-) rename Marlin/src/HAL/ESP32/{ => wifi}/WebSocketSerial.cpp (99%) rename Marlin/src/HAL/ESP32/{ => wifi}/WebSocketSerial.h (96%) rename Marlin/src/HAL/ESP32/{ => wifi}/ota.cpp (98%) rename Marlin/src/HAL/ESP32/{ => wifi}/ota.h (100%) rename Marlin/src/HAL/ESP32/{ => wifi}/spiffs.cpp (94%) rename Marlin/src/HAL/ESP32/{ => wifi}/spiffs.h (100%) rename Marlin/src/HAL/ESP32/{ => wifi}/web.cpp (94%) rename Marlin/src/HAL/ESP32/{ => wifi}/web.h (100%) rename Marlin/src/HAL/ESP32/{ => wifi}/wifi.cpp (96%) rename Marlin/src/HAL/ESP32/{ => wifi}/wifi.h (100%) rename Marlin/src/HAL/GD32_MFL/{ => sd}/SDCard.cpp (99%) rename Marlin/src/HAL/GD32_MFL/{ => sd}/SDCard.h (99%) rename Marlin/src/HAL/GD32_MFL/{ => sd}/sdio.cpp (98%) rename Marlin/src/HAL/GD32_MFL/{ => sd}/sdio.h (100%) rename Marlin/src/HAL/STM32/{ => sd}/msc_sd.cpp (96%) rename Marlin/src/HAL/STM32/{ => sd}/msc_sd.h (100%) rename Marlin/src/HAL/STM32/{ => sd}/usb_host.cpp (96%) rename Marlin/src/HAL/STM32/{ => sd}/usb_host.h (100%) rename Marlin/src/HAL/STM32F1/{ => sd}/msc_sd.cpp (96%) rename Marlin/src/HAL/STM32F1/{ => sd}/msc_sd.h (93%) rename Marlin/src/HAL/STM32F1/{ => sd}/onboard_sd.cpp (99%) rename Marlin/src/HAL/STM32F1/{ => sd}/onboard_sd.h (100%) rename Marlin/src/HAL/STM32F1/{ => sd}/sdio.cpp (98%) rename Marlin/src/HAL/STM32F1/{ => sd}/sdio.h (98%) diff --git a/Marlin/src/HAL/AVR/HAL.h b/Marlin/src/HAL/AVR/HAL.h index b420236956..e7a82a3b83 100644 --- a/Marlin/src/HAL/AVR/HAL.h +++ b/Marlin/src/HAL/AVR/HAL.h @@ -204,7 +204,7 @@ public: static void isr_on() { sei(); } static void isr_off() { cli(); } - static void delay_ms(const int ms) { _delay_ms(ms); } + static void delay_ms(const int ms) { delay(ms); } // Tasks, called from idle() static void idletask() {} diff --git a/Marlin/src/HAL/DUE/usb/ctrl_access.c b/Marlin/src/HAL/DUE/usb/ctrl_access.c index b766ed1273..ec0e4adc4b 100644 --- a/Marlin/src/HAL/DUE/usb/ctrl_access.c +++ b/Marlin/src/HAL/DUE/usb/ctrl_access.c @@ -63,8 +63,8 @@ #include "compiler.h" #include "preprocessor.h" #ifdef FREERTOS_USED -#include "FreeRTOS.h" -#include "semphr.h" +#include +#include #endif #include "ctrl_access.h" diff --git a/Marlin/src/HAL/ESP32/HAL.cpp b/Marlin/src/HAL/ESP32/HAL.cpp index 415e2510e2..705b856aaa 100644 --- a/Marlin/src/HAL/ESP32/HAL.cpp +++ b/Marlin/src/HAL/ESP32/HAL.cpp @@ -34,13 +34,13 @@ #if ENABLED(WIFISUPPORT) #include - #include "wifi.h" + #include "wifi/wifi.h" #if ENABLED(OTASUPPORT) - #include "ota.h" + #include "wifi/ota.h" #endif #if ENABLED(WEBSUPPORT) - #include "spiffs.h" - #include "web.h" + #include "wifi/spiffs.h" + #include "wifi/web.h" #endif #endif @@ -175,8 +175,6 @@ uint8_t MarlinHAL::get_reset_source() { return rtc_get_reset_reason(1); } void MarlinHAL::reboot() { ESP.restart(); } -void _delay_ms(const int ms) { delay(ms); } - // return free memory between end of heap (or end bss) and whatever is current int MarlinHAL::freeMemory() { return ESP.getFreeHeap(); } diff --git a/Marlin/src/HAL/ESP32/HAL.h b/Marlin/src/HAL/ESP32/HAL.h index 0acb3676a2..baa03d8a76 100644 --- a/Marlin/src/HAL/ESP32/HAL.h +++ b/Marlin/src/HAL/ESP32/HAL.h @@ -37,11 +37,11 @@ #include "i2s.h" #if ENABLED(WIFISUPPORT) - #include "WebSocketSerial.h" + #include "wifi/WebSocketSerial.h" #endif #if ENABLED(ESP3D_WIFISUPPORT) - #include "esp3dlib.h" + #include #endif #include "FlushableHardwareSerial.h" @@ -165,8 +165,6 @@ int freeMemory(); #pragma GCC diagnostic pop -void _delay_ms(const int ms); - // ------------------------ // MarlinHAL Class // ------------------------ @@ -194,7 +192,7 @@ public: static void isr_on() { if (spinlock.owner != portMUX_FREE_VAL) portEXIT_CRITICAL(&spinlock); } static void isr_off() { portENTER_CRITICAL(&spinlock); } - static void delay_ms(const int ms) { _delay_ms(ms); } + static void delay_ms(const int ms) { delay(ms); } // Tasks, called from idle() static void idletask(); diff --git a/Marlin/src/HAL/ESP32/u8g_esp32_spi.cpp b/Marlin/src/HAL/ESP32/u8g_esp32_spi.cpp index a4c1980adc..42903da9d3 100644 --- a/Marlin/src/HAL/ESP32/u8g_esp32_spi.cpp +++ b/Marlin/src/HAL/ESP32/u8g_esp32_spi.cpp @@ -35,7 +35,7 @@ #if HAS_MEDIA #include "../../sd/cardreader.h" #if ENABLED(ESP3D_WIFISUPPORT) - #include "sd_ESP32.h" + #include #endif #endif diff --git a/Marlin/src/HAL/ESP32/WebSocketSerial.cpp b/Marlin/src/HAL/ESP32/wifi/WebSocketSerial.cpp similarity index 99% rename from Marlin/src/HAL/ESP32/WebSocketSerial.cpp rename to Marlin/src/HAL/ESP32/wifi/WebSocketSerial.cpp index eb5b9d6039..9c8933289d 100644 --- a/Marlin/src/HAL/ESP32/WebSocketSerial.cpp +++ b/Marlin/src/HAL/ESP32/wifi/WebSocketSerial.cpp @@ -21,7 +21,7 @@ */ #ifdef ARDUINO_ARCH_ESP32 -#include "../../inc/MarlinConfigPre.h" +#include "../../../inc/MarlinConfigPre.h" #if ENABLED(WIFISUPPORT) diff --git a/Marlin/src/HAL/ESP32/WebSocketSerial.h b/Marlin/src/HAL/ESP32/wifi/WebSocketSerial.h similarity index 96% rename from Marlin/src/HAL/ESP32/WebSocketSerial.h rename to Marlin/src/HAL/ESP32/wifi/WebSocketSerial.h index 6b3e419d10..3d2fdf1e6a 100644 --- a/Marlin/src/HAL/ESP32/WebSocketSerial.h +++ b/Marlin/src/HAL/ESP32/wifi/WebSocketSerial.h @@ -21,8 +21,8 @@ */ #pragma once -#include "../../inc/MarlinConfig.h" -#include "../../core/serial_hook.h" +#include "../../../inc/MarlinConfig.h" +#include "../../../core/serial_hook.h" #include diff --git a/Marlin/src/HAL/ESP32/ota.cpp b/Marlin/src/HAL/ESP32/wifi/ota.cpp similarity index 98% rename from Marlin/src/HAL/ESP32/ota.cpp rename to Marlin/src/HAL/ESP32/wifi/ota.cpp index be5847b831..03508840a5 100644 --- a/Marlin/src/HAL/ESP32/ota.cpp +++ b/Marlin/src/HAL/ESP32/wifi/ota.cpp @@ -27,7 +27,7 @@ #undef ENABLED #undef DISABLED -#include "../../inc/MarlinConfigPre.h" +#include "../../../inc/MarlinConfigPre.h" #if ALL(WIFISUPPORT, OTASUPPORT) diff --git a/Marlin/src/HAL/ESP32/ota.h b/Marlin/src/HAL/ESP32/wifi/ota.h similarity index 100% rename from Marlin/src/HAL/ESP32/ota.h rename to Marlin/src/HAL/ESP32/wifi/ota.h diff --git a/Marlin/src/HAL/ESP32/spiffs.cpp b/Marlin/src/HAL/ESP32/wifi/spiffs.cpp similarity index 94% rename from Marlin/src/HAL/ESP32/spiffs.cpp rename to Marlin/src/HAL/ESP32/wifi/spiffs.cpp index 043ad7849a..ba891acda9 100644 --- a/Marlin/src/HAL/ESP32/spiffs.cpp +++ b/Marlin/src/HAL/ESP32/wifi/spiffs.cpp @@ -21,11 +21,11 @@ */ #ifdef ARDUINO_ARCH_ESP32 -#include "../../inc/MarlinConfigPre.h" +#include "../../../inc/MarlinConfigPre.h" #if ALL(WIFISUPPORT, WEBSUPPORT) -#include "../../core/serial.h" +#include "../../../core/serial.h" #include #include diff --git a/Marlin/src/HAL/ESP32/spiffs.h b/Marlin/src/HAL/ESP32/wifi/spiffs.h similarity index 100% rename from Marlin/src/HAL/ESP32/spiffs.h rename to Marlin/src/HAL/ESP32/wifi/spiffs.h diff --git a/Marlin/src/HAL/ESP32/web.cpp b/Marlin/src/HAL/ESP32/wifi/web.cpp similarity index 94% rename from Marlin/src/HAL/ESP32/web.cpp rename to Marlin/src/HAL/ESP32/wifi/web.cpp index 63a101595f..f08dfd87c0 100644 --- a/Marlin/src/HAL/ESP32/web.cpp +++ b/Marlin/src/HAL/ESP32/wifi/web.cpp @@ -21,11 +21,11 @@ */ #ifdef ARDUINO_ARCH_ESP32 -#include "../../inc/MarlinConfigPre.h" +#include "../../../inc/MarlinConfigPre.h" #if ALL(WIFISUPPORT, WEBSUPPORT) -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #undef DISABLED // esp32-hal-gpio.h #include diff --git a/Marlin/src/HAL/ESP32/web.h b/Marlin/src/HAL/ESP32/wifi/web.h similarity index 100% rename from Marlin/src/HAL/ESP32/web.h rename to Marlin/src/HAL/ESP32/wifi/web.h diff --git a/Marlin/src/HAL/ESP32/wifi.cpp b/Marlin/src/HAL/ESP32/wifi/wifi.cpp similarity index 96% rename from Marlin/src/HAL/ESP32/wifi.cpp rename to Marlin/src/HAL/ESP32/wifi/wifi.cpp index aa2796adea..1f31ca1bb9 100644 --- a/Marlin/src/HAL/ESP32/wifi.cpp +++ b/Marlin/src/HAL/ESP32/wifi/wifi.cpp @@ -21,11 +21,11 @@ */ #ifdef ARDUINO_ARCH_ESP32 -#include "../../inc/MarlinConfigPre.h" +#include "../../../inc/MarlinConfigPre.h" #if ENABLED(WIFISUPPORT) -#include "../../core/serial.h" +#include "../../../core/serial.h" #include #include diff --git a/Marlin/src/HAL/ESP32/wifi.h b/Marlin/src/HAL/ESP32/wifi/wifi.h similarity index 100% rename from Marlin/src/HAL/ESP32/wifi.h rename to Marlin/src/HAL/ESP32/wifi/wifi.h diff --git a/Marlin/src/HAL/GD32_MFL/SDCard.cpp b/Marlin/src/HAL/GD32_MFL/sd/SDCard.cpp similarity index 99% rename from Marlin/src/HAL/GD32_MFL/SDCard.cpp rename to Marlin/src/HAL/GD32_MFL/sd/SDCard.cpp index 15d33d2596..c46e0fc6fb 100644 --- a/Marlin/src/HAL/GD32_MFL/SDCard.cpp +++ b/Marlin/src/HAL/GD32_MFL/sd/SDCard.cpp @@ -15,12 +15,12 @@ // If not, see . // -#include "../platforms.h" +#include "../../platforms.h" #ifdef ARDUINO_ARCH_MFL -#include "../../inc/MarlinConfig.h" -#include "../shared/Delay.h" +#include "../../../inc/MarlinConfig.h" +#include "../../shared/Delay.h" #include "SDCard.h" #include diff --git a/Marlin/src/HAL/GD32_MFL/SDCard.h b/Marlin/src/HAL/GD32_MFL/sd/SDCard.h similarity index 99% rename from Marlin/src/HAL/GD32_MFL/SDCard.h rename to Marlin/src/HAL/GD32_MFL/sd/SDCard.h index 467482a605..e202be6eb5 100644 --- a/Marlin/src/HAL/GD32_MFL/SDCard.h +++ b/Marlin/src/HAL/GD32_MFL/sd/SDCard.h @@ -16,9 +16,9 @@ // #pragma once -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" -#include "SDIO.hpp" +#include namespace sdio { diff --git a/Marlin/src/HAL/GD32_MFL/sdio.cpp b/Marlin/src/HAL/GD32_MFL/sd/sdio.cpp similarity index 98% rename from Marlin/src/HAL/GD32_MFL/sdio.cpp rename to Marlin/src/HAL/GD32_MFL/sd/sdio.cpp index 4b6d75d74f..69905feb51 100644 --- a/Marlin/src/HAL/GD32_MFL/sdio.cpp +++ b/Marlin/src/HAL/GD32_MFL/sd/sdio.cpp @@ -20,11 +20,11 @@ * */ -#include "../platforms.h" +#include "../../platforms.h" #ifdef ARDUINO_ARCH_MFL -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ENABLED(ONBOARD_SDIO) @@ -215,7 +215,6 @@ void DMA1_IRQHandler() { } } - extern "C" { void SDIO_IRQHandler(void) { @@ -228,6 +227,5 @@ extern "C" { } // extern "C" - #endif // ONBOARD_SDIO #endif // ARDUINO_ARCH_MFL diff --git a/Marlin/src/HAL/GD32_MFL/sdio.h b/Marlin/src/HAL/GD32_MFL/sd/sdio.h similarity index 100% rename from Marlin/src/HAL/GD32_MFL/sdio.h rename to Marlin/src/HAL/GD32_MFL/sd/sdio.h diff --git a/Marlin/src/HAL/HAL.h b/Marlin/src/HAL/HAL.h index f3e16cfdf1..a211dfe259 100644 --- a/Marlin/src/HAL/HAL.h +++ b/Marlin/src/HAL/HAL.h @@ -27,7 +27,7 @@ #define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) #endif -#include HAL_PATH(..,HAL.h) +#include HAL_PATH(.., HAL.h) extern MarlinHAL hal; #define HAL_ADC_RANGE _BV(HAL_ADC_RESOLUTION) diff --git a/Marlin/src/HAL/LINUX/HAL.h b/Marlin/src/HAL/LINUX/HAL.h index bb5fb73e05..68e0e1062c 100644 --- a/Marlin/src/HAL/LINUX/HAL.h +++ b/Marlin/src/HAL/LINUX/HAL.h @@ -124,7 +124,7 @@ public: static void isr_on() {} static void isr_off() {} - static void delay_ms(const int ms) { _delay_ms(ms); } + static void delay_ms(const int ms) { delay(ms); } // Tasks, called from idle() static void idletask() {} diff --git a/Marlin/src/HAL/LINUX/arduino.cpp b/Marlin/src/HAL/LINUX/arduino.cpp index a387a9623e..0a09a11091 100644 --- a/Marlin/src/HAL/LINUX/arduino.cpp +++ b/Marlin/src/HAL/LINUX/arduino.cpp @@ -31,8 +31,6 @@ void cli() { } // Disable void sei() { } // Enable // Time functions -void _delay_ms(const int ms) { delay(ms); } - unsigned long millis() { return (unsigned long)Clock::millis(); } diff --git a/Marlin/src/HAL/LINUX/include/Arduino.h b/Marlin/src/HAL/LINUX/include/Arduino.h index b11e75ccbc..87148a40b2 100644 --- a/Marlin/src/HAL/LINUX/include/Arduino.h +++ b/Marlin/src/HAL/LINUX/include/Arduino.h @@ -74,7 +74,6 @@ extern "C" { // Time functions extern "C" void delay(const int ms); -void _delay_ms(const int ms); void delayMicroseconds(unsigned long); unsigned long millis(); diff --git a/Marlin/src/HAL/NATIVE_SIM/HAL.h b/Marlin/src/HAL/NATIVE_SIM/HAL.h index ffede7ef34..661c502f22 100644 --- a/Marlin/src/HAL/NATIVE_SIM/HAL.h +++ b/Marlin/src/HAL/NATIVE_SIM/HAL.h @@ -195,7 +195,7 @@ public: static void isr_on() {} static void isr_off() {} - static void delay_ms(const int ms) { _delay_ms(ms); } + static void delay_ms(const int ms) { delay(ms); } // Tasks, called from idle() static void idletask(); diff --git a/Marlin/src/HAL/RP2040/HAL.cpp b/Marlin/src/HAL/RP2040/HAL.cpp index 6e35fac938..8c35d45542 100644 --- a/Marlin/src/HAL/RP2040/HAL.cpp +++ b/Marlin/src/HAL/RP2040/HAL.cpp @@ -87,7 +87,7 @@ void MarlinHAL::init() { #if PIN_EXISTS(USB_CONNECT) OUT_WRITE(USB_CONNECT_PIN, !USB_CONNECT_INVERTING); // USB clear connection - delay_ms(1000); // Give OS time to notice + delay_ms(1000); // Give OS time to notice WRITE(USB_CONNECT_PIN, USB_CONNECT_INVERTING); #endif } diff --git a/Marlin/src/HAL/RP2040/HAL.h b/Marlin/src/HAL/RP2040/HAL.h index fbd3b61e1c..4862986d11 100644 --- a/Marlin/src/HAL/RP2040/HAL.h +++ b/Marlin/src/HAL/RP2040/HAL.h @@ -139,7 +139,7 @@ public: static void isr_on() { __enable_irq(); } static void isr_off() { __disable_irq(); } - static void delay_ms(const int ms) { ::delay(ms); } + static void delay_ms(const int ms) { delay(ms); } // Tasks, called from idle() static void idletask() {} diff --git a/Marlin/src/HAL/STM32/HAL.cpp b/Marlin/src/HAL/STM32/HAL.cpp index a44c333096..bdccdd546d 100644 --- a/Marlin/src/HAL/STM32/HAL.cpp +++ b/Marlin/src/HAL/STM32/HAL.cpp @@ -43,8 +43,8 @@ #endif #if HAS_SD_HOST_DRIVE - #include "msc_sd.h" - #include "usbd_cdc_if.h" + #include "sd/msc_sd.h" + #include #endif // ------------------------ @@ -97,7 +97,7 @@ void MarlinHAL::init() { #if PIN_EXISTS(USB_CONNECT) OUT_WRITE(USB_CONNECT_PIN, !USB_CONNECT_INVERTING); // USB clear connection - delay(1000); // Give OS time to notice + delay_ms(1000); // Give OS time to notice WRITE(USB_CONNECT_PIN, USB_CONNECT_INVERTING); #endif } diff --git a/Marlin/src/HAL/STM32/HAL.h b/Marlin/src/HAL/STM32/HAL.h index f43413fcd9..a8ef51bcfc 100644 --- a/Marlin/src/HAL/STM32/HAL.h +++ b/Marlin/src/HAL/STM32/HAL.h @@ -23,18 +23,14 @@ #define CPU_32_BIT -#include "../../core/macros.h" -#include "../shared/Marduino.h" +#include "../../inc/MarlinConfigPre.h" + #include "../shared/math_32bit.h" #include "../shared/HAL_SPI.h" #include "temp_soc.h" #include "fastio.h" #include "Servo.h" -#include "../../inc/MarlinConfigPre.h" - -#include - // // Default graphical display delays // diff --git a/Marlin/src/HAL/STM32/msc_sd.cpp b/Marlin/src/HAL/STM32/sd/msc_sd.cpp similarity index 96% rename from Marlin/src/HAL/STM32/msc_sd.cpp rename to Marlin/src/HAL/STM32/sd/msc_sd.cpp index d4afc5990a..f198b3e49a 100644 --- a/Marlin/src/HAL/STM32/msc_sd.cpp +++ b/Marlin/src/HAL/STM32/sd/msc_sd.cpp @@ -20,20 +20,19 @@ * along with this program. If not, see . * */ -#include "../platforms.h" +#include "../../platforms.h" #ifdef HAL_STM32 -#include "../../inc/MarlinConfigPre.h" +#include "../../../inc/MarlinConfigPre.h" #if HAS_SD_HOST_DRIVE -#include "../shared/Marduino.h" +#include "../../../sd/cardreader.h" + #include "msc_sd.h" -#include "usbd_core.h" - -#include "../../sd/cardreader.h" +#include #include #include diff --git a/Marlin/src/HAL/STM32/msc_sd.h b/Marlin/src/HAL/STM32/sd/msc_sd.h similarity index 100% rename from Marlin/src/HAL/STM32/msc_sd.h rename to Marlin/src/HAL/STM32/sd/msc_sd.h diff --git a/Marlin/src/HAL/STM32/usb_host.cpp b/Marlin/src/HAL/STM32/sd/usb_host.cpp similarity index 96% rename from Marlin/src/HAL/STM32/usb_host.cpp rename to Marlin/src/HAL/STM32/sd/usb_host.cpp index afafe1d4f3..f411771c8a 100644 --- a/Marlin/src/HAL/STM32/usb_host.cpp +++ b/Marlin/src/HAL/STM32/sd/usb_host.cpp @@ -20,18 +20,17 @@ * */ -#include "../platforms.h" +#include "../../platforms.h" #ifdef HAL_STM32 -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if ALL(USE_OTG_USB_HOST, USBHOST) #include "usb_host.h" -#include "../shared/Marduino.h" -#include "usbh_core.h" -#include "usbh_msc.h" +#include +#include USBH_HandleTypeDef hUsbHost; USBHost usb; diff --git a/Marlin/src/HAL/STM32/usb_host.h b/Marlin/src/HAL/STM32/sd/usb_host.h similarity index 100% rename from Marlin/src/HAL/STM32/usb_host.h rename to Marlin/src/HAL/STM32/sd/usb_host.h diff --git a/Marlin/src/HAL/STM32F1/HAL.cpp b/Marlin/src/HAL/STM32F1/HAL.cpp index 4072e55652..b0f86ae4ed 100644 --- a/Marlin/src/HAL/STM32F1/HAL.cpp +++ b/Marlin/src/HAL/STM32F1/HAL.cpp @@ -253,7 +253,7 @@ void MarlinHAL::init() { #endif #if PIN_EXISTS(USB_CONNECT) OUT_WRITE(USB_CONNECT_PIN, !USB_CONNECT_INVERTING); // USB clear connection - delay(1000); // Give OS time to notice + delay_ms(1000); // Give OS time to notice WRITE(USB_CONNECT_PIN, USB_CONNECT_INVERTING); #endif TERN_(POSTMORTEM_DEBUGGING, install_min_serial()); // Install the minimal serial handler diff --git a/Marlin/src/HAL/STM32F1/HAL.h b/Marlin/src/HAL/STM32F1/HAL.h index daf94dceb5..68773bdf27 100644 --- a/Marlin/src/HAL/STM32F1/HAL.h +++ b/Marlin/src/HAL/STM32F1/HAL.h @@ -40,7 +40,7 @@ #include "../../inc/MarlinConfigPre.h" #if HAS_SD_HOST_DRIVE - #include "msc_sd.h" + #include "sd/msc_sd.h" #endif // ------------------------ diff --git a/Marlin/src/HAL/STM32F1/msc_sd.cpp b/Marlin/src/HAL/STM32F1/sd/msc_sd.cpp similarity index 96% rename from Marlin/src/HAL/STM32F1/msc_sd.cpp rename to Marlin/src/HAL/STM32F1/sd/msc_sd.cpp index 067b46eb8b..5f1ba30c8a 100644 --- a/Marlin/src/HAL/STM32F1/msc_sd.cpp +++ b/Marlin/src/HAL/STM32F1/sd/msc_sd.cpp @@ -22,20 +22,21 @@ */ #ifdef __STM32F1__ -#include "../../inc/MarlinConfigPre.h" +#include "../../../inc/MarlinConfigPre.h" #if HAS_SD_HOST_DRIVE #include "msc_sd.h" -#include "SPI.h" -#include "usb_reg_map.h" +#include "../SPI.h" + +#include #define PRODUCT_ID 0x29 USBMassStorage MarlinMSC; Serial1Class MarlinCompositeSerial(true); -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if SD_CONNECTION_IS(ONBOARD) diff --git a/Marlin/src/HAL/STM32F1/msc_sd.h b/Marlin/src/HAL/STM32F1/sd/msc_sd.h similarity index 93% rename from Marlin/src/HAL/STM32F1/msc_sd.h rename to Marlin/src/HAL/STM32F1/sd/msc_sd.h index 371211efc6..871d98eaf2 100644 --- a/Marlin/src/HAL/STM32F1/msc_sd.h +++ b/Marlin/src/HAL/STM32F1/sd/msc_sd.h @@ -24,8 +24,8 @@ #include -#include "../../inc/MarlinConfigPre.h" -#include "../../core/serial_hook.h" +#include "../../../inc/MarlinConfigPre.h" +#include "../../../core/serial_hook.h" extern USBMassStorage MarlinMSC; extern Serial1Class MarlinCompositeSerial; diff --git a/Marlin/src/HAL/STM32F1/onboard_sd.cpp b/Marlin/src/HAL/STM32F1/sd/onboard_sd.cpp similarity index 99% rename from Marlin/src/HAL/STM32F1/onboard_sd.cpp rename to Marlin/src/HAL/STM32F1/sd/onboard_sd.cpp index a3d8dcb2d5..ace1204b75 100644 --- a/Marlin/src/HAL/STM32F1/onboard_sd.cpp +++ b/Marlin/src/HAL/STM32F1/sd/onboard_sd.cpp @@ -13,13 +13,13 @@ #ifdef __STM32F1__ -#include "../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfig.h" #if SD_CONNECTION_IS(ONBOARD) #include "onboard_sd.h" -#include "SPI.h" -#include "fastio.h" +#include "../SPI.h" +#include "../fastio.h" #ifndef ONBOARD_SPI_DEVICE #define ONBOARD_SPI_DEVICE SPI_DEVICE diff --git a/Marlin/src/HAL/STM32F1/onboard_sd.h b/Marlin/src/HAL/STM32F1/sd/onboard_sd.h similarity index 100% rename from Marlin/src/HAL/STM32F1/onboard_sd.h rename to Marlin/src/HAL/STM32F1/sd/onboard_sd.h diff --git a/Marlin/src/HAL/STM32F1/sdio.cpp b/Marlin/src/HAL/STM32F1/sd/sdio.cpp similarity index 98% rename from Marlin/src/HAL/STM32F1/sdio.cpp rename to Marlin/src/HAL/STM32F1/sd/sdio.cpp index 258422eba3..d657fd3b0e 100644 --- a/Marlin/src/HAL/STM32F1/sdio.cpp +++ b/Marlin/src/HAL/STM32F1/sd/sdio.cpp @@ -19,11 +19,11 @@ * along with this program. If not, see . * */ -#ifdef ARDUINO_ARCH_STM32F1 +#ifdef __STM32F1__ #include -#include "../../inc/MarlinConfig.h" // Allow pins/pins.h to set density +#include "../../../inc/MarlinConfig.h" // Allow pins/pins.h to set density #if ANY(STM32_HIGH_DENSITY, STM32_XL_DENSITY) @@ -308,4 +308,4 @@ bool SDIO_GetCmdResp7() { } #endif // STM32_HIGH_DENSITY || STM32_XL_DENSITY -#endif // ARDUINO_ARCH_STM32F1 +#endif // __STM32F1__ diff --git a/Marlin/src/HAL/STM32F1/sdio.h b/Marlin/src/HAL/STM32F1/sd/sdio.h similarity index 98% rename from Marlin/src/HAL/STM32F1/sdio.h rename to Marlin/src/HAL/STM32F1/sd/sdio.h index 08c884666d..ffcd354915 100644 --- a/Marlin/src/HAL/STM32F1/sdio.h +++ b/Marlin/src/HAL/STM32F1/sd/sdio.h @@ -21,7 +21,7 @@ */ #pragma once -#include "../../inc/MarlinConfig.h" // Allow pins/pins.h to override SDIO clock / retries +#include "../../../inc/MarlinConfig.h" // Allow pins/pins.h to override SDIO clock / retries #include #include diff --git a/Marlin/src/HAL/shared/math_32bit.h b/Marlin/src/HAL/shared/math_32bit.h index 1fb233e3e8..daf82e0650 100644 --- a/Marlin/src/HAL/shared/math_32bit.h +++ b/Marlin/src/HAL/shared/math_32bit.h @@ -22,6 +22,7 @@ #pragma once #include "../../core/macros.h" +#include /** * Math helper functions for 32 bit CPUs diff --git a/Marlin/src/inc/MarlinConfig.h b/Marlin/src/inc/MarlinConfig.h index 0164b7c2f7..f962a5ff5c 100644 --- a/Marlin/src/inc/MarlinConfig.h +++ b/Marlin/src/inc/MarlinConfig.h @@ -25,7 +25,6 @@ // Prefix header for all Marlin sources // -#include "MarlinConfigPre-6-type.h" // Include even with __MARLIN_DEPS__ #include "Conditionals-6-type.h" #ifndef __MARLIN_DEPS__ diff --git a/Marlin/src/inc/MarlinConfigPre-6-type.h b/Marlin/src/inc/MarlinConfigPre-6-type.h index 31597c6eb8..09367219d9 100644 --- a/Marlin/src/inc/MarlinConfigPre-6-type.h +++ b/Marlin/src/inc/MarlinConfigPre-6-type.h @@ -21,7 +21,6 @@ */ #pragma once -#include "MarlinConfigPre-5-post.h" #include "Conditionals-5-post.h" #ifndef __MARLIN_DEPS__ diff --git a/Marlin/src/sd/usb_flashdrive/Sd2Card_FlashDrive.cpp b/Marlin/src/sd/usb_flashdrive/Sd2Card_FlashDrive.cpp index e6e6f30ae6..8b25df16b9 100644 --- a/Marlin/src/sd/usb_flashdrive/Sd2Card_FlashDrive.cpp +++ b/Marlin/src/sd/usb_flashdrive/Sd2Card_FlashDrive.cpp @@ -84,10 +84,10 @@ #elif ENABLED(USE_OTG_USB_HOST) #if HAS_SD_HOST_DRIVE - #include HAL_PATH(../.., msc_sd.h) + #include HAL_PATH(../.., sd/msc_sd.h) #endif - #include HAL_PATH(../.., usb_host.h) + #include HAL_PATH(../.., sd/usb_host.h) #define UHS_START usb.start() #define rREVISION 0 @@ -293,7 +293,7 @@ uint32_t DiskIODriver_USBFlash::cardSize() { #if USB_DEBUG < 3 const uint32_t #endif - lun0_capacity = bulk.GetCapacity(0); + lun0_capacity = bulk.GetCapacity(0); return lun0_capacity; } diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs2/Usb.cpp b/Marlin/src/sd/usb_flashdrive/lib-uhs2/Usb.cpp index aa102e228f..6c45b7eee7 100644 --- a/Marlin/src/sd/usb_flashdrive/lib-uhs2/Usb.cpp +++ b/Marlin/src/sd/usb_flashdrive/lib-uhs2/Usb.cpp @@ -29,7 +29,7 @@ #include "../../../inc/MarlinConfigPre.h" -#if HAS_USB_FLASH_DRIVE && DISABLED(USE_UHS3_USB) +#if ALL(HAS_USB_FLASH_DRIVE, USE_UHS2_USB) #include "Usb.h" @@ -792,4 +792,4 @@ uint8_t USB::setConf(uint8_t addr, uint8_t ep, uint8_t conf_value) { return ctrlReq(addr, ep, bmREQ_SET, USB_REQUEST_SET_CONFIGURATION, conf_value, 0x00, 0x0000, 0x0000, 0x0000, nullptr, nullptr); } -#endif // HAS_USB_FLASH_DRIVE && !USE_UHS3_USB +#endif // HAS_USB_FLASH_DRIVE && USE_UHS2_USB diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs2/masstorage.cpp b/Marlin/src/sd/usb_flashdrive/lib-uhs2/masstorage.cpp index a6124ab0fe..c311d7f9dd 100644 --- a/Marlin/src/sd/usb_flashdrive/lib-uhs2/masstorage.cpp +++ b/Marlin/src/sd/usb_flashdrive/lib-uhs2/masstorage.cpp @@ -25,7 +25,7 @@ #include "../../../inc/MarlinConfigPre.h" -#if HAS_USB_FLASH_DRIVE && DISABLED(USE_UHS3_USB) +#if ALL(HAS_USB_FLASH_DRIVE, USE_UHS2_USB) #include "masstorage.h" @@ -1204,4 +1204,4 @@ uint8_t BulkOnly::Read(uint8_t lun __attribute__((unused)), uint32_t addr __attr #endif } -#endif // HAS_USB_FLASH_DRIVE && !USE_UHS3_USB +#endif // HAS_USB_FLASH_DRIVE && USE_UHS2_USB diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs2/message.cpp b/Marlin/src/sd/usb_flashdrive/lib-uhs2/message.cpp index afe9e86e52..2984a6cf03 100644 --- a/Marlin/src/sd/usb_flashdrive/lib-uhs2/message.cpp +++ b/Marlin/src/sd/usb_flashdrive/lib-uhs2/message.cpp @@ -25,7 +25,7 @@ #include "../../../inc/MarlinConfigPre.h" -#if HAS_USB_FLASH_DRIVE && DISABLED(USE_UHS3_USB) +#if ALL(HAS_USB_FLASH_DRIVE, USE_UHS2_USB) #include "Usb.h" @@ -125,4 +125,4 @@ void E_Notify(double d, int lvl) { #endif // DEBUG_USB_HOST -#endif // HAS_USB_FLASH_DRIVE && !USE_UHS3_USB +#endif // HAS_USB_FLASH_DRIVE && USE_UHS2_USB diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs2/parsetools.cpp b/Marlin/src/sd/usb_flashdrive/lib-uhs2/parsetools.cpp index 4b2ef4b1f9..ae34006742 100644 --- a/Marlin/src/sd/usb_flashdrive/lib-uhs2/parsetools.cpp +++ b/Marlin/src/sd/usb_flashdrive/lib-uhs2/parsetools.cpp @@ -25,7 +25,7 @@ #include "../../../inc/MarlinConfigPre.h" -#if HAS_USB_FLASH_DRIVE && DISABLED(USE_UHS3_USB) +#if ALL(HAS_USB_FLASH_DRIVE, USE_UHS2_USB) #include "Usb.h" @@ -74,4 +74,4 @@ bool PTPListParser::Parse(uint8_t **pp, uint16_t *pcntdn, PTP_ARRAY_EL_FUNC pf, return true; } -#endif // HAS_USB_FLASH_DRIVE && !USE_UHS3_USB +#endif // HAS_USB_FLASH_DRIVE && USE_UHS2_USB diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs2/usbhost.cpp b/Marlin/src/sd/usb_flashdrive/lib-uhs2/usbhost.cpp index 6f3d44dd7f..47282bbd63 100644 --- a/Marlin/src/sd/usb_flashdrive/lib-uhs2/usbhost.cpp +++ b/Marlin/src/sd/usb_flashdrive/lib-uhs2/usbhost.cpp @@ -25,7 +25,7 @@ #include "../../../inc/MarlinConfigPre.h" -#if HAS_USB_FLASH_DRIVE && DISABLED(USE_UHS3_USB) +#if ALL(HAS_USB_FLASH_DRIVE, USE_UHS2_USB) #if !PINS_EXIST(USB_CS, USB_INTR) #error "USB_FLASH_DRIVE_SUPPORT requires USB_CS_PIN and USB_INTR_PIN (or USE_UHS3_USB) to be defined." @@ -203,4 +203,4 @@ uint8_t MAX3421e::IntHandler() { return HIRQ_sendback; } -#endif // HAS_USB_FLASH_DRIVE && !USE_UHS3_USB +#endif // HAS_USB_FLASH_DRIVE && USE_UHS2_USB From 38d6d61912df9a5220acdffc4064b287b78dab90 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sun, 27 Apr 2025 18:50:35 -0500 Subject: [PATCH 261/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20MSC?= =?UTF-8?q?=20for=20RP2040=20-=20alpha?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/HAL/RP2040/HAL.h | 8 +- Marlin/src/HAL/RP2040/HAL_MinSerial.cpp | 1 - Marlin/src/HAL/RP2040/inc/Conditionals_adv.h | 2 +- Marlin/src/HAL/RP2040/msc_sd.cpp | 148 ++++++++----------- ini/raspberrypi.ini | 1 + 5 files changed, 64 insertions(+), 96 deletions(-) diff --git a/Marlin/src/HAL/RP2040/HAL.h b/Marlin/src/HAL/RP2040/HAL.h index 4862986d11..11472f72f5 100644 --- a/Marlin/src/HAL/RP2040/HAL.h +++ b/Marlin/src/HAL/RP2040/HAL.h @@ -29,16 +29,16 @@ #include "arduino_extras.h" #include "../../core/macros.h" -#include "../shared/Marduino.h" #include "../shared/math_32bit.h" #include "../shared/HAL_SPI.h" #include "fastio.h" -//#include "Servo.h" #include "watchdog.h" #include "../../inc/MarlinConfigPre.h" -#include +#if HAS_SD_HOST_DRIVE + #include "msc_sd.h" +#endif // // Serial Ports @@ -142,7 +142,7 @@ public: static void delay_ms(const int ms) { delay(ms); } // Tasks, called from idle() - static void idletask() {} + static void idletask() { TERN_(HAS_SD_HOST_DRIVE, tuh_task()); } // Reset static uint8_t get_reset_source(); diff --git a/Marlin/src/HAL/RP2040/HAL_MinSerial.cpp b/Marlin/src/HAL/RP2040/HAL_MinSerial.cpp index 5a65163591..d829edff24 100644 --- a/Marlin/src/HAL/RP2040/HAL_MinSerial.cpp +++ b/Marlin/src/HAL/RP2040/HAL_MinSerial.cpp @@ -29,7 +29,6 @@ #include "../shared/HAL_MinSerial.h" - static void TXBegin() { #if !WITHIN(SERIAL_PORT, -1, 2) #warning "Using POSTMORTEM_DEBUGGING requires a physical U(S)ART hardware in case of severe error." diff --git a/Marlin/src/HAL/RP2040/inc/Conditionals_adv.h b/Marlin/src/HAL/RP2040/inc/Conditionals_adv.h index 442639e130..b96b3baa64 100644 --- a/Marlin/src/HAL/RP2040/inc/Conditionals_adv.h +++ b/Marlin/src/HAL/RP2040/inc/Conditionals_adv.h @@ -21,7 +21,7 @@ */ #pragma once -#if ALL(SDSUPPORT, USBD_USE_CDC_MSC) && DISABLED(NO_SD_HOST_DRIVE) +#if HAS_MEDIA && DISABLED(NO_SD_HOST_DRIVE) #define HAS_SD_HOST_DRIVE 1 #endif diff --git a/Marlin/src/HAL/RP2040/msc_sd.cpp b/Marlin/src/HAL/RP2040/msc_sd.cpp index 58c900302d..b0de2241e5 100644 --- a/Marlin/src/HAL/RP2040/msc_sd.cpp +++ b/Marlin/src/HAL/RP2040/msc_sd.cpp @@ -27,109 +27,77 @@ #if HAS_SD_HOST_DRIVE -#include "../shared/Marduino.h" -#include "msc_sd.h" -#include "usbd_core.h" - #include "../../sd/cardreader.h" -#include -#include +#include // TinyUSB device stack #define BLOCK_SIZE 512 -#define PRODUCT_ID 0x29 +#define SD_MULTIBLOCK_RETRY_CNT 1 -class Sd2CardUSBMscHandler : public USBMscHandler { -public: - DiskIODriver* diskIODriver() { - #if HAS_MULTI_VOLUME - #if SHARED_VOLUME_IS(SD_ONBOARD) - return &card.media_driver_sdcard; - #elif SHARED_VOLUME_IS(USB_FLASH_DRIVE) - return &card.media_driver_usbFlash; - #endif - #else - return card.diskIODriver(); +DiskIODriver* diskIODriver() { + #if HAS_MULTI_VOLUME + #if SHARED_VOLUME_IS(SD_ONBOARD) + return &card.media_driver_sdcard; + #elif SHARED_VOLUME_IS(USB_FLASH_DRIVE) + return &card.media_driver_usbFlash; #endif - } + #else + return card.diskIODriver(); + #endif +} - bool GetCapacity(uint32_t *pBlockNum, uint16_t *pBlockSize) { - *pBlockNum = diskIODriver()->cardSize(); - *pBlockSize = BLOCK_SIZE; - return true; - } +/** Callbacks used by TinyUSB MSC **/ - bool Write(uint8_t *pBuf, uint32_t blkAddr, uint16_t blkLen) { - auto sd2card = diskIODriver(); - // single block - if (blkLen == 1) { - watchdog_refresh(); - sd2card->writeBlock(blkAddr, pBuf); - return true; +extern "C" { + +bool tud_msc_ready_cb(uint8_t lun) { + return diskIODriver()->isReady(); +} + +int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, void* buffer, uint32_t bufsize) { + const uint32_t blocks = bufsize / BLOCK_SIZE; + for (uint16_t rcount = SD_MULTIBLOCK_RETRY_CNT; rcount--; ) { + if (diskIODriver()->readBlocks(lba, (uint8_t*)buffer, blocks)) + return bufsize; // Success + } + return -1; // Failure after retries +} + +int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint8_t const* buffer, uint32_t bufsize) { + const uint32_t blocks = bufsize / BLOCK_SIZE; + for (uint16_t rcount = SD_MULTIBLOCK_RETRY_CNT; rcount--; ) { + if (diskIODriver()->writeBlocks(lba, buffer, blocks)) + return bufsize; // Success + } + return -1; // Failure after retries +} + +void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) { + memcpy(vendor_id, "MARLIN ", 8); + memcpy(product_id, "Product ", 16); + memcpy(product_rev, "0.01", 4); +} + +void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size) { + *block_count = diskIODriver()->cardSize(); + *block_size = BLOCK_SIZE; +} + +void tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject) { + if (load_eject) { + if (start) { + // Handle media load + } else { + // Handle media eject } - - // multi block optimization - sd2card->writeStart(blkAddr, blkLen); - while (blkLen--) { - watchdog_refresh(); - sd2card->writeData(pBuf); - pBuf += BLOCK_SIZE; - } - sd2card->writeStop(); - return true; } +} - bool Read(uint8_t *pBuf, uint32_t blkAddr, uint16_t blkLen) { - auto sd2card = diskIODriver(); - // single block - if (blkLen == 1) { - watchdog_refresh(); - sd2card->readBlock(blkAddr, pBuf); - return true; - } - - // multi block optimization - sd2card->readStart(blkAddr); - while (blkLen--) { - watchdog_refresh(); - sd2card->readData(pBuf); - pBuf += BLOCK_SIZE; - } - sd2card->readStop(); - return true; - } - - bool IsReady() { - return diskIODriver()->isReady(); - } -}; - -Sd2CardUSBMscHandler usbMscHandler; - -/* USB Mass storage Standard Inquiry Data */ -uint8_t Marlin_STORAGE_Inquirydata[] = { /* 36 */ - /* LUN 0 */ - 0x00, - 0x80, - 0x02, - 0x02, - (STANDARD_INQUIRY_DATA_LEN - 5), - 0x00, - 0x00, - 0x00, - 'M', 'A', 'R', 'L', 'I', 'N', ' ', ' ', /* Manufacturer : 8 bytes */ - 'P', 'r', 'o', 'd', 'u', 'c', 't', ' ', /* Product : 16 Bytes */ - ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', - '0', '.', '0', '1', /* Version : 4 Bytes */ -}; - -USBMscHandler *pSingleMscHandler = &usbMscHandler; +} // extern "C" void MSC_SD_init() { - USBDevice.end(); - delay(200); - USBDevice.registerMscHandlers(1, &pSingleMscHandler, Marlin_STORAGE_Inquirydata); - USBDevice.begin(); + tusb_init(); + // Add USB reinitialization logic if needed } #endif // HAS_SD_HOST_DRIVE diff --git a/ini/raspberrypi.ini b/ini/raspberrypi.ini index c61b89b461..059f4d1821 100644 --- a/ini/raspberrypi.ini +++ b/ini/raspberrypi.ini @@ -21,6 +21,7 @@ lib_ignore = WiFi build_flags = ${common.build_flags} -D__PLAT_RP2040__ -DPLATFORM_M997_SUPPORT -Wno-expansion-to-defined -Wno-vla -Wno-ignored-qualifiers #debug_tool = jlink #upload_protocol = jlink +custom_marlin.HAS_SD_HOST_DRIVE = tinyusb [env:RP2040-alt] extends = env:RP2040 From f78aaf956277bd73840a007a319ca487068f0683 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Thu, 24 Apr 2025 11:06:47 -0500 Subject: [PATCH 262/787] =?UTF-8?q?=F0=9F=9A=B8=20Detect=20multi-volume=20?= =?UTF-8?q?insert=20/=20remove?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/MarlinCore.cpp | 7 +- .../lcd/extui/anycubic_chiron/chiron_tft.cpp | 2 +- .../extui/mks_ui/tft_lvgl_configuration.cpp | 24 +-- Marlin/src/lcd/marlinui.cpp | 36 ++++- Marlin/src/lcd/marlinui.h | 2 +- Marlin/src/sd/cardreader.cpp | 152 ++++++++++++++---- Marlin/src/sd/cardreader.h | 11 ++ 7 files changed, 168 insertions(+), 66 deletions(-) diff --git a/Marlin/src/MarlinCore.cpp b/Marlin/src/MarlinCore.cpp index de6677fc9a..aa229e80b6 100644 --- a/Marlin/src/MarlinCore.cpp +++ b/Marlin/src/MarlinCore.cpp @@ -1349,8 +1349,11 @@ void setup() { #endif #endif - #if HAS_MEDIA && ANY(SDCARD_EEPROM_EMULATION, POWER_LOSS_RECOVERY) - SETUP_RUN(card.mount()); // Mount media with settings before first_load + #if HAS_MEDIA + SETUP_RUN(card.init()); // Prepare for media usage + #if ANY(SDCARD_EEPROM_EMULATION, POWER_LOSS_RECOVERY) + SETUP_RUN(card.mount()); // Mount media with settings before first_load + #endif #endif // Prepare some LCDs to display early diff --git a/Marlin/src/lcd/extui/anycubic_chiron/chiron_tft.cpp b/Marlin/src/lcd/extui/anycubic_chiron/chiron_tft.cpp index e6e8c88155..b4e1978283 100644 --- a/Marlin/src/lcd/extui/anycubic_chiron/chiron_tft.cpp +++ b/Marlin/src/lcd/extui/anycubic_chiron/chiron_tft.cpp @@ -740,7 +740,7 @@ void ChironTFT::panelAction(uint8_t req) { break; case 26: // A26 Refresh SD - if (card.isMounted())card.release(); + card.release(); card.mount(); safe_delay(500); filenavigator.reset(); diff --git a/Marlin/src/lcd/extui/mks_ui/tft_lvgl_configuration.cpp b/Marlin/src/lcd/extui/mks_ui/tft_lvgl_configuration.cpp index 729d8bc4b2..903afad884 100644 --- a/Marlin/src/lcd/extui/mks_ui/tft_lvgl_configuration.cpp +++ b/Marlin/src/lcd/extui/mks_ui/tft_lvgl_configuration.cpp @@ -131,32 +131,16 @@ void tft_lvgl_init() { // Init TFT first! SPI_TFT.spiInit(SPI_FULL_SPEED); SPI_TFT.lcdInit(); - hal.watchdog_refresh(); // LVGL init takes time - #if HAS_USB_FLASH_DRIVE - #if HAS_MULTI_VOLUME && !HAS_SD_HOST_DRIVE - if (card.isSDCardInserted()) - card.selectMediaSDCard(); - else - card.selectMediaFlashDrive(); - #endif - // Wait up to two seconds for USB Drive to mount - for (uint16_t usb_flash_loop = 500; --usb_flash_loop;) { - hal.watchdog_refresh(); - card.media_driver_usbFlash.idle(); - delay(4); - if (card.media_driver_usbFlash.isInserted()) break; - } - card.mount(); - #elif HAS_LOGO_IN_FLASH + #if HAS_LOGO_IN_FLASH + // Leave the boot screen visible for a moment delay(1000); - hal.watchdog_refresh(); + hal.watchdog_refresh(); // LVGL init takes time delay(1000); + hal.watchdog_refresh(); // LVGL init takes time #endif - hal.watchdog_refresh(); // LVGL init takes time - #if HAS_MEDIA UpdateAssets(); hal.watchdog_refresh(); // LVGL init takes time diff --git a/Marlin/src/lcd/marlinui.cpp b/Marlin/src/lcd/marlinui.cpp index f6b1b60c7d..2b730581c8 100644 --- a/Marlin/src/lcd/marlinui.cpp +++ b/Marlin/src/lcd/marlinui.cpp @@ -1891,40 +1891,60 @@ uint8_t expand_u8str_P(char * const outstr, PGM_P const ptpl, const int8_t ind, #include "extui/ui_api.h" #endif - void MarlinUI::media_changed(const uint8_t old_status, const uint8_t status) { + void MarlinUI::media_changed(const MediaPresence old_status, const MediaPresence status) { TERN_(HAS_DISPLAY_SLEEP, refresh_screen_timeout()); if (old_status == status) { TERN_(EXTENSIBLE_UI, ExtUI::onMediaError()); // Failed to mount/unmount return; } - if (old_status < 2) { // Skip this section on first boot check - if (status) { // Media Mounted + if (old_status > MEDIA_BOOT) { // Skip this section on first boot check + + if (status > old_status) { // Media Mounted + #if ENABLED(EXTENSIBLE_UI) + ExtUI::onMediaMounted(); + #elif ENABLED(BROWSE_MEDIA_ON_INSERT) + clear_menu_history(); quick_feedback(); goto_screen(MEDIA_MENU_GATEWAY); + #else + if (card.isSDCardSelected()) LCD_MESSAGE(MSG_MEDIA_INSERTED_SD); else if (card.isFlashDriveSelected()) LCD_MESSAGE(MSG_MEDIA_INSERTED_USB); else LCD_MESSAGE(MSG_MEDIA_INSERTED); + #endif } else { // Media Removed + #if ENABLED(EXTENSIBLE_UI) + ExtUI::onMediaRemoved(); - #elif HAS_SD_DETECT // Q: Does "Media Removed" need to be shown for manual release too? - LCD_MESSAGE(MSG_MEDIA_REMOVED); - #if HAS_MARLINUI_MENU - if (ENABLED(HAS_WIRED_LCD) || !defer_return_to_status) return_to_status(); - #endif + + #elif HAS_SD_DETECT || HAS_USB_FLASH_DRIVE // Q: Does "Media Removed" need to be shown for manual release too? + + if ((old_status ^ status) & INSERT_SD) + LCD_MESSAGE(MSG_MEDIA_REMOVED_SD); + else if ((old_status ^ status) & INSERT_USB) + LCD_MESSAGE(MSG_MEDIA_REMOVED_USB); + else + LCD_MESSAGE(MSG_MEDIA_REMOVED); + + if (ENABLED(HAS_WIRED_LCD) || !defer_return_to_status) + return_to_status(); + #elif HAS_WIRED_LCD + return_to_status(); + #endif } } diff --git a/Marlin/src/lcd/marlinui.h b/Marlin/src/lcd/marlinui.h index 9f2ac5a69a..076fc63f2a 100644 --- a/Marlin/src/lcd/marlinui.h +++ b/Marlin/src/lcd/marlinui.h @@ -256,7 +256,7 @@ public: #if HAS_MEDIA #define MEDIA_MENU_GATEWAY TERN(PASSWORD_ON_SD_PRINT_MENU, password.media_gatekeeper, menu_media) - static void media_changed(const uint8_t old_stat, const uint8_t stat); + static void media_changed(const MediaPresence old_stat, const MediaPresence stat); #endif #if HAS_LCD_BRIGHTNESS diff --git a/Marlin/src/sd/cardreader.cpp b/Marlin/src/sd/cardreader.cpp index 21bc6e780a..5502561ea4 100644 --- a/Marlin/src/sd/cardreader.cpp +++ b/Marlin/src/sd/cardreader.cpp @@ -145,6 +145,7 @@ int16_t CardReader::nrItems = -1; #endif DiskIODriver* CardReader::driver = nullptr; + MarlinVolume CardReader::volume; MediaFile CardReader::myfile; @@ -483,11 +484,15 @@ void CardReader::mount() { nrItems = -1; if (root.isOpen()) root.close(); - if (!driver->init(SD_SPI_SPEED, SD_SS_PIN) + const bool driver_init = ( + driver->init(SD_SPI_SPEED, SD_SS_PIN) #if PIN_EXISTS(LCD_SDSS) && (LCD_SDSS_PIN != SD_SS_PIN) - && !driver->init(SD_SPI_SPEED, LCD_SDSS_PIN) + || driver->init(SD_SPI_SPEED, LCD_SDSS_PIN) #endif - ) SERIAL_ECHO_MSG(STR_SD_INIT_FAIL); + ); + + if (!driver_init) + SERIAL_ECHO_MSG(STR_SD_INIT_FAIL); else if (!volume.init(driver)) SERIAL_WARN_MSG(STR_SD_VOL_INIT_FAIL); else if (!root.openRoot(&volume)) @@ -519,69 +524,146 @@ void CardReader::mount() { #include "../module/stepper.h" #endif +// Provide a little time for drives to prepare +void CardReader::init() { + #if HAS_USB_FLASH_DRIVE + for (uint8_t i = 10; --i;) { + media_driver_usbFlash.idle(); + hal.watchdog_refresh(); + if (media_driver_usbFlash.isInserted()) break; + delay(20); + } + #endif +} + /** - * Handle SD card events + * Handle media insertion and removal events + * based on SD Card detect and/or driver.isInserted() + * + * MULTI_VOLUME: + * - Track insert/remove for both media drives. + * - If the MOUNTED media is removed call release(). + * - If media is INSERTED when NO MEDIA is mounted, select and mount it. */ void CardReader::manage_media() { - #if HAS_USB_FLASH_DRIVE // Wrap for optimal non-virtual? - driver->idle(); // Handle device tasks (e.g., USB Drive insert / remove) + /** + * Handle device tasks (e.g., USB Drive insert / remove) + * - USB Flash Drive needs to run even when not selected. + * - SD Card currently has no background tasks. + */ + //driver->idle(); + #if HAS_USB_FLASH_DRIVE + //if (!isFlashDriveSelected()) + media_driver_usbFlash.idle(); #endif - static uint8_t prev_stat = 2; // At boot we don't know if media is present or not - uint8_t stat = uint8_t(isInserted()); + // Prevent re-entry during Marlin::idle + #if HAS_MULTI_VOLUME + static bool no_reenter = false; + if (no_reenter) return; + #endif + + static MediaPresence prev_stat = MEDIA_BOOT; // At boot we don't know if media is present or not + + // Live status is based on available media flags + MediaPresence stat = MediaPresence( + #if HAS_MULTI_VOLUME + (isSDCardInserted() ? INSERT_SD : 0) // Without SD Detect it's always "inserted" + | (isFlashDriveInserted() ? INSERT_USB : 0) + #else + isInserted() ? INSERT_MEDIA : 0 // Without SD Detect it's always "inserted" + #endif + ); + if (stat == prev_stat) return; // Already checked and still no change? DEBUG_SECTION(cmm, "CardReader::manage_media()", true); DEBUG_ECHOLNPGM("Media present: ", prev_stat, " -> ", stat); - if (!ui.detected()) { - DEBUG_ECHOLNPGM("SD: No UI Detected."); - return; - } + // Without a UI there's no auto-mount or release + if (!ui.detected()) { DEBUG_ECHOLNPGM("SD: No UI Detected."); return; } - flag.workDirIsRoot = true; // Return to root on mount/release/init - - const uint8_t old_stat = prev_stat; + const MediaPresence old_stat = prev_stat, + old_real = old_stat == MEDIA_BOOT ? INSERT_NONE : old_stat; prev_stat = stat; // Change now to prevent re-entry in safe_delay - if (stat) { // Media Inserted - safe_delay(500); // Some boards need a delay to get settled + #if HAS_MULTI_VOLUME + const int8_t vdiff = (old_real ^ stat), vadd = vdiff & stat; + #endif + const bool did_insert = TERN(HAS_MULTI_VOLUME, vadd, stat) != INSERT_NONE; - // Try to mount the media (only later with SD_IGNORE_AT_STARTUP) - if (TERN1(SD_IGNORE_AT_STARTUP, old_stat != 2)) mount(); - if (!isMounted()) stat = 0; // Not mounted? + if (did_insert) { // Media Inserted + + TERN_(HAS_MULTI_VOLUME, ui.refresh()); // Refresh for insert events without messages + + // Some media is already mounted? Nothing to do. + if (TERN0(HAS_MULTI_VOLUME, isMounted())) return; + + // Prevent re-entry during the following phases + TERN_(HAS_MULTI_VOLUME, no_reenter = true); + + // Try to mount the media (but not at boot if SD_IGNORE_AT_STARTUP) + if (TERN1(SD_IGNORE_AT_STARTUP, old_stat > MEDIA_BOOT)) { + #if HAS_MULTI_VOLUME + if ((vadd & INSERT_SD) && !isSDCardSelected()) + selectMediaSDCard(); + if ((vadd & INSERT_USB) && !isFlashDriveSelected()) + selectMediaFlashDrive(); + #endif + safe_delay(500); // Time for inserted media to settle. May re-enter for multiple media? + mount(); + } + + // If the selected media isn't mounted throw an alert in ui.media_changed + if (!isMounted()) stat = old_real; TERN_(RESET_STEPPERS_ON_MEDIA_INSERT, reset_stepper_drivers()); // Workaround for Cheetah bug + + // Re-enable media detection logic + TERN_(HAS_MULTI_VOLUME, no_reenter = false); + } + else if ( + // Media was removed from the device slot + #if HAS_MULTI_VOLUME + (isSDCardSelected() && (vdiff & INSERT_SD)) + || (isFlashDriveSelected() && (vdiff & INSERT_USB)) + #else + stat // == INSERT_MEDIA + #endif + ) { + flag.workDirIsRoot = true; // Return to root on release + release(); + //TERN_(HAS_MULTI_VOLUME, prev_stat = INSERT_NONE); // HACK to try mounting any remaining media } else { - TERN_(HAS_SD_DETECT, release()); // Card is released + #if HAS_MULTI_VOLUME + stat = old_real; // Ignore un-mounted media being ejected + ui.refresh(); // Refresh for menus that show inserted unmounted media + #endif } - ui.media_changed(old_stat, stat); // Update the UI or flag an error + ui.media_changed(old_stat, stat); // Update the UI or flag an error - if (!stat) return; // Exit if no media is present - - bool do_auto = true; UNUSED(do_auto); + if (stat == INSERT_NONE) return; // Exit if no media is present // First mount on boot? Load emulated EEPROM and look for PLR file. - if (old_stat == 2) { + if (old_stat <= MEDIA_BOOT) { DEBUG_ECHOLNPGM("First mount."); // Load settings the first time media is inserted (not just during init) TERN_(SDCARD_EEPROM_EMULATION, settings.first_load()); - // Check for PLR file. Skip One-Click and auto#.g if found - TERN_(POWER_LOSS_RECOVERY, if (recovery.check()) do_auto = false); + // Check for PLR file. If found skip other procedures! + if (TERN0(POWER_LOSS_RECOVERY, recovery.check())) return; } - // Find the newest file and prompt to print it. - TERN_(ONE_CLICK_PRINT, if (do_auto && one_click_check()) do_auto = false); + // Find the newest file and prompt to print it. Skip other procedures! + if (TERN0(ONE_CLICK_PRINT, one_click_check())) return; - // Also for the first mount run auto#.g for machine init. - // (Skip if PLR or One-Click Print was invoked.) - if (old_stat == 2) { + // On first mount at boot run auto#.g for machine init. + if (old_stat <= MEDIA_BOOT) { // Look for auto0.g on the next idle() - IF_DISABLED(NO_SD_AUTOSTART, if (do_auto) autofile_begin()); + IF_DISABLED(NO_SD_AUTOSTART, autofile_begin()); } } @@ -590,6 +672,8 @@ void CardReader::manage_media() { * Used by M22, "Release Media", manage_media. */ void CardReader::release() { + if (!flag.mounted) return; + // Card removed while printing? Abort! if (isStillPrinting()) abortFilePrintSoon(); diff --git a/Marlin/src/sd/cardreader.h b/Marlin/src/sd/cardreader.h index 1a8843da58..6c1f05b8af 100644 --- a/Marlin/src/sd/cardreader.h +++ b/Marlin/src/sd/cardreader.h @@ -78,6 +78,14 @@ typedef struct { ; } card_flags_t; +enum MediaPresence : int8_t { + MEDIA_BOOT = -1, + INSERT_NONE = 0x00, + INSERT_MEDIA = 0x01, + INSERT_SD = TERN(HAS_MULTI_VOLUME, 0x02, 0x00), + INSERT_USB = TERN(HAS_MULTI_VOLUME, 0x04, 0x00) +}; + enum ListingFlags : uint8_t { LS_LONG_FILENAME, LS_ONLY_BIN, LS_TIMESTAMP }; enum SortFlag : int8_t { AS_REV = -1, AS_OFF, AS_FWD, AS_ALSO_REV }; @@ -102,6 +110,9 @@ public: CardReader(); + // Init at startup before mounting media + static void init(); + /** * Media Selection - Only one drive may be active at a time, * so switching drives (currently) returns to the root folder. From 99c29cd9242387176a6be0f70acace28ac27ec03 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Thu, 24 Apr 2025 11:20:15 -0500 Subject: [PATCH 263/787] =?UTF-8?q?=F0=9F=9A=B8=20Simplified=20Media=20Men?= =?UTF-8?q?u?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/feature/password/password.cpp | 2 +- Marlin/src/feature/password/password.h | 2 + Marlin/src/lcd/TFTGLCD/marlinui_TFTGLCD.cpp | 8 +- Marlin/src/lcd/language/language_en.h | 9 +- Marlin/src/lcd/marlinui.h | 6 +- Marlin/src/lcd/menu/menu.h | 3 +- Marlin/src/lcd/menu/menu_item.h | 3 + Marlin/src/lcd/menu/menu_main.cpp | 154 +++++++++++++++----- Marlin/src/lcd/menu/menu_media.cpp | 46 +++--- Marlin/src/lcd/menu/menu_password.cpp | 12 +- Marlin/src/lcd/tft/ui_color_ui.cpp | 2 +- 11 files changed, 171 insertions(+), 76 deletions(-) diff --git a/Marlin/src/feature/password/password.cpp b/Marlin/src/feature/password/password.cpp index 1d376cc586..d36b3edd09 100644 --- a/Marlin/src/feature/password/password.cpp +++ b/Marlin/src/feature/password/password.cpp @@ -36,7 +36,7 @@ uint32_t Password::value, Password::value_entry; // // Authenticate user with password. -// Called from Setup, after SD Prinitng Stops/Aborts, and M510 +// Called from Setup, after SD Printing Stops/Aborts, and M510 // void Password::lock_machine() { is_locked = true; diff --git a/Marlin/src/feature/password/password.h b/Marlin/src/feature/password/password.h index 208765b212..0f8bc28bd8 100644 --- a/Marlin/src/feature/password/password.h +++ b/Marlin/src/feature/password/password.h @@ -37,6 +37,8 @@ public: static void access_menu_password(); static void authentication_done(); static void media_gatekeeper(); + static void media_gatekeeper_sd(); + static void media_gatekeeper_usb(); private: static void authenticate_user(const screenFunc_t, const screenFunc_t); diff --git a/Marlin/src/lcd/TFTGLCD/marlinui_TFTGLCD.cpp b/Marlin/src/lcd/TFTGLCD/marlinui_TFTGLCD.cpp index 4ac012ba93..d772447551 100644 --- a/Marlin/src/lcd/TFTGLCD/marlinui_TFTGLCD.cpp +++ b/Marlin/src/lcd/TFTGLCD/marlinui_TFTGLCD.cpp @@ -175,9 +175,9 @@ void TFTGLCD::clr_screen() { SPI_SEND_ONE(CLR_SCREEN); WRITE(TFTGLCD_CS, HIGH); #else - Wire.beginTransmission(uint8_t(LCD_I2C_ADDRESS)); //set I2C device address + Wire.beginTransmission(uint8_t(LCD_I2C_ADDRESS)); // Transmit to LCD via I2C Wire.write(CLR_SCREEN); - Wire.endTransmission(); //transmit data + Wire.endTransmission(); // Send the data #endif } @@ -378,10 +378,6 @@ void MarlinUI::clear_for_drawing() { clear_lcd(); } void MarlinUI::_set_contrast() { lcd.setContrast(contrast); } #endif -#if !IS_TFTGLCD_PANEL - void lcd_moveto(const uint8_t col, const uint8_t row) { lcd.setCursor(col, row); } -#endif - static void center_text(FSTR_P const fstart, const uint8_t y) { const uint8_t len = utf8_strlen(fstart); lcd_moveto(len < LCD_WIDTH ? (LCD_WIDTH - len) / 2 : 0, y); diff --git a/Marlin/src/lcd/language/language_en.h b/Marlin/src/lcd/language/language_en.h index 7ea17d5bb3..5ed5b24635 100644 --- a/Marlin/src/lcd/language/language_en.h +++ b/Marlin/src/lcd/language/language_en.h @@ -574,10 +574,8 @@ namespace LanguageNarrow_en { LSTR MSG_CANCEL_OBJECT = _UxGT("Cancel Obj"); LSTR MSG_CANCEL_OBJECT_N = _UxGT("Cancel Obj {"); LSTR MSG_CONTINUE_PRINT_JOB = _UxGT("Continue Job"); - LSTR MSG_MEDIA_MENU = MEDIA_TYPE_EN _UxGT(" Print"); LSTR MSG_TURN_OFF = _UxGT("Turn off now"); LSTR MSG_END_LOOPS = _UxGT("End Loops"); - LSTR MSG_NO_MEDIA = _UxGT("No ") MEDIA_TYPE_EN; LSTR MSG_DWELL = _UxGT("Sleep..."); LSTR MSG_USERWAIT = _UxGT("Click to Resume..."); LSTR MSG_PRINT_PAUSED = _UxGT("Print Paused"); @@ -641,6 +639,10 @@ namespace LanguageNarrow_en { LSTR MSG_RUN_AUTOFILES = _UxGT("Run Autofiles"); LSTR MSG_RUN_AUTOFILES_SD = _UxGT("Run SD Autofiles"); LSTR MSG_RUN_AUTOFILES_USB = _UxGT("Run USB Autofiles"); + LSTR MSG_MEDIA_MENU = MEDIA_TYPE_EN _UxGT(" Print"); + LSTR MSG_MEDIA_MENU_SD = _UxGT("Select from SD"); + LSTR MSG_MEDIA_MENU_USB = _UxGT("Select from USB"); + LSTR MSG_NO_MEDIA = _UxGT("No ") MEDIA_TYPE_EN _UxGT(" Detected"); LSTR MSG_ZPROBE_OUT = _UxGT("Z Probe Past Bed"); LSTR MSG_SKEW_FACTOR = _UxGT("Skew Factor"); @@ -1130,6 +1132,9 @@ namespace LanguageWide_en { LSTR MSG_CANCEL_OBJECT_N = _UxGT("Cancel Object {"); LSTR MSG_CONTINUE_PRINT_JOB = _UxGT("Continue Print Job"); LSTR MSG_MEDIA_MENU = _UxGT("Select from ") MEDIA_TYPE_EN; + LSTR MSG_MEDIA_MENU_SD = _UxGT("Select from SD Card"); + LSTR MSG_MEDIA_MENU_USB = _UxGT("Select from USB Drive"); + LSTR MSG_NO_MEDIA = _UxGT("No ") MEDIA_TYPE_EN _UxGT(" Found"); LSTR MSG_TURN_OFF = _UxGT("Turn off the printer"); LSTR MSG_END_LOOPS = _UxGT("End Repeat Loops"); LSTR MSG_MEDIA_NOT_INSERTED = _UxGT("No media inserted."); // ProUI diff --git a/Marlin/src/lcd/marlinui.h b/Marlin/src/lcd/marlinui.h index 076fc63f2a..a610796ebc 100644 --- a/Marlin/src/lcd/marlinui.h +++ b/Marlin/src/lcd/marlinui.h @@ -255,7 +255,9 @@ public: #endif #if HAS_MEDIA - #define MEDIA_MENU_GATEWAY TERN(PASSWORD_ON_SD_PRINT_MENU, password.media_gatekeeper, menu_media) + #define MEDIA_MENU_GATEWAY TERN(PASSWORD_ON_SD_PRINT_MENU, password.media_gatekeeper, menu_file_selector) + #define MEDIA_MENU_GATEWAY_SD TERN(PASSWORD_ON_SD_PRINT_MENU, password.media_gatekeeper_sd, menu_file_selector_sd) + #define MEDIA_MENU_GATEWAY_USB TERN(PASSWORD_ON_SD_PRINT_MENU, password.media_gatekeeper_usb, menu_file_selector_usb) static void media_changed(const MediaPresence old_stat, const MediaPresence stat); #endif @@ -864,7 +866,7 @@ public: TERN_(REVERSE_SELECT_DIRECTION, encoderDirection = -(ENCODERBASE)); } - #else + #else // !HAS_ENCODER_ACTION static void update_buttons() {} static bool hw_button_pressed() { return false; } diff --git a/Marlin/src/lcd/menu/menu.h b/Marlin/src/lcd/menu/menu.h index b7861655e2..47f5a312eb 100644 --- a/Marlin/src/lcd/menu/menu.h +++ b/Marlin/src/lcd/menu/menu.h @@ -212,7 +212,8 @@ void menu_move(); #if HAS_MEDIA void menu_file_selector(); - void menu_media(); + void menu_file_selector_sd(); + void menu_file_selector_usb(); #endif //////////////////////////////////////////// diff --git a/Marlin/src/lcd/menu/menu_item.h b/Marlin/src/lcd/menu/menu_item.h index af4558cefc..d79956aea7 100644 --- a/Marlin/src/lcd/menu/menu_item.h +++ b/Marlin/src/lcd/menu/menu_item.h @@ -226,6 +226,9 @@ class MenuItem_bool : public MenuEditItemBase { * should be done before the menu loop (START_MENU / START_SCREEN). */ +// CAUTION! When using menu items in a lambda or sub-function always use: +#define INJECT_MENU_ITEMS(FN) { FN; if (ui.screen_changed) return; } + /** * SCREEN_OR_MENU_LOOP generates header code for a screen or menu * diff --git a/Marlin/src/lcd/menu/menu_main.cpp b/Marlin/src/lcd/menu/menu_main.cpp index 7e2d458e41..04bbc41074 100644 --- a/Marlin/src/lcd/menu/menu_main.cpp +++ b/Marlin/src/lcd/menu/menu_main.cpp @@ -237,8 +237,8 @@ void menu_configuration(); void menu_main() { const bool busy = printingIsActive(); #if HAS_MEDIA - const bool card_detected = card.isMounted(), - card_open = card_detected && card.isFileOpen(); + const bool card_is_mounted = card.isMounted(), + card_open = card_is_mounted && card.isFileOpen(); #endif START_MENU(); @@ -248,45 +248,123 @@ void menu_main() { #define MEDIA_MENU_AT_TOP #endif - auto media_menus = [&]{ - #if HAS_MEDIA - if (card_detected) { - if (!card_open) { - #if ENABLED(MENU_ADDAUTOSTART) - ACTION_ITEM(MSG_RUN_AUTOFILES, card.autofile_begin); // Run Auto Files - #endif + // Show "Attach" for drives that don't auto-detect media (yet) + //#define ATTACH_WITHOUT_INSERT_SD + #define ATTACH_WITHOUT_INSERT_USB - #if HAS_SD_DETECT - GCODES_ITEM(MSG_CHANGE_MEDIA, F("M21" TERN_(HAS_MULTI_VOLUME, "S"))); // M21 Change Media - #if HAS_MULTI_VOLUME - GCODES_ITEM(MSG_ATTACH_USB, F("M21U")); // M21 Attach USB Media - #endif - #else // - or - - ACTION_ITEM(MSG_RELEASE_MEDIA, []{ // M22 Release Media - queue.inject(F("M22")); - #if ENABLED(TFT_COLOR_UI) - // Menu display issue on item removal with multi language selection menu - if (encoderTopLine > 0) encoderTopLine--; - ui.refresh(); - #endif - }); - #endif - SUBMENU(MSG_MEDIA_MENU, MEDIA_MENU_GATEWAY); // Media Menu (or Password First) - } + // Show all "inserted" drives and mount as-needed + #define SHOW_UNMOUNTED_DRIVES + + /** + * Previously: + * - The "selected" media is mounted? + * - [Run Auto Files] + * - HAS_SD_DETECT: + * - [Change Media] = M21 / M21S + * - HAS_MULTI_VOLUME? + * - [Attach USB Drive] = M21U + * - ELSE: + * - [Release Media] = M22 + * - [Select from Media] (or Password Gateway) > + * + * - The "selected" media is not mounted? + * - HAS_SD_DETECT? + * - [No Media] (does nothing) + * - HAS_MULTI_VOLUME? + * - [Attach SD Card] = M21S + * - [Attach USB Drive] = M21U + * - ELSE: + * - [Attach Media] = M21 + * + * Updated: + * - Something is mounted? + * - [Run SD/USB Autofiles] + * - [Release SD/USB] = M22 + * - [Select from SD/USB] (or Password Gateway) > + * + * - Something is inserted and SHOW_UNMOUNTED_DRIVES? + * - [Select from SD/USB] (or Password Gateway) > + * + * - The "selected" Card is NOT DETECTED? + * - Trust all media detect methods? + * - [No Media] (does nothing) + * - HAS_MULTI_VOLUME? + * - [Attach SD Card] = M21S + * - [Attach USB Drive] = M21U + * - ELSE: + * - [Attach SD Card/USB Drive] = M21 + * + * Ideal: + * - Password Gateway? + * - Use gateway passthroughs for all SD/USB Drive menu items... + * - [Run SD Autofiles] + * - [Run USB Autofiles] + * - [Select from SD Card] (or Password Gateway) > + * - [Select from USB Drive] (or Password Gateway) > + * - [Eject SD Card/USB Drive] + */ + auto media_menu_items = [&]{ + #if HAS_MEDIA + if (card_open) return; + + if (card_is_mounted) { + #if ENABLED(MENU_ADDAUTOSTART) + // [Run AutoFiles] for mounted drive(s) + if (card.isSDCardMounted()) + ACTION_ITEM(MSG_RUN_AUTOFILES_SD, card.autofile_begin); + if (card.isFlashDriveMounted()) + ACTION_ITEM(MSG_RUN_AUTOFILES_USB, card.autofile_begin); + #endif + + #if ENABLED(TFT_COLOR_UI) + // Menu display issue on item removal with multi language selection menu + #define M22_ITEM(T) do{ \ + ACTION_ITEM(T, []{ \ + queue.inject(F("M22")); encoderTopLine -= (encoderTopLine > 0); ui.refresh(); \ + }); \ + }while(0) + #else + #define M22_ITEM(T) GCODES_ITEM(T, F("M22")) + #endif + + // [Release Media] for mounted drive(s) + if (card.isSDCardMounted()) + M22_ITEM(MSG_RELEASE_SD); + if (card.isFlashDriveMounted()) + M22_ITEM(MSG_RELEASE_USB); + + // [Select from SD/USB] (or Password First) + if (card.isSDCardMounted()) + SUBMENU(MSG_MEDIA_MENU_SD, MEDIA_MENU_GATEWAY); + else if (TERN0(SHOW_UNMOUNTED_DRIVES, card.isSDCardInserted())) + SUBMENU(MSG_MEDIA_MENU_SD, MEDIA_MENU_GATEWAY_SD); + if (card.isFlashDriveMounted()) + SUBMENU(MSG_MEDIA_MENU_USB, MEDIA_MENU_GATEWAY); + else if (TERN0(SHOW_UNMOUNTED_DRIVES, card.isFlashDriveInserted())) + SUBMENU(MSG_MEDIA_MENU_USB, MEDIA_MENU_GATEWAY_USB); } else { - #if HAS_SD_DETECT - ACTION_ITEM(MSG_NO_MEDIA, nullptr); // "No Media" - #else - #if HAS_MULTI_VOLUME - GCODES_ITEM(MSG_ATTACH_SD, F("M21S")); // M21S Attach SD Card - GCODES_ITEM(MSG_ATTACH_USB, F("M21U")); // M21U Attach USB Media + // NOTE: If the SD Card has no SD_DETECT it will always appear to be "inserted" + const bool att_sd = ENABLED(ATTACH_WITHOUT_INSERT_SD) || card.isSDCardInserted(), + att_usb = ENABLED(ATTACH_WITHOUT_INSERT_USB) || card.isFlashDriveInserted(); + if (!att_sd && !att_usb) { + ACTION_ITEM(MSG_NO_MEDIA, nullptr); // [No Media] + } + else { + #if ALL(HAS_MULTI_VOLUME, SHOW_UNMOUNTED_DRIVES) + // [Select from SD/USB] (or Password First) + if (TERN0(SHOW_UNMOUNTED_DRIVES, card.isSDCardInserted())) + SUBMENU(MSG_MEDIA_MENU_SD, MEDIA_MENU_GATEWAY_SD); + if (TERN0(SHOW_UNMOUNTED_DRIVES, card.isFlashDriveInserted())) + SUBMENU(MSG_MEDIA_MENU_USB, MEDIA_MENU_GATEWAY_USB); #else - GCODES_ITEM(MSG_ATTACH_MEDIA, F("M21")); // M21 Attach Media + #define M21(T) F("M21" TERN_(HAS_MULTI_VOLUME, T)) + if (att_sd) GCODES_ITEM(MSG_ATTACH_SD, M21("S")); // M21 S - [Attach SD Card] + if (att_usb) GCODES_ITEM(MSG_ATTACH_USB, M21("U")); // M21 U - [Attach USB Drive] #endif - #endif + } } - #endif + #endif // HAS_MEDIA }; if (busy) { @@ -317,7 +395,9 @@ void menu_main() { else { // SD Card / Flash Drive - TERN_(MEDIA_MENU_AT_TOP, media_menus()); + #if ENABLED(MEDIA_MENU_AT_TOP) + INJECT_MENU_ITEMS(media_menu_items()); + #endif if (TERN0(MACHINE_CAN_PAUSE, printingIsPaused())) ACTION_ITEM(MSG_RESUME_PRINT, ui.resume_print); @@ -407,7 +487,7 @@ void menu_main() { // SD Card / Flash Drive #if DISABLED(MEDIA_MENU_AT_TOP) - if (!busy) media_menus(); + if (!busy) INJECT_MENU_ITEMS(media_menu_items()); #endif #if HAS_SERVICE_INTERVALS diff --git a/Marlin/src/lcd/menu/menu_media.cpp b/Marlin/src/lcd/menu/menu_media.cpp index 8747685fe5..f4c409c4a3 100644 --- a/Marlin/src/lcd/menu/menu_media.cpp +++ b/Marlin/src/lcd/menu/menu_media.cpp @@ -101,29 +101,27 @@ class MenuItem_sdfolder : public MenuItem_sdbase { } }; -#if HAS_MULTI_VOLUME - void menu_media_select() { - START_MENU(); - BACK_ITEM_F(TERN1(BROWSE_MEDIA_ON_INSERT, screen_history_depth) ? GET_TEXT_F(MSG_MAIN_MENU) : GET_TEXT_F(MSG_BACK)); - #if HAS_SDCARD - ACTION_ITEM(MSG_SD_CARD, []{ card.selectMediaSDCard(); card.mount(); ui.goto_screen(menu_file_selector); }); - #endif - #if HAS_USB_FLASH_DRIVE - ACTION_ITEM(MSG_USB_DISK, []{ card.selectMediaFlashDrive(); card.mount(); ui.goto_screen(menu_file_selector); }); - #endif - END_MENU(); +// Shortcut menu items to go directly to inserted — not necessarily mounted — drives +void menu_file_selector_sd() { + if (!card.isSDCardSelected()) { + card.release(); + card.selectMediaSDCard(); } -#endif - -/** - * "Select From Media" menu item. Depending on single or multiple drives: - * - menu_file_selector - List files on the current media - * - menu_media_select - Select one of the attached drives, then go to the file list - */ -void menu_media() { - ui.goto_screen(TERN(HAS_MULTI_VOLUME, menu_media_select, menu_file_selector)); + if (!card.isSDCardMounted()) card.mount(); + ui.goto_screen(menu_file_selector); } +// Shortcut menu items to go directly to inserted — not necessarily mounted — drives +void menu_file_selector_usb() { + if (!card.isFlashDriveSelected()) { + card.release(); + card.selectMediaFlashDrive(); + } + if (!card.isFlashDriveMounted()) card.mount(); + ui.goto_screen(menu_file_selector); +} + +// Shortcut menu items to go directly to inserted — not necessarily mounted — drives void menu_file_selector() { ui.encoder_direction_menus(); @@ -135,11 +133,9 @@ void menu_file_selector() { #endif START_MENU(); - #if HAS_MULTI_VOLUME - ACTION_ITEM(MSG_BACK, []{ ui.goto_screen(menu_media_select); }); - #else - BACK_ITEM_F(TERN1(BROWSE_MEDIA_ON_INSERT, screen_history_depth) ? GET_TEXT_F(MSG_MAIN_MENU) : GET_TEXT_F(MSG_BACK)); - #endif + + BACK_ITEM_F(TERN1(BROWSE_MEDIA_ON_INSERT, screen_history_depth) ? GET_TEXT_F(MSG_MAIN_MENU) : GET_TEXT_F(MSG_BACK)); + if (card.flag.workDirIsRoot) { #if !HAS_SD_DETECT ACTION_ITEM(MSG_REFRESH, []{ encoderTopLine = 0; card.mount(); }); diff --git a/Marlin/src/lcd/menu/menu_password.cpp b/Marlin/src/lcd/menu/menu_password.cpp index 33d4231cd5..5e3db846ac 100644 --- a/Marlin/src/lcd/menu/menu_password.cpp +++ b/Marlin/src/lcd/menu/menu_password.cpp @@ -140,8 +140,18 @@ void Password::access_menu_password() { #if ENABLED(PASSWORD_ON_SD_PRINT_MENU) void Password::media_gatekeeper() { - authenticate_user(menu_media, menu_main); + authenticate_user(menu_file_selector, menu_main); } + #if HAS_SDCARD + void Password::media_gatekeeper_sd() { + authenticate_user(menu_file_selector_sd, menu_main); + } + #endif + #if HAS_USB_FLASH_DRIVE + void Password::media_gatekeeper_usb() { + authenticate_user(menu_file_selector_usb, menu_main); + } + #endif #endif void Password::start_over() { diff --git a/Marlin/src/lcd/tft/ui_color_ui.cpp b/Marlin/src/lcd/tft/ui_color_ui.cpp index 8186650070..6c90cb6c36 100644 --- a/Marlin/src/lcd/tft/ui_color_ui.cpp +++ b/Marlin/src/lcd/tft/ui_color_ui.cpp @@ -323,7 +323,7 @@ void MarlinUI::draw_status_screen() { if (cm && pa) add_control(SDCARD_ICON_X, SDCARD_ICON_Y, STOP, imgCancel, true, COLOR_CONTROL_CANCEL); else - add_control(SDCARD_ICON_X, SDCARD_ICON_Y, menu_media, imgSD, cm && !pa, COLOR_CONTROL_ENABLED, COLOR_CONTROL_DISABLED); + add_control(SDCARD_ICON_X, SDCARD_ICON_Y, menu_file_selector, imgSD, cm && !pa, COLOR_CONTROL_ENABLED, COLOR_CONTROL_DISABLED); #endif #endif From 85f6090f2046d2c616f333c3d8df538405af8315 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sat, 26 Apr 2025 17:54:54 -0500 Subject: [PATCH 264/787] =?UTF-8?q?=F0=9F=94=A7=20Apply=20DEFAULT=5FVOLUME?= =?UTF-8?q?=20on=20boot?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/Configuration_adv.h | 3 ++- Marlin/src/HAL/STM32/sd/msc_sd.cpp | 1 + Marlin/src/inc/Changes.h | 28 +++++++++++++++++++++++++++ Marlin/src/inc/Conditionals-4-adv.h | 9 +++++---- Marlin/src/inc/SanityCheck.h | 16 ++++++++++++--- Marlin/src/sd/cardreader.cpp | 30 ++++++++++++++--------------- 6 files changed, 64 insertions(+), 23 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index b1ad8d9629..a48a337270 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -1960,7 +1960,8 @@ #if ENABLED(MULTI_VOLUME) #define VOLUME_SD_ONBOARD #define VOLUME_USB_FLASH_DRIVE - #define DEFAULT_SHARED_VOLUME SV_USB_FLASH_DRIVE + #define DEFAULT_VOLUME SD_ONBOARD // :[ 'SD_ONBOARD', 'USB_FLASH_DRIVE' ] + #define DEFAULT_SHARED_VOLUME USB_FLASH_DRIVE // :[ 'SD_ONBOARD', 'USB_FLASH_DRIVE' ] #endif #endif // HAS_MEDIA diff --git a/Marlin/src/HAL/STM32/sd/msc_sd.cpp b/Marlin/src/HAL/STM32/sd/msc_sd.cpp index f198b3e49a..9bb65aab4a 100644 --- a/Marlin/src/HAL/STM32/sd/msc_sd.cpp +++ b/Marlin/src/HAL/STM32/sd/msc_sd.cpp @@ -48,6 +48,7 @@ class Sd2CardUSBMscHandler : public USBMscHandler { public: DiskIODriver* diskIODriver() { + // TODO: Explore a variable shared volume, or auto share the un-mounted volume(s) #if HAS_MULTI_VOLUME #if SHARED_VOLUME_IS(SD_ONBOARD) return &card.media_driver_sdcard; diff --git a/Marlin/src/inc/Changes.h b/Marlin/src/inc/Changes.h index abd7db8011..839804d920 100644 --- a/Marlin/src/inc/Changes.h +++ b/Marlin/src/inc/Changes.h @@ -799,3 +799,31 @@ #undef _POWERSTEP01 #undef _TMC26X #undef _TMC26X_STANDALONE + +#if ENABLED(MULTI_VOLUME) + // Change to a generic ID without SV_ prefix + #define SV_SD_ONBOARD 201 + #define SV_USB_FLASH_DRIVE 202 + #if DEFAULT_VOLUME_IS(SV_SD_ONBOARD) || SHARED_VOLUME_IS(SV_SD_ONBOARD) + #error "SV_SD_ONBOARD is now SD_ONBOARD." + #elif DEFAULT_VOLUME_IS(SV_USB_FLASH_DRIVE) || SHARED_VOLUME_IS(SV_USB_FLASH_DRIVE) + #error "SV_USB_FLASH_DRIVE is now USB_FLASH_DRIVE." + #endif + // Skip less clear "bad value" errors in inc/SanityCheck.h + #if DEFAULT_VOLUME_IS(SV_SD_ONBOARD) + #undef DEFAULT_VOLUME + #define DEFAULT_VOLUME SD_ONBOARD + #elif DEFAULT_VOLUME_IS(SV_USB_FLASH_DRIVE) + #undef DEFAULT_VOLUME + #define DEFAULT_VOLUME USB_FLASH_DRIVE + #endif + #if SHARED_VOLUME_IS(SV_SD_ONBOARD) + #undef DEFAULT_SHARED_VOLUME + #define DEFAULT_SHARED_VOLUME SD_ONBOARD + #elif SHARED_VOLUME_IS(SV_USB_FLASH_DRIVE) + #undef DEFAULT_SHARED_VOLUME + #define DEFAULT_SHARED_VOLUME USB_FLASH_DRIVE + #endif + #undef SV_SD_ONBOARD + #undef SV_USB_FLASH_DRIVE +#endif diff --git a/Marlin/src/inc/Conditionals-4-adv.h b/Marlin/src/inc/Conditionals-4-adv.h index a9427c3605..629ee98273 100644 --- a/Marlin/src/inc/Conditionals-4-adv.h +++ b/Marlin/src/inc/Conditionals-4-adv.h @@ -1248,11 +1248,12 @@ #if ENABLED(MULTI_VOLUME) #define HAS_MULTI_VOLUME 1 - #define SV_SD_ONBOARD 101 - #define SV_USB_FLASH_DRIVE 102 - #define _VOLUME_ID(N) _CAT(SV_, N) - #define SHARED_VOLUME_IS(N) (DEFAULT_SHARED_VOLUME == _VOLUME_ID(N)) + #define SD_ONBOARD 101 + #define USB_FLASH_DRIVE 102 + #define DEFAULT_VOLUME_IS(N) (DEFAULT_VOLUME == N) + #define SHARED_VOLUME_IS(N) (DEFAULT_SHARED_VOLUME == N) #else + #define DEFAULT_VOLUME_IS(...) 0 #define SHARED_VOLUME_IS(...) 0 #endif diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index 074cfe0dcb..cff241db72 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -416,10 +416,20 @@ static_assert(COUNT(arm) == LOGICAL_AXES, "AXIS_RELATIVE_MODES must contain " _L /** * SD Card Settings */ -#if ALL(HAS_MEDIA, HAS_SD_DETECT, SD_CONNECTION_TYPICAL, ELB_FULL_GRAPHIC_CONTROLLER, HAS_MARLINUI_MENU) && SD_DETECT_STATE == LOW - #error "SD_DETECT_STATE must be set HIGH for SD on the ELB_FULL_GRAPHIC_CONTROLLER." +#if HAS_MEDIA + #if HAS_MULTI_VOLUME + #if !(DEFAULT_VOLUME_IS(SD_ONBOARD) || DEFAULT_VOLUME_IS(USB_FLASH_DRIVE)) + #error "DEFAULT_VOLUME must be either SD_ONBOARD or USB_FLASH_DRIVE." + #endif + #if !(SHARED_VOLUME_IS(SD_ONBOARD) || SHARED_VOLUME_IS(USB_FLASH_DRIVE)) + #error "DEFAULT_SHARED_VOLUME must be either SD_ONBOARD or USB_FLASH_DRIVE." + #endif + #endif + #if ALL(ELB_FULL_GRAPHIC_CONTROLLER, HAS_MARLINUI_MENU, SD_CONNECTION_TYPICAL, HAS_SD_DETECT) && SD_DETECT_STATE == LOW + #error "SD_DETECT_STATE must be set HIGH for SD on the ELB_FULL_GRAPHIC_CONTROLLER." + #endif + #undef SD_CONNECTION_TYPICAL #endif -#undef SD_CONNECTION_TYPICAL /** * SD File Sorting diff --git a/Marlin/src/sd/cardreader.cpp b/Marlin/src/sd/cardreader.cpp index 5502561ea4..b7d6f70f65 100644 --- a/Marlin/src/sd/cardreader.cpp +++ b/Marlin/src/sd/cardreader.cpp @@ -28,10 +28,6 @@ #if HAS_MEDIA -#if HAS_MULTI_VOLUME && !SHARED_VOLUME_IS(SD_ONBOARD) && !SHARED_VOLUME_IS(USB_FLASH_DRIVE) - #error "DEFAULT_SHARED_VOLUME must be either SV_SD_ONBOARD or SV_USB_FLASH_DRIVE." -#endif - //#define DEBUG_CARDREADER #include "cardreader.h" @@ -144,7 +140,13 @@ int16_t CardReader::nrItems = -1; DiskIODriver_USBFlash CardReader::media_driver_usbFlash; #endif -DiskIODriver* CardReader::driver = nullptr; +DiskIODriver* CardReader::driver = ( + #if HAS_USB_FLASH_DRIVE && !DEFAULT_VOLUME_IS(SD_ONBOARD) + &CardReader::media_driver_usbFlash + #else + &CardReader::media_driver_sdcard + #endif +); MarlinVolume CardReader::volume; MediaFile CardReader::myfile; @@ -158,12 +160,6 @@ MediaFile CardReader::myfile; uint32_t CardReader::filesize, CardReader::sdpos; CardReader::CardReader() { - #if HAS_USB_FLASH_DRIVE && !SHARED_VOLUME_IS(SD_ONBOARD) - selectMediaFlashDrive(); - #else - selectMediaSDCard(); - #endif - #if ENABLED(SDCARD_SORT_ALPHA) sort_count = 0; #if ENABLED(SDSORT_GCODE) @@ -604,11 +600,15 @@ void CardReader::manage_media() { // Try to mount the media (but not at boot if SD_IGNORE_AT_STARTUP) if (TERN1(SD_IGNORE_AT_STARTUP, old_stat > MEDIA_BOOT)) { + // If both SD/FD mount simultaneously prefer the default #if HAS_MULTI_VOLUME - if ((vadd & INSERT_SD) && !isSDCardSelected()) - selectMediaSDCard(); - if ((vadd & INSERT_USB) && !isFlashDriveSelected()) - selectMediaFlashDrive(); + #if HAS_USB_FLASH_DRIVE && !DEFAULT_VOLUME_IS(SD_ONBOARD) + if (vadd & INSERT_USB) selectMediaFlashDrive(); + else if (vadd & INSERT_SD) selectMediaSDCard(); + #else + if (vadd & INSERT_SD) selectMediaSDCard(); + else if (vadd & INSERT_USB) selectMediaFlashDrive(); + #endif #endif safe_delay(500); // Time for inserted media to settle. May re-enter for multiple media? mount(); From 827c03b05648ea994496319d0e00904c587d0c8f Mon Sep 17 00:00:00 2001 From: Norman Chong <8681541+Grenite@users.noreply.github.com> Date: Mon, 28 Apr 2025 23:18:59 -0400 Subject: [PATCH 265/787] =?UTF-8?q?=F0=9F=A9=B9=20Fix=20Ultimain=202=20MOT?= =?UTF-8?q?OR=5FCURRENT=5FPWM=5FRANGE=20(#27705)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/pins/ramps/pins_ULTIMAIN_2.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/src/pins/ramps/pins_ULTIMAIN_2.h b/Marlin/src/pins/ramps/pins_ULTIMAIN_2.h index 4633bfc037..b7b04352d0 100644 --- a/Marlin/src/pins/ramps/pins_ULTIMAIN_2.h +++ b/Marlin/src/pins/ramps/pins_ULTIMAIN_2.h @@ -85,7 +85,7 @@ #define MOTOR_CURRENT_PWM_E_PIN 46 // Motor current PWM conversion, PWM value = MotorCurrentSetting * 255 / range #ifndef MOTOR_CURRENT_PWM_RANGE - #define MOTOR_CURRENT_PWM_RANGE 2000 + #define MOTOR_CURRENT_PWM_RANGE 2900 #endif #define DEFAULT_PWM_MOTOR_CURRENT {1300, 1300, 1250} From fea70777df6cd61aad0035bd13e89430284b8334 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Tue, 29 Apr 2025 06:10:06 +0000 Subject: [PATCH 266/787] [cron] Bump distribution date (2025-04-29) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index d48398ed22..da4a399ef0 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-04-27" +//#define STRING_DISTRIBUTION_DATE "2025-04-29" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index f3a12580c9..c4282ea03a 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-04-27" + #define STRING_DISTRIBUTION_DATE "2025-04-29" #endif /** From 585cbbb20316b75f70514b340339601ba37d70ab Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 29 Apr 2025 13:41:53 -0500 Subject: [PATCH 267/787] =?UTF-8?q?=F0=9F=A9=B9=20Minor=20ExtUI/DGUS=20cod?= =?UTF-8?q?e=20fix/cleanup?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/lcd/extui/anycubic_chiron/chiron_extui.cpp | 6 ++---- Marlin/src/lcd/extui/anycubic_i3mega/anycubic_extui.cpp | 6 ++---- Marlin/src/lcd/extui/anycubic_vyper/vyper_extui.cpp | 6 ++---- Marlin/src/lcd/extui/dgus_e3s1pro/dgus_e3s1pro_extui.cpp | 6 ++---- Marlin/src/lcd/extui/dgus_reloaded/DGUSRxHandler.cpp | 2 +- Marlin/src/lcd/extui/dgus_reloaded/dgus_reloaded_extui.cpp | 6 ++---- Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_extui.cpp | 6 ++---- Marlin/src/lcd/extui/ia_creality/ia_creality_extui.cpp | 6 ++---- Marlin/src/lcd/extui/nextion/nextion_extui.cpp | 6 ++---- 9 files changed, 17 insertions(+), 33 deletions(-) diff --git a/Marlin/src/lcd/extui/anycubic_chiron/chiron_extui.cpp b/Marlin/src/lcd/extui/anycubic_chiron/chiron_extui.cpp index b983fa3740..83db56ae20 100644 --- a/Marlin/src/lcd/extui/anycubic_chiron/chiron_extui.cpp +++ b/Marlin/src/lcd/extui/anycubic_chiron/chiron_extui.cpp @@ -70,13 +70,11 @@ namespace ExtUI { void onUserConfirmRequired(const char * const msg) { chiron.confirmationRequest(msg); } // For fancy LCDs include an icon ID, message, and translated button title - void onUserConfirmRequired(const int icon, const char * const cstr, FSTR_P const fBtn) { + void onUserConfirmRequired(const int, const char * const cstr, FSTR_P const) { onUserConfirmRequired(cstr); - UNUSED(icon); UNUSED(fBtn); } - void onUserConfirmRequired(const int icon, FSTR_P const fstr, FSTR_P const fBtn) { + void onUserConfirmRequired(const int, FSTR_P const fstr, FSTR_P const) { onUserConfirmRequired(fstr); - UNUSED(icon); UNUSED(fBtn); } #if ENABLED(ADVANCED_PAUSE_FEATURE) diff --git a/Marlin/src/lcd/extui/anycubic_i3mega/anycubic_extui.cpp b/Marlin/src/lcd/extui/anycubic_i3mega/anycubic_extui.cpp index 7070c22602..d6dc4002b1 100644 --- a/Marlin/src/lcd/extui/anycubic_i3mega/anycubic_extui.cpp +++ b/Marlin/src/lcd/extui/anycubic_i3mega/anycubic_extui.cpp @@ -58,13 +58,11 @@ namespace ExtUI { void onUserConfirmRequired(const char * const msg) { anycubicTFT.onUserConfirmRequired(msg); } // For fancy LCDs include an icon ID, message, and translated button title - void onUserConfirmRequired(const int icon, const char * const cstr, FSTR_P const fBtn) { + void onUserConfirmRequired(const int, const char * const cstr, FSTR_P const) { onUserConfirmRequired(cstr); - UNUSED(icon); UNUSED(fBtn); } - void onUserConfirmRequired(const int icon, FSTR_P const fstr, FSTR_P const fBtn) { + void onUserConfirmRequired(const int, FSTR_P const fstr, FSTR_P const) { onUserConfirmRequired(fstr); - UNUSED(icon); UNUSED(fBtn); } #if ENABLED(ADVANCED_PAUSE_FEATURE) diff --git a/Marlin/src/lcd/extui/anycubic_vyper/vyper_extui.cpp b/Marlin/src/lcd/extui/anycubic_vyper/vyper_extui.cpp index 5fbe813446..8cd6e89ef1 100644 --- a/Marlin/src/lcd/extui/anycubic_vyper/vyper_extui.cpp +++ b/Marlin/src/lcd/extui/anycubic_vyper/vyper_extui.cpp @@ -70,13 +70,11 @@ namespace ExtUI { void onUserConfirmRequired(const char * const msg) { dgus.confirmationRequest(msg); } // For fancy LCDs include an icon ID, message, and translated button title - void onUserConfirmRequired(const int icon, const char * const cstr, FSTR_P const fBtn) { + void onUserConfirmRequired(const int, const char * const cstr, FSTR_P const) { onUserConfirmRequired(cstr); - UNUSED(icon); UNUSED(fBtn); } - void onUserConfirmRequired(const int icon, FSTR_P const fstr, FSTR_P const fBtn) { + void onUserConfirmRequired(const int, FSTR_P const fstr, FSTR_P const) { onUserConfirmRequired(fstr); - UNUSED(icon); UNUSED(fBtn); } #if ENABLED(ADVANCED_PAUSE_FEATURE) diff --git a/Marlin/src/lcd/extui/dgus_e3s1pro/dgus_e3s1pro_extui.cpp b/Marlin/src/lcd/extui/dgus_e3s1pro/dgus_e3s1pro_extui.cpp index 3b3f6db5b2..20012b689f 100644 --- a/Marlin/src/lcd/extui/dgus_e3s1pro/dgus_e3s1pro_extui.cpp +++ b/Marlin/src/lcd/extui/dgus_e3s1pro/dgus_e3s1pro_extui.cpp @@ -88,13 +88,11 @@ namespace ExtUI { } // For fancy LCDs include an icon ID, message, and translated button title - void onUserConfirmRequired(const int icon, const char * const cstr, FSTR_P const fBtn) { + void onUserConfirmRequired(const int, const char * const cstr, FSTR_P const) { onUserConfirmRequired(cstr); - UNUSED(icon); UNUSED(fBtn); } - void onUserConfirmRequired(const int icon, FSTR_P const fstr, FSTR_P const fBtn) { + void onUserConfirmRequired(const int, FSTR_P const fstr, FSTR_P const) { onUserConfirmRequired(fstr); - UNUSED(icon); UNUSED(fBtn); } #if ENABLED(ADVANCED_PAUSE_FEATURE) diff --git a/Marlin/src/lcd/extui/dgus_reloaded/DGUSRxHandler.cpp b/Marlin/src/lcd/extui/dgus_reloaded/DGUSRxHandler.cpp index a0551fa28c..e195654caa 100644 --- a/Marlin/src/lcd/extui/dgus_reloaded/DGUSRxHandler.cpp +++ b/Marlin/src/lcd/extui/dgus_reloaded/DGUSRxHandler.cpp @@ -503,7 +503,7 @@ void DGUSRxHandler::probe(DGUS_VP &vp, void *data_ptr) { UNUSED(data_ptr); #if ENABLED(MESH_BED_LEVELING) - screen.setStatusMessage(FPSTR(DGUS_MSG_ABL_REQUIRED)); + screen.setStatusMessage(GET_TEXT_F(DGUS_MSG_ABL_REQUIRED)); return; #endif diff --git a/Marlin/src/lcd/extui/dgus_reloaded/dgus_reloaded_extui.cpp b/Marlin/src/lcd/extui/dgus_reloaded/dgus_reloaded_extui.cpp index 9aeb06dba1..e8ee497297 100644 --- a/Marlin/src/lcd/extui/dgus_reloaded/dgus_reloaded_extui.cpp +++ b/Marlin/src/lcd/extui/dgus_reloaded/dgus_reloaded_extui.cpp @@ -83,13 +83,11 @@ namespace ExtUI { } // For fancy LCDs include an icon ID, message, and translated button title - void onUserConfirmRequired(const int icon, const char * const cstr, FSTR_P const fBtn) { + void onUserConfirmRequired(const int, const char * const cstr, FSTR_P const) { onUserConfirmRequired(cstr); - UNUSED(icon); UNUSED(fBtn); } - void onUserConfirmRequired(const int icon, FSTR_P const fstr, FSTR_P const fBtn) { + void onUserConfirmRequired(const int, FSTR_P const fstr, FSTR_P const) { onUserConfirmRequired(fstr); - UNUSED(icon); UNUSED(fBtn); } #if ENABLED(ADVANCED_PAUSE_FEATURE) diff --git a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_extui.cpp b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_extui.cpp index c26a809037..2f9da20ecc 100644 --- a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_extui.cpp +++ b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_extui.cpp @@ -133,13 +133,11 @@ namespace ExtUI { #endif // For fancy LCDs include an icon ID, message, and translated button title - void onUserConfirmRequired(const int icon, const char * const cstr, FSTR_P const fBtn) { + void onUserConfirmRequired(const int, const char * const cstr, FSTR_P const) { onUserConfirmRequired(cstr); - UNUSED(icon); UNUSED(fBtn); } - void onUserConfirmRequired(const int icon, FSTR_P const fstr, FSTR_P const fBtn) { + void onUserConfirmRequired(const int, FSTR_P const fstr, FSTR_P const) { onUserConfirmRequired(fstr); - UNUSED(icon); UNUSED(fBtn); } #if ENABLED(ADVANCED_PAUSE_FEATURE) diff --git a/Marlin/src/lcd/extui/ia_creality/ia_creality_extui.cpp b/Marlin/src/lcd/extui/ia_creality/ia_creality_extui.cpp index 4a1d49a020..86a19f6089 100644 --- a/Marlin/src/lcd/extui/ia_creality/ia_creality_extui.cpp +++ b/Marlin/src/lcd/extui/ia_creality/ia_creality_extui.cpp @@ -233,13 +233,11 @@ void onUserConfirmRequired(const char *const msg) { } // For fancy LCDs include an icon ID, message, and translated button title -void onUserConfirmRequired(const int icon, const char * const cstr, FSTR_P const fBtn) { +void onUserConfirmRequired(const int, const char * const cstr, FSTR_P const) { onUserConfirmRequired(cstr); - UNUSED(icon); UNUSED(fBtn); } -void onUserConfirmRequired(const int icon, FSTR_P const fstr, FSTR_P const fBtn) { +void onUserConfirmRequired(const int, FSTR_P const fstr, FSTR_P const) { onUserConfirmRequired(fstr); - UNUSED(icon); UNUSED(fBtn); } #if ENABLED(ADVANCED_PAUSE_FEATURE) diff --git a/Marlin/src/lcd/extui/nextion/nextion_extui.cpp b/Marlin/src/lcd/extui/nextion/nextion_extui.cpp index 570624afcc..7beecfecbf 100644 --- a/Marlin/src/lcd/extui/nextion/nextion_extui.cpp +++ b/Marlin/src/lcd/extui/nextion/nextion_extui.cpp @@ -56,13 +56,11 @@ namespace ExtUI { void onUserConfirmRequired(const char * const msg) { nextion.confirmationRequest(msg); } // For fancy LCDs include an icon ID, message, and translated button title - void onUserConfirmRequired(const int icon, const char * const cstr, FSTR_P const fBtn) { + void onUserConfirmRequired(const int, const char * const cstr, FSTR_P const) { onUserConfirmRequired(cstr); - UNUSED(icon); UNUSED(fBtn); } - void onUserConfirmRequired(const int icon, FSTR_P const fstr, FSTR_P const fBtn) { + void onUserConfirmRequired(const int, FSTR_P const fstr, FSTR_P const) { onUserConfirmRequired(fstr); - UNUSED(icon); UNUSED(fBtn); } #if ENABLED(ADVANCED_PAUSE_FEATURE) From e3433ea5996a8e0b3e3c9f9673464d99ac23a812 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Wed, 30 Apr 2025 00:30:45 +0000 Subject: [PATCH 268/787] [cron] Bump distribution date (2025-04-30) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index da4a399ef0..31c1157635 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-04-29" +//#define STRING_DISTRIBUTION_DATE "2025-04-30" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index c4282ea03a..b823785698 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-04-29" + #define STRING_DISTRIBUTION_DATE "2025-04-30" #endif /** From 1c719fd10de836efa01d71bf0208ecc40f607f3e Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Wed, 30 Apr 2025 10:21:13 -0500 Subject: [PATCH 269/787] =?UTF-8?q?=F0=9F=8E=A8=20Cosmetic=2004-29?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/lcd/extui/mks_ui/draw_dialog.cpp | 2 +- Marlin/src/lcd/menu/menu_main.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Marlin/src/lcd/extui/mks_ui/draw_dialog.cpp b/Marlin/src/lcd/extui/mks_ui/draw_dialog.cpp index 8713bf8909..1989724370 100644 --- a/Marlin/src/lcd/extui/mks_ui/draw_dialog.cpp +++ b/Marlin/src/lcd/extui/mks_ui/draw_dialog.cpp @@ -123,7 +123,7 @@ static void btn_ok_event_cb(lv_obj_t *btn, lv_event_t event) { #endif } else if (DIALOG_IS(TYPE_FINISH_PRINT)) { - uiCfg.print_state = IDLE; + uiCfg.print_state = IDLE; clear_cur_ui(); lv_draw_ready_print(); } diff --git a/Marlin/src/lcd/menu/menu_main.cpp b/Marlin/src/lcd/menu/menu_main.cpp index 04bbc41074..401c59f5c0 100644 --- a/Marlin/src/lcd/menu/menu_main.cpp +++ b/Marlin/src/lcd/menu/menu_main.cpp @@ -351,11 +351,11 @@ void menu_main() { ACTION_ITEM(MSG_NO_MEDIA, nullptr); // [No Media] } else { - #if ALL(HAS_MULTI_VOLUME, SHOW_UNMOUNTED_DRIVES) + #if ENABLED(SHOW_UNMOUNTED_DRIVES) // [Select from SD/USB] (or Password First) - if (TERN0(SHOW_UNMOUNTED_DRIVES, card.isSDCardInserted())) + if (card.isSDCardInserted()) SUBMENU(MSG_MEDIA_MENU_SD, MEDIA_MENU_GATEWAY_SD); - if (TERN0(SHOW_UNMOUNTED_DRIVES, card.isFlashDriveInserted())) + if (card.isFlashDriveInserted()) SUBMENU(MSG_MEDIA_MENU_USB, MEDIA_MENU_GATEWAY_USB); #else #define M21(T) F("M21" TERN_(HAS_MULTI_VOLUME, T)) From 48cc310c588b8ab52cffdc8f86855a05a4b20122 Mon Sep 17 00:00:00 2001 From: ellensp <530024+ellensp@users.noreply.github.com> Date: Thu, 1 May 2025 07:37:11 +1200 Subject: [PATCH 270/787] =?UTF-8?q?=F0=9F=94=A7=20More=20thorough=20TEMP?= =?UTF-8?q?=5FSENSOR=5F*=20cleanup=20(#27826)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/inc/Conditionals-3-etc.h | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/Marlin/src/inc/Conditionals-3-etc.h b/Marlin/src/inc/Conditionals-3-etc.h index e4dcdda58f..2456728554 100644 --- a/Marlin/src/inc/Conditionals-3-etc.h +++ b/Marlin/src/inc/Conditionals-3-etc.h @@ -42,30 +42,32 @@ // Clean up unused temperature sensors and sub-options -#if !TEMP_SENSOR_0 +#define UNUSED_TEMP_SENSOR(N) (!TEMP_SENSOR_##N || N >= HOTENDS) +#if UNUSED_TEMP_SENSOR(0) #undef TEMP_SENSOR_0 #endif -#if !TEMP_SENSOR_1 +#if UNUSED_TEMP_SENSOR(1) #undef TEMP_SENSOR_1 #endif -#if !TEMP_SENSOR_2 +#if UNUSED_TEMP_SENSOR(2) #undef TEMP_SENSOR_2 #endif -#if !TEMP_SENSOR_3 +#if UNUSED_TEMP_SENSOR(3) #undef TEMP_SENSOR_3 #endif -#if !TEMP_SENSOR_4 +#if UNUSED_TEMP_SENSOR(4) #undef TEMP_SENSOR_4 #endif -#if !TEMP_SENSOR_5 +#if UNUSED_TEMP_SENSOR(5) #undef TEMP_SENSOR_5 #endif -#if !TEMP_SENSOR_6 +#if UNUSED_TEMP_SENSOR(6) #undef TEMP_SENSOR_6 #endif -#if !TEMP_SENSOR_7 +#if UNUSED_TEMP_SENSOR(7) #undef TEMP_SENSOR_7 #endif +#undef UNUSED_TEMP_SENSOR #if !TEMP_SENSOR_BED #undef TEMP_SENSOR_BED From 4096beaf527e3dfa27f12cc7cfff6502f94ef2ca Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Thu, 1 May 2025 00:34:50 +0000 Subject: [PATCH 271/787] [cron] Bump distribution date (2025-05-01) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 31c1157635..a2ef14eecd 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-04-30" +//#define STRING_DISTRIBUTION_DATE "2025-05-01" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index b823785698..618bca9810 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-04-30" + #define STRING_DISTRIBUTION_DATE "2025-05-01" #endif /** From e16885c558e8c03b43f2127780a4ec15ee29dd1e Mon Sep 17 00:00:00 2001 From: staff1010 <132726146+staff1010@users.noreply.github.com> Date: Sat, 3 May 2025 00:13:26 +0800 Subject: [PATCH 272/787] =?UTF-8?q?=F0=9F=9A=B8=20Fix=20MKS=20UI=20G-code?= =?UTF-8?q?=20result=20display=20(#27825)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Scott Lahteine --- Marlin/src/lcd/extui/mks_ui/draw_gcode.cpp | 25 +++++++--- Marlin/src/lcd/extui/mks_ui/draw_gcode.h | 1 + Marlin/src/lcd/extui/mks_ui/draw_keyboard.cpp | 2 +- .../src/lcd/extui/mks_ui/draw_move_motor.cpp | 24 +++++---- Marlin/src/lcd/extui/mks_ui/draw_ui.cpp | 8 +++ .../lcd/extui/mks_ui/draw_z_offset_wizard.cpp | 24 +++++---- Marlin/src/lcd/extui/mks_ui/wifi_module.cpp | 49 +++++++------------ 7 files changed, 70 insertions(+), 63 deletions(-) diff --git a/Marlin/src/lcd/extui/mks_ui/draw_gcode.cpp b/Marlin/src/lcd/extui/mks_ui/draw_gcode.cpp index 8a3366e01d..68c5cd22d4 100644 --- a/Marlin/src/lcd/extui/mks_ui/draw_gcode.cpp +++ b/Marlin/src/lcd/extui/mks_ui/draw_gcode.cpp @@ -34,6 +34,7 @@ static lv_obj_t *scr, *outL, *outV = 0; static int currentWritePos = 0; extern uint8_t public_buf[513]; extern "C" { extern char public_buf_m[100]; } +extern bool gcode_output_update_flag; enum { ID_GCODE_RETURN = 1, @@ -43,6 +44,8 @@ enum { static void event_handler(lv_obj_t *obj, lv_event_t event) { if (event != LV_EVENT_RELEASED) return; lv_clear_gcode(); + public_buf[0] = public_buf_m[0] = 0; // Clear output buffer + MYSERIAL1.setHook(); switch (obj->mks_obj_id) { case ID_GCODE_RETURN: lv_draw_more(); @@ -56,20 +59,22 @@ static void event_handler(lv_obj_t *obj, lv_event_t event) { void lv_show_gcode_output(void * that, const char * txt) { // Ignore echo of command - if (!memcmp(txt, "echo:", 5)) { - public_buf[0] = 0; // Clear output buffer + if (txt[0] == 'e' && txt[4] == ':') { // !memcmp_P(txt, PSTR("echo:"), 5) + public_buf[0] = public_buf_m[0] = 0; // Clear output buffer return; } // Avoid overflow if the answer is too large size_t len = strlen((const char*)public_buf), tlen = strlen(txt); - if (len + tlen + 1 < sizeof(public_buf)) { + if (len + tlen + 2 <= sizeof(public_buf)) { memcpy(public_buf + len, txt, tlen); public_buf[len + tlen] = '\n'; + public_buf[len + tlen + 1] = '\0'; } } void lv_serial_capt_hook(void * userPointer, uint8_t c) { + gcode_output_update_flag = false; if (c == '\n' || currentWritePos == sizeof(public_buf_m) - 1) { // End of line, probably end of command anyway public_buf_m[currentWritePos] = 0; lv_show_gcode_output(userPointer, public_buf_m); @@ -82,17 +87,21 @@ void lv_serial_capt_hook(void * userPointer, uint8_t c) { void lv_eom_hook(void *) { // Message is done, let's remove the hook now MYSERIAL1.setHook(); + // Update message display + gcode_output_update_flag = true; } void lv_draw_gcode(bool clear) { if (clear) { currentWritePos = 0; - public_buf[0] = 0; + public_buf[0] = public_buf_m[0] = 0; + MYSERIAL1.setHook(); + gcode_output_update_flag = false; } scr = lv_screen_create(GCODE_UI, more_menu.gcode); - lv_screen_menu_item(scr, more_menu.entergcode, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_GCODE_COMMAND, 1); + lv_screen_menu_item(scr, more_menu.entergcode, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_GCODE_COMMAND, 0); outL = lv_label_create(scr, PARA_UI_POS_X, PARA_UI_POS_Y * 2, "Result:"); - outV = lv_label_create(scr, PARA_UI_POS_X, PARA_UI_POS_Y * 3, (const char*)public_buf); + outV = lv_label_create(scr, PARA_UI_POS_X, PARA_UI_POS_Y * 2 + 20, (const char*)public_buf); lv_big_button_create(scr, "F:/bmp_back70x40.bin", common_menu.text_back, PARA_UI_BACK_POS_X + 10, PARA_UI_BACK_POS_Y, event_handler, ID_GCODE_RETURN, true); } @@ -105,4 +114,8 @@ void lv_clear_gcode() { outV = 0; } +void disp_gcode_output() { + lv_label_set_text(outV, (const char*)public_buf); +} + #endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/mks_ui/draw_gcode.h b/Marlin/src/lcd/extui/mks_ui/draw_gcode.h index df752e7cc9..0cb19fb1ad 100644 --- a/Marlin/src/lcd/extui/mks_ui/draw_gcode.h +++ b/Marlin/src/lcd/extui/mks_ui/draw_gcode.h @@ -27,6 +27,7 @@ void lv_draw_gcode(bool clear = false); void lv_clear_gcode(); +void disp_gcode_output(); #ifdef __cplusplus } /* C-declarations for C++ */ diff --git a/Marlin/src/lcd/extui/mks_ui/draw_keyboard.cpp b/Marlin/src/lcd/extui/mks_ui/draw_keyboard.cpp index ec7e549c41..0d049a2f64 100644 --- a/Marlin/src/lcd/extui/mks_ui/draw_keyboard.cpp +++ b/Marlin/src/lcd/extui/mks_ui/draw_keyboard.cpp @@ -160,7 +160,7 @@ static void lv_kb_event_cb(lv_obj_t *kb, lv_event_t event) { goto_previous_ui(); break; case GCodeCommand: - if (ret_ta_txt[0] && !queue.ring_buffer.full(3)) { + if (ret_ta_txt[0]) { // Hook for the next bytes to arrive from the serial port MYSERIAL1.setHook(lv_serial_capt_hook, lv_eom_hook, 0); // Run the command as soon as possible diff --git a/Marlin/src/lcd/extui/mks_ui/draw_move_motor.cpp b/Marlin/src/lcd/extui/mks_ui/draw_move_motor.cpp index 635421b4c3..aa9fbdcd95 100644 --- a/Marlin/src/lcd/extui/mks_ui/draw_move_motor.cpp +++ b/Marlin/src/lcd/extui/mks_ui/draw_move_motor.cpp @@ -59,19 +59,17 @@ void disp_cur_pos() { static void event_handler(lv_obj_t *obj, lv_event_t event) { char str_1[16]; if (event != LV_EVENT_RELEASED) return; - if (!queue.ring_buffer.full(3)) { - bool do_inject = true; - float dist = uiCfg.move_dist; - switch (obj->mks_obj_id) { - case ID_M_X_N: dist *= -1; case ID_M_X_P: cur_label = 'X'; break; - case ID_M_Y_N: dist *= -1; case ID_M_Y_P: cur_label = 'Y'; break; - case ID_M_Z_N: dist *= -1; case ID_M_Z_P: cur_label = 'Z'; break; - default: do_inject = false; - } - if (do_inject) { - sprintf_P(public_buf_l, PSTR("G91\nG1 %c%s F%d\nG90"), cur_label, dtostrf(dist, 1, 3, str_1), uiCfg.moveSpeed); - queue.inject(public_buf_l); - } + bool do_inject = true; + float dist = uiCfg.move_dist; + switch (obj->mks_obj_id) { + case ID_M_X_N: dist *= -1; case ID_M_X_P: cur_label = 'X'; break; + case ID_M_Y_N: dist *= -1; case ID_M_Y_P: cur_label = 'Y'; break; + case ID_M_Z_N: dist *= -1; case ID_M_Z_P: cur_label = 'Z'; break; + default: do_inject = false; + } + if (do_inject) { + sprintf_P(public_buf_l, PSTR("G91\nG1 %c%s F%d\nG90"), cur_label, dtostrf(dist, 1, 3, str_1), uiCfg.moveSpeed); + queue.inject(public_buf_l); } switch (obj->mks_obj_id) { diff --git a/Marlin/src/lcd/extui/mks_ui/draw_ui.cpp b/Marlin/src/lcd/extui/mks_ui/draw_ui.cpp index 2e66db2c86..4278092472 100644 --- a/Marlin/src/lcd/extui/mks_ui/draw_ui.cpp +++ b/Marlin/src/lcd/extui/mks_ui/draw_ui.cpp @@ -71,6 +71,7 @@ uint32_t size = 809; uint16_t row; bool temps_update_flag; uint8_t printing_rate_update_flag; +bool gcode_output_update_flag; extern bool once_flag; extern uint8_t sel_id; @@ -864,6 +865,13 @@ void GUI_RefreshPage() { } break; + case GCODE_UI: + if (gcode_output_update_flag) { + gcode_output_update_flag = false; + disp_gcode_output(); + } + break; + default: break; } diff --git a/Marlin/src/lcd/extui/mks_ui/draw_z_offset_wizard.cpp b/Marlin/src/lcd/extui/mks_ui/draw_z_offset_wizard.cpp index 9d16c9dff2..cdd151322b 100644 --- a/Marlin/src/lcd/extui/mks_ui/draw_z_offset_wizard.cpp +++ b/Marlin/src/lcd/extui/mks_ui/draw_z_offset_wizard.cpp @@ -73,19 +73,17 @@ static void event_handler(lv_obj_t *obj, lv_event_t event) { char str_1[16]; if (event != LV_EVENT_RELEASED) return; //lv_clear_z_offset_wizard(); - if (!queue.ring_buffer.full(3)) { - bool do_inject = true; - float dist = uiCfg.move_dist; - switch (obj->mks_obj_id) { - case ID_M_Z_N: dist *= -1; case ID_M_Z_P: cur_label = 'Z'; break; - default: do_inject = false; - } - if (do_inject) { - sprintf_P(public_buf_l, PSTR("G91\nG1 %c%s F%d\nG90"), cur_label, dtostrf(dist, 1, 3, str_1), uiCfg.moveSpeed); - queue.inject(public_buf_l); - //calculated_z_offset = probe.offset.z + current_position.z - z_offset_ref; - disp_cur_wizard_pos(); - } + bool do_inject = true; + float dist = uiCfg.move_dist; + switch (obj->mks_obj_id) { + case ID_M_Z_N: dist *= -1; case ID_M_Z_P: cur_label = 'Z'; break; + default: do_inject = false; + } + if (do_inject) { + sprintf_P(public_buf_l, PSTR("G91\nG1 %c%s F%d\nG90"), cur_label, dtostrf(dist, 1, 3, str_1), uiCfg.moveSpeed); + queue.inject(public_buf_l); + //calculated_z_offset = probe.offset.z + current_position.z - z_offset_ref; + disp_cur_wizard_pos(); } switch (obj->mks_obj_id) { diff --git a/Marlin/src/lcd/extui/mks_ui/wifi_module.cpp b/Marlin/src/lcd/extui/mks_ui/wifi_module.cpp index 1bc1e043d9..e6adbcbc03 100644 --- a/Marlin/src/lcd/extui/mks_ui/wifi_module.cpp +++ b/Marlin/src/lcd/extui/mks_ui/wifi_module.cpp @@ -770,8 +770,9 @@ int package_to_wifi(WIFI_RET_TYPE type, uint8_t *buf, int len) { } int send_to_wifi(uint8_t * const buf, const int len) { return package_to_wifi(WIFI_TRANS_INF, buf, len); } +int print_to_wifi(const char * const buf) { return package_to_wifi(WIFI_TRANS_INF, (uint8_t*)buf, strlen(buf)); } -inline void send_ok_to_wifi() { send_to_wifi((uint8_t *)"ok\r\n", strlen("ok\r\n")); } +inline void send_ok_to_wifi() { print_to_wifi("ok\r\n"); } void set_cur_file_sys(int fileType) { gCfgItems.fileSysType = fileType; } @@ -905,7 +906,7 @@ uint8_t exploreDisk(const char * const path, const uint8_t recu_level, const boo } strcat_P(Fstream, PSTR("\r\n")); - send_to_wifi((uint8_t*)Fstream, strlen(Fstream)); + print_to_wifi(Fstream); } return fileCnt; @@ -950,9 +951,9 @@ static void wifi_gcode_exec(uint8_t * const cmd_line) { int index = 0; if (spStr == nullptr) { gCfgItems.fileSysType = FILE_SYS_SD; - send_to_wifi((uint8_t *)(STR_BEGIN_FILE_LIST "\r\n"), strlen(STR_BEGIN_FILE_LIST "\r\n")); + print_to_wifi(STR_BEGIN_FILE_LIST "\r\n"); get_file_list("0:/", false); - send_to_wifi((uint8_t *)(STR_END_FILE_LIST "\r\n"), strlen(STR_END_FILE_LIST "\r\n")); + print_to_wifi(STR_END_FILE_LIST "\r\n"); send_ok_to_wifi(); break; } @@ -962,7 +963,7 @@ static void wifi_gcode_exec(uint8_t * const cmd_line) { if (gCfgItems.wifi_type == ESP_WIFI) { char * const path = (char *)tempBuf; if (strlen(&mStr[index]) < 80) { - send_to_wifi((uint8_t *)(STR_BEGIN_FILE_LIST "\r\n"), strlen(STR_BEGIN_FILE_LIST "\r\n")); + print_to_wifi(STR_BEGIN_FILE_LIST "\r\n"); if (strncmp(&mStr[index], "1:", 2) == 0) gCfgItems.fileSysType = FILE_SYS_SD; @@ -972,7 +973,7 @@ static void wifi_gcode_exec(uint8_t * const cmd_line) { strcpy(path, &mStr[index]); const bool with_longnames = strchr(mStr, 'L') != nullptr; get_file_list(path, with_longnames); - send_to_wifi((uint8_t *)(STR_END_FILE_LIST "\r\n"), strlen(STR_END_FILE_LIST "\r\n")); + print_to_wifi(STR_END_FILE_LIST "\r\n"); } send_ok_to_wifi(); } @@ -1033,9 +1034,9 @@ static void wifi_gcode_exec(uint8_t * const cmd_line) { card.openFileRead(cur_name); if (card.isFileOpen()) - send_to_wifi((uint8_t *)"File selected\r\n", strlen("File selected\r\n")); + print_to_wifi("File selected\r\n"); else { - send_to_wifi((uint8_t *)"file.open failed\r\n", strlen("file.open failed\r\n")); + print_to_wifi("file.open failed\r\n"); strcpy_P(list_file.file_name[sel_id], PSTR("notValid")); } send_ok_to_wifi(); @@ -1149,7 +1150,7 @@ static void wifi_gcode_exec(uint8_t * const cmd_line) { print_rate = uiCfg.totalSend; ZERO(tempBuf); sprintf_P((char *)tempBuf, PSTR("M27 %d\r\n"), print_rate); - send_to_wifi((uint8_t *)tempBuf, strlen((char *)tempBuf)); + print_to_wifi(tempBuf); } break; @@ -1182,7 +1183,7 @@ static void wifi_gcode_exec(uint8_t * const cmd_line) { ZERO(tempBuf); sprintf_P((char *)tempBuf, PSTR("Writing to file: %s\r\n"), (char *)file_writer.saveFileName); wifi_ret_ack(); - send_to_wifi((uint8_t *)tempBuf, strlen((char *)tempBuf)); + print_to_wifi(tempBuf); wifi_link_state = WIFI_WAIT_TRANS_START; } else { @@ -1246,7 +1247,7 @@ static void wifi_gcode_exec(uint8_t * const cmd_line) { ); } - send_to_wifi((uint8_t *)tempBuf, strlen((char *)tempBuf)); + print_to_wifi(tempBuf); queue.enqueue_one(F("M105")); break; @@ -1255,7 +1256,7 @@ static void wifi_gcode_exec(uint8_t * const cmd_line) { ZERO(tempBuf); sprintf_P((char *)tempBuf, PSTR("M992 %d%d:%d%d:%d%d\r\n"), print_time.hours/10, print_time.hours%10, print_time.minutes/10, print_time.minutes%10, print_time.seconds/10, print_time.seconds%10); wifi_ret_ack(); - send_to_wifi((uint8_t *)tempBuf, strlen((char *)tempBuf)); + print_to_wifi(tempBuf); } break; @@ -1265,7 +1266,7 @@ static void wifi_gcode_exec(uint8_t * const cmd_line) { if (strlen((char *)list_file.file_name[sel_id]) > (100 - 1)) return; sprintf_P((char *)tempBuf, PSTR("M994 %s;%d\n"), list_file.file_name[sel_id], (int)gCfgItems.curFilesize); wifi_ret_ack(); - send_to_wifi((uint8_t *)tempBuf, strlen((char *)tempBuf)); + print_to_wifi(tempBuf); } break; @@ -1275,22 +1276,10 @@ static void wifi_gcode_exec(uint8_t * const cmd_line) { #define SENDPAUSE "M997 PAUSE\r\n" switch (uiCfg.print_state) { default: break; - case IDLE: - wifi_ret_ack(); - send_to_wifi((uint8_t *)SENDIDLE, strlen(SENDIDLE)); - break; - case WORKING: - wifi_ret_ack(); - send_to_wifi((uint8_t *)SENDPRINTING, strlen(SENDPRINTING)); - break; - case PAUSED: - wifi_ret_ack(); - send_to_wifi((uint8_t *)SENDPAUSE, strlen(SENDPAUSE)); - break; - case REPRINTING: - wifi_ret_ack(); - send_to_wifi((uint8_t *)SENDPAUSE, strlen(SENDPAUSE)); - break; + case IDLE: wifi_ret_ack(); print_to_wifi(SENDIDLE); break; + case WORKING: wifi_ret_ack(); print_to_wifi(SENDPRINTING); break; + case PAUSED: wifi_ret_ack(); print_to_wifi(SENDPAUSE); break; + case REPRINTING: wifi_ret_ack(); print_to_wifi(SENDPAUSE); break; } if (!uiCfg.command_send) get_wifi_list_command_send(); break; @@ -1307,7 +1296,7 @@ static void wifi_gcode_exec(uint8_t * const cmd_line) { ZERO(tempBuf); send_ok_to_wifi(); #define SENDFW "FIRMWARE_NAME:Robin_nano\r\n" - send_to_wifi((uint8_t *)SENDFW, strlen(SENDFW)); + print_to_wifi(SENDFW); break; default: From b74c81d3e426899009a85827d834dbbe74579036 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Fri, 2 May 2025 11:58:45 -0500 Subject: [PATCH 273/787] =?UTF-8?q?=F0=9F=94=A7=20Bricolemon=20cleanup,=20?= =?UTF-8?q?update=20(#27829)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/pins/pins_postprocess.h | 22 ++-- .../src/pins/samd/pins_BRICOLEMON_LITE_V1_0.h | 73 ++++++----- Marlin/src/pins/samd/pins_BRICOLEMON_V1_0.h | 123 ++++++++---------- Marlin/src/pins/samd/pins_MINITRONICS20.h | 10 +- 4 files changed, 111 insertions(+), 117 deletions(-) diff --git a/Marlin/src/pins/pins_postprocess.h b/Marlin/src/pins/pins_postprocess.h index 9e82d854f9..4d2455bd31 100644 --- a/Marlin/src/pins/pins_postprocess.h +++ b/Marlin/src/pins/pins_postprocess.h @@ -891,7 +891,7 @@ #endif #define AUTO_ASSIGNED_X2_DIAG 1 #endif -#endif +#endif // HAS_X2_STEPPER #ifndef X2_CS_PIN #define X2_CS_PIN -1 @@ -976,7 +976,7 @@ #endif #define AUTO_ASSIGNED_Y2_DIAG 1 #endif -#endif +#endif // HAS_Y2_STEPPER #ifndef Y2_CS_PIN #define Y2_CS_PIN -1 @@ -1061,7 +1061,7 @@ #endif #define AUTO_ASSIGNED_Z2_DIAG 1 #endif -#endif +#endif // NUM_Z_STEPPERS >= 2 #ifndef Z2_CS_PIN #define Z2_CS_PIN -1 @@ -1146,7 +1146,7 @@ #endif #define AUTO_ASSIGNED_Z3_DIAG 1 #endif -#endif +#endif // NUM_Z_STEPPERS >= 3 #ifndef Z3_CS_PIN #define Z3_CS_PIN -1 @@ -1231,7 +1231,7 @@ #endif #define AUTO_ASSIGNED_Z4_DIAG 1 #endif -#endif +#endif // NUM_Z_STEPPERS >= 4 #ifndef Z4_CS_PIN #define Z4_CS_PIN -1 @@ -1316,7 +1316,7 @@ #endif #define AUTO_ASSIGNED_I_DIAG 1 #endif -#endif +#endif // HAS_I_AXIS #ifndef I_CS_PIN #define I_CS_PIN -1 @@ -1401,7 +1401,7 @@ #endif #define AUTO_ASSIGNED_J_DIAG 1 #endif -#endif +#endif // HAS_J_AXIS #ifndef J_CS_PIN #define J_CS_PIN -1 @@ -1486,7 +1486,7 @@ #endif #define AUTO_ASSIGNED_K_DIAG 1 #endif -#endif +#endif // HAS_K_AXIS #ifndef K_CS_PIN #define K_CS_PIN -1 @@ -1571,7 +1571,7 @@ #endif #define AUTO_ASSIGNED_U_DIAG 1 #endif -#endif +#endif // HAS_U_AXIS #ifndef U_CS_PIN #define U_CS_PIN -1 @@ -1656,7 +1656,7 @@ #endif #define AUTO_ASSIGNED_V_DIAG 1 #endif -#endif +#endif // HAS_V_AXIS #ifndef V_CS_PIN #define V_CS_PIN -1 @@ -1734,7 +1734,7 @@ #endif #define AUTO_ASSIGNED_W_DIAG 1 #endif -#endif +#endif // HAS_W_AXIS #ifndef W_CS_PIN #define W_CS_PIN -1 diff --git a/Marlin/src/pins/samd/pins_BRICOLEMON_LITE_V1_0.h b/Marlin/src/pins/samd/pins_BRICOLEMON_LITE_V1_0.h index 98ec48de80..f79a743c2a 100644 --- a/Marlin/src/pins/samd/pins_BRICOLEMON_LITE_V1_0.h +++ b/Marlin/src/pins/samd/pins_BRICOLEMON_LITE_V1_0.h @@ -22,13 +22,15 @@ #pragma once /** - * BRICOLEMON LITE Board. Based on atsamd51 (AGCM4), bootloader and credits by ADAFRUIT. + * Bricolemon Lite Board. Based on atsamd51 (AGCM4), bootloader and credits by ADAFRUIT. + * https://lemoncrest.com https://bricogeek.com + * * This board its a 3.3V LOGIC Board, following the ADAFRUIT example, all of the board is open source. * Schematic: Refer to the Bricolemon - * 3DSTEP: https://github.com/bricogeek/bricolemon/blob/master/Documentacion/Bricolemon%20Lite/LC_BG_002_PCB_V1I4.step - * PinDemux: https://github.com/bricogeek/bricolemon/blob/master/Documentacion/Bricolemon/PinDEMUX.xlsx + * 3DSTEP: https://github.com/bricogeek/bricolemon/blob/master/Documentacion/Bricolemon%20Lite/LC_BG_002_PCB_V1I4.step + * PinDemux: https://github.com/bricogeek/bricolemon/blob/master/Documentacion/Bricolemon/PinDEMUX.xlsx * - * NOTE: We need the Serial port on the -1 to make it work!!. Remember to change it on configuration.h #define SERIAL_PORT -1 + * NOTE: Requires SERIAL_PORT -1 */ #if NOT_TARGET(ARDUINO_GRAND_CENTRAL_M4) @@ -36,37 +38,50 @@ #endif #ifndef BOARD_INFO_NAME - #define BOARD_INFO_NAME "BRICOLEMON LITE V1.0" // Lemoncrest & BricoGeek collaboration. + #define BOARD_INFO_NAME "Bricolemon Lite v1.0" // Lemoncrest & BricoGeek collaboration. #endif -/** - * EEPROM EMULATION: Works with some bugs already, but the board needs an I2C EEPROM memory soldered on. - */ -//#define FLASH_EEPROM_EMULATION -#define I2C_EEPROM // EEPROM on I2C-0 -#define MARLIN_EEPROM_SIZE 0x10000U // 64K (CAT24C512) - -// This is another option to emulate an EEPROM, but it's more efficient to not lose the data in the first place. -//#define SDCARD_EEPROM_EMULATION +// +// EEPROM Emulation: Works (with some bugs) already, but the board needs an I2C EEPROM memory soldered on. +// +#if NO_EEPROM_SELECTED + #define I2C_EEPROM // EEPROM on I2C-0 + //#define FLASH_EEPROM_EMULATION + //#define SDCARD_EEPROM_EMULATION + #if ENABLED(I2C_EEPROM) + #define MARLIN_EEPROM_SIZE 0x10000U // 64K (CAT24C512) + #if ENABLED(SDCARD_EEPROM_EMULATION) + #define MARLIN_EEPROM_SIZE 0x800U // 2K + #else + #define MARLIN_EEPROM_SIZE 0x800U // 2K + #endif + #undef NO_EEPROM_SELECTED +#endif // -// BLTOUCH PIN: This pin is the signal pin for the BLTOUCH sensor. +// Servos // -#define SERVO0_PIN 33 // BLTouch PWM +#define SERVO0_PIN 33 // BL_TOUCH + +// +// TMC StallGuard DIAG pins - Require soldered bridges! +// +#define X_DIAG_PIN 10 // X_STOP +#define Y_DIAG_PIN 11 // Y_STOP +#define Z_DIAG_PIN 12 // Z_STOP +#define E0_DIAG_PIN 32 // E_STOP // // Limit Switches // -#define X_STOP_PIN 10 -#define Y_STOP_PIN 11 -#define Z_STOP_PIN 12 +#define X_STOP_PIN X_DIAG_PIN +#define Y_STOP_PIN Y_DIAG_PIN +#define Z_STOP_PIN Z_DIAG_PIN // -// Z Probe (when not Z_MIN_PIN) +// Filament Runout Sensor // -#ifndef Z_MIN_PROBE_PIN - #define Z_MIN_PROBE_PIN 12 -#endif +#define FIL_RUNOUT_PIN 32 // E_STOP // // Steppers @@ -87,10 +102,6 @@ #define E0_DIR_PIN 25 #define E0_ENABLE_PIN 29 -// Filament runout. You may choose to use this pin for some other purpose. It's a normal GPIO that can be configured as I/O. -// For example, a switch to detect any kind of behavior, Power supply pin .... etc. -#define FIL_RUNOUT_PIN 32 - // // Temperature Sensors // @@ -579,16 +590,16 @@ // Default TMC slave addresses #ifndef X_SLAVE_ADDRESS - #define X_SLAVE_ADDRESS 0 + #define X_SLAVE_ADDRESS 0 #endif #ifndef Y_SLAVE_ADDRESS - #define Y_SLAVE_ADDRESS 1 + #define Y_SLAVE_ADDRESS 1 #endif #ifndef Z_SLAVE_ADDRESS - #define Z_SLAVE_ADDRESS 2 + #define Z_SLAVE_ADDRESS 2 #endif #ifndef E0_SLAVE_ADDRESS - #define E0_SLAVE_ADDRESS 3 + #define E0_SLAVE_ADDRESS 3 #endif static_assert(X_SLAVE_ADDRESS == 0, "X_SLAVE_ADDRESS must be 0 for BOARD_BRICOLEMON_LITE_V1_0."); static_assert(Y_SLAVE_ADDRESS == 1, "Y_SLAVE_ADDRESS must be 1 for BOARD_BRICOLEMON_LITE_V1_0."); diff --git a/Marlin/src/pins/samd/pins_BRICOLEMON_V1_0.h b/Marlin/src/pins/samd/pins_BRICOLEMON_V1_0.h index 37f0b79f6b..8de6ac5b71 100644 --- a/Marlin/src/pins/samd/pins_BRICOLEMON_V1_0.h +++ b/Marlin/src/pins/samd/pins_BRICOLEMON_V1_0.h @@ -22,7 +22,8 @@ #pragma once /** - * BRICOLEMON Board. Based on ATSAMD51 (AGCM4), bootloader and credits by ADAFRUIT. + * Bricolemon Board. Based on ATSAMD51 (AGCM4), bootloader and credits by ADAFRUIT. + * https://lemoncrest.com https://bricogeek.com */ #if NOT_TARGET(ARDUINO_GRAND_CENTRAL_M4) @@ -30,11 +31,11 @@ #endif #ifndef BOARD_INFO_NAME - #define BOARD_INFO_NAME "BRICOLEMON V1.0" // Lemoncrest & BricoGeek collaboration. + #define BOARD_INFO_NAME "Bricolemon V1.0" // Lemoncrest & BricoGeek collaboration. #endif /** - * BRICOLEMON Board. Based on atsamd51 (AGCM4), bootloader and credits by ADAFRUIT. + * Bricolemon Board. Based on atsamd51 (AGCM4), bootloader and credits by ADAFRUIT. * This board its a 3.3V LOGIC Board, following the ADAFRUIT example, all of the board is open source. * Schematic: https://github.com/bricogeek/bricolemon/blob/master/Documentacion/Bricolemon/EsquemaBricolemon_REVB.pdf * 3DSTEP: https://github.com/bricogeek/bricolemon/blob/master/Documentacion/Bricolemon/BricolemonREVB.step @@ -43,41 +44,52 @@ * NOTE: We need the Serial port on the -1 to make it work!!. Remember to change it on configuration.h #define SERIAL_PORT -1 */ -/** - * EEPROM EMULATION: Works with some bugs already, but the board needs an I2C EEPROM memory soldered on. - */ -//#define FLASH_EEPROM_EMULATION -#define I2C_EEPROM // EEPROM on I2C-0 -#define MARLIN_EEPROM_SIZE 0x10000U // 64K (CAT24C512) - -//This its another option to emulate an EEPROM, but its more efficient to dont loose the data the first One. -//#define SDCARD_EEPROM_EMULATION +// +// EEPROM Emulation: Works (with some bugs) already, but the board needs an I2C EEPROM memory soldered on. +// +#if NO_EEPROM_SELECTED + #define I2C_EEPROM // EEPROM on I2C-0 + //#define FLASH_EEPROM_EMULATION + //#define SDCARD_EEPROM_EMULATION + #if ENABLED(I2C_EEPROM) + #define MARLIN_EEPROM_SIZE 0x10000U // 64K (CAT24C512) + #if ENABLED(SDCARD_EEPROM_EMULATION) + #define MARLIN_EEPROM_SIZE 0x800U // 2K + #else + #define MARLIN_EEPROM_SIZE 0x800U // 2K + #endif + #undef NO_EEPROM_SELECTED +#endif // -// BLTouch +// Servos // -#define SERVO0_PIN 33 // BLTouch PWM +#define SERVO0_PIN 33 // BL_TOUCH // -// Limit Switches +// TMC StallGuard DIAG pins - Require soldered bridges! // -#define X_STOP_PIN 10 -#define Y_STOP_PIN 11 -#define Z_STOP_PIN 12 - -/** - * NOTE: Useful if extra TMC2209 are to be used as independent axes. - * We need to configure the new digital PIN, for this we could configure on the board the extra pin of this stepper, for example as a MIN_PIN/MAX_PIN. This pin is the D14. - */ -//#define Z2_STOP_PIN 14 -//#define X2_STOP_PIN 14 -//#define Y2_STOP_PIN 14 +#define X_DIAG_PIN 10 // X_STOP +#define Y_DIAG_PIN 11 // Y_STOP +#define Z_DIAG_PIN 12 // Z_STOP +#define E0_DIAG_PIN 48 // E0_STOP +#define E1_DIAG_PIN 14 // E1_STOP // -// Z Probe (when not Z_MIN_PIN) +// Limit Switches // -#ifndef Z_MIN_PROBE_PIN - #define Z_MIN_PROBE_PIN 12 +#define X_STOP_PIN X_DIAG_PIN +#define Y_STOP_PIN Y_DIAG_PIN +#define Z_STOP_PIN Z_DIAG_PIN + +// +// Filament Runout Sensor +// +#ifndef FIL_RUNOUT_PIN + #define FIL_RUNOUT_PIN 48 // E0_STOP +#endif +#ifndef FIL_RUNOUT2_PIN + #define FIL_RUNOUT2_PIN 14 // E1_STOP #endif // @@ -103,47 +115,18 @@ #define E1_DIR_PIN 46 #define E1_ENABLE_PIN 47 -// Filament runout. You may choose to use this pin for some other purpose. It's a normal GPIO that can be configured as I/O. -// For example, a switch to detect any kind of behavior, Power supply pin .... etc. -#define FIL_RUNOUT_PIN 32 - -// This board have the option to use an extra TMC2209 stepper, one of the use could be as a second extruder. -#if EXTRUDERS < 2 - // TODO: Corregir aquí que cuando tenemos dos extrusores o lo que sea, utiliza los endstop que le sobran, osea los max, no hay Z2_endstop - #if NUM_Z_STEPPERS > 1 - #define Z2_STOP_PIN 14 - #endif -#else - // If we want to configure the extra stepper as a Extruder, we should have undef all of the extra motors. - #undef X2_DRIVER_TYPE - #undef Y2_DRIVER_TYPE - #undef Z2_DRIVER_TYPE - #undef Z3_DRIVER_TYPE - #undef Z4_DRIVER_TYPE - - // Si tenemos más de un extrusor lo que hacemos es definir el nuevo extrusor así como sus pines - // Acordarse de definir el #define TEMP_SENSOR_1, ya que este contiene el tipo de sonda del extrusor E1 - - #define FIL_RUNOUT2_PIN 14 - -#endif - // -// Extruder / Bed -// - // Temperature Sensors +// #define TEMP_0_PIN 1 - -// You could use one of the ADC for a temp chamber if you don't use the second extruder, for example. -#if TEMP_SENSOR_CHAMBER > 0 - #define TEMP_CHAMBER_PIN 3 -#else - #define TEMP_1_PIN 3 -#endif - +#define TEMP_1_PIN 3 #define TEMP_BED_PIN 2 +// You could use one of the ADC for a chamber if you don't use the second extruder, for example. +#if TEMP_SENSOR_CHAMBER + #define TEMP_CHAMBER_PIN TEMP_1_PIN +#endif + // // Heaters / Fans // @@ -635,19 +618,19 @@ // Default TMC slave addresses #ifndef X_SLAVE_ADDRESS - #define X_SLAVE_ADDRESS 0 + #define X_SLAVE_ADDRESS 0 #endif #ifndef Y_SLAVE_ADDRESS - #define Y_SLAVE_ADDRESS 1 + #define Y_SLAVE_ADDRESS 1 #endif #ifndef Z_SLAVE_ADDRESS - #define Z_SLAVE_ADDRESS 2 + #define Z_SLAVE_ADDRESS 2 #endif #ifndef E0_SLAVE_ADDRESS - #define E0_SLAVE_ADDRESS 3 + #define E0_SLAVE_ADDRESS 3 #endif #ifndef E1_SLAVE_ADDRESS - #define E1_SLAVE_ADDRESS 0 + #define E1_SLAVE_ADDRESS 0 #endif static_assert(X_SLAVE_ADDRESS == 0, "X_SLAVE_ADDRESS must be 0 for BOARD_BRICOLEMON_V1_0."); static_assert(Y_SLAVE_ADDRESS == 1, "Y_SLAVE_ADDRESS must be 1 for BOARD_BRICOLEMON_V1_0."); diff --git a/Marlin/src/pins/samd/pins_MINITRONICS20.h b/Marlin/src/pins/samd/pins_MINITRONICS20.h index 0f61aea713..827cc57d1f 100644 --- a/Marlin/src/pins/samd/pins_MINITRONICS20.h +++ b/Marlin/src/pins/samd/pins_MINITRONICS20.h @@ -519,19 +519,19 @@ // Default TMC slave addresses #ifndef X_SLAVE_ADDRESS - #define X_SLAVE_ADDRESS 0 + #define X_SLAVE_ADDRESS 0 #endif #ifndef Y_SLAVE_ADDRESS - #define Y_SLAVE_ADDRESS 1 + #define Y_SLAVE_ADDRESS 1 #endif #ifndef Z_SLAVE_ADDRESS - #define Z_SLAVE_ADDRESS 2 + #define Z_SLAVE_ADDRESS 2 #endif #ifndef E0_SLAVE_ADDRESS - #define E0_SLAVE_ADDRESS 3 + #define E0_SLAVE_ADDRESS 3 #endif #ifndef E1_SLAVE_ADDRESS - #define E1_SLAVE_ADDRESS 0 + #define E1_SLAVE_ADDRESS 0 #endif static_assert(X_SLAVE_ADDRESS == 0, "X_SLAVE_ADDRESS must be 0 for BOARD_MINITRONICS20."); static_assert(Y_SLAVE_ADDRESS == 1, "Y_SLAVE_ADDRESS must be 1 for BOARD_MINITRONICS20."); From 019915b09750b10dae64a80d59e4fc30265d3b3a Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Fri, 2 May 2025 18:08:56 +0000 Subject: [PATCH 274/787] [cron] Bump distribution date (2025-05-02) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index a2ef14eecd..58bd8e05ce 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-05-01" +//#define STRING_DISTRIBUTION_DATE "2025-05-02" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 618bca9810..8d83493ab4 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-05-01" + #define STRING_DISTRIBUTION_DATE "2025-05-02" #endif /** From 0c72dc376ca78c5354054d6c9b80a286e7d2ffa5 Mon Sep 17 00:00:00 2001 From: B Date: Sat, 3 May 2025 13:20:29 -0700 Subject: [PATCH 275/787] =?UTF-8?q?=F0=9F=94=A8=20Creality=20V4.2.7=20(GD3?= =?UTF-8?q?2)=20(#27796)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/HAL/GD32_MFL/timers.cpp | 9 +++- Marlin/src/core/boards.h | 3 +- .../pins/gd32f3/pins_CREALITY_V422_GD32_MFL.h | 8 +--- .../pins/gd32f3/pins_CREALITY_V427_GD32_MFL.h | 48 +++++++++++++++++++ Marlin/src/pins/pins.h | 2 + 5 files changed, 62 insertions(+), 8 deletions(-) create mode 100644 Marlin/src/pins/gd32f3/pins_CREALITY_V427_GD32_MFL.h diff --git a/Marlin/src/HAL/GD32_MFL/timers.cpp b/Marlin/src/HAL/GD32_MFL/timers.cpp index 5b2c2de7ef..632499742c 100644 --- a/Marlin/src/HAL/GD32_MFL/timers.cpp +++ b/Marlin/src/HAL/GD32_MFL/timers.cpp @@ -92,7 +92,9 @@ bool is_temp_timer_initialized = false; // Retrieves the clock frequency of the stepper timer uint32_t GetStepperTimerClkFreq() { - return Step_Timer.getTimerClockFrequency(); + // Cache result + static uint32_t clkFreq = Step_Timer.getTimerClockFrequency(); + return clkFreq; } /** @@ -191,10 +193,12 @@ void SetTimerInterruptPriorities() { // Detect timer conflicts // ------------------------ +TERN_(HAS_TMC_SW_SERIAL, static constexpr timer::TIMER_Base timer_serial[] = {static_cast(TIMER_SERIAL)}); TERN_(SPEAKER, static constexpr timer::TIMER_Base timer_tone[] = {static_cast(TIMER_TONE)}); TERN_(HAS_SERVOS, static constexpr timer::TIMER_Base timer_servo[] = {static_cast(TIMER_SERVO)}); enum TimerPurpose { + PURPOSE_SERIAL, PURPOSE_TONE, PURPOSE_SERVO, PURPOSE_STEP, @@ -205,6 +209,9 @@ enum TimerPurpose { // Includes the timer purpose to ease debugging when evaluating at build-time // This cannot yet account for timers used for PWM output, such as for fans static constexpr struct { TimerPurpose p; int t; } timers_in_use[] = { + #if HAS_TMC_SW_SERIAL + { PURPOSE_SERIAL, timer_base_to_index(timer_serial[0]) }, // Set in variant.h + #endif #if ENABLED(SPEAKER) { PURPOSE_TONE, timer_base_to_index(timer_tone[0]) }, // Set in variant.h #endif diff --git a/Marlin/src/core/boards.h b/Marlin/src/core/boards.h index e7851d001a..32ee85daab 100644 --- a/Marlin/src/core/boards.h +++ b/Marlin/src/core/boards.h @@ -386,7 +386,7 @@ #define BOARD_CREALITY_V422 5039 // Creality v4.2.2 (STM32F103RC / STM32F103RE) ... GD32 Variant Below! #define BOARD_CREALITY_V423 5040 // Creality v4.2.3 (STM32F103RC / STM32F103RE) #define BOARD_CREALITY_V425 5041 // Creality v4.2.5 (STM32F103RC / STM32F103RE) -#define BOARD_CREALITY_V427 5042 // Creality v4.2.7 (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V427 5042 // Creality v4.2.7 (STM32F103RC / STM32F103RE) ... GD32 Variant Below! #define BOARD_CREALITY_V4210 5043 // Creality v4.2.10 (STM32F103RC / STM32F103RE) as found in the CR-30 #define BOARD_CREALITY_V431 5044 // Creality v4.3.1 (STM32F103RC / STM32F103RE) #define BOARD_CREALITY_V431_A 5045 // Creality v4.3.1a (STM32F103RC / STM32F103RE) @@ -563,6 +563,7 @@ // #define BOARD_CREALITY_V422_GD32_MFL 7400 // Creality V4.2.2 MFL (GD32F303RE) ... STM32 Variant Above! +#define BOARD_CREALITY_V427_GD32_MFL 7401 // Creality V4.2.7 MFL (GD32F303RE) ... STM32 Variant Above! // // Raspberry Pi diff --git a/Marlin/src/pins/gd32f3/pins_CREALITY_V422_GD32_MFL.h b/Marlin/src/pins/gd32f3/pins_CREALITY_V422_GD32_MFL.h index 70b171eef9..8b5cd90b15 100644 --- a/Marlin/src/pins/gd32f3/pins_CREALITY_V422_GD32_MFL.h +++ b/Marlin/src/pins/gd32f3/pins_CREALITY_V422_GD32_MFL.h @@ -27,11 +27,7 @@ #define ALLOW_GD32F3 -#ifndef BOARD_INFO_NAME - #define BOARD_INFO_NAME "Creality V4.2.2 MFL" -#endif -#ifndef DEFAULT_MACHINE_NAME - #define DEFAULT_MACHINE_NAME "Ender-3 MFL" -#endif +#define BOARD_INFO_NAME "Creality V4.2.2 MFL" +#define DEFAULT_MACHINE_NAME "Ender-3 MFL" #include "../stm32f1/pins_CREALITY_V4.h" diff --git a/Marlin/src/pins/gd32f3/pins_CREALITY_V427_GD32_MFL.h b/Marlin/src/pins/gd32f3/pins_CREALITY_V427_GD32_MFL.h new file mode 100644 index 0000000000..afa1b0620f --- /dev/null +++ b/Marlin/src/pins/gd32f3/pins_CREALITY_V427_GD32_MFL.h @@ -0,0 +1,48 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +/** + * Creality MFL GD32 V4.2.7 (GD32F303RE) board pin assignments + */ + +#define ALLOW_GD32F3 + +#define BOARD_INFO_NAME "Creality V4.2.7 MFL" +#define DEFAULT_MACHINE_NAME "Creality3D MFL" + +// +// Steppers +// +#define X_STEP_PIN PB9 +#define X_DIR_PIN PC2 + +#define Y_STEP_PIN PB7 +#define Y_DIR_PIN PB8 + +#define Z_STEP_PIN PB5 +#define Z_DIR_PIN PB6 + +#define E0_STEP_PIN PB3 +#define E0_DIR_PIN PB4 + +#include "../stm32f1/pins_CREALITY_V4.h" diff --git a/Marlin/src/pins/pins.h b/Marlin/src/pins/pins.h index 8c974cce48..7b2daae1ea 100644 --- a/Marlin/src/pins/pins.h +++ b/Marlin/src/pins/pins.h @@ -977,6 +977,8 @@ #elif MB(CREALITY_V422_GD32_MFL) #include "gd32f3/pins_CREALITY_V422_GD32_MFL.h" // GD32F303RE env:GD32F303RE_creality_mfl +#elif MB(CREALITY_V427_GD32_MFL) + #include "gd32f3/pins_CREALITY_V427_GD32_MFL.h" // GD32F303RE env:GD32F303RE_creality_mfl // // Raspberry Pi RP2040 From b9ffe93d1f00a6a1b7c91710f54c29a22deeadd2 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Sun, 4 May 2025 00:34:56 +0000 Subject: [PATCH 276/787] [cron] Bump distribution date (2025-05-04) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 58bd8e05ce..a58dfbe2a8 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-05-02" +//#define STRING_DISTRIBUTION_DATE "2025-05-04" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 8d83493ab4..b066410475 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-05-02" + #define STRING_DISTRIBUTION_DATE "2025-05-04" #endif /** From a8d18a0554aec9be9583b0799f750b6858a155d0 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sat, 3 May 2025 19:57:05 -0500 Subject: [PATCH 277/787] =?UTF-8?q?=F0=9F=8E=A8=20ProUI=20code=20style?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/lcd/e3v2/proui/dwin.cpp | 77 +++++++++++++++++++----------- 1 file changed, 49 insertions(+), 28 deletions(-) diff --git a/Marlin/src/lcd/e3v2/proui/dwin.cpp b/Marlin/src/lcd/e3v2/proui/dwin.cpp index b1df0234b0..2b6087385e 100644 --- a/Marlin/src/lcd/e3v2/proui/dwin.cpp +++ b/Marlin/src/lcd/e3v2/proui/dwin.cpp @@ -589,7 +589,11 @@ void drawPrintProgressElapsed() { #endif void ICON_ResumeOrPause() { - if (checkkey == ID_PrintProcess) (print_job_timer.isPaused() || hmiFlag.pause_flag) ? ICON_Resume() : ICON_Pause(); + if (checkkey != ID_PrintProcess) return; + if (print_job_timer.isPaused() || hmiFlag.pause_flag) + ICON_Resume(); + else + ICON_Pause(); } // Print a string (up to 30 characters) in the header, @@ -927,19 +931,28 @@ void sdCardFolder(char * const dirname) { void onClickSDItem() { const uint16_t hasUpDir = !card.flag.workDirIsRoot; - if (hasUpDir && currentMenu->selected == 1) return sdCardUp(); + if (hasUpDir && currentMenu->selected == 1) { + sdCardUp(); + return; + } else { const uint16_t filenum = currentMenu->selected - 1 - hasUpDir; card.selectFileByIndexSorted(filenum); // Enter that folder! - if (card.flag.filenameIsDir) return sdCardFolder(card.filename); + if (card.flag.filenameIsDir) { + sdCardFolder(card.filename); + return; + } - if (card.fileIsBinary()) - return dwinPopupConfirm(ICON_Error, F("Please check filenames"), F("Only G-code can be printed")); + if (card.fileIsBinary()) { + dwinPopupConfirm(ICON_Error, F("Please check filenames"), F("Only G-code can be printed")); + return; + } else { dwinPrintHeader(card.longest_filename()); // Save filename - return gotoConfirmToPrint(); + gotoConfirmToPrint(); + return; } } } @@ -1171,7 +1184,7 @@ void onClickPauseOrStop() { case PRINT_STOP: if (hmiFlag.select_flag) ExtUI::stopPrint(); break; // Stop confirmed then abort print default: break; } - return gotoPrintProcess(); + gotoPrintProcess(); } // Printing @@ -1205,10 +1218,12 @@ void hmiPrinting() { ExtUI::resumePrint(); break; } - else - return gotoPopup(popupPauseOrStop, onClickPauseOrStop); - case PRINT_STOP: - return gotoPopup(popupPauseOrStop, onClickPauseOrStop); + gotoPopup(popupPauseOrStop, onClickPauseOrStop); + return; + case PRINT_STOP: { + gotoPopup(popupPauseOrStop, onClickPauseOrStop); + return; + } default: break; } } @@ -1256,8 +1271,9 @@ void drawMainArea() { void hmiWaitForUser() { EncoderState encoder_diffState = get_encoder_state(); if (encoder_diffState != ENCODER_DIFF_NO && !ui.backlight) { - if (checkkey == ID_WaitResponse) hmiReturnScreen(); - return ui.refresh_brightness(); + ui.refresh_brightness(); + hmiReturnScreen(); + return; } if (!wait_for_user) { switch (checkkey) { @@ -1387,7 +1403,8 @@ void eachMomentUpdate() { } #if HAS_PLR_UI_FLAG else if (DWIN_lcd_sd_status && recovery.ui_flag_resume) { // Resume interrupted print - return gotoPowerLossRecovery(); + gotoPowerLossRecovery(); + return; } #endif @@ -1426,7 +1443,8 @@ void eachMomentUpdate() { if (hmiFlag.select_flag) { queue.inject(F("M1000C")); select_page.reset(); - return gotoMainMenu(); + gotoMainMenu(); + return; } else { hmiSaveProcessID(ID_NothingToDo); @@ -1510,15 +1528,17 @@ void hmiReturnScreen() { drawMainArea(); } +#if ANY(TJC_DISPLAY, DACAI_DISPLAY) + #define HOME_AND_KILL_ICON ICON_BLTouch +#else + #define HOME_AND_KILL_ICON ICON_Printer_0 +#endif + void dwinHomingStart() { hmiFlag.home_flag = true; hmiSaveProcessID(ID_Homing); title.showCaption(GET_TEXT_F(MSG_HOMING)); - #if ANY(TJC_DISPLAY, DACAI_DISPLAY) - dwinShowPopup(ICON_BLTouch, GET_TEXT_F(MSG_HOMING), GET_TEXT_F(MSG_PLEASE_WAIT)); - #else - dwinShowPopup(ICON_Printer_0, GET_TEXT_F(MSG_HOMING), GET_TEXT_F(MSG_PLEASE_WAIT)); - #endif + dwinShowPopup(HOME_AND_KILL_ICON, GET_TEXT_F(MSG_HOMING), GET_TEXT_F(MSG_PLEASE_WAIT)); } void dwinHomingDone() { @@ -1941,11 +1961,7 @@ void MarlinUI::update() { #endif void MarlinUI::kill_screen(FSTR_P const lcd_error, FSTR_P const) { - #if ANY(TJC_DISPLAY, DACAI_DISPLAY) - dwinDrawPopup(ICON_BLTouch, GET_TEXT_F(MSG_PRINTER_KILLED), lcd_error); - #else - dwinDrawPopup(ICON_Printer_0, GET_TEXT_F(MSG_PRINTER_KILLED), lcd_error); - #endif + dwinDrawPopup(HOME_AND_KILL_ICON, GET_TEXT_F(MSG_PRINTER_KILLED), lcd_error); DWINUI::drawCenteredString(hmiData.colorPopupTxt, 270, GET_TEXT_F(MSG_TURN_OFF)); dwinUpdateLCD(); } @@ -2051,7 +2067,8 @@ void dwinRedrawScreen() { dwinResetStatusLine(); if (hmiFlag.select_flag) { // Confirm gotoMainMenu(); - return card.openAndPrintFile(card.filename); + card.openAndPrintFile(card.filename); + return; } else hmiReturnScreen(); @@ -2061,7 +2078,10 @@ void dwinRedrawScreen() { void gotoConfirmToPrint() { #if HAS_GCODE_PREVIEW - if (hmiData.enablePreview) return gotoPopup(preview.drawFromSD, onClickConfirmToPrint); + if (hmiData.enablePreview) { + gotoPopup(preview.drawFromSD, onClickConfirmToPrint); + return; + } #endif card.openAndPrintFile(card.filename); // Direct print SD file } @@ -2194,7 +2214,8 @@ void axisMove(AxisEnum axis) { #if HAS_HOTEND if (axis == E_AXIS && thermalManager.tooColdToExtrude(0)) { gcode.process_subcommands_now(F("G92E0")); // Reset extruder position - return dwinPopupConfirm(ICON_TempTooLow, GET_TEXT_F(MSG_HOTEND_TOO_COLD), GET_TEXT_F(MSG_PLEASE_PREHEAT)); + dwinPopupConfirm(ICON_TempTooLow, GET_TEXT_F(MSG_HOTEND_TOO_COLD), GET_TEXT_F(MSG_PLEASE_PREHEAT)); + return; } #endif planner.synchronize(); From 414951e42cdc49f6e3091978d1822bfb1b636cbd Mon Sep 17 00:00:00 2001 From: Andrew <18502096+classicrocker883@users.noreply.github.com> Date: Sat, 3 May 2025 21:08:27 -0400 Subject: [PATCH 278/787] =?UTF-8?q?=F0=9F=9A=B8=20Fix=20ProUI=20LCD=20wake?= =?UTF-8?q?=20up=20(#27832)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/lcd/e3v2/proui/dwin.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Marlin/src/lcd/e3v2/proui/dwin.cpp b/Marlin/src/lcd/e3v2/proui/dwin.cpp index 2b6087385e..aa77704786 100644 --- a/Marlin/src/lcd/e3v2/proui/dwin.cpp +++ b/Marlin/src/lcd/e3v2/proui/dwin.cpp @@ -1957,7 +1957,10 @@ void MarlinUI::update() { } #if HAS_LCD_BRIGHTNESS - void MarlinUI::_set_brightness() { dwinLCDBrightness(backlight ? brightness : 0); } + void MarlinUI::_set_brightness() { + if (!backlight) wait_for_user = true; + dwinLCDBrightness(backlight ? brightness : 0); + } #endif void MarlinUI::kill_screen(FSTR_P const lcd_error, FSTR_P const) { @@ -2273,7 +2276,7 @@ void setMoveZ() { hmiValue.axis = Z_AXIS; setPFloatOnClick(Z_MIN_POS, Z_MAX_POS, void applyBrightness() { ui.set_brightness(menuData.value); } void liveBrightness() { dwinLCDBrightness(menuData.value); } void setBrightness() { setIntOnClick(LCD_BRIGHTNESS_MIN, LCD_BRIGHTNESS_MAX, ui.brightness, applyBrightness, liveBrightness); } - void turnOffBacklight() { hmiSaveProcessID(ID_WaitResponse); ui.set_brightness(0); dwinRedrawScreen(); } + void turnOffBacklight() { ui.set_brightness(0); dwinRedrawScreen(); } #endif #if ENABLED(CASE_LIGHT_MENU) From 4e1e7fa1b0dd6f9fdd6d18b88ccbe13cf3d36152 Mon Sep 17 00:00:00 2001 From: InsanityAutomation <38436470+InsanityAutomation@users.noreply.github.com> Date: Sat, 3 May 2025 22:07:40 -0400 Subject: [PATCH 279/787] =?UTF-8?q?=E2=9C=A8=20SWITCHING=5FNOZZLE=5FLIFT?= =?UTF-8?q?=5FTO=5FPROBE=20(#27804)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/Configuration.h | 1 + Marlin/src/inc/Conditionals-1-axes.h | 2 +- Marlin/src/inc/Conditionals-3-etc.h | 4 ++++ Marlin/src/inc/SanityCheck.h | 2 ++ Marlin/src/module/probe.cpp | 4 ++++ Marlin/src/module/tool_change.cpp | 6 ++++++ buildroot/tests/LPC1768 | 2 +- 7 files changed, 19 insertions(+), 2 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 91a3b342b6..5effb31883 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -260,6 +260,7 @@ #define SWITCHING_NOZZLE_SERVO_ANGLES { 0, 90 } // A pair of angles for { E0, E1 }. // For Dual Servo use two pairs: { { lower, raise }, { lower, raise } } #define SWITCHING_NOZZLE_SERVO_DWELL 2500 // Dwell time to wait for servo to make physical move + #define SWITCHING_NOZZLE_LIFT_TO_PROBE // Lift toolheads out of the way while probing #endif // Switch nozzles by bumping the toolhead. Requires EVENT_GCODE_TOOLCHANGE_#. diff --git a/Marlin/src/inc/Conditionals-1-axes.h b/Marlin/src/inc/Conditionals-1-axes.h index e55f69c797..8e84d7d4d4 100644 --- a/Marlin/src/inc/Conditionals-1-axes.h +++ b/Marlin/src/inc/Conditionals-1-axes.h @@ -87,7 +87,7 @@ #endif /** - * Multi-Material-Unit supported models + * Multi-Material-Unit supported models */ #ifdef MMU_MODEL #define HAS_MMU 1 diff --git a/Marlin/src/inc/Conditionals-3-etc.h b/Marlin/src/inc/Conditionals-3-etc.h index 2456728554..b361a50a58 100644 --- a/Marlin/src/inc/Conditionals-3-etc.h +++ b/Marlin/src/inc/Conditionals-3-etc.h @@ -69,6 +69,10 @@ #endif #undef UNUSED_TEMP_SENSOR +#if !HAS_HOTEND + #undef PREHEAT_1_TEMP_HOTEND + #undef PREHEAT_2_TEMP_HOTEND +#endif #if !TEMP_SENSOR_BED #undef TEMP_SENSOR_BED #undef THERMAL_PROTECTION_BED diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index cff241db72..8a293b52a8 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -736,6 +736,8 @@ static_assert(COUNT(arm) == LOGICAL_AXES, "AXIS_RELATIVE_MODES must contain " _L #error "SWITCHING_NOZZLE requires NUM_SERVOS >= 1." #elif !defined(SWITCHING_NOZZLE_SERVO_NR) #error "SWITCHING_NOZZLE requires SWITCHING_NOZZLE_SERVO_NR." + #elif ALL(SWITCHING_NOZZLE_LIFT_TO_PROBE, NOZZLE_AS_PROBE) + #error "SWITCHING_NOZZLE_LIFT_TO_PROBE cannot be used with NOZZLE_AS_PROBE." #elif SWITCHING_NOZZLE_SERVO_NR == 0 && !PIN_EXISTS(SERVO0) #error "SERVO0_PIN must be defined for your SWITCHING_NOZZLE." #elif SWITCHING_NOZZLE_SERVO_NR == 1 && !PIN_EXISTS(SERVO1) diff --git a/Marlin/src/module/probe.cpp b/Marlin/src/module/probe.cpp index 4f7d7c7690..9a998ec569 100644 --- a/Marlin/src/module/probe.cpp +++ b/Marlin/src/module/probe.cpp @@ -406,6 +406,10 @@ FORCE_INLINE void probe_specific_action(const bool deploy) { #endif // PAUSE_BEFORE_DEPLOY_STOW + #if ENABLED(SWITCHING_NOZZLE_LIFT_TO_PROBE) + servo[SWITCHING_NOZZLE_SERVO_NR].move(servo_angles[SWITCHING_NOZZLE_SERVO_NR][deploy ? 1 : 0]); + #endif + #if ENABLED(SOLENOID_PROBE) #if HAS_SOLENOID_1 diff --git a/Marlin/src/module/tool_change.cpp b/Marlin/src/module/tool_change.cpp index 12aca3fff6..fcaa64cefe 100644 --- a/Marlin/src/module/tool_change.cpp +++ b/Marlin/src/module/tool_change.cpp @@ -1415,6 +1415,12 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) { #endif } // (new_tool != old_tool) + else { + // For switching-nozzle-with-servos you may have manually-edited servo angles + // or other functions that can affect angles. So here we ensure a T# command + // restores active tool position even when recalling the same tool. + TERN_(SWITCHING_NOZZLE_TWO_SERVOS, lower_nozzle(new_tool)); + } planner.synchronize(); diff --git a/buildroot/tests/LPC1768 b/buildroot/tests/LPC1768 index cd911a9060..f00efb8341 100755 --- a/buildroot/tests/LPC1768 +++ b/buildroot/tests/LPC1768 @@ -30,7 +30,7 @@ restore_configs opt_set MOTHERBOARD BOARD_MKS_SBASE \ EXTRUDERS 2 TEMP_SENSOR_1 1 \ NUM_SERVOS 2 SERVO_DELAY '{ 300, 300 }' SWITCHING_NOZZLE_SERVO_ANGLES '{ { 0, 90 }, { 90, 0 } }' -opt_enable SWITCHING_NOZZLE SWITCHING_NOZZLE_E1_SERVO_NR EDITABLE_SERVO_ANGLES SERVO_DETACH_GCODE \ +opt_enable SWITCHING_NOZZLE SWITCHING_NOZZLE_E1_SERVO_NR SWITCHING_NOZZLE_LIFT_TO_PROBE EDITABLE_SERVO_ANGLES SERVO_DETACH_GCODE \ ULTIMAKERCONTROLLER REALTIME_REPORTING_COMMANDS FULL_REPORT_TO_HOST_FEATURE exec_test $1 $2 "MKS SBASE with SWITCHING_NOZZLE, Grbl Realtime Report" "$3" From 1f31027fd2588e8cf4c556347b5be043d2ff07a1 Mon Sep 17 00:00:00 2001 From: MrKuskov <94338763+MrKuskov@users.noreply.github.com> Date: Sun, 4 May 2025 09:11:23 +0700 Subject: [PATCH 280/787] =?UTF-8?q?=E2=9C=A8=20FILAMENT=5FMOTION=5FDISTANC?= =?UTF-8?q?E=5FMM=20(#27812)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Scott Lahteine --- Marlin/Configuration.h | 7 +++- Marlin/src/feature/runout.cpp | 9 +++- Marlin/src/feature/runout.h | 77 ++++++++++++++++++++++++++--------- 3 files changed, 71 insertions(+), 22 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 5effb31883..dc042ff1cb 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -2037,8 +2037,11 @@ //#define FILAMENT_MOTION_SENSOR #if ENABLED(FILAMENT_MOTION_SENSOR) - //#define FILAMENT_SWITCH_AND_MOTION + //#define FILAMENT_SWITCH_AND_MOTION // Define separate pins below to sense motion #if ENABLED(FILAMENT_SWITCH_AND_MOTION) + + #define FILAMENT_MOTION_DISTANCE_MM 3.0 // (mm) Missing distance required to trigger runout + #define NUM_MOTION_SENSORS 1 // Number of sensors, up to one per extruder. Define a FIL_MOTION#_PIN for each. //#define FIL_MOTION1_PIN -1 @@ -2074,7 +2077,7 @@ //#define FIL_MOTION8_STATE LOW //#define FIL_MOTION8_PULLUP //#define FIL_MOTION8_PULLDOWN - #endif + #endif // FILAMENT_SWITCH_AND_MOTION #endif // FILAMENT_MOTION_SENSOR #endif // FILAMENT_RUNOUT_DISTANCE_MM #endif // FILAMENT_RUNOUT_SENSOR diff --git a/Marlin/src/feature/runout.cpp b/Marlin/src/feature/runout.cpp index cb7c6279bc..147f38ef09 100644 --- a/Marlin/src/feature/runout.cpp +++ b/Marlin/src/feature/runout.cpp @@ -33,7 +33,7 @@ FilamentMonitor runout; bool FilamentMonitorBase::enabled = true, - FilamentMonitorBase::filament_ran_out; // = false + FilamentMonitorBase::filament_ran_out; // = false #if ENABLED(HOST_ACTION_COMMANDS) bool FilamentMonitorBase::host_handling; // = false @@ -51,6 +51,11 @@ bool FilamentMonitorBase::enabled = true, #if ENABLED(FILAMENT_MOTION_SENSOR) uint8_t FilamentSensorEncoder::motion_detected; #endif + + #if ENABLED(FILAMENT_SWITCH_AND_MOTION) + bool RunoutResponseDelayed::ignore_motion = false; + constexpr float RunoutResponseDelayed::motion_distance_mm; + #endif #else int8_t RunoutResponseDebounced::runout_count[NUM_RUNOUT_SENSORS]; // = 0 #endif @@ -72,6 +77,8 @@ bool FilamentMonitorBase::enabled = true, void event_filament_runout(const uint8_t extruder) { + runout.init_for_restart(false); // Reset and disable + if (did_pause_print) return; // Action already in progress. Purge triggered repeated runout. #if ENABLED(TOOLCHANGE_MIGRATION_FEATURE) diff --git a/Marlin/src/feature/runout.h b/Marlin/src/feature/runout.h index d7c41907ed..8047db4f41 100644 --- a/Marlin/src/feature/runout.h +++ b/Marlin/src/feature/runout.h @@ -46,8 +46,10 @@ #if ENABLED(FILAMENT_MOTION_SENSOR) #define HAS_FILAMENT_MOTION 1 -#endif -#if DISABLED(FILAMENT_MOTION_SENSOR) || ENABLED(FILAMENT_SWITCH_AND_MOTION) + #if ENABLED(FILAMENT_SWITCH_AND_MOTION) + #define HAS_FILAMENT_SWITCH 1 + #endif +#else #define HAS_FILAMENT_SWITCH 1 #endif @@ -129,6 +131,7 @@ class TFilamentMonitor : public FilamentMonitorBase { // Handle a block completion. RunoutResponseDelayed uses this to // add up the length of filament moved while the filament is out. + // Called from ISR context! static void block_completed(const block_t * const b) { if (enabled) { response.block_completed(b); @@ -171,6 +174,12 @@ class TFilamentMonitor : public FilamentMonitorBase { } } } + + // Reset after a filament runout or upon resuming a job + static void init_for_restart(const bool onoff=true) { + response.init_for_restart(onoff); + } + }; /*************************** FILAMENT PRESENCE SENSORS ***************************/ @@ -267,6 +276,7 @@ class FilamentSensorBase { } public: + // Called from ISR context to indicate a block was completed static void block_completed(const block_t * const b) { // If the sensor wheel has moved since the last call to // this method reset the runout counter for the extruder. @@ -303,6 +313,7 @@ class FilamentSensorBase { } public: + // Called from ISR context to indicate a block was completed static void block_completed(const block_t * const) {} static void run() { @@ -332,6 +343,7 @@ class FilamentSensorBase { TERN_(HAS_FILAMENT_SWITCH, static FilamentSensorSwitch switch_sensor); public: + // Called from ISR context to indicate a block was completed static void block_completed(const block_t * const b) { TERN_(HAS_FILAMENT_MOTION, encoder_sensor.block_completed(b)); TERN_(HAS_FILAMENT_SWITCH, switch_sensor.block_completed(b)); @@ -362,10 +374,17 @@ class FilamentSensorBase { class RunoutResponseDelayed { private: static countdown_t mm_countdown; + static bool ignore_motion; // Flag to ignore the encoder public: static float runout_distance_mm; + #if ENABLED(FILAMENT_SWITCH_AND_MOTION) + static constexpr float motion_distance_mm = FILAMENT_MOTION_DISTANCE_MM; + #endif + + static void set_ignore_motion(const bool ignore=true) { ignore_motion = ignore; } + static void reset() { for (uint8_t i = 0; i < NUM_RUNOUT_SENSORS; ++i) filament_present(i); #if ENABLED(FILAMENT_SWITCH_AND_MOTION) @@ -377,24 +396,27 @@ class FilamentSensorBase { #if ENABLED(FILAMENT_RUNOUT_SENSOR_DEBUG) static millis_t t = 0; const millis_t ms = millis(); - if (ELAPSED(ms, t)) { - t = millis() + 1000UL; - for (uint8_t i = 0; i < NUM_RUNOUT_SENSORS; ++i) - SERIAL_ECHO(i ? F(", ") : F("Runout remaining mm: "), mm_countdown.runout[i]); - #if ENABLED(FILAMENT_SWITCH_AND_MOTION) - for (uint8_t i = 0; i < NUM_MOTION_SENSORS; ++i) - SERIAL_ECHO(i ? F(", ") : F("Motion remaining mm: "), mm_countdown.motion[i]); - #endif - SERIAL_EOL(); - } + if (PENDING(ms, t)) return; + t = ms + 1000UL; + for (uint8_t i = 0; i < NUM_RUNOUT_SENSORS; ++i) + SERIAL_ECHO(i ? F(", ") : F("Runout remaining mm: "), mm_countdown.runout[i]); + #if ENABLED(FILAMENT_SWITCH_AND_MOTION) + for (uint8_t i = 0; i < NUM_MOTION_SENSORS; ++i) + SERIAL_ECHO(i ? F(", ") : F("Motion remaining mm: "), mm_countdown.motion[i]); + #endif + SERIAL_EOL(); #endif } + // Get runout status for all presence sensors and motion sensors static runout_flags_t has_run_out() { runout_flags_t runout_flags{0}; + // Runout based on filament presence for (uint8_t i = 0; i < NUM_RUNOUT_SENSORS; ++i) if (mm_countdown.runout[i] < 0) runout_flags.set(i); + // Runout based on filament motion #if ENABLED(FILAMENT_SWITCH_AND_MOTION) - for (uint8_t i = 0; i < NUM_MOTION_SENSORS; ++i) if (mm_countdown.motion[i] < 0) runout_flags.set(i); + if (!ignore_motion) + for (uint8_t i = 0; i < NUM_MOTION_SENSORS; ++i) if (mm_countdown.motion[i] < 0) runout_flags.set(i); #endif return runout_flags; } @@ -419,8 +441,8 @@ class FilamentSensorBase { #if ENABLED(FILAMENT_SWITCH_AND_MOTION) static void filament_motion_present(const uint8_t extruder) { // Same logic as filament_present - if (mm_countdown.motion[extruder] < runout_distance_mm || did_pause_print) { - mm_countdown.motion[extruder] = runout_distance_mm; + if (mm_countdown.motion[extruder] < motion_distance_mm || did_pause_print) { + mm_countdown.motion[extruder] = motion_distance_mm; mm_countdown.motion_reset.clear(extruder); } else @@ -428,29 +450,42 @@ class FilamentSensorBase { } #endif + // Called from ISR context to indicate a block was completed static void block_completed(const block_t * const b) { - const int32_t esteps = b->steps.e; - if (!esteps) return; - // No calculation unless paused or printing if (!should_monitor_runout()) return; + // Only extrusion moves are examined + const int32_t esteps = b->steps.e; + if (!esteps) return; + // No need to ignore retract/unretract movement since they complement each other const uint8_t e = b->extruder; const float mm = (b->direction_bits.e ? esteps : -esteps) * planner.mm_per_step[E_AXIS_N(e)]; + // Apply E distance to runout countdown, reset if flagged if (e < NUM_RUNOUT_SENSORS) { mm_countdown.runout[e] -= mm; if (mm_countdown.runout_reset[e]) filament_present(e); // Reset pending. Try to reset. } + // Apply E distance to motion countdown, reset if flagged #if ENABLED(FILAMENT_SWITCH_AND_MOTION) - if (e < NUM_MOTION_SENSORS) { + if (!ignore_motion && e < NUM_MOTION_SENSORS) { mm_countdown.motion[e] -= mm; if (mm_countdown.motion_reset[e]) filament_motion_present(e); // Reset pending. Try to reset. } #endif } + + // Reset after a filament runout or upon resuming a job + static void init_for_restart(const bool onoff=true) { + UNUSED(onoff); + #if ENABLED(FILAMENT_SWITCH_AND_MOTION) + reset(); + set_ignore_motion(!onoff); + #endif + } }; #else // !HAS_FILAMENT_RUNOUT_DISTANCE @@ -478,11 +513,15 @@ class FilamentSensorBase { return runout_flags; } + // Called from ISR context to indicate a block was completed static void block_completed(const block_t * const) { } static void filament_present(const uint8_t extruder) { runout_count[extruder] = runout_threshold; } + + // Reset after a filament runout or upon resuming a job + static void init_for_restart(const bool=true) { reset(); } }; #endif // !HAS_FILAMENT_RUNOUT_DISTANCE From cbe8a6867cd18e77e0ba7c4bdeb0e96f24e2bb1b Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sat, 3 May 2025 21:56:33 -0500 Subject: [PATCH 281/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Fix?= =?UTF-8?q?=20mac=5Fgcc=20HOMEBREW=5FPATH?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- buildroot/bin/mac_gcc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/buildroot/bin/mac_gcc b/buildroot/bin/mac_gcc index 05ee9dd295..6c5d7ea24a 100755 --- a/buildroot/bin/mac_gcc +++ b/buildroot/bin/mac_gcc @@ -11,7 +11,9 @@ which port >/dev/null && HAS_MACPORTS=1 which brew >/dev/null && HAS_HOMEBREW=1 MACPORTS_PATH=$(dirname "$(which port)") -HOMEBREW_PATH="$(brew --prefix)/bin" +if ((HAS_HOMEBREW)); then + HOMEBREW_PATH="$(brew --prefix)/bin" +fi if [[ $1 == "apple" || $1 == "darwin" || $1 == "system" ]]; then From 9bbbcd439b5acab59338352d7c65d6e54352afcc Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sun, 4 May 2025 13:55:50 -0500 Subject: [PATCH 282/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Cla?= =?UTF-8?q?rify=20parking=5Fextruder=5Funpark=5Fafter=5Fhoming?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/gcode/calibrate/G28.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Marlin/src/gcode/calibrate/G28.cpp b/Marlin/src/gcode/calibrate/G28.cpp index 6c8af9ddb0..e9d72a83f6 100644 --- a/Marlin/src/gcode/calibrate/G28.cpp +++ b/Marlin/src/gcode/calibrate/G28.cpp @@ -300,7 +300,8 @@ void GcodeSuite::G28() { #endif // PARKING_EXTRUDER homing requires different handling of movement / solenoid activation, depending on the side of homing #if ENABLED(PARKING_EXTRUDER) - const bool pe_final_change_must_unpark = parking_extruder_unpark_after_homing(old_tool_index, X_HOME_DIR + 1 == old_tool_index * 2); + const bool homed_towards_tool = old_tool_index == TERN(X_HOME_TO_MIN, 0, 1), + pe_final_change_must_unpark = parking_extruder_unpark_after_homing(old_tool_index, homed_towards_tool); #endif tool_change(0, true); #endif From 44ef6e2b70c8a68913f10aab550422b9ad351e37 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sun, 4 May 2025 15:19:22 -0500 Subject: [PATCH 283/787] =?UTF-8?q?=F0=9F=A9=B9=20Fix=20Y=5FSTOP=5FPIN=20a?= =?UTF-8?q?lias=20for=20Y=5FMAX=5FPIN?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/pins/pins_postprocess.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/src/pins/pins_postprocess.h b/Marlin/src/pins/pins_postprocess.h index 4d2455bd31..a18c099196 100644 --- a/Marlin/src/pins/pins_postprocess.h +++ b/Marlin/src/pins/pins_postprocess.h @@ -638,7 +638,7 @@ #endif #elif Y_HOME_TO_MIN #define Y_STOP_PIN Y_MIN_PIN - #elif X_HOME_TO_MAX + #elif Y_HOME_TO_MAX #define Y_STOP_PIN Y_MAX_PIN #endif #if !defined(Y2_STOP_PIN) && ENABLED(Y_DUAL_ENDSTOPS) && PIN_EXISTS(Y_STOP) From 555b080d85501e92e401f185b0494489dc20ff29 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Mon, 5 May 2025 00:33:33 +0000 Subject: [PATCH 284/787] [cron] Bump distribution date (2025-05-05) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index a58dfbe2a8..4abad36238 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-05-04" +//#define STRING_DISTRIBUTION_DATE "2025-05-05" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index b066410475..bb924b75bb 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-05-04" + #define STRING_DISTRIBUTION_DATE "2025-05-05" #endif /** From 735cd9a092e4b843ccd68efc1f4573e25ceecb3a Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Mon, 5 May 2025 12:28:11 -0500 Subject: [PATCH 285/787] =?UTF-8?q?=F0=9F=A9=B9=20Fix=20TH3D=20EZ=20V2=20s?= =?UTF-8?q?ensorless=20homing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/pins/stm32f4/pins_TH3D_EZBOARD_V2.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/src/pins/stm32f4/pins_TH3D_EZBOARD_V2.h b/Marlin/src/pins/stm32f4/pins_TH3D_EZBOARD_V2.h index ebb651e0d5..4d2e2f556d 100644 --- a/Marlin/src/pins/stm32f4/pins_TH3D_EZBOARD_V2.h +++ b/Marlin/src/pins/stm32f4/pins_TH3D_EZBOARD_V2.h @@ -63,13 +63,13 @@ // #if ANY(SENSORLESS_HOMING, SENSORLESS_PROBING) // Sensorless homing pins - #if ENABLED(X_AXIS_SENSORLESS_HOMING) + #if AXIS_HAS_STALLGUARD(X) && defined(X_STALL_SENSITIVITY) #define X_STOP_PIN PB4 #else #define X_STOP_PIN PC1 #endif - #if ENABLED(Y_AXIS_SENSORLESS_HOMING) + #if AXIS_HAS_STALLGUARD(Y) && defined(Y_STALL_SENSITIVITY) #define Y_STOP_PIN PB9 #else #define Y_STOP_PIN PC2 From c9e7d6f55c411a7aecf289e3d343b1c10375d03d Mon Sep 17 00:00:00 2001 From: B Date: Mon, 5 May 2025 11:08:45 -0700 Subject: [PATCH 286/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Upd?= =?UTF-8?q?ate=20GD32=20MFL=20Platform,=20Arduino=20Core=20(#27830)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/HAL/GD32_MFL/HAL.h | 2 +- Marlin/src/HAL/GD32_MFL/MarlinSerial.cpp | 6 +- Marlin/src/HAL/GD32_MFL/MarlinSerial.h | 4 +- Marlin/src/HAL/GD32_MFL/fastio.h | 17 +- Marlin/src/HAL/GD32_MFL/pinsDebug.h | 10 +- Marlin/src/HAL/GD32_MFL/sd/SDCard.cpp | 246 +++++++++++------------ Marlin/src/HAL/GD32_MFL/sd/SDCard.h | 198 +++++++++--------- Marlin/src/HAL/GD32_MFL/sd/sdio.cpp | 2 +- Marlin/src/HAL/GD32_MFL/sd/sdio.h | 2 +- Marlin/src/HAL/GD32_MFL/timers.h | 4 +- ini/gd32.ini | 4 +- 11 files changed, 253 insertions(+), 242 deletions(-) diff --git a/Marlin/src/HAL/GD32_MFL/HAL.h b/Marlin/src/HAL/GD32_MFL/HAL.h index fd3a10d72b..56e52b53b5 100644 --- a/Marlin/src/HAL/GD32_MFL/HAL.h +++ b/Marlin/src/HAL/GD32_MFL/HAL.h @@ -105,7 +105,7 @@ extern "C" char* dtostrf(double val, signed char width, unsigned char prec, char class MarlinHAL { public: // Before setup() - MarlinHAL() {} + MarlinHAL() = default; // Watchdog static void watchdog_init() IF_DISABLED(USE_WATCHDOG, {}); diff --git a/Marlin/src/HAL/GD32_MFL/MarlinSerial.cpp b/Marlin/src/HAL/GD32_MFL/MarlinSerial.cpp index 271247295c..95ea8bea25 100644 --- a/Marlin/src/HAL/GD32_MFL/MarlinSerial.cpp +++ b/Marlin/src/HAL/GD32_MFL/MarlinSerial.cpp @@ -33,8 +33,8 @@ using namespace arduino; -MarlinSerial& MarlinSerial::get_instance(usart::USART_Base Base, pin_size_t rxPin, pin_size_t txPin) { - UsartSerial& serial = UsartSerial::get_instance(Base, rxPin, txPin); +auto MarlinSerial::get_instance(usart::USART_Base Base, pin_size_t rxPin, pin_size_t txPin) -> MarlinSerial& { + auto& serial = UsartSerial::get_instance(Base, rxPin, txPin); return *reinterpret_cast(&serial); } @@ -61,7 +61,7 @@ MarlinSerial& MarlinSerial::get_instance(usart::USART_Base Base, pin_size_t rxPi static void emergency_callback() { if (!current_serial_instance) return; - const uint8_t last_data = current_serial_instance->get_last_data(); + const auto last_data = current_serial_instance->get_last_data(); emergency_parser.update(current_serial_instance->emergency_state, last_data); } diff --git a/Marlin/src/HAL/GD32_MFL/MarlinSerial.h b/Marlin/src/HAL/GD32_MFL/MarlinSerial.h index f47c6da032..6b33ce0e61 100644 --- a/Marlin/src/HAL/GD32_MFL/MarlinSerial.h +++ b/Marlin/src/HAL/GD32_MFL/MarlinSerial.h @@ -43,7 +43,7 @@ using namespace arduino; struct MarlinSerial : public UsartSerial { - static MarlinSerial& get_instance(usart::USART_Base Base, pin_size_t rxPin = NO_PIN, pin_size_t txPin = NO_PIN); + static auto get_instance(usart::USART_Base Base, pin_size_t rxPin = NO_PIN, pin_size_t txPin = NO_PIN) -> MarlinSerial&; void begin(unsigned long baudrate, uint16_t config); inline void begin(unsigned long baudrate) { begin(baudrate, SERIAL_8N1); } @@ -57,7 +57,7 @@ struct MarlinSerial : public UsartSerial { EmergencyParser::State emergency_state; // Accessor method to get the last received byte - uint8_t get_last_data() { return usart_.get_last_data(); } + auto get_last_data() -> uint8_t { return usart_.get_last_data(); } // Register the emergency callback void register_emergency_callback(void (*callback)()); diff --git a/Marlin/src/HAL/GD32_MFL/fastio.h b/Marlin/src/HAL/GD32_MFL/fastio.h index 35bd2b1ef7..35829e856f 100644 --- a/Marlin/src/HAL/GD32_MFL/fastio.h +++ b/Marlin/src/HAL/GD32_MFL/fastio.h @@ -21,26 +21,27 @@ */ #pragma once -// Fast I/O interfaces for GD32F303RE +// Fast I/O interfaces for GD32 #include +#include #include #include template static inline void fast_write_pin_wrapper(pin_size_t IO, T V) { - auto port = getPortFromPin(IO); - auto pin = getPinInPort(IO); - if (static_cast(V)) gpio::fast_set_pin(port, pin); - else gpio::fast_clear_pin(port, pin); + const PortPinPair& pp = port_pin_map[IO]; + gpio::fast_write_pin(pp.port, pp.pin, static_cast(V)); } -static inline bool fast_read_pin_wrapper(pin_size_t IO) { - return gpio::fast_read_pin(getPortFromPin(IO), getPinInPort(IO)); +static inline auto fast_read_pin_wrapper(pin_size_t IO) -> bool { + const PortPinPair& pp = port_pin_map[IO]; + return gpio::fast_read_pin(pp.port, pp.pin); } static inline void fast_toggle_pin_wrapper(pin_size_t IO) { - gpio::fast_toggle_pin(getPortFromPin(IO), getPinInPort(IO)); + const PortPinPair& pp = port_pin_map[IO]; + gpio::fast_toggle_pin(pp.port, pp.pin); } // ------------------------ diff --git a/Marlin/src/HAL/GD32_MFL/pinsDebug.h b/Marlin/src/HAL/GD32_MFL/pinsDebug.h index d3b3794df2..be7e4ce1ba 100644 --- a/Marlin/src/HAL/GD32_MFL/pinsDebug.h +++ b/Marlin/src/HAL/GD32_MFL/pinsDebug.h @@ -70,8 +70,9 @@ bool isAnalogPin(const pin_t pin) { if (!isValidPin(pin)) return false; if (getAdcChannel(pin) != adc::ADC_Channel::INVALID) { - auto& instance = gpio::GPIO::get_instance(getPortFromPin(pin)).value(); - return instance.get_pin_mode(getPinInPort(pin)) == gpio::Pin_Mode::ANALOG && !M43_NEVER_TOUCH(pin); + const PortPinPair& pp = port_pin_map[pin]; + auto& instance = gpio::GPIO::get_instance(pp.port).value(); + return instance.get_pin_mode(pp.pin) == gpio::Pin_Mode::ANALOG && !M43_NEVER_TOUCH(pin); } return false; @@ -80,8 +81,9 @@ bool isAnalogPin(const pin_t pin) { bool getValidPinMode(const pin_t pin) { if (!isValidPin(pin)) return false; - auto& instance = gpio::GPIO::get_instance(getPortFromPin(pin)).value(); - gpio::Pin_Mode mode = instance.get_pin_mode(getPinInPort(pin)); + const PortPinPair& pp = port_pin_map[pin]; + auto& instance = gpio::GPIO::get_instance(pp.port).value(); + gpio::Pin_Mode mode = instance.get_pin_mode(pp.pin); return mode != gpio::Pin_Mode::ANALOG && mode != gpio::Pin_Mode::INPUT_FLOATING && mode != gpio::Pin_Mode::INPUT_PULLUP && mode != gpio::Pin_Mode::INPUT_PULLDOWN; diff --git a/Marlin/src/HAL/GD32_MFL/sd/SDCard.cpp b/Marlin/src/HAL/GD32_MFL/sd/SDCard.cpp index c46e0fc6fb..2e7ba4dfd9 100644 --- a/Marlin/src/HAL/GD32_MFL/sd/SDCard.cpp +++ b/Marlin/src/HAL/GD32_MFL/sd/SDCard.cpp @@ -28,7 +28,7 @@ namespace sdio { -CardDMA& CardDMA::get_instance() { +auto CardDMA::get_instance() -> CardDMA& { static CardDMA instance; return instance; } @@ -38,9 +38,7 @@ CardDMA::CardDMA() : sdcard_cid_{0U, 0U, 0U, 0U}, sdcard_scr_{0U, 0U}, desired_clock_(Default_Desired_Clock), - stop_condition_(0U), total_bytes_(0U), - count_(0U), sdio_(SDIO::get_instance()), config_(sdio_.get_config()), dmaBase_(dma::DMA_Base::DMA1_BASE), @@ -50,15 +48,15 @@ CardDMA::CardDMA() : transfer_error_(SDIO_Error_Type::OK), interface_version_(Interface_Version::UNKNOWN), card_type_(Card_Type::UNKNOWN), + current_state_(Operational_State::READY), transfer_end_(false), - is_rx_(false), multiblock_(false), - current_state_(Operational_State::READY) + is_rx_(false) { } // Initialize card and put in standby state -SDIO_Error_Type CardDMA::init() { +auto CardDMA::init() -> SDIO_Error_Type { // Reset SDIO peripheral sdio_.reset(); sync_domains(); @@ -79,7 +77,7 @@ SDIO_Error_Type CardDMA::init() { } // Startup command procedure according to SDIO specification -SDIO_Error_Type CardDMA::begin_startup_procedure() { +auto CardDMA::begin_startup_procedure() -> SDIO_Error_Type { sdio_.set_power_mode(Power_Control::POWER_ON); sdio_.set_clock_enable(true); sync_domains(); @@ -124,12 +122,12 @@ SDIO_Error_Type CardDMA::begin_startup_procedure() { } // Voltage validation -SDIO_Error_Type CardDMA::validate_voltage() { +auto CardDMA::validate_voltage() -> SDIO_Error_Type { uint32_t response = 0U; uint32_t count = 0U; bool valid_voltage = false; - while ((count < Max_Voltage_Checks) && (valid_voltage == false)) { + while (count < Max_Voltage_Checks && valid_voltage == false) { if (send_command_and_check(Command_Index::CMD55, 0, Command_Response::RSP_SHORT, Wait_Type::WT_NONE, [this, cmd = Command_Index::CMD55]() { return get_r1_result(cmd); @@ -144,7 +142,7 @@ SDIO_Error_Type CardDMA::validate_voltage() { return SDIO_Error_Type::ACMD41_FAILED; } response = sdio_.get_response(Response_Type::RESPONSE0); - valid_voltage = (((response >> 31U) == 1U) ? true : false); + valid_voltage = ((response >> 31U) == 1U); count++; } @@ -171,7 +169,7 @@ void CardDMA::begin_shutdown_procedure() { } // Initialize card -SDIO_Error_Type CardDMA::card_init() { +auto CardDMA::card_init() -> SDIO_Error_Type { if (sdio_.get_power_mode() == static_cast(Power_Control::POWER_OFF)) { return SDIO_Error_Type::INVALID_OPERATION; } @@ -221,7 +219,7 @@ SDIO_Error_Type CardDMA::card_init() { return SDIO_Error_Type::OK; } -SDIO_Error_Type CardDMA::store_cid() { +auto CardDMA::store_cid() -> SDIO_Error_Type { // Store the CID register values sdcard_cid_[0] = sdio_.get_response(Response_Type::RESPONSE0); sdcard_cid_[1] = sdio_.get_response(Response_Type::RESPONSE1); @@ -231,7 +229,7 @@ SDIO_Error_Type CardDMA::store_cid() { return SDIO_Error_Type::OK; } -SDIO_Error_Type CardDMA::store_csd() { +auto CardDMA::store_csd() -> SDIO_Error_Type { // Store the CSD register values sdcard_csd_[0] = sdio_.get_response(Response_Type::RESPONSE0); sdcard_csd_[1] = sdio_.get_response(Response_Type::RESPONSE1); @@ -241,7 +239,7 @@ SDIO_Error_Type CardDMA::store_csd() { return SDIO_Error_Type::OK; } -SDIO_Error_Type CardDMA::set_hardware_bus_width(Bus_Width width) { +auto CardDMA::set_hardware_bus_width(Bus_Width width) -> SDIO_Error_Type { if (card_type_ == Card_Type::SD_MMC || width == Bus_Width::WIDTH_8BIT) { return SDIO_Error_Type::UNSUPPORTED_FUNCTION; } @@ -283,7 +281,7 @@ SDIO_Error_Type CardDMA::set_hardware_bus_width(Bus_Width width) { return SDIO_Error_Type::UNSUPPORTED_FUNCTION; } -SDIO_Error_Type CardDMA::read(uint8_t* buf, uint32_t address, uint32_t count) { +auto CardDMA::read(uint8_t* buf, uint32_t address, uint32_t count) -> SDIO_Error_Type { if (current_state_ == Operational_State::READY) { transfer_error_ = SDIO_Error_Type::OK; current_state_ = Operational_State::BUSY; @@ -340,7 +338,7 @@ SDIO_Error_Type CardDMA::read(uint8_t* buf, uint32_t address, uint32_t count) { } } -SDIO_Error_Type CardDMA::write(uint8_t* buf, uint32_t address, uint32_t count) { +auto CardDMA::write(uint8_t* buf, uint32_t address, uint32_t count) -> SDIO_Error_Type { // Enable the interrupts sdio_.set_interrupt_enable(Interrupt_Type::DTCRCERRIE, true); sdio_.set_interrupt_enable(Interrupt_Type::DTTMOUTIE, true); @@ -363,7 +361,7 @@ SDIO_Error_Type CardDMA::write(uint8_t* buf, uint32_t address, uint32_t count) { // CMD25/CMD24 (WRITE_MULTIPLE_BLOCK/WRITE_BLOCK) send write command Command_Index write_cmd = (count > 1U) ? Command_Index::CMD25 : Command_Index::CMD24; if (send_command_and_check(write_cmd, address, Command_Response::RSP_SHORT, - Wait_Type::WT_NONE, [this, cmd = write_cmd]() { + Wait_Type::WT_NONE, [this, cmd = write_cmd]() { return get_r1_result(cmd); }) != SDIO_Error_Type::OK) { sdio_.clear_multiple_interrupt_flags(clear_common_flags); @@ -379,16 +377,16 @@ SDIO_Error_Type CardDMA::write(uint8_t* buf, uint32_t address, uint32_t count) { Block_Size block_size = get_data_block_size_index(total_bytes_); sdio_.set_data_state_machine_and_send(Data_Timeout, total_bytes_, block_size, - Transfer_Mode::BLOCK, Transfer_Direction::SDIO_TO_CARD, true); + Transfer_Mode::BLOCK, Transfer_Direction::SDIO_TO_CARD, true); - while ((dma_.get_flag(dma::Status_Flags::FLAG_FTFIF)) || (dma_.get_flag(dma::Status_Flags::FLAG_ERRIF))) { + while (dma_.get_flag(dma::Status_Flags::FLAG_FTFIF) || dma_.get_flag(dma::Status_Flags::FLAG_ERRIF)) { // Wait for the IRQ handler to clear } return SDIO_Error_Type::OK; } -SDIO_Error_Type CardDMA::erase(uint32_t address_start, uint32_t address_end) { +auto CardDMA::erase(uint32_t address_start, uint32_t address_end) -> SDIO_Error_Type { SDIO_Error_Type result = SDIO_Error_Type::OK; // Card command classes CSD @@ -459,9 +457,11 @@ void CardDMA::handle_interrupts() { disable_all_interrupts(); sdio_.set_data_state_machine_enable(false); - if ((multiblock_) && (!is_rx_)) { + if (multiblock_ && !is_rx_) { transfer_error_ = stop_transfer(); - if (transfer_error_ != SDIO_Error_Type::OK) {} + if (transfer_error_ != SDIO_Error_Type::OK) { + return; + } } if (!is_rx_) { @@ -497,7 +497,7 @@ void CardDMA::handle_interrupts() { } } -SDIO_Error_Type CardDMA::select_deselect() { +auto CardDMA::select_deselect() -> SDIO_Error_Type { // CMD7 (SELECT/DESELECT_CARD) if (send_command_and_check(Command_Index::CMD7, static_cast(sdcard_rca_ << RCA_Shift), Command_Response::RSP_SHORT, Wait_Type::WT_NONE, [this, cmd = Command_Index::CMD7]() { @@ -508,7 +508,7 @@ SDIO_Error_Type CardDMA::select_deselect() { return SDIO_Error_Type::OK; } -SDIO_Error_Type CardDMA::get_card_interface_status(uint32_t* status) { +auto CardDMA::get_card_interface_status(uint32_t* status) -> SDIO_Error_Type { if (status == nullptr) return SDIO_Error_Type::INVALID_PARAMETER; // CMD13 (SEND_STATUS) @@ -524,7 +524,7 @@ SDIO_Error_Type CardDMA::get_card_interface_status(uint32_t* status) { return SDIO_Error_Type::OK; } -SDIO_Error_Type CardDMA::get_sdcard_status(uint32_t* status) { +auto CardDMA::get_sdcard_status(uint32_t* status) -> SDIO_Error_Type { uint32_t count = 0U; // CMD16 (SET_BLOCKLEN) @@ -599,7 +599,7 @@ void CardDMA::check_dma_complete() { } } -SDIO_Error_Type CardDMA::stop_transfer() { +auto CardDMA::stop_transfer() -> SDIO_Error_Type { // CMD12 (STOP_TRANSMISSION) if (send_command_and_check(Command_Index::CMD12, 0, Command_Response::RSP_SHORT, Wait_Type::WT_NONE, [this, cmd = Command_Index::CMD12]() { return get_r1_result(cmd); @@ -609,7 +609,7 @@ SDIO_Error_Type CardDMA::stop_transfer() { return SDIO_Error_Type::OK; } -Transfer_State CardDMA::get_transfer_state() { +auto CardDMA::get_transfer_state() -> Transfer_State { Transfer_State transfer_state = Transfer_State::IDLE; if (sdio_.get_flag(Status_Flags::FLAG_TXRUN) | sdio_.get_flag(Status_Flags::FLAG_RXRUN)) { transfer_state = Transfer_State::BUSY; @@ -618,7 +618,7 @@ Transfer_State CardDMA::get_transfer_state() { return transfer_state; } -uint32_t CardDMA::get_card_capacity() const { +[[nodiscard]] auto CardDMA::get_card_capacity() const -> uint32_t { auto extract_bits = [](uint32_t value, uint8_t start_bit, uint8_t length) -> uint32_t { return (value >> start_bit) & ((1U << length) - 1U); }; @@ -665,7 +665,7 @@ uint32_t CardDMA::get_card_capacity() const { return capacity; } -SDIO_Error_Type CardDMA::get_card_specific_data(Card_Info* info) { +auto CardDMA::get_card_specific_data(Card_Info* info) -> SDIO_Error_Type { if (info == nullptr) return SDIO_Error_Type::INVALID_PARAMETER; // Store basic card information @@ -735,28 +735,20 @@ SDIO_Error_Type CardDMA::get_card_specific_data(Card_Info* info) { return SDIO_Error_Type::OK; } -constexpr Block_Size CardDMA::get_data_block_size_index(uint16_t size) { - switch (size) { - case 1: return Block_Size::BYTES_1; - case 2: return Block_Size::BYTES_2; - case 4: return Block_Size::BYTES_4; - case 8: return Block_Size::BYTES_8; - case 16: return Block_Size::BYTES_16; - case 32: return Block_Size::BYTES_32; - case 64: return Block_Size::BYTES_64; - case 128: return Block_Size::BYTES_128; - case 256: return Block_Size::BYTES_256; - case 512: return Block_Size::BYTES_512; - case 1024: return Block_Size::BYTES_1024; - case 2048: return Block_Size::BYTES_2048; - case 4096: return Block_Size::BYTES_4096; - case 8192: return Block_Size::BYTES_8192; - case 16384: return Block_Size::BYTES_16384; - default: return Block_Size::BYTES_1; - } +constexpr auto CardDMA::get_data_block_size_index(uint16_t size) -> Block_Size { + if (size < 1 || size > 16384) return Block_Size::BYTES_1; + + // Check if size is a power of two + if ((size & (size - 1)) != 0) return Block_Size::BYTES_1; + + // Count trailing zeros to find the index + uint16_t index = 0; + while ((size >>= 1) != 0) ++index; + + return static_cast(index); } -SDIO_Error_Type CardDMA::get_card_state(Card_State* card_state) { +auto CardDMA::get_card_state(Card_State* card_state) -> SDIO_Error_Type { // CMD13 (SEND_STATUS) if (send_command_and_check(Command_Index::CMD13, static_cast(sdcard_rca_ << RCA_Shift), Command_Response::RSP_SHORT, Wait_Type::WT_NONE, [this, cmd = Command_Index::CMD13]() { @@ -773,7 +765,7 @@ SDIO_Error_Type CardDMA::get_card_state(Card_State* card_state) { if (response & All_R1_Error_Bits) { for (const auto& entry : errorTableR1) { - if (response & entry.mask) { + if (TEST(response, entry.bit_position)) { return entry.errorType; } } @@ -783,23 +775,28 @@ SDIO_Error_Type CardDMA::get_card_state(Card_State* card_state) { return SDIO_Error_Type::OK; } -SDIO_Error_Type CardDMA::get_command_sent_result() { - volatile uint32_t timeout = 0x00FFFFFFU; +auto CardDMA::get_command_sent_result() -> SDIO_Error_Type { + constexpr uint32_t MAX_TIMEOUT = 0x00FFFFFFU; + uint32_t timeout = MAX_TIMEOUT; - while ((sdio_.get_flag(Status_Flags::FLAG_CMDSEND) == false) && (timeout != 0U)) { - timeout = timeout - 1U; + // Wait for command sent flag or timeout + while (!sdio_.get_flag(Status_Flags::FLAG_CMDSEND) && timeout) { + --timeout; } - if (timeout == 0U) return SDIO_Error_Type::RESPONSE_TIMEOUT; - sdio_.clear_multiple_interrupt_flags(clear_command_flags); + // Check if timeout occurred + if (timeout == 0U) { + return SDIO_Error_Type::RESPONSE_TIMEOUT; + } + + // Clear command flags and return success + sdio_.clear_multiple_interrupt_flags(clear_command_flags); return SDIO_Error_Type::OK; } -SDIO_Error_Type CardDMA::check_sdio_status(Command_Index index, bool check_index, bool ignore_crc) { +auto CardDMA::check_sdio_status(Command_Index index, bool check_index, bool ignore_crc) -> SDIO_Error_Type { // Wait until one of the relevant flags is set - bool flag_set = sdio_.wait_cmd_flags(); - - if (!flag_set) { + if (!sdio_.wait_cmd_flags()) { return SDIO_Error_Type::RESPONSE_TIMEOUT; } @@ -810,56 +807,55 @@ SDIO_Error_Type CardDMA::check_sdio_status(Command_Index index, bool check_index // If cmd was received, check the index // Responses that dont do an index check will send an invalid cmd index if (check_index && (index != Command_Index::INVALID)) { - uint8_t idx = sdio_.get_command_index(); - if (idx != static_cast(index)) { + uint8_t received_idx = sdio_.get_command_index(); + if (received_idx != static_cast(index)) { + sdio_.clear_multiple_interrupt_flags(clear_command_flags); return SDIO_Error_Type::ILLEGAL_COMMAND; } } - // Clear all flags before returning + + // Command received successfully sdio_.clear_multiple_interrupt_flags(clear_command_flags); return SDIO_Error_Type::OK; } - // Timeout check + // Check for timeout if (sdio_.get_flag(Status_Flags::FLAG_CMDTMOUT)) { sdio_.clear_flag(Clear_Flags::FLAG_CMDTMOUTC); return SDIO_Error_Type::RESPONSE_TIMEOUT; } - // CRC check - if (!ignore_crc) { - if (sdio_.get_flag(Status_Flags::FLAG_CCRCERR)) { - sdio_.clear_flag(Clear_Flags::FLAG_CCRCERRC); - return SDIO_Error_Type::COMMAND_CRC_ERROR; - } + // Check for CRC error if not ignored + if (!ignore_crc && sdio_.get_flag(Status_Flags::FLAG_CCRCERR)) { + sdio_.clear_flag(Clear_Flags::FLAG_CCRCERRC); + return SDIO_Error_Type::COMMAND_CRC_ERROR; } - // Responses that dont do an index check will send an invalid cmd index + // Final index check (redundant with the first check, but keeping for safety) + // This code path should rarely be taken due to the earlier checks if (check_index && (index != Command_Index::INVALID)) { - uint8_t idx = sdio_.get_command_index(); - if (idx != static_cast(index)) { + uint8_t received_idx = sdio_.get_command_index(); + if (received_idx != static_cast(index)) { + sdio_.clear_multiple_interrupt_flags(clear_command_flags); return SDIO_Error_Type::ILLEGAL_COMMAND; } } - // Clear all flags before returning + // Clear all flags and return success sdio_.clear_multiple_interrupt_flags(clear_command_flags); - return SDIO_Error_Type::OK; } -SDIO_Error_Type CardDMA::get_r1_result(Command_Index index) { +auto CardDMA::get_r1_result(Command_Index index) -> SDIO_Error_Type { SDIO_Error_Type result = check_sdio_status(index, true, false); - if (result != SDIO_Error_Type::OK) { - return result; - } + if (result != SDIO_Error_Type::OK) return result; // Get the R1 response and check for errors uint32_t response = sdio_.get_response(Response_Type::RESPONSE0); if (response & All_R1_Error_Bits) { for (const auto& entry : errorTableR1) { - if (response & entry.mask) { + if (TEST(response, entry.bit_position)) { return entry.errorType; } } @@ -869,7 +865,7 @@ SDIO_Error_Type CardDMA::get_r1_result(Command_Index index) { return SDIO_Error_Type::OK; } -SDIO_Error_Type CardDMA::get_r6_result(Command_Index index, uint16_t* rca) { +auto CardDMA::get_r6_result(Command_Index index, uint16_t* rca) -> SDIO_Error_Type { SDIO_Error_Type result = check_sdio_status(index, true, false); if (result != SDIO_Error_Type::OK) return result; @@ -877,7 +873,7 @@ SDIO_Error_Type CardDMA::get_r6_result(Command_Index index, uint16_t* rca) { if (response & R6_Error_Bits) { for (const auto& entry : errorTableR6) { - if (response & entry.mask) { + if (TEST(response, entry.bit_position)) { return entry.errorType; } } @@ -888,18 +884,13 @@ SDIO_Error_Type CardDMA::get_r6_result(Command_Index index, uint16_t* rca) { return SDIO_Error_Type::OK; } -SDIO_Error_Type CardDMA::get_r7_result() { - return check_sdio_status(Command_Index::INVALID, false, false); -} - -SDIO_Error_Type CardDMA::get_scr(uint16_t rca, uint32_t* scr) { +auto CardDMA::get_scr(uint16_t rca, uint32_t* scr) -> SDIO_Error_Type { uint32_t temp_scr[2] = {0U, 0U}; uint32_t index_scr = 0U; - uint32_t* src_data = scr; // CMD16 (SET_BLOCKLEN) if (send_command_and_check(Command_Index::CMD16, 8U, Command_Response::RSP_SHORT, - Wait_Type::WT_NONE, [this, cmd = Command_Index::CMD16]() { + Wait_Type::WT_NONE, [this, cmd = Command_Index::CMD16]() { return get_r1_result(cmd); }) != SDIO_Error_Type::OK) { return SDIO_Error_Type::CMD16_FAILED; @@ -907,7 +898,7 @@ SDIO_Error_Type CardDMA::get_scr(uint16_t rca, uint32_t* scr) { // CMD55 (APP_CMD) if (send_command_and_check(Command_Index::CMD55, static_cast(sdcard_rca_ << RCA_Shift), - Command_Response::RSP_SHORT, Wait_Type::WT_NONE, [this, cmd = Command_Index::CMD55]() { + Command_Response::RSP_SHORT, Wait_Type::WT_NONE, [this, cmd = Command_Index::CMD55]() { return get_r1_result(cmd); }) != SDIO_Error_Type::OK) { return SDIO_Error_Type::CMD55_FAILED; @@ -919,7 +910,7 @@ SDIO_Error_Type CardDMA::get_scr(uint16_t rca, uint32_t* scr) { // ACMD51 (SEND_SCR) if (send_command_and_check(Command_Index::ACMD51, 0U, Command_Response::RSP_SHORT, - Wait_Type::WT_NONE, [this, cmd = Command_Index::ACMD51]() { + Wait_Type::WT_NONE, [this, cmd = Command_Index::ACMD51]() { return get_r1_result(cmd); }) != SDIO_Error_Type::OK) { return SDIO_Error_Type::ACMD51_FAILED; @@ -928,36 +919,41 @@ SDIO_Error_Type CardDMA::get_scr(uint16_t rca, uint32_t* scr) { // Store SCR while (!sdio_.check_scr_flags()) { if (sdio_.get_flag(Status_Flags::FLAG_RXDTVAL)) { - *(temp_scr + index_scr) = sdio_.read_fifo_word(); - ++index_scr; + temp_scr[index_scr++] = sdio_.read_fifo_word(); } } + // Check for errors if (sdio_.get_flag(Status_Flags::FLAG_DTTMOUT)) { sdio_.clear_flag(Clear_Flags::FLAG_DTTMOUTC); return SDIO_Error_Type::DATA_TIMEOUT; - } else if (sdio_.get_flag(Status_Flags::FLAG_DTCRCERR)) { + } + else if (sdio_.get_flag(Status_Flags::FLAG_DTCRCERR)) { sdio_.clear_flag(Clear_Flags::FLAG_DTCRCERRC); return SDIO_Error_Type::DATA_CRC_ERROR; - } else if (sdio_.get_flag(Status_Flags::FLAG_RXORE)) { + } + else if (sdio_.get_flag(Status_Flags::FLAG_RXORE)) { sdio_.clear_flag(Clear_Flags::FLAG_RXOREC); return SDIO_Error_Type::RX_FIFO_OVERRUN; } sdio_.clear_multiple_interrupt_flags(clear_data_flags); - constexpr uint32_t Zero_Seven = (0xFFU << 0U); - constexpr uint32_t Eight_Fifteen = (0xFFU << 8U); - constexpr uint32_t Sixteen_Twentythree = (0xFFU << 16U); - constexpr uint32_t TwentyFour_Thirtyone = (0xFFU << 24U); + constexpr uint32_t BYTE0_MASK = 0xFFU; + constexpr uint32_t BYTE1_MASK = 0xFF00U; + constexpr uint32_t BYTE2_MASK = 0xFF0000U; + constexpr uint32_t BYTE3_MASK = 0xFF000000U; - // adjust SCR value - *src_data = ((temp_scr[1] & Zero_Seven) << 24U) | ((temp_scr[1] & Eight_Fifteen) << 8U) | - ((temp_scr[1] & Sixteen_Twentythree) >> 8U) | ((temp_scr[1] & TwentyFour_Thirtyone) >> 24U); + // Byte-swap the SCR values (convert from big-endian to little-endian) + scr[0] = ((temp_scr[1] & BYTE0_MASK) << 24) | + ((temp_scr[1] & BYTE1_MASK) << 8) | + ((temp_scr[1] & BYTE2_MASK) >> 8) | + ((temp_scr[1] & BYTE3_MASK) >> 24); - src_data = src_data + 1U; - *src_data = ((temp_scr[0] & Zero_Seven) << 24U) | ((temp_scr[0] & Eight_Fifteen) << 8U) | - ((temp_scr[0] & Sixteen_Twentythree) >> 8U) | ((temp_scr[0] & TwentyFour_Thirtyone) >> 24U); + scr[1] = ((temp_scr[0] & BYTE0_MASK) << 24) | + ((temp_scr[0] & BYTE1_MASK) << 8) | + ((temp_scr[0] & BYTE2_MASK) >> 8) | + ((temp_scr[0] & BYTE3_MASK) >> 24); return SDIO_Error_Type::OK; } @@ -965,23 +961,22 @@ SDIO_Error_Type CardDMA::get_scr(uint16_t rca, uint32_t* scr) { // DMA for rx/tx is always DMA1 channel 3 void CardDMA::set_dma_parameters(uint8_t* buf, uint32_t count, bool is_write) { constexpr uint32_t flag_bits = (1U << static_cast(dma::INTF_Bits::GIF3)); - dma_.clear_flags(flag_bits); // Disable and reset DMA dma_.set_channel_enable(false); dma_.clear_channel(); - dma_.init({ - count, - static_cast(reinterpret_cast(buf)), - static_cast(reinterpret_cast(sdio_.reg_address(SDIO_Regs::FIFO))), - dma::Bit_Width::WIDTH_32BIT, - dma::Bit_Width::WIDTH_32BIT, - dma::Increase_Mode::INCREASE_DISABLE, - dma::Increase_Mode::INCREASE_ENABLE, - dma::Channel_Priority::MEDIUM_PRIORITY, - is_write ? dma::Transfer_Direction::M2P : dma::Transfer_Direction::P2M + dma_.init(dma::DMA_Config{ + .count = count, + .memory_address = static_cast(reinterpret_cast(buf)), + .peripheral_address = static_cast(reinterpret_cast(sdio_.reg_address(SDIO_Regs::FIFO))), + .peripheral_bit_width = dma::Bit_Width::WIDTH_32BIT, + .memory_bit_width = dma::Bit_Width::WIDTH_32BIT, + .peripheral_increase = dma::Increase_Mode::INCREASE_DISABLE, + .memory_increase = dma::Increase_Mode::INCREASE_ENABLE, + .channel_priority = dma::Channel_Priority::MEDIUM_PRIORITY, + .direction = is_write ? dma::Transfer_Direction::M2P : dma::Transfer_Direction::P2M }); dma_.set_memory_to_memory_enable(false); @@ -995,24 +990,29 @@ void CardDMA::set_dma_parameters(uint8_t* buf, uint32_t count, bool is_write) { dma_.set_channel_enable(true); } -SDIO_Error_Type CardDMA::wait_for_card_ready() { - volatile uint32_t timeout = 0x00FFFFFFU; +auto CardDMA::wait_for_card_ready() -> SDIO_Error_Type { + constexpr uint32_t MAX_TIMEOUT = 0x00FFFFFFU; + uint32_t timeout = MAX_TIMEOUT; uint32_t response = sdio_.get_response(Response_Type::RESPONSE0); - while (((response & static_cast(R1_Status::READY_FOR_DATA)) == 0U) && (timeout != 0U)) { - // Continue to send CMD13 to poll the state of card until buffer empty or timeout - timeout = timeout - 1U; + // Poll until card is ready for data or timeout occurs + while (((response & static_cast(R1_Status::READY_FOR_DATA)) == 0U) && timeout) { + --timeout; + // CMD13 (SEND_STATUS) if (send_command_and_check(Command_Index::CMD13, static_cast(sdcard_rca_ << RCA_Shift), - Command_Response::RSP_SHORT, Wait_Type::WT_NONE, [this, cmd = Command_Index::CMD13]() { + Command_Response::RSP_SHORT, Wait_Type::WT_NONE, [this, cmd = Command_Index::CMD13]() { return get_r1_result(cmd); }) != SDIO_Error_Type::OK) { return SDIO_Error_Type::CMD13_FAILED; } + + // Get updated response response = sdio_.get_response(Response_Type::RESPONSE0); } - return (timeout == 0U) ? SDIO_Error_Type::ERROR : SDIO_Error_Type::OK; + // Return error if timeout occurred, otherwise success + return timeout ? SDIO_Error_Type::OK : SDIO_Error_Type::ERROR; } } // namespace sdio diff --git a/Marlin/src/HAL/GD32_MFL/sd/SDCard.h b/Marlin/src/HAL/GD32_MFL/sd/SDCard.h index e202be6eb5..b03d128dc8 100644 --- a/Marlin/src/HAL/GD32_MFL/sd/SDCard.h +++ b/Marlin/src/HAL/GD32_MFL/sd/SDCard.h @@ -26,76 +26,82 @@ class DMA; class CardDMA { public: - static CardDMA& get_instance(); + static auto get_instance() -> CardDMA&; - SDIO_Error_Type init(); - SDIO_Error_Type card_init(); - SDIO_Error_Type begin_startup_procedure(); + // Initialization + auto init() -> SDIO_Error_Type; + auto card_init() -> SDIO_Error_Type; + + // Startup and shutdown procedures + auto begin_startup_procedure() -> SDIO_Error_Type; void begin_shutdown_procedure(); + // Configuration - SDIO_Error_Type set_hardware_bus_width(Bus_Width width); - // Main read/write functions for single and multiblock transfers - SDIO_Error_Type read(uint8_t* buf, uint32_t address, uint32_t count); - SDIO_Error_Type write(uint8_t* buf, uint32_t address, uint32_t count); - // DMA transfers - // Other card functions - SDIO_Error_Type erase(uint32_t address_start, uint32_t address_end); - // Interrupt handler - void handle_interrupts(); + auto set_hardware_bus_width(Bus_Width width) -> SDIO_Error_Type; + auto send_bus_width_command(uint32_t width_value) -> SDIO_Error_Type; + + // Main read/write/erase functions + auto read(uint8_t* buf, uint32_t address, uint32_t count) -> SDIO_Error_Type; + auto write(uint8_t* buf, uint32_t address, uint32_t count) -> SDIO_Error_Type; + auto erase(uint32_t address_start, uint32_t address_end) -> SDIO_Error_Type; + // Card select - SDIO_Error_Type select_deselect(); + auto select_deselect() -> SDIO_Error_Type; - SDIO_Error_Type get_card_interface_status(uint32_t* status); - SDIO_Error_Type get_sdcard_status(uint32_t* status); + // Status and state + auto get_card_interface_status(uint32_t* status) -> SDIO_Error_Type; + auto get_sdcard_status(uint32_t* status) -> SDIO_Error_Type; + auto get_transfer_state() -> Transfer_State; + auto get_card_state(Card_State* card_state) -> SDIO_Error_Type; + auto check_sdio_status(Command_Index index = Command_Index::INVALID, bool check_index = false, bool ignore_crc = false) -> SDIO_Error_Type; - void check_dma_complete(); - SDIO_Error_Type stop_transfer(); - - Transfer_State get_transfer_state(); - uint32_t get_card_capacity() const; - - SDIO_Error_Type send_bus_width_command(uint32_t width_value); - - SDIO_Error_Type get_card_specific_data(Card_Info* info); - constexpr Block_Size get_data_block_size_index(uint16_t size); - - SDIO_Error_Type get_card_state(Card_State* card_state); - SDIO_Error_Type check_sdio_status(Command_Index index = Command_Index::INVALID, bool check_index = false, bool ignore_crc = false); - - // DMA configuration + // DMA void set_dma_parameters(uint8_t* buf, uint32_t count, bool is_write); + void check_dma_complete(); + + // Stop transfer + auto stop_transfer() -> SDIO_Error_Type; + + // Card information + auto get_card_specific_data(Card_Info* info) -> SDIO_Error_Type; + constexpr auto get_data_block_size_index(uint16_t size) -> Block_Size; + [[nodiscard]] auto get_card_capacity() const -> uint32_t; // SDIO configuration void sdio_configure(const SDIO_Config config) { sdio_.init(config); } - // Varaible stored parameters - SDIO_Error_Type get_scr(uint16_t rca, uint32_t* scr); - SDIO_Error_Type store_cid(); - SDIO_Error_Type store_csd(); + // Interrupt handler + void handle_interrupts(); - // Accessor methods - SDIO_Config& get_config() { return config_; } - dma::DMA& get_dma_instance() { return dma_; } + // Varaible stored parameters + auto get_scr(uint16_t rca, uint32_t* scr) -> SDIO_Error_Type; + auto store_cid() -> SDIO_Error_Type; + auto store_csd() -> SDIO_Error_Type; + + // Inlined accessor methods + auto get_config() -> SDIO_Config& { return config_; } + auto get_dma_instance() -> dma::DMA& { return dma_; } void set_data_end_interrupt() { sdio_.set_interrupt_enable(Interrupt_Type::DTENDIE, true); } void set_sdio_dma_enable(bool enable) { sdio_.set_dma_enable(enable); } - bool get_is_sdio_rx() { return is_rx_; } + auto get_is_sdio_rx() -> bool { return is_rx_; } void clear_sdio_data_flags() { sdio_.clear_multiple_interrupt_flags(clear_data_flags); } void clear_sdio_cmd_flags() { sdio_.clear_multiple_interrupt_flags(clear_command_flags); } void clear_sdio_common_flags() { sdio_.clear_multiple_interrupt_flags(clear_common_flags); } - Operational_State get_state() { return current_state_; } + auto get_state() -> Operational_State { return current_state_; } void set_state(Operational_State state) { current_state_ = state; } - void set_transfer_end(bool value) { transfer_end_ = value; } void set_transfer_error(SDIO_Error_Type error) { transfer_error_ = error; } + void set_transfer_end(bool end) { transfer_end_ = end; }; - inline SDIO_Error_Type set_desired_clock(uint32_t desired_clock, bool wide_bus, bool low_power) { - sdio_.init({ - desired_clock, - Clock_Edge::RISING_EDGE, - wide_bus ? Bus_Width::WIDTH_4BIT : Bus_Width::WIDTH_1BIT, - false, - low_power, - false + auto set_desired_clock(uint32_t desired_clock, bool wide_bus, bool low_power) -> SDIO_Error_Type { + sdio_.init(SDIO_Config{ + .desired_clock = desired_clock, + .enable_bypass = false, + .enable_powersave = low_power, + .enable_hwclock = false, + .clock_edge = Clock_Edge::RISING_EDGE, + .width = wide_bus ? Bus_Width::WIDTH_4BIT : Bus_Width::WIDTH_1BIT }); + sync_domains(); desired_clock_ = desired_clock; @@ -107,19 +113,17 @@ private: // Prevent copying or assigning CardDMA(const CardDMA&) = delete; - CardDMA& operator=(const CardDMA&) = delete; + auto operator=(const CardDMA&) -> CardDMA& = delete; // Helper function - SDIO_Error_Type wait_for_card_ready(); + auto wait_for_card_ready() -> SDIO_Error_Type; // Member variables alignas(4) uint32_t sdcard_csd_[4]; alignas(4) uint32_t sdcard_cid_[4]; alignas(4) uint32_t sdcard_scr_[2]; uint32_t desired_clock_; - uint32_t stop_condition_; uint32_t total_bytes_; - uint32_t count_; SDIO& sdio_; SDIO_Config& config_; const dma::DMA_Base dmaBase_; @@ -129,66 +133,70 @@ private: SDIO_Error_Type transfer_error_; Interface_Version interface_version_; Card_Type card_type_; - volatile bool transfer_end_; - volatile bool is_rx_; - volatile bool multiblock_; - volatile Operational_State current_state_; + Operational_State current_state_; + bool transfer_end_; + bool multiblock_; + bool is_rx_; // Private helper methods - SDIO_Error_Type validate_voltage(); - SDIO_Error_Type get_r1_result(Command_Index index); - //SDIO_Error_Type get_r2_r3_result(); - SDIO_Error_Type get_r6_result(Command_Index index, uint16_t* rca); - SDIO_Error_Type get_r7_result(); - //SDIO_Error_Type get_r1_error_type(uint32_t response); - SDIO_Error_Type get_command_sent_result(); + auto validate_voltage() -> SDIO_Error_Type; + auto get_command_sent_result() -> SDIO_Error_Type; + auto get_r1_result(Command_Index index) -> SDIO_Error_Type; + auto get_r6_result(Command_Index index, uint16_t* rca) -> SDIO_Error_Type; + auto get_r7_result() -> SDIO_Error_Type { return check_sdio_status(Command_Index::INVALID, false, false); }; + void sync_domains() { delayMicroseconds(8); } - inline void sync_domains() { - delayMicroseconds(8); - } - - inline bool validate_transfer_params(uint32_t* buf, uint16_t size) { + auto validate_transfer_params(uint32_t* buf, uint16_t size) -> bool { if (buf == nullptr) return false; // Size must be > 0, <= 2048 and power of 2 - if ((size == 0U) || (size > 2048U) || (size & (size - 1U))) { - return false; - } - return true; + return size > 0U && size <= 2048U && !(size & (size - 1U)); } void process_sdsc_specific_csd(Card_Info* info, const uint8_t* csd_bytes) { - info->csd.device_size = (static_cast(csd_bytes[6] & 0x03U) << 10U) | - (static_cast(csd_bytes[7]) << 2U) | - (static_cast((csd_bytes[8] & 0xC0U) >> 6U)); - info->csd.device_size_multiplier = static_cast((csd_bytes[9] & 0x03U) << 1U | - (csd_bytes[10] & 0x80U) >> 7U); + const uint32_t device_size = ((csd_bytes[6] & 0x3U) << 10) | + (csd_bytes[7] << 2) | + ((csd_bytes[8] >> 6) & 0x3U); - info->block_size = static_cast(1 << info->csd.read_block_length); - info->capacity = static_cast((info->csd.device_size + 1U) * - (1U << (info->csd.device_size_multiplier + 2U)) * - info->block_size); + const uint8_t device_size_multiplier = ((csd_bytes[9] & 0x3U) << 1) | + ((csd_bytes[10] >> 7) & 0x1U); + + // Store calculated values + info->csd.device_size = device_size; + info->csd.device_size_multiplier = device_size_multiplier; + + // Calculate block size and capacity + info->block_size = 1U << info->csd.read_block_length; + info->capacity = (device_size + 1U) * + (1U << (device_size_multiplier + 2U)) * + info->block_size; } void process_sdhc_specific_csd(Card_Info* info, const uint8_t* csd_bytes) { - info->csd.device_size = static_cast((csd_bytes[7] & 0x3FU) << 16U) | - static_cast((csd_bytes[8]) << 8U) | - static_cast(csd_bytes[9]); + info->csd.device_size = static_cast((csd_bytes[7] & 0x3FU) << 16) | + static_cast((csd_bytes[8]) << 8) | + static_cast(csd_bytes[9]); + // Set block size and calculate capacity info->block_size = BLOCK_SIZE; info->capacity = static_cast((info->csd.device_size + 1U) * - BLOCK_SIZE * KILOBYTE); + BLOCK_SIZE * KILOBYTE); } void process_common_csd_tail(Card_Info* info, const uint8_t* csd_bytes) { - info->csd.sector_size = static_cast(((csd_bytes[9] & 0x3FU) << 1U) | - (csd_bytes[10] & 0x80U) >> 7U); - info->csd.speed_factor = static_cast((csd_bytes[11] & 0x1CU) >> 2U); - info->csd.write_block_length = static_cast(((csd_bytes[11] & 0x03U) << 2U) | - ((csd_bytes[12] & 0xC0U) >> 6U)); - info->csd.checksum = static_cast((csd_bytes[15] & 0xFEU) >> 1U); + // Calculate sector_size + info->csd.sector_size = static_cast(((csd_bytes[9] & 0x3FU) << 1) | + (csd_bytes[10] & 0x80U) >> 7); + + // Calculate speed_factor and write_block_length + info->csd.speed_factor = static_cast((csd_bytes[11] & 0x1CU) >> 2); + info->csd.write_block_length = static_cast(((csd_bytes[11] & 0x3U) << 2) | + ((csd_bytes[12] & 0xC0U) >> 6)); + + // Calculate checksum + info->csd.checksum = static_cast((csd_bytes[15] & 0xFEU) >> 1); } - inline void disable_all_interrupts() { + void disable_all_interrupts() { sdio_.set_interrupt_enable(Interrupt_Type::DTCRCERRIE, false); sdio_.set_interrupt_enable(Interrupt_Type::DTTMOUTIE, false); sdio_.set_interrupt_enable(Interrupt_Type::DTENDIE, false); @@ -200,8 +208,8 @@ private: } template - inline SDIO_Error_Type send_command_and_check(Command_Index command, uint32_t argument, - Command_Response response, Wait_Type type, CheckFunc check_result) { + auto send_command_and_check(Command_Index command, uint32_t argument, + Command_Response response, Wait_Type type, CheckFunc check_result) -> SDIO_Error_Type { sdio_.set_command_state_machine(command, argument, response, type); sync_domains(); sdio_.set_command_state_machine_enable(true); diff --git a/Marlin/src/HAL/GD32_MFL/sd/sdio.cpp b/Marlin/src/HAL/GD32_MFL/sd/sdio.cpp index 69905feb51..a474c1977e 100644 --- a/Marlin/src/HAL/GD32_MFL/sd/sdio.cpp +++ b/Marlin/src/HAL/GD32_MFL/sd/sdio.cpp @@ -47,7 +47,7 @@ inline constexpr uint8_t SDIO_READ_RETRIES = READ_RETRIES; Card_State cardState = Card_State::READY; -bool SDIO_SetBusWidth(Bus_Width width) { +auto SDIO_SetBusWidth(Bus_Width width) -> bool { return (CardDMA_I.set_hardware_bus_width(width) == SDIO_Error_Type::OK); } diff --git a/Marlin/src/HAL/GD32_MFL/sd/sdio.h b/Marlin/src/HAL/GD32_MFL/sd/sdio.h index b6b027ba77..a39e8c7a66 100644 --- a/Marlin/src/HAL/GD32_MFL/sd/sdio.h +++ b/Marlin/src/HAL/GD32_MFL/sd/sdio.h @@ -32,5 +32,5 @@ #define SDIO_CMD_PIN PD2 void sdio_mfl_init(); -bool SDIO_SetBusWidth(sdio::Bus_Width width); +auto SDIO_SetBusWidth(sdio::Bus_Width width) -> bool; void DMA1_IRQHandler(dma::DMA_Channel channel); diff --git a/Marlin/src/HAL/GD32_MFL/timers.h b/Marlin/src/HAL/GD32_MFL/timers.h index 0eb6bd563a..49d005b8cd 100644 --- a/Marlin/src/HAL/GD32_MFL/timers.h +++ b/Marlin/src/HAL/GD32_MFL/timers.h @@ -89,7 +89,7 @@ static inline constexpr struct {timer::TIMER_Base base; uint8_t timer_number;} b }; // Converts a timer base to an integer timer index. -constexpr int timer_base_to_index(timer::TIMER_Base base) { +constexpr auto timer_base_to_index(timer::TIMER_Base base) -> int { for (const auto& timer : base_to_index) { if (timer.base == base) { return static_cast(timer.timer_number); @@ -131,7 +131,7 @@ FORCE_INLINE static hal_timer_t HAL_timer_get_count(const uint8_t timer_number) FORCE_INLINE static void HAL_timer_set_compare(const uint8_t timer_number, const hal_timer_t value) { if (!HAL_timer_initialized(timer_number)) return; - const uint32_t new_value = static_cast(value + 1U); + const auto new_value = static_cast(value + 1U); GeneralTimer& timer = (timer_number == MF_TIMER_STEP) ? Step_Timer : Temp_Timer; if (timer_number == MF_TIMER_STEP || timer_number == MF_TIMER_TEMP) { diff --git a/ini/gd32.ini b/ini/gd32.ini index 5187895021..d9cc3f7082 100644 --- a/ini/gd32.ini +++ b/ini/gd32.ini @@ -10,7 +10,7 @@ #################################### [gd32_base] -platform = https://github.com/bmourit/platform-mfl/archive/refs/tags/V1.0.3.zip +platform = https://github.com/bmourit/platform-mfl/archive/refs/tags/V1.0.4.zip board_build.core = gd32 build_src_filter = ${common.default_src_filter} + + build_unflags = -std=gnu++11 -std=gnu++14 -std=gnu++17 @@ -28,7 +28,7 @@ extra_scripts = ${common.extra_scripts} # [env:GD32F303RE_creality_mfl] extends = gd32_base -board = mfl_creality_422 +board = mfl_creality_v4 board_build.offset = 0x7000 board_upload.offset_address = 0x08007000 board_build.rename = firmware-{time}.bin From e2583b4f85eb128611b0af1af7117e215ddb0961 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Tue, 6 May 2025 00:31:19 +0000 Subject: [PATCH 287/787] [cron] Bump distribution date (2025-05-06) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 4abad36238..38fbe78024 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-05-05" +//#define STRING_DISTRIBUTION_DATE "2025-05-06" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index bb924b75bb..200c24ea62 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-05-05" + #define STRING_DISTRIBUTION_DATE "2025-05-06" #endif /** From 67948ad6c62b1034b815d219c0b7bfc475b03767 Mon Sep 17 00:00:00 2001 From: Andrew <18502096+classicrocker883@users.noreply.github.com> Date: Mon, 5 May 2025 21:19:52 -0400 Subject: [PATCH 288/787] =?UTF-8?q?=F0=9F=9A=B8=20Fix=20ProUI=20LCD=20wake?= =?UTF-8?q?=20up=20(2)=20(#27835)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Followup to #27832 --- Marlin/src/lcd/e3v2/proui/dwin.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Marlin/src/lcd/e3v2/proui/dwin.cpp b/Marlin/src/lcd/e3v2/proui/dwin.cpp index aa77704786..c3a69c1c66 100644 --- a/Marlin/src/lcd/e3v2/proui/dwin.cpp +++ b/Marlin/src/lcd/e3v2/proui/dwin.cpp @@ -1278,7 +1278,7 @@ void hmiWaitForUser() { if (!wait_for_user) { switch (checkkey) { case ID_PrintDone: select_page.reset(); gotoMainMenu(); break; - default: hmiReturnScreen(); break; + default: ui.reset_status(true); hmiReturnScreen(); break; } } } @@ -1958,8 +1958,11 @@ void MarlinUI::update() { #if HAS_LCD_BRIGHTNESS void MarlinUI::_set_brightness() { - if (!backlight) wait_for_user = true; dwinLCDBrightness(backlight ? brightness : 0); + if (!backlight) + wait_for_user = true; + else if (checkkey != ID_PrintDone) + wait_for_user = false; } #endif From 3a3c3b8a222f0b9f989e7f2fb2afc109637685f7 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Mon, 5 May 2025 20:32:02 -0500 Subject: [PATCH 289/787] =?UTF-8?q?=F0=9F=94=A8=20Fix=20build=20flags=20fo?= =?UTF-8?q?r=20env:mks=5Fmonster8=5Fusb=5Fflash=5Fdrive?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ini/stm32f4.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ini/stm32f4.ini b/ini/stm32f4.ini index 0e9dc9102a..c29e3180eb 100644 --- a/ini/stm32f4.ini +++ b/ini/stm32f4.ini @@ -639,7 +639,7 @@ upload_protocol = jlink [env:mks_monster8_usb_flash_drive] extends = env:mks_monster8 platform_packages = ${stm_flash_drive.platform_packages} -build_flags = ${stm_flash_drive.build_flags} ${stm32f4_I2C1_CAN.build_flags} ${USB_HS_IN_FS.build_flags} +build_flags = ${env:mks_monster8.build_flags} ${stm_flash_drive.build_flags} ${stm32f4_I2C1_CAN.build_flags} ${USB_HS_IN_FS.build_flags} # # MKS Monster8 V1 / V2 (STM32F407VET6 ARM Cortex-M4) with USB Flash Drive Support and Shared Media From b7a1681d38cb30e5477e0560ef8cf29791b0286c Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Mon, 5 May 2025 21:07:47 -0500 Subject: [PATCH 290/787] =?UTF-8?q?=F0=9F=94=A8=20Fix=20some=20build=5Ffla?= =?UTF-8?q?gs=20inheritance?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- buildroot/share/PlatformIO/variants/README.md | 23 +++++++++++++ ini/stm32-common.ini | 3 +- ini/stm32f4.ini | 32 +++++++++---------- 3 files changed, 40 insertions(+), 18 deletions(-) create mode 100644 buildroot/share/PlatformIO/variants/README.md diff --git a/buildroot/share/PlatformIO/variants/README.md b/buildroot/share/PlatformIO/variants/README.md new file mode 100644 index 0000000000..ae64b1b439 --- /dev/null +++ b/buildroot/share/PlatformIO/variants/README.md @@ -0,0 +1,23 @@ +# Marlin Custom Variants + +This `buildroot/share/PlatformIO/variants` folder contains Marlin custom variants for both generic and custom boards. + +Marlin specifies board variants in PlatformIO INI files in one of two ways: +- The `board_build.variant = VARIANT_MAME` field specifies the variant subfolder name directly. +- The `board = board_name` field names a custom board JSON file that contains a `build.variant` field. + +## Variant File Naming + +With the latest STM32 platform (17.x) the `variant.h` and `variant.cpp` files are required to have more unique names. If the variant is based on a generic board definition the name `variant_generic.h`/`.cpp` should be used. Otherwise, the capitalized name of the `board` should be used. + +### Examples + +| board | board file | variant | Variant Files | +|-------|------------|---------|---------------| +|`marlin_STM32F407VGT6_CCM`|`marlin_STM32F407VGT6_CCM.json`|`MARLIN_BTT_E3_RRF`|`variants/MARLIN_BTT_E3_RRF/variant.*`| +|`genericSTM32F103VE`|n/a|`MARLIN_F103Vx`|`variants/MARLIN_F103Vx/variant_generic.*`| +|`marlin_STM32F407ZE`|`marlin_STM32F407ZE.json`|`MARLIN_F407ZE`|`variants/MARLIN_F407ZE/variant_MARLIN_F407ZE.*`| + +# Marlin Custom Boards + +The `buildroot/share/PlatformIO/boards` folder contains Marlin's custom board definition JSON files. These files provide hardware IDs, board statistics, additional build flags, custom variant name, linker definition filename, remote debug options, upload devices, etc. diff --git a/ini/stm32-common.ini b/ini/stm32-common.ini index ec058d1087..12c07ef824 100644 --- a/ini/stm32-common.ini +++ b/ini/stm32-common.ini @@ -41,6 +41,5 @@ extra_scripts = ${common_stm32.extra_scripts} [stm_flash_drive] # Arduino_Core_STM32 uses usb-host-msc-cdc-msc-3 branch platform_packages = framework-arduinoststm32@https://github.com/rhapsodyv/Arduino_Core_STM32/archive/39f37d6d6a.zip -build_flags = ${common_stm32.build_flags} - -DHAL_PCD_MODULE_ENABLED -DHAL_HCD_MODULE_ENABLED +build_flags = -DHAL_PCD_MODULE_ENABLED -DHAL_HCD_MODULE_ENABLED -DUSBHOST -DUSBH_IRQ_PRIO=3 -DUSBH_IRQ_SUBPRIO=4 diff --git a/ini/stm32f4.ini b/ini/stm32f4.ini index c29e3180eb..f32734eee3 100644 --- a/ini/stm32f4.ini +++ b/ini/stm32f4.ini @@ -219,7 +219,7 @@ upload_protocol = stlink [env:BTT_SKR_PRO_usb_flash_drive] extends = env:BTT_SKR_PRO platform_packages = ${stm_flash_drive.platform_packages} -build_flags = ${stm_flash_drive.build_flags} -DSTM32F407_5ZX +build_flags = ${env:BTT_SKR_PRO.build_flags} ${stm_flash_drive.build_flags} -DSTM32F407_5ZX build_unflags = ${env:BTT_SKR_PRO.build_unflags} -DUSBCON -DUSBD_USE_CDC # @@ -266,7 +266,7 @@ build_flags = ${stm32_variant.build_flags} -DSTM32F407IX [env:BTT_GTR_V1_0_usb_flash_drive] extends = env:BTT_GTR_V1_0 platform_packages = ${stm_flash_drive.platform_packages} -build_flags = ${stm_flash_drive.build_flags} -DSTM32F407IX +build_flags = ${env:BTT_GTR_V1_0.build_flags} ${stm_flash_drive.build_flags} -DSTM32F407IX build_unflags = ${env:BTT_GTR_V1_0.build_unflags} -DUSBCON -DUSBD_USE_CDC # @@ -304,7 +304,7 @@ board = marlin_STM32F407VGT6_CCM board_build.variant = MARLIN_F4x7Vx board_build.offset = 0x8000 board_upload.offset_address = 0x08008000 -build_flags = ${stm_flash_drive.build_flags} ${USB_HS_IN_FS.build_flags} +build_flags = ${stm32_variant.build_flags} ${stm_flash_drive.build_flags} ${USB_HS_IN_FS.build_flags} -DHSE_VALUE=8000000U -DHAL_SD_MODULE_ENABLED -DPIN_SERIAL3_RX=PD_9 -DPIN_SERIAL3_TX=PD_8 upload_protocol = stlink @@ -362,7 +362,7 @@ build_flags = ${stm32_variant.build_flags} extends = env:STM32F446ZE_btt platform_packages = ${stm_flash_drive.platform_packages} build_unflags = -DUSBD_USE_CDC -build_flags = ${stm_flash_drive.build_flags} -DSTM32F446_5VX +build_flags = ${env:STM32F446ZE_btt.build_flags} ${stm_flash_drive.build_flags} -DSTM32F446_5VX ${USB_HS_IN_FS.build_flags} -DUSBD_USE_CDC_MSC # @@ -385,7 +385,7 @@ build_flags = ${stm32_variant.build_flags} extends = env:STM32F429ZG_btt platform_packages = ${stm_flash_drive.platform_packages} build_unflags = -DUSBD_USE_CDC -build_flags = ${stm_flash_drive.build_flags} +build_flags = ${env:STM32F429ZG_btt.build_flags} ${stm_flash_drive.build_flags} ${USB_HS_IN_FS.build_flags} -DUSBD_USE_CDC_MSC # @@ -406,7 +406,7 @@ build_flags = ${stm32_variant.build_flags} extends = env:STM32F407ZE_btt platform_packages = ${stm_flash_drive.platform_packages} build_unflags = -DUSBD_USE_CDC -build_flags = ${stm_flash_drive.build_flags} ${USB_HS_IN_FS.build_flags} -DUSBD_USE_CDC_MSC +build_flags = ${env:STM32F407ZE_btt.build_flags} ${stm_flash_drive.build_flags} ${USB_HS_IN_FS.build_flags} -DUSBD_USE_CDC_MSC # # Lerdge base @@ -438,7 +438,7 @@ board_build.crypt_lerdge = Lerdge_X_firmware_force.bin [env:LERDGEX_usb_flash_drive] extends = env:LERDGEX platform_packages = ${stm_flash_drive.platform_packages} -build_flags = ${stm_flash_drive.build_flags} ${lerdge_common.build_flags} +build_flags = ${env:LERDGEX.build_flags} ${stm_flash_drive.build_flags} # # Lerdge S (STM32F407ZG) @@ -453,7 +453,7 @@ board_build.crypt_lerdge = Lerdge_firmware_force.bin [env:LERDGES_usb_flash_drive] extends = env:LERDGES platform_packages = ${stm_flash_drive.platform_packages} -build_flags = ${stm_flash_drive.build_flags} ${lerdge_common.build_flags} +build_flags = ${env:LERDGES.build_flags} ${stm_flash_drive.build_flags} # # Lerdge K (STM32F407ZG) @@ -469,7 +469,7 @@ build_flags = ${lerdge_common.build_flags} -DLERDGEK [env:LERDGEK_usb_flash_drive] extends = env:LERDGEK platform_packages = ${stm_flash_drive.platform_packages} -build_flags = ${stm_flash_drive.build_flags} ${lerdge_common.build_flags} +build_flags = ${env:LERDGEK.build_flags} ${stm_flash_drive.build_flags} # # RUMBA32 @@ -512,7 +512,7 @@ board = genericSTM32F407VET6 board_build.variant = MARLIN_F4x7Vx board_build.offset = 0x0000 board_upload.offset_address = 0x08000000 -build_flags = ${stm_flash_drive.build_flags} +build_flags = ${stm32_variant.build_flags} ${stm_flash_drive.build_flags} build_unflags = ${stm32_variant.build_unflags} -DUSBCON -DUSBD_USE_CDC debug_tool = jlink upload_protocol = jlink @@ -544,7 +544,7 @@ upload_protocol = jlink [env:mks_robin_nano_v3_usb_flash_drive] extends = env:mks_robin_nano_v3 platform_packages = ${stm_flash_drive.platform_packages} -build_flags = ${stm_flash_drive.build_flags} ${stm32f4_I2C1.build_flags} ${USB_HS_IN_FS.build_flags} +build_flags = ${env:mks_robin_nano_v3.build_flags} ${stm_flash_drive.build_flags} ${stm32f4_I2C1.build_flags} ${USB_HS_IN_FS.build_flags} # # MKS Robin Nano V3 with USB Flash Drive Support and Shared Media @@ -600,7 +600,7 @@ upload_protocol = jlink [env:mks_eagle_usb_flash_drive] extends = env:mks_eagle platform_packages = ${stm_flash_drive.platform_packages} -build_flags = ${stm_flash_drive.build_flags} ${stm32f4_I2C1.build_flags} ${USB_HS_IN_FS.build_flags} +build_flags = ${env:mks_eagle.build_flags} ${stm_flash_drive.build_flags} ${stm32f4_I2C1.build_flags} ${USB_HS_IN_FS.build_flags} # # MKS Eagle with USB Flash Drive Support and Shared Media @@ -699,9 +699,9 @@ board_build.offset = 0xC000 board_upload.offset_address = 0x0800C000 board_build.rename = elegoo.bin platform_packages = ${stm_flash_drive.platform_packages} -build_flags = ${stm32_variant.build_flags} ${stm32f4_I2C1.build_flags} - ${stm_flash_drive.build_flags} ${USB_HS_IN_FS.build_flags} - -DHAL_PCD_MODULE_ENABLED -DHAL_SD_MODULE_ENABLED -DHAL_SRAM_MODULE_ENABLED +build_flags = ${stm32_variant.build_flags} ${stm_flash_drive.build_flags} + ${stm32f4_I2C1.build_flags} ${USB_HS_IN_FS.build_flags} + -DHAL_SD_MODULE_ENABLED -DHAL_SRAM_MODULE_ENABLED -DMCU_STM32F407VE -DSS_TIMER=4 -DENABLE_HWSERIAL3 -DSTM32_FLASH_SIZE=512 -DTIMER_TONE=TIM3 -DTIMER_SERVO=TIM2 @@ -997,6 +997,6 @@ board = marlin_STM32F407VGT6_CCM board_build.variant = MARLIN_F4x7Vx board_build.offset = 0x8000 board_upload.offset_address = 0x08008000 -build_flags = ${stm_flash_drive.build_flags} ${USB_HS_IN_FS.build_flags} +build_flags = ${stm32_variant.build_flags} ${stm_flash_drive.build_flags} ${USB_HS_IN_FS.build_flags} -DHSE_VALUE=8000000U -DHAL_SD_MODULE_ENABLED -DPIN_SERIAL3_RX=PD_9 -DPIN_SERIAL3_TX=PD_8 From 5266ffb922402f2a5decfc2eb70a93c71bbca1a0 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Wed, 7 May 2025 00:31:25 +0000 Subject: [PATCH 291/787] [cron] Bump distribution date (2025-05-07) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 38fbe78024..1453ec68e8 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-05-06" +//#define STRING_DISTRIBUTION_DATE "2025-05-07" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 200c24ea62..a682e48fa1 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-05-06" + #define STRING_DISTRIBUTION_DATE "2025-05-07" #endif /** From d806175a80786eba5ebc98ddfd889ff22daa9b51 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 6 May 2025 22:06:47 -0500 Subject: [PATCH 292/787] =?UTF-8?q?=E2=9C=A8=20OTA=5FFIRMWARE=5FUPDATE=20(?= =?UTF-8?q?Creality=20STM32F401RE)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Followup to #25773 --- Marlin/Configuration_adv.h | 3 +++ Marlin/src/gcode/ota/M936.cpp | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index a48a337270..f31a284d81 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -1938,6 +1938,9 @@ //#define CUSTOM_FIRMWARE_UPLOAD #endif + // "Over-the-air" Firmware Update with M936 - Required to set EEPROM flag + //#define OTA_FIRMWARE_UPDATE + /** * Set this option to one of the following (or the board's defaults apply): * diff --git a/Marlin/src/gcode/ota/M936.cpp b/Marlin/src/gcode/ota/M936.cpp index f42d197f4e..353e423c77 100644 --- a/Marlin/src/gcode/ota/M936.cpp +++ b/Marlin/src/gcode/ota/M936.cpp @@ -34,7 +34,6 @@ /** * M936: Set one of the OTA update flags. * V2 = Upgrade the motherboard firmware - * V3 = Upgrade the RTS controller firmware */ void GcodeSuite::M936() { static uint8_t ota_update_flag = 0x00; From 222efe13824c9dd2b1c79f7e9f2f6bcd85d2ba41 Mon Sep 17 00:00:00 2001 From: David Buezas Date: Wed, 7 May 2025 05:15:44 +0200 Subject: [PATCH 293/787] =?UTF-8?q?=F0=9F=94=A7=20No=20SMOOTH=5FLIN=5FADVA?= =?UTF-8?q?NCE=20+=20NONLINEAR=5FEXTRUSION=20(#27817)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/inc/SanityCheck.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index 8a293b52a8..df86cea522 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -868,6 +868,8 @@ static_assert(COUNT(arm) == LOGICAL_AXES, "AXIS_RELATIVE_MODES must contain " _L #error "SMOOTH_LIN_ADVANCE requires a 32-bit CPU." #elif ENABLED(S_CURVE_ACCELERATION) #error "SMOOTH_LIN_ADVANCE is not compatible with S_CURVE_ACCELERATION." + #elif ENABLED(NONLINEAR_EXTRUSION) + #error "SMOOTH_LIN_ADVANCE doesn't currently support NONLINEAR_EXTRUSION." #elif ENABLED(INPUT_SHAPING_E_SYNC) && NONE(INPUT_SHAPING_X, INPUT_SHAPING_Y) #error "INPUT_SHAPING_E_SYNC requires INPUT_SHAPING_X or INPUT_SHAPING_Y." #endif From a4d254ee62b36d44f9ca22dffba04c5d4c43f8fe Mon Sep 17 00:00:00 2001 From: ellensp <530024+ellensp@users.noreply.github.com> Date: Thu, 8 May 2025 06:36:06 +1200 Subject: [PATCH 294/787] =?UTF-8?q?=F0=9F=9A=B8=20Fix=2016x4=20SD=20Print?= =?UTF-8?q?=20Progress=20display=20(#27844)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/lcd/HD44780/marlinui_HD44780.cpp | 2 +- ini/native.ini | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/src/lcd/HD44780/marlinui_HD44780.cpp b/Marlin/src/lcd/HD44780/marlinui_HD44780.cpp index 265f62ab88..359122f8b6 100644 --- a/Marlin/src/lcd/HD44780/marlinui_HD44780.cpp +++ b/Marlin/src/lcd/HD44780/marlinui_HD44780.cpp @@ -1001,7 +1001,7 @@ void MarlinUI::draw_status_screen() { #if LCD_WIDTH < 20 #if HAS_PRINT_PROGRESS - TERN_(SHOW_PROGRESS_PERCENT, setPercentPos(0, 2)); + TERN_(SHOW_PROGRESS_PERCENT, setPercentPos(0, 1)); rotate_progress(); #endif diff --git a/ini/native.ini b/ini/native.ini index f01e72ca67..f27285e83a 100644 --- a/ini/native.ini +++ b/ini/native.ini @@ -58,7 +58,7 @@ debug_build_flags = -fstack-protector-strong -g -g3 -ggdb lib_compat_mode = off build_src_filter = ${common.default_src_filter} + lib_deps = ${common.lib_deps} - MarlinSimUI=https://github.com/p3p/MarlinSimUI/archive/6ea016e104.zip + MarlinSimUI=https://github.com/p3p/MarlinSimUI/archive/dd9c41f1b2.zip Adafruit NeoPixel=https://github.com/p3p/Adafruit_NeoPixel/archive/c6b319f447.zip LiquidCrystal=https://github.com/p3p/LiquidCrystal/archive/322fb5fc23.zip extra_scripts = ${common.extra_scripts} From aa7af2e2ea6f3744152031d10ee645cd8d470855 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Thu, 8 May 2025 00:31:45 +0000 Subject: [PATCH 295/787] [cron] Bump distribution date (2025-05-08) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 1453ec68e8..e21fc7c479 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-05-07" +//#define STRING_DISTRIBUTION_DATE "2025-05-08" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index a682e48fa1..9eb50bff90 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-05-07" + #define STRING_DISTRIBUTION_DATE "2025-05-08" #endif /** From 72f3a4ac3118e8235030e907bf3473ea7502eba3 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Thu, 8 May 2025 13:45:38 -0500 Subject: [PATCH 296/787] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20Optimal=20recalcul?= =?UTF-8?q?ate=5Fmax=5Fe=5Fjerk?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/module/planner.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/src/module/planner.h b/Marlin/src/module/planner.h index a2f91edc81..73c77ee7f5 100644 --- a/Marlin/src/module/planner.h +++ b/Marlin/src/module/planner.h @@ -1088,8 +1088,8 @@ class Planner { #if HAS_LINEAR_E_JERK FORCE_INLINE static void recalculate_max_e_jerk() { const float prop = junction_deviation_mm * SQRT(0.5) / (1.0f - SQRT(0.5)); - EXTRUDER_LOOP() - max_e_jerk[E_INDEX_N(e)] = SQRT(prop * settings.max_acceleration_mm_per_s2[E_AXIS_N(e)]); + for (uint8_t i = 0; i < DISTINCT_E; ++i) + max_e_jerk[i] = SQRT(prop * settings.max_acceleration_mm_per_s2[E_AXIS + i]); } #endif From fd117480d2cca5d55c787035550005c2d4cc1776 Mon Sep 17 00:00:00 2001 From: B Date: Thu, 8 May 2025 14:17:47 -0700 Subject: [PATCH 297/787] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20GD32:=20Fast=20GPI?= =?UTF-8?q?O=20optimization=20(#27845)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/HAL/GD32_MFL/fastio.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Marlin/src/HAL/GD32_MFL/fastio.h b/Marlin/src/HAL/GD32_MFL/fastio.h index 35829e856f..11020f3e52 100644 --- a/Marlin/src/HAL/GD32_MFL/fastio.h +++ b/Marlin/src/HAL/GD32_MFL/fastio.h @@ -29,17 +29,17 @@ #include template -static inline void fast_write_pin_wrapper(pin_size_t IO, T V) { +FORCE_INLINE static void fast_write_pin_wrapper(pin_size_t IO, T V) { const PortPinPair& pp = port_pin_map[IO]; gpio::fast_write_pin(pp.port, pp.pin, static_cast(V)); } -static inline auto fast_read_pin_wrapper(pin_size_t IO) -> bool { +FORCE_INLINE static auto fast_read_pin_wrapper(pin_size_t IO) -> bool { const PortPinPair& pp = port_pin_map[IO]; return gpio::fast_read_pin(pp.port, pp.pin); } -static inline void fast_toggle_pin_wrapper(pin_size_t IO) { +FORCE_INLINE static void fast_toggle_pin_wrapper(pin_size_t IO) { const PortPinPair& pp = port_pin_map[IO]; gpio::fast_toggle_pin(pp.port, pp.pin); } From 94e2558e6c34abdb8ef3d64a3d7b1580b634a22f Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Fri, 9 May 2025 00:31:31 +0000 Subject: [PATCH 298/787] [cron] Bump distribution date (2025-05-09) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index e21fc7c479..e9be5139e7 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-05-08" +//#define STRING_DISTRIBUTION_DATE "2025-05-09" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 9eb50bff90..336dd6bff4 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-05-08" + #define STRING_DISTRIBUTION_DATE "2025-05-09" #endif /** From b22df8b189c85302040f932df6175e01277af7da Mon Sep 17 00:00:00 2001 From: B Date: Fri, 9 May 2025 09:58:25 -0700 Subject: [PATCH 299/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Fix?= =?UTF-8?q?=20GD32=20EEPROM=20timings=20(#27846)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../HAL/GD32_MFL/eeprom/eeprom_bl24cxx.cpp | 2 +- Marlin/src/libs/BL24CXX.cpp | 87 +++++++++++++++++-- 2 files changed, 79 insertions(+), 10 deletions(-) diff --git a/Marlin/src/HAL/GD32_MFL/eeprom/eeprom_bl24cxx.cpp b/Marlin/src/HAL/GD32_MFL/eeprom/eeprom_bl24cxx.cpp index 9c44933fe3..1053c80a41 100644 --- a/Marlin/src/HAL/GD32_MFL/eeprom/eeprom_bl24cxx.cpp +++ b/Marlin/src/HAL/GD32_MFL/eeprom/eeprom_bl24cxx.cpp @@ -62,7 +62,7 @@ bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, ui // so only write bytes that have changed! if (v != eeprom_read_byte(p)) { eeprom_write_byte(p, v); - if (++written & 0x7F) delay(4); else safe_delay(4); + if (++written & 0x7F) delay(2); else safe_delay(2); if (eeprom_read_byte(p) != v) { SERIAL_ECHO_MSG(STR_ERR_EEPROM_WRITE); return true; diff --git a/Marlin/src/libs/BL24CXX.cpp b/Marlin/src/libs/BL24CXX.cpp index 43c68887b1..091b233549 100644 --- a/Marlin/src/libs/BL24CXX.cpp +++ b/Marlin/src/libs/BL24CXX.cpp @@ -44,6 +44,10 @@ #define EEPROM_DEVICE_ADDRESS (0x50 << 1) #endif +#ifdef ARDUINO_ARCH_MFL + #define EXTRA_EEPROM_DELAY +#endif + // IO direction setting #ifdef __STM32F1__ #define SDA_IN() do{ PIN_MAP[IIC_EEPROM_SDA].gpio_device->regs->CRH &= 0XFFFF0FFF; PIN_MAP[IIC_EEPROM_SDA].gpio_device->regs->CRH |= 8 << 12; }while(0) @@ -60,6 +64,14 @@ #define IIC_SDA_1() WRITE(IIC_EEPROM_SDA, HIGH) #define READ_SDA() READ(IIC_EEPROM_SDA) +#ifdef EXTRA_EEPROM_DELAY + #define EXTRA_DELAY 1 + #define EXTRA_DELAY_LOW 4 // SCL low period (tLOW) +#else + #define EXTRA_DELAY 0 + #define EXTRA_DELAY_LOW 0 +#endif + // // Simple IIC interface via libmaple // @@ -70,28 +82,51 @@ void IIC::init() { SET_OUTPUT(IIC_EEPROM_SCL); IIC_SCL_1(); IIC_SDA_1(); + + #ifdef EXTRA_EEPROM_DELAY + delay_us(EXTRA_DELAY); // Ensure bus free time + #endif } // Generate IIC start signal void IIC::start() { SDA_OUT(); // SDA line output IIC_SDA_1(); + + #ifdef EXTRA_EEPROM_DELAY + delay_us(4 + EXTRA_DELAY); // Setup time before SCL high + #endif + IIC_SCL_1(); - delay_us(4); + delay_us(4 + EXTRA_DELAY); IIC_SDA_0(); // START:when CLK is high, DATA change from high to low - delay_us(4); + delay_us(4 + EXTRA_DELAY); IIC_SCL_0(); // Clamp the I2C bus, ready to send or receive data + + #ifdef EXTRA_EEPROM_DELAY + delay_us(EXTRA_DELAY_LOW); // Ensure SCL low period + #endif } // Generate IIC stop signal void IIC::stop() { SDA_OUT(); // SDA line output IIC_SCL_0(); + + #ifdef EXTRA_EEPROM_DELAY + delay_us(EXTRA_DELAY_LOW); // Ensure SCL low period + #endif + IIC_SDA_0(); // STOP:when CLK is high DATA change from low to high - delay_us(4); + delay_us(4 + EXTRA_DELAY); IIC_SCL_1(); + + #ifdef EXTRA_EEPROM_DELAY + delay_us(4 + EXTRA_DELAY); // Setup time with SCL high + #endif + IIC_SDA_1(); // Send I2C bus end signal - delay_us(4); + delay_us(4 + EXTRA_DELAY); } // Wait for the response signal to arrive @@ -100,8 +135,9 @@ void IIC::stop() { uint8_t IIC::wait_ack() { uint8_t ucErrTime = 0; SDA_IN(); // SDA is set as input - IIC_SDA_1(); delay_us(1); - IIC_SCL_1(); delay_us(1); + IIC_SDA_1(); delay_us(1 + EXTRA_DELAY); + IIC_SCL_1(); delay_us(1 + EXTRA_DELAY); + while (READ_SDA()) { if (++ucErrTime > 250) { stop(); @@ -109,29 +145,52 @@ uint8_t IIC::wait_ack() { } } IIC_SCL_0(); // Clock output 0 + + #ifdef EXTRA_EEPROM_DELAY + delay_us(EXTRA_DELAY); // Hold time after SCL falls + #endif + return 0; } // Generate ACK response void IIC::ack() { IIC_SCL_0(); + + #ifdef EXTRA_EEPROM_DELAY + delay_us(EXTRA_DELAY_LOW); // Ensure SCL low period + #endif + SDA_OUT(); IIC_SDA_0(); delay_us(2); IIC_SCL_1(); - delay_us(2); + delay_us(2 + EXTRA_DELAY); IIC_SCL_0(); + + #ifdef EXTRA_EEPROM_DELAY + delay_us(EXTRA_DELAY); // Data hold time + #endif } // No ACK response void IIC::nAck() { IIC_SCL_0(); + + #ifdef EXTRA_EEPROM_DELAY + delay_us(EXTRA_DELAY_LOW); // Ensure SCL low period + #endif + SDA_OUT(); IIC_SDA_1(); delay_us(2); IIC_SCL_1(); - delay_us(2); + delay_us(2 + EXTRA_DELAY); IIC_SCL_0(); + + #ifdef EXTRA_EEPROM_DELAY + delay_us(EXTRA_DELAY); // Data hold time + #endif } // Send one IIC byte @@ -141,13 +200,18 @@ void IIC::nAck() { void IIC::send_byte(uint8_t txd) { SDA_OUT(); IIC_SCL_0(); // Pull down the clock to start data transmission + + #ifdef EXTRA_EEPROM_DELAY + delay_us(EXTRA_DELAY_LOW); // Ensure SCL low period + #endif + for (uint8_t t = 0; t < 8; ++t) { // IIC_SDA = (txd & 0x80) >> 7; if (txd & 0x80) IIC_SDA_1(); else IIC_SDA_0(); txd <<= 1; delay_us(2); // All three delays are necessary for TEA5767 IIC_SCL_1(); - delay_us(2); + delay_us(2 + EXTRA_DELAY); IIC_SCL_0(); delay_us(2); } @@ -161,6 +225,11 @@ uint8_t IIC::read_byte(unsigned char ack_chr) { IIC_SCL_0(); delay_us(2); IIC_SCL_1(); + + #ifdef EXTRA_EEPROM_DELAY + delay_us(EXTRA_DELAY); // Delay before reading to allow EEPROM to output data + #endif + receive <<= 1; if (READ_SDA()) receive++; delay_us(1); From 6cda10de0fa8224c30f86baff50be3b14a1e9e1e Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Fri, 9 May 2025 16:21:29 -0500 Subject: [PATCH 300/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Rel?= =?UTF-8?q?ocate=20some=20factory=20reset,=20etc.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/lcd/marlinui.cpp | 22 +++++ Marlin/src/lcd/marlinui.h | 1 + Marlin/src/module/endstops.cpp | 35 +++++++ Marlin/src/module/endstops.h | 5 + Marlin/src/module/settings.cpp | 148 ++---------------------------- Marlin/src/module/temperature.cpp | 91 +++++++++++++++++- Marlin/src/module/temperature.h | 10 +- 7 files changed, 164 insertions(+), 148 deletions(-) diff --git a/Marlin/src/lcd/marlinui.cpp b/Marlin/src/lcd/marlinui.cpp index 2b730581c8..28697affab 100644 --- a/Marlin/src/lcd/marlinui.cpp +++ b/Marlin/src/lcd/marlinui.cpp @@ -140,6 +140,28 @@ constexpr uint8_t epps = ENCODER_PULSES_PER_STEP; preheat_t MarlinUI::material_preset[PREHEAT_COUNT]; // Initialized by settings.load + void MarlinUI::reset_material_presets() { + #define _PITEM(N,T) PREHEAT_##N##_##T, + #if HAS_HOTEND + constexpr uint16_t hpre[] = { REPEAT2_S(1, INCREMENT(PREHEAT_COUNT), _PITEM, TEMP_HOTEND) }; + #endif + #if HAS_HEATED_BED + constexpr uint16_t bpre[] = { REPEAT2_S(1, INCREMENT(PREHEAT_COUNT), _PITEM, TEMP_BED) }; + #endif + #if HAS_HEATED_CHAMBER + constexpr uint16_t cpre[] = { REPEAT2_S(1, INCREMENT(PREHEAT_COUNT), _PITEM, TEMP_CHAMBER) }; + #endif + #if HAS_FAN + constexpr uint8_t fpre[] = { REPEAT2_S(1, INCREMENT(PREHEAT_COUNT), _PITEM, FAN_SPEED) }; + #endif + for (uint8_t i = 0; i < PREHEAT_COUNT; ++i) { + TERN_(HAS_HOTEND, material_preset[i].hotend_temp = hpre[i]); + TERN_(HAS_HEATED_BED, material_preset[i].bed_temp = bpre[i]); + TERN_(HAS_HEATED_CHAMBER, material_preset[i].chamber_temp = cpre[i]); + TERN_(HAS_FAN, material_preset[i].fan_speed = fpre[i]); + } + } + FSTR_P MarlinUI::get_preheat_label(const uint8_t m) { #define _PDEF(N) static PGMSTR(preheat_##N##_label, PREHEAT_##N##_LABEL); #define _PLBL(N) preheat_##N##_label, diff --git a/Marlin/src/lcd/marlinui.h b/Marlin/src/lcd/marlinui.h index a610796ebc..578d143d96 100644 --- a/Marlin/src/lcd/marlinui.h +++ b/Marlin/src/lcd/marlinui.h @@ -648,6 +648,7 @@ public: #if HAS_PREHEAT enum PreheatTarget : uint8_t { PT_HOTEND, PT_BED, PT_FAN, PT_CHAMBER, PT_ALL = 0xFF }; static preheat_t material_preset[PREHEAT_COUNT]; + static void reset_material_presets(); static FSTR_P get_preheat_label(const uint8_t m); static void apply_preheat(const uint8_t m, const uint8_t pmask, const uint8_t e=active_extruder); static void preheat_set_fan(const uint8_t m) { TERN_(HAS_FAN, apply_preheat(m, _BV(PT_FAN))); } diff --git a/Marlin/src/module/endstops.cpp b/Marlin/src/module/endstops.cpp index 7b8cb41505..b0ad431476 100644 --- a/Marlin/src/module/endstops.cpp +++ b/Marlin/src/module/endstops.cpp @@ -251,6 +251,41 @@ void Endstops::init() { } // Endstops::init +void Endstops::factory_reset() { + #if ENABLED(X_DUAL_ENDSTOPS) + #ifndef X2_ENDSTOP_ADJUSTMENT + #define X2_ENDSTOP_ADJUSTMENT 0 + #endif + endstops.x2_endstop_adj = X2_ENDSTOP_ADJUSTMENT; + #endif + + #if ENABLED(Y_DUAL_ENDSTOPS) + #ifndef Y2_ENDSTOP_ADJUSTMENT + #define Y2_ENDSTOP_ADJUSTMENT 0 + #endif + endstops.y2_endstop_adj = Y2_ENDSTOP_ADJUSTMENT; + #endif + + #if ENABLED(Z_MULTI_ENDSTOPS) + #ifndef Z2_ENDSTOP_ADJUSTMENT + #define Z2_ENDSTOP_ADJUSTMENT 0 + #endif + endstops.z2_endstop_adj = Z2_ENDSTOP_ADJUSTMENT; + #if NUM_Z_STEPPERS >= 3 + #ifndef Z3_ENDSTOP_ADJUSTMENT + #define Z3_ENDSTOP_ADJUSTMENT 0 + #endif + endstops.z3_endstop_adj = Z3_ENDSTOP_ADJUSTMENT; + #endif + #if NUM_Z_STEPPERS >= 4 + #ifndef Z4_ENDSTOP_ADJUSTMENT + #define Z4_ENDSTOP_ADJUSTMENT 0 + #endif + endstops.z4_endstop_adj = Z4_ENDSTOP_ADJUSTMENT; + #endif + #endif +} + // Called at ~1kHz from Temperature ISR: Poll endstop state if required void Endstops::poll() { diff --git a/Marlin/src/module/endstops.h b/Marlin/src/module/endstops.h index 1ef217b64a..40975632ff 100644 --- a/Marlin/src/module/endstops.h +++ b/Marlin/src/module/endstops.h @@ -172,6 +172,11 @@ class Endstops { */ static void init(); + /** + * Saved settings initialization + */ + static void factory_reset(); + /** * Are endstops or the Z min probe or the CALIBRATION probe set to abort the move? */ diff --git a/Marlin/src/module/settings.cpp b/Marlin/src/module/settings.cpp index 8c99c54323..d325ef95d9 100644 --- a/Marlin/src/module/settings.cpp +++ b/Marlin/src/module/settings.cpp @@ -3510,151 +3510,17 @@ void MarlinSettings::reset() { // // Endstop Adjustments // - - #if ENABLED(X_DUAL_ENDSTOPS) - #ifndef X2_ENDSTOP_ADJUSTMENT - #define X2_ENDSTOP_ADJUSTMENT 0 - #endif - endstops.x2_endstop_adj = X2_ENDSTOP_ADJUSTMENT; - #endif - - #if ENABLED(Y_DUAL_ENDSTOPS) - #ifndef Y2_ENDSTOP_ADJUSTMENT - #define Y2_ENDSTOP_ADJUSTMENT 0 - #endif - endstops.y2_endstop_adj = Y2_ENDSTOP_ADJUSTMENT; - #endif - - #if ENABLED(Z_MULTI_ENDSTOPS) - #ifndef Z2_ENDSTOP_ADJUSTMENT - #define Z2_ENDSTOP_ADJUSTMENT 0 - #endif - endstops.z2_endstop_adj = Z2_ENDSTOP_ADJUSTMENT; - #if NUM_Z_STEPPERS >= 3 - #ifndef Z3_ENDSTOP_ADJUSTMENT - #define Z3_ENDSTOP_ADJUSTMENT 0 - #endif - endstops.z3_endstop_adj = Z3_ENDSTOP_ADJUSTMENT; - #endif - #if NUM_Z_STEPPERS >= 4 - #ifndef Z4_ENDSTOP_ADJUSTMENT - #define Z4_ENDSTOP_ADJUSTMENT 0 - #endif - endstops.z4_endstop_adj = Z4_ENDSTOP_ADJUSTMENT; - #endif - #endif + endstops.factory_reset(); // - // Preheat parameters + // Material Presets // - #if HAS_PREHEAT - #define _PITEM(N,T) PREHEAT_##N##_##T, - #if HAS_HOTEND - constexpr uint16_t hpre[] = { REPEAT2_S(1, INCREMENT(PREHEAT_COUNT), _PITEM, TEMP_HOTEND) }; - #endif - #if HAS_HEATED_BED - constexpr uint16_t bpre[] = { REPEAT2_S(1, INCREMENT(PREHEAT_COUNT), _PITEM, TEMP_BED) }; - #endif - #if HAS_HEATED_CHAMBER - constexpr uint16_t cpre[] = { REPEAT2_S(1, INCREMENT(PREHEAT_COUNT), _PITEM, TEMP_CHAMBER) }; - #endif - #if HAS_FAN - constexpr uint8_t fpre[] = { REPEAT2_S(1, INCREMENT(PREHEAT_COUNT), _PITEM, FAN_SPEED) }; - #endif - for (uint8_t i = 0; i < PREHEAT_COUNT; ++i) { - TERN_(HAS_HOTEND, ui.material_preset[i].hotend_temp = hpre[i]); - TERN_(HAS_HEATED_BED, ui.material_preset[i].bed_temp = bpre[i]); - TERN_(HAS_HEATED_CHAMBER, ui.material_preset[i].chamber_temp = cpre[i]); - TERN_(HAS_FAN, ui.material_preset[i].fan_speed = fpre[i]); - } - #endif + TERN_(HAS_PREHEAT, ui.reset_material_presets()); // - // Hotend PID + // Temperature Manager // - - #if ENABLED(PIDTEMP) - #if ENABLED(PID_PARAMS_PER_HOTEND) - constexpr float defKp[] = - #ifdef DEFAULT_Kp_LIST - DEFAULT_Kp_LIST - #else - ARRAY_BY_HOTENDS1(DEFAULT_Kp) - #endif - , defKi[] = - #ifdef DEFAULT_Ki_LIST - DEFAULT_Ki_LIST - #else - ARRAY_BY_HOTENDS1(DEFAULT_Ki) - #endif - , defKd[] = - #ifdef DEFAULT_Kd_LIST - DEFAULT_Kd_LIST - #else - ARRAY_BY_HOTENDS1(DEFAULT_Kd) - #endif - ; - static_assert(WITHIN(COUNT(defKp), 1, HOTENDS), "DEFAULT_Kp_LIST must have between 1 and HOTENDS items."); - static_assert(WITHIN(COUNT(defKi), 1, HOTENDS), "DEFAULT_Ki_LIST must have between 1 and HOTENDS items."); - static_assert(WITHIN(COUNT(defKd), 1, HOTENDS), "DEFAULT_Kd_LIST must have between 1 and HOTENDS items."); - #if ENABLED(PID_EXTRUSION_SCALING) - constexpr float defKc[] = - #ifdef DEFAULT_Kc_LIST - DEFAULT_Kc_LIST - #else - ARRAY_BY_HOTENDS1(DEFAULT_Kc) - #endif - ; - static_assert(WITHIN(COUNT(defKc), 1, HOTENDS), "DEFAULT_Kc_LIST must have between 1 and HOTENDS items."); - #endif - #if ENABLED(PID_FAN_SCALING) - constexpr float defKf[] = - #ifdef DEFAULT_Kf_LIST - DEFAULT_Kf_LIST - #else - ARRAY_BY_HOTENDS1(DEFAULT_Kf) - #endif - ; - static_assert(WITHIN(COUNT(defKf), 1, HOTENDS), "DEFAULT_Kf_LIST must have between 1 and HOTENDS items."); - #endif - #define PID_DEFAULT(N,E) def##N[E] - #else - #define PID_DEFAULT(N,E) DEFAULT_##N - #endif - HOTEND_LOOP() { - thermalManager.temp_hotend[e].pid.set( - PID_DEFAULT(Kp, ALIM(e, defKp)), - PID_DEFAULT(Ki, ALIM(e, defKi)), - PID_DEFAULT(Kd, ALIM(e, defKd)) - OPTARG(PID_EXTRUSION_SCALING, PID_DEFAULT(Kc, ALIM(e, defKc))) - OPTARG(PID_FAN_SCALING, PID_DEFAULT(Kf, ALIM(e, defKf))) - ); - } - #endif - - // - // PID Extrusion Scaling - // - TERN_(PID_EXTRUSION_SCALING, thermalManager.lpq_len = 20); // Default last-position-queue size - - // - // Heated Bed PID - // - #if ENABLED(PIDTEMPBED) - thermalManager.temp_bed.pid.set(DEFAULT_bedKp, DEFAULT_bedKi, DEFAULT_bedKd); - #endif - - // - // Heated Chamber PID - // - #if ENABLED(PIDTEMPCHAMBER) - thermalManager.temp_chamber.pid.set(DEFAULT_chamberKp, DEFAULT_chamberKi, DEFAULT_chamberKd); - #endif - - // - // User-Defined Thermistors - // - TERN_(HAS_USER_THERMISTORS, thermalManager.reset_user_thermistors()); + thermalManager.factory_reset(); // // Power Monitor @@ -3750,6 +3616,7 @@ void MarlinSettings::reset() { // #if ENABLED(LIN_ADVANCE) #if ENABLED(DISTINCT_E_FACTORS) + constexpr float linAdvanceK[] = ADVANCE_K; EXTRUDER_LOOP() { const float a = linAdvanceK[_MAX(uint8_t(e), COUNT(linAdvanceK) - 1)]; @@ -3767,8 +3634,9 @@ void MarlinSettings::reset() { #else stepper.set_advance_tau(ADVANCE_TAU); #endif + #endif - #endif + #endif // LIN_ADVANCE // // Motor Current PWM diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index 0ef0a2f961..30690345a5 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -711,6 +711,93 @@ volatile bool Temperature::raw_temps_ready = false; #endif +void Temperature::factory_reset() { + // + // Hotend PID + // + #if ENABLED(PIDTEMP) + #if ENABLED(PID_PARAMS_PER_HOTEND) + constexpr float defKp[] = + #ifdef DEFAULT_Kp_LIST + DEFAULT_Kp_LIST + #else + ARRAY_BY_HOTENDS1(DEFAULT_Kp) + #endif + , defKi[] = + #ifdef DEFAULT_Ki_LIST + DEFAULT_Ki_LIST + #else + ARRAY_BY_HOTENDS1(DEFAULT_Ki) + #endif + , defKd[] = + #ifdef DEFAULT_Kd_LIST + DEFAULT_Kd_LIST + #else + ARRAY_BY_HOTENDS1(DEFAULT_Kd) + #endif + ; + static_assert(WITHIN(COUNT(defKp), 1, HOTENDS), "DEFAULT_Kp_LIST must have between 1 and HOTENDS items."); + static_assert(WITHIN(COUNT(defKi), 1, HOTENDS), "DEFAULT_Ki_LIST must have between 1 and HOTENDS items."); + static_assert(WITHIN(COUNT(defKd), 1, HOTENDS), "DEFAULT_Kd_LIST must have between 1 and HOTENDS items."); + #if ENABLED(PID_EXTRUSION_SCALING) + constexpr float defKc[] = + #ifdef DEFAULT_Kc_LIST + DEFAULT_Kc_LIST + #else + ARRAY_BY_HOTENDS1(DEFAULT_Kc) + #endif + ; + static_assert(WITHIN(COUNT(defKc), 1, HOTENDS), "DEFAULT_Kc_LIST must have between 1 and HOTENDS items."); + #endif + #if ENABLED(PID_FAN_SCALING) + constexpr float defKf[] = + #ifdef DEFAULT_Kf_LIST + DEFAULT_Kf_LIST + #else + ARRAY_BY_HOTENDS1(DEFAULT_Kf) + #endif + ; + static_assert(WITHIN(COUNT(defKf), 1, HOTENDS), "DEFAULT_Kf_LIST must have between 1 and HOTENDS items."); + #endif + #define PID_DEFAULT(N,E) def##N[E] + #else + #define PID_DEFAULT(N,E) DEFAULT_##N + #endif + HOTEND_LOOP() { + temp_hotend[e].pid.set( + PID_DEFAULT(Kp, ALIM(e, defKp)), + PID_DEFAULT(Ki, ALIM(e, defKi)), + PID_DEFAULT(Kd, ALIM(e, defKd)) + OPTARG(PID_EXTRUSION_SCALING, PID_DEFAULT(Kc, ALIM(e, defKc))) + OPTARG(PID_FAN_SCALING, PID_DEFAULT(Kf, ALIM(e, defKf))) + ); + } + #endif // PIDTEMP + + // + // PID Extrusion Scaling + // + TERN_(PID_EXTRUSION_SCALING, lpq_len = 20); // Default last-position-queue size + + // + // Heated Bed PID + // + #if ENABLED(PIDTEMPBED) + temp_bed.pid.set(DEFAULT_bedKp, DEFAULT_bedKi, DEFAULT_bedKd); + #endif + + // + // Heated Chamber PID + // + #if ENABLED(PIDTEMPCHAMBER) + temp_chamber.pid.set(DEFAULT_chamberKp, DEFAULT_chamberKi, DEFAULT_chamberKd); + #endif + + // User-Defined Thermistors + TERN_(HAS_USER_THERMISTORS, reset_user_thermistors()); + +} // factory_reset + #if HAS_PID_HEATING inline void say_default_() { SERIAL_ECHOPGM("#define DEFAULT_"); } @@ -939,9 +1026,9 @@ volatile bool Temperature::raw_temps_ready = false; auto _set_hotend_pid = [](const uint8_t tool, const raw_pid_t &in_pid) { #if ENABLED(PIDTEMP) #if ENABLED(PID_PARAMS_PER_HOTEND) - thermalManager.temp_hotend[tool].pid.set(in_pid); + temp_hotend[tool].pid.set(in_pid); #else - HOTEND_LOOP() thermalManager.temp_hotend[e].pid.set(in_pid); + HOTEND_LOOP() temp_hotend[e].pid.set(in_pid); #endif updatePID(); #endif diff --git a/Marlin/src/module/temperature.h b/Marlin/src/module/temperature.h index 77c16bba0a..c96d9aba74 100644 --- a/Marlin/src/module/temperature.h +++ b/Marlin/src/module/temperature.h @@ -809,16 +809,14 @@ class Temperature { #endif public: - /** - * Instance Methods - */ - - void init(); - /** * Static (class) methods */ + static void init(); + + static void factory_reset(); + #if HAS_USER_THERMISTORS static user_thermistor_t user_thermistor[USER_THERMISTORS]; static void M305_report(const uint8_t t_index, const bool forReplay=true); From fad7bc66e9e00f51b89fcc5a3d916e96addba8f2 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Fri, 9 May 2025 16:23:14 -0500 Subject: [PATCH 301/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Use?= =?UTF-8?q?=20'DISTINCT=5FE=5FFACTORS'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/gcode/feature/advance/M900.cpp | 30 ++++++++++--------- Marlin/src/inc/Conditionals-1-axes.h | 2 ++ Marlin/src/inc/SanityCheck.h | 2 +- .../generic/max_acceleration_screen.cpp | 4 +-- .../generic/max_velocity_screen.cpp | 2 +- Marlin/src/lcd/menu/menu_advanced.cpp | 8 ++--- Marlin/src/lcd/menu/menu_tune.cpp | 4 +-- 7 files changed, 28 insertions(+), 24 deletions(-) diff --git a/Marlin/src/gcode/feature/advance/M900.cpp b/Marlin/src/gcode/feature/advance/M900.cpp index 51a40f934e..dc59b5bc90 100644 --- a/Marlin/src/gcode/feature/advance/M900.cpp +++ b/Marlin/src/gcode/feature/advance/M900.cpp @@ -36,9 +36,11 @@ /** * M900: Get or Set Linear Advance K-factor * T Which tool to address - * K Set current advance K factor (Slot 0). - * L Set secondary advance K factor (Slot 1). Requires ADVANCE_K_EXTRA. - * S<0/1> Activate slot 0 or 1. Requires ADVANCE_K_EXTRA. + * K Set current advance K factor (aka Slot 0). + * + * With ADVANCE_K_EXTRA: + * S<0/1> Activate slot 0 or 1. + * L Set secondary advance K factor (Slot 1). */ void GcodeSuite::M900() { @@ -72,31 +74,31 @@ void GcodeSuite::M900() { float &lref = other_extruder_advance_K[E_INDEX_N(tool_index)]; - const bool old_slot = TEST(lin_adv_slot, tool_index), // The tool's current slot (0 or 1) - new_slot = parser.boolval('S', old_slot); // The passed slot (default = current) + const bool old_slot = TEST(lin_adv_slot, tool_index), // Each tool uses 1 bit to store its current slot (0 or 1) + new_slot = parser.boolval('S', old_slot); // The new slot (0 or 1) to set for the tool (default = no change) // If a new slot is being selected swap the current and // saved K values. Do here so K/L will apply correctly. if (new_slot != old_slot) { // Not the same slot? SET_BIT_TO(lin_adv_slot, tool_index, new_slot); // Update the slot for the tool - newK = lref; // Get new K value from backup - lref = oldK; // Save K to backup + newK = lref; // Get the backup K value (to apply below) + lref = oldK; // Back up the active K value } // Set the main K value. Apply if the main slot is active. if (parser.seenval('K')) { const float K = parser.value_float(); if (!WITHIN(K, 0, 10)) echo_value_oor('K'); - else if (new_slot) lref = K; // S1 Knn - else newK = K; // S0 Knn + else if (new_slot) lref = K; // S1 Knn (set main K in its backup slot) + else newK = K; // S0 Knn (use main K now) } // Set the extra K value. Apply if the extra slot is active. if (parser.seenval('L')) { const float L = parser.value_float(); if (!WITHIN(L, 0, 10)) echo_value_oor('L'); - else if (!new_slot) lref = L; // S0 Lnn - else newK = L; // S1 Lnn + else if (!new_slot) lref = L; // S0 Lnn (set extra K in its backup slot) + else newK = L; // S1 Lnn (use extra K now) } #else @@ -133,7 +135,7 @@ void GcodeSuite::M900() { #if ENABLED(ADVANCE_K_EXTRA) - #if DISTINCT_E < 2 + #if DISABLED(DISTINCT_E_FACTORS) SERIAL_ECHOLNPGM("Advance S", new_slot, " K", kref, "(S", !new_slot, " K", lref, ")"); #else EXTRUDER_LOOP() { @@ -146,7 +148,7 @@ void GcodeSuite::M900() { #else // !ADVANCE_K_EXTRA SERIAL_ECHO_START(); - #if DISTINCT_E < 2 + #if DISABLED(DISTINCT_E_FACTORS) SERIAL_ECHOPGM("Advance K=", planner.extruder_advance_K[0]); #if ENABLED(SMOOTH_LIN_ADVANCE) SERIAL_ECHOPGM(" TAU=", stepper.get_advance_tau()); @@ -172,7 +174,7 @@ void GcodeSuite::M900_report(const bool forReplay/*=true*/) { TERN_(MARLIN_SMALL_BUILD, return); report_heading(forReplay, F(STR_LINEAR_ADVANCE)); - #if DISTINCT_E < 2 + #if DISABLED(DISTINCT_E_FACTORS) report_echo_start(forReplay); SERIAL_ECHOPGM(" M900 K", planner.extruder_advance_K[0]); #if ENABLED(SMOOTH_LIN_ADVANCE) diff --git a/Marlin/src/inc/Conditionals-1-axes.h b/Marlin/src/inc/Conditionals-1-axes.h index 8e84d7d4d4..49b236d80e 100644 --- a/Marlin/src/inc/Conditionals-1-axes.h +++ b/Marlin/src/inc/Conditionals-1-axes.h @@ -544,6 +544,8 @@ #endif // Helper macros for extruder and hotend arrays +#define _DISTINCT_E_LOOP(E) for (int8_t E = 0; E < DISTINCT_E; E++) +#define DISTINCT_E_LOOP() _DISTINCT_E_LOOP(e) #define _EXTRUDER_LOOP(E) for (int8_t E = 0; E < EXTRUDERS; E++) #define EXTRUDER_LOOP() _EXTRUDER_LOOP(e) #define _HOTEND_LOOP(H) for (int8_t H = 0; H < HOTENDS; H++) diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index df86cea522..ff75824673 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -846,7 +846,7 @@ static_assert(COUNT(arm) == LOGICAL_AXES, "AXIS_RELATIVE_MODES must contain " _L * Linear Advance 1.5 - Check K value range */ #if ENABLED(LIN_ADVANCE) - #if DISTINCT_E > 1 + #if ENABLED(DISTINCT_E_FACTORS) constexpr float lak[] = ADVANCE_K; static_assert(COUNT(lak) <= DISTINCT_E, "The ADVANCE_K array has too many elements (i.e., more than " STRINGIFY(DISTINCT_E) ")."); #define _LIN_ASSERT(N) static_assert(N >= COUNT(lak) || WITHIN(lak[N], 0, 10), "ADVANCE_K values must be from 0 to 10 (Changed in LIN_ADVANCE v1.5, Marlin 1.1.9)."); diff --git a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/max_acceleration_screen.cpp b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/max_acceleration_screen.cpp index 492b908776..e4178e6e2e 100644 --- a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/max_acceleration_screen.cpp +++ b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/max_acceleration_screen.cpp @@ -39,7 +39,7 @@ void MaxAccelerationScreen::onRedraw(draw_mode_t what) { w.color(z_axis) .adjuster( 6, GET_TEXT_F(MSG_AMAX_Z), getAxisMaxAcceleration_mm_s2(Z) ); #if DISTINCT_E == 1 w.color(e_axis).adjuster( 8, GET_TEXT_F(MSG_AMAX_E), getAxisMaxAcceleration_mm_s2(E0) ); - #elif DISTINCT_E > 1 + #elif ENABLED(DISTINCT_E_FACTORS) w.heading(GET_TEXT_F(MSG_AMAX_E)); w.color(e_axis).adjuster( 8, F(STR_E0), getAxisMaxAcceleration_mm_s2(E0) ); w.color(e_axis).adjuster(10, F(STR_E1), getAxisMaxAcceleration_mm_s2(E1) ); @@ -64,7 +64,7 @@ bool MaxAccelerationScreen::onTouchHeld(uint8_t tag) { case 7: UI_INCREMENT(AxisMaxAcceleration_mm_s2, Z ); break; case 8: UI_DECREMENT(AxisMaxAcceleration_mm_s2, E0); break; case 9: UI_INCREMENT(AxisMaxAcceleration_mm_s2, E0); break; - #if DISTINCT_E > 1 + #if ENABLED(DISTINCT_E_FACTORS) case 10: UI_DECREMENT(AxisMaxAcceleration_mm_s2, E1); break; case 11: UI_INCREMENT(AxisMaxAcceleration_mm_s2, E1); break; #if DISTINCT_E > 2 diff --git a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/max_velocity_screen.cpp b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/max_velocity_screen.cpp index 666a7542cc..2a396205f1 100644 --- a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/max_velocity_screen.cpp +++ b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/max_velocity_screen.cpp @@ -66,7 +66,7 @@ bool MaxVelocityScreen::onTouchHeld(uint8_t tag) { #if DISTINCT_E case 8: UI_DECREMENT(AxisMaxFeedrate_mm_s, E0); break; case 9: UI_INCREMENT(AxisMaxFeedrate_mm_s, E0); break; - #if DISTINCT_E > 1 + #if ENABLED(DISTINCT_E_FACTORS) case 10: UI_DECREMENT(AxisMaxFeedrate_mm_s, E1); break; case 11: UI_INCREMENT(AxisMaxFeedrate_mm_s, E1); break; #if DISTINCT_E > 2 diff --git a/Marlin/src/lcd/menu/menu_advanced.cpp b/Marlin/src/lcd/menu/menu_advanced.cpp index 296312bb1f..92f2f51536 100644 --- a/Marlin/src/lcd/menu/menu_advanced.cpp +++ b/Marlin/src/lcd/menu/menu_advanced.cpp @@ -116,14 +116,14 @@ void menu_backlash(); BACK_ITEM(MSG_ADVANCED_SETTINGS); #if ENABLED(LIN_ADVANCE) - #if DISTINCT_E < 2 + #if DISABLED(DISTINCT_E_FACTORS) EDIT_ITEM(float42_52, MSG_ADVANCE_K, &planner.extruder_advance_K[0], 0, 10); #else EXTRUDER_LOOP() EDIT_ITEM_N(float42_52, e, MSG_ADVANCE_K_E, &planner.extruder_advance_K[e], 0, 10); #endif #if ENABLED(SMOOTH_LIN_ADVANCE) - #if DISTINCT_E < 2 + #if DISABLED(DISTINCT_E_FACTORS) editable.decimal = stepper.get_advance_tau(); EDIT_ITEM(float54, MSG_ADVANCE_TAU, &editable.decimal, 0.0f, 0.5f, []{ stepper.set_advance_tau(editable.decimal); }); #else @@ -749,14 +749,14 @@ void menu_advanced_settings() { #endif #if ENABLED(LIN_ADVANCE) && DISABLED(HAS_ADV_FILAMENT_MENU) - #if DISTINCT_E < 2 + #if DISABLED(DISTINCT_E_FACTORS) EDIT_ITEM(float42_52, MSG_ADVANCE_K, &planner.extruder_advance_K[0], 0, 10); #else EXTRUDER_LOOP() EDIT_ITEM_N(float42_52, e, MSG_ADVANCE_K_E, &planner.extruder_advance_K[e], 0, 10); #endif #if ENABLED(SMOOTH_LIN_ADVANCE) - #if DISTINCT_E < 2 + #if DISABLED(DISTINCT_E_FACTORS) editable.decimal = stepper.get_advance_tau(); EDIT_ITEM(float54, MSG_ADVANCE_TAU, &editable.decimal, 0.0f, 0.5f, []{ stepper.set_advance_tau(editable.decimal); }); #else diff --git a/Marlin/src/lcd/menu/menu_tune.cpp b/Marlin/src/lcd/menu/menu_tune.cpp index 51d877fc5c..d5cb805244 100644 --- a/Marlin/src/lcd/menu/menu_tune.cpp +++ b/Marlin/src/lcd/menu/menu_tune.cpp @@ -215,14 +215,14 @@ void menu_tune() { // Advance K: // #if ENABLED(LIN_ADVANCE) && DISABLED(SLIM_LCD_MENUS) - #if DISTINCT_E < 2 + #if DISABLED(DISTINCT_E_FACTORS) EDIT_ITEM(float42_52, MSG_ADVANCE_K, &planner.extruder_advance_K[0], 0, 10); #else EXTRUDER_LOOP() EDIT_ITEM_N(float42_52, e, MSG_ADVANCE_K_E, &planner.extruder_advance_K[e], 0, 10); #endif #if ENABLED(SMOOTH_LIN_ADVANCE) - #if DISTINCT_E < 2 + #if DISABLED(DISTINCT_E_FACTORS) editable.decimal = stepper.get_advance_tau(); EDIT_ITEM(float54, MSG_ADVANCE_TAU, &editable.decimal, 0.0f, 0.5f, []{ stepper.set_advance_tau(editable.decimal); }); #else From 54c1a1df4e79f1ac4e704f4311d706e934c3e9e7 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Fri, 9 May 2025 16:23:37 -0500 Subject: [PATCH 302/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Sin?= =?UTF-8?q?gleton=20notation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/feature/max7219.cpp | 2 +- Marlin/src/module/stepper.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Marlin/src/feature/max7219.cpp b/Marlin/src/feature/max7219.cpp index 5a61922c1d..16c7c4f55b 100644 --- a/Marlin/src/feature/max7219.cpp +++ b/Marlin/src/feature/max7219.cpp @@ -770,7 +770,7 @@ void Max7219::idle_tasks() { #ifdef MAX7219_DEBUG_SLOWDOWN static uint8_t last_slowdown_count = 0; - const uint8_t slowdown_count = Planner::slowdown_count; + const uint8_t slowdown_count = planner.slowdown_count; if (slowdown_count != last_slowdown_count) { mark16(MAX7219_DEBUG_SLOWDOWN, last_slowdown_count, slowdown_count, &row_change_mask); last_slowdown_count = slowdown_count; diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp index 1d02620e6f..e9f83aa532 100644 --- a/Marlin/src/module/stepper.cpp +++ b/Marlin/src/module/stepper.cpp @@ -2933,7 +2933,7 @@ hal_timer_t Stepper::block_phase_isr() { #endif // INPUT_SHAPING_E_SYNC float lookahead(uint32_t t) { - for (uint8_t i = 0; block_t *block = Planner::get_future_block(i); i++) { + for (uint8_t i = 0; block_t *block = planner.get_future_block(i); i++) { if (block->is_sync()) continue; if (t <= block->acceleration_time) { if (!block->use_advance_lead) return 0.0f; @@ -2969,7 +2969,7 @@ hal_timer_t Stepper::block_phase_isr() { float target_adv_steps = 0; if (current_block) { const uint32_t t = extruder_advance_tau_ticks[0] + curr_timer_tick; - target_adv_steps = lookahead(t) * Planner::extruder_advance_K[0]; + target_adv_steps = lookahead(t) * planner.extruder_advance_K[0]; } else { curr_step_rate = 0; From b12028f4dd0fecd99532175cd5a094b86cec8d54 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Fri, 9 May 2025 16:37:06 -0500 Subject: [PATCH 303/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20ALI?= =?UTF-8?q?M(I,ARR)=20macro?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/core/macros.h | 3 +++ Marlin/src/lcd/dogm/marlinui_DOGM.cpp | 2 +- Marlin/src/module/planner.h | 2 +- Marlin/src/module/settings.cpp | 7 ++----- Marlin/src/module/stepper.h | 3 +-- 5 files changed, 8 insertions(+), 9 deletions(-) diff --git a/Marlin/src/core/macros.h b/Marlin/src/core/macros.h index c75d684566..bef89040b3 100644 --- a/Marlin/src/core/macros.h +++ b/Marlin/src/core/macros.h @@ -547,6 +547,9 @@ #endif +// Limit an index to an array size +#define ALIM(I,ARR) _MIN(I, (signed)COUNT(ARR) - 1) + // Macros for adding #define INC_0 1 #define INC_1 2 diff --git a/Marlin/src/lcd/dogm/marlinui_DOGM.cpp b/Marlin/src/lcd/dogm/marlinui_DOGM.cpp index 29316c553d..721389cb2c 100644 --- a/Marlin/src/lcd/dogm/marlinui_DOGM.cpp +++ b/Marlin/src/lcd/dogm/marlinui_DOGM.cpp @@ -197,7 +197,7 @@ bool MarlinUI::detected() { return true; } #endif { #if ENABLED(CUSTOM_BOOTSCREEN_ANIMATED_FRAME_TIME) - const uint8_t fr = _MIN(f, COUNT(custom_bootscreen_animation) - 1); + const uint8_t fr = ALIM(f, custom_bootscreen_animation); const millis_t frame_time = pgm_read_word(&custom_bootscreen_animation[fr].duration); #endif u8g.firstPage(); diff --git a/Marlin/src/module/planner.h b/Marlin/src/module/planner.h index 73c77ee7f5..1c23f95cb1 100644 --- a/Marlin/src/module/planner.h +++ b/Marlin/src/module/planner.h @@ -359,7 +359,7 @@ typedef struct PlannerSettings { #if ENABLED(EDITABLE_STEPS_PER_UNIT) float axis_steps_per_mm[DISTINCT_AXES]; #else - #define _DLIM(I) _MIN(I, (signed)COUNT(_dasu) - 1) + #define _DLIM(I) ALIM(I, _dasu) #define _DASU(N) _dasu[_DLIM(N)], #define _EASU(N) _dasu[_DLIM(E_AXIS + N)], static constexpr float axis_steps_per_mm[DISTINCT_AXES] = { diff --git a/Marlin/src/module/settings.cpp b/Marlin/src/module/settings.cpp index d325ef95d9..1a46c6cc2a 100644 --- a/Marlin/src/module/settings.cpp +++ b/Marlin/src/module/settings.cpp @@ -200,9 +200,6 @@ typedef struct { bool NUM_AXIS_LIST_(X:1, Y:1, Z:1, I:1, J:1, K:1, U:1, V:1, #undef _EN_ITEM -// Limit an index to an array size -#define ALIM(I,ARR) _MIN(I, (signed)COUNT(ARR) - 1) - // Defaults for reset / fill in on load static const uint32_t _DMA[] PROGMEM = DEFAULT_MAX_ACCELERATION; static const feedRate_t _DMF[] PROGMEM = DEFAULT_MAX_FEEDRATE; @@ -3619,7 +3616,7 @@ void MarlinSettings::reset() { constexpr float linAdvanceK[] = ADVANCE_K; EXTRUDER_LOOP() { - const float a = linAdvanceK[_MAX(uint8_t(e), COUNT(linAdvanceK) - 1)]; + const float a = linAdvanceK[ALIM(e, linAdvanceK)]; planner.extruder_advance_K[e] = a; TERN_(ADVANCE_K_EXTRA, other_extruder_advance_K[e] = a); } @@ -3630,7 +3627,7 @@ void MarlinSettings::reset() { #if ENABLED(DISTINCT_E_FACTORS) constexpr float linAdvanceTau[] = ADVANCE_TAU; EXTRUDER_LOOP() - stepper.set_advance_tau(linAdvanceTau[_MAX(uint8_t(e), COUNT(linAdvanceTau) - 1)], e); + stepper.set_advance_tau(linAdvanceTau[ALIM(e, linAdvanceTau)], e); #else stepper.set_advance_tau(ADVANCE_TAU); #endif diff --git a/Marlin/src/module/stepper.h b/Marlin/src/module/stepper.h index 83ada9202e..1c06d83351 100644 --- a/Marlin/src/module/stepper.h +++ b/Marlin/src/module/stepper.h @@ -140,7 +140,6 @@ constexpr ena_mask_t enable_overlap[] = { #ifdef SHAPING_MAX_STEPRATE constexpr float max_step_rate = SHAPING_MAX_STEPRATE; #else - #define ISALIM(I, ARR) _MIN(I, COUNT(ARR) - 1) constexpr float _ISDASU[] = DEFAULT_AXIS_STEPS_PER_UNIT; constexpr feedRate_t _ISDMF[] = DEFAULT_MAX_FEEDRATE; constexpr float max_shaped_rate = TERN0(INPUT_SHAPING_X, _ISDMF[X_AXIS] * _ISDASU[X_AXIS]) + @@ -149,7 +148,7 @@ constexpr ena_mask_t enable_overlap[] = { #if defined(__AVR__) || !defined(ADAPTIVE_STEP_SMOOTHING) // min_step_isr_frequency is known at compile time on AVRs and any reduction in SRAM is welcome template constexpr float max_isr_rate() { - return _MAX(_ISDMF[ISALIM(INDEX - 1, _ISDMF)] * _ISDASU[ISALIM(INDEX - 1, _ISDASU)], max_isr_rate()); + return _MAX(_ISDMF[ALIM(INDEX - 1, _ISDMF)] * _ISDASU[ALIM(INDEX - 1, _ISDASU)], max_isr_rate()); } template<> constexpr float max_isr_rate<0>() { return TERN0(ADAPTIVE_STEP_SMOOTHING, min_step_isr_frequency); From 4de6d655acb80a3ea1d5b39607da5d4aed44c9ae Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Sat, 10 May 2025 00:30:25 +0000 Subject: [PATCH 304/787] [cron] Bump distribution date (2025-05-10) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index e9be5139e7..3c4711b876 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-05-09" +//#define STRING_DISTRIBUTION_DATE "2025-05-10" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 336dd6bff4..64a498179d 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-05-09" + #define STRING_DISTRIBUTION_DATE "2025-05-10" #endif /** From 12fdde24d89643969554222b0d94cf190cf1fe85 Mon Sep 17 00:00:00 2001 From: David Buezas Date: Tue, 13 May 2025 23:14:04 +0200 Subject: [PATCH 305/787] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20Optimize=20Smooth?= =?UTF-8?q?=20Linear=20Advance=20(via=20fixed-point)=20(#27818)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/Configuration_adv.h | 6 +- Marlin/src/gcode/feature/advance/M900.cpp | 46 ++++--- Marlin/src/inc/SanityCheck.h | 2 +- Marlin/src/lcd/e3v2/jyersui/dwin.cpp | 25 ++-- Marlin/src/lcd/e3v2/proui/dwin.cpp | 7 +- Marlin/src/lcd/extui/ui_api.cpp | 4 +- Marlin/src/lcd/menu/menu_advanced.cpp | 28 +++-- Marlin/src/lcd/menu/menu_tune.cpp | 9 +- Marlin/src/lcd/sovol_rts/sovol_rts.cpp | 6 +- Marlin/src/lcd/tft/touch.cpp | 76 ++++++------ Marlin/src/module/planner.cpp | 13 +- Marlin/src/module/planner.h | 31 ++++- Marlin/src/module/settings.cpp | 44 ++++--- Marlin/src/module/stepper.cpp | 141 ++++++++++++---------- Marlin/src/module/stepper.h | 26 ++-- Marlin/src/module/tool_change.cpp | 2 +- 16 files changed, 265 insertions(+), 201 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index f31a284d81..762ae2aa81 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -2366,11 +2366,11 @@ * Higher k and higher XY acceleration may require larger ADVANCE_TAU to avoid skipping steps. */ #if ENABLED(DISTINCT_E_FACTORS) - #define ADVANCE_TAU { 0.01 } // (s) Smoothing time to reduce extruder acceleration, per extruder + #define ADVANCE_TAU { 0.02 } // (s) Smoothing time to reduce extruder acceleration, per extruder #else - #define ADVANCE_TAU 0.01 // (s) Smoothing time to reduce extruder acceleration + #define ADVANCE_TAU 0.02 // (s) Smoothing time to reduce extruder acceleration #endif - #define SMOOTH_LIN_ADV_HZ 5000 // (Hz) How often to update extruder speed + #define SMOOTH_LIN_ADV_HZ 1000 // (Hz) How often to update extruder speed #define INPUT_SHAPING_E_SYNC // Synchronize the extruder-shaped XY axes (to increase precision) #endif #endif diff --git a/Marlin/src/gcode/feature/advance/M900.cpp b/Marlin/src/gcode/feature/advance/M900.cpp index dc59b5bc90..7b92cad9d2 100644 --- a/Marlin/src/gcode/feature/advance/M900.cpp +++ b/Marlin/src/gcode/feature/advance/M900.cpp @@ -29,7 +29,7 @@ #include "../../../module/stepper.h" #if ENABLED(ADVANCE_K_EXTRA) - float other_extruder_advance_K[DISTINCT_E]; + float other_extruder_advance_K[EXTRUDERS]; uint8_t lin_adv_slot = 0; #endif @@ -62,17 +62,17 @@ void GcodeSuite::M900() { } #endif - float &kref = planner.extruder_advance_K[E_INDEX_N(tool_index)], newK = kref; - const float oldK = newK; + const float oldK = planner.get_advance_k(tool_index); + float newK = oldK; #if ENABLED(SMOOTH_LIN_ADVANCE) - const float oldU = stepper.get_advance_tau(E_INDEX_N(tool_index)); + const float oldU = stepper.get_advance_tau(tool_index); float newU = oldU; #endif #if ENABLED(ADVANCE_K_EXTRA) - float &lref = other_extruder_advance_K[E_INDEX_N(tool_index)]; + float &lref = other_extruder_advance_K[tool_index]; const bool old_slot = TEST(lin_adv_slot, tool_index), // Each tool uses 1 bit to store its current slot (0 or 1) new_slot = parser.boolval('S', old_slot); // The new slot (0 or 1) to set for the tool (default = no change) @@ -125,9 +125,9 @@ void GcodeSuite::M900() { if (newK != oldK || TERN0(SMOOTH_LIN_ADVANCE, newU != oldU)) { planner.synchronize(); - if (newK != oldK) kref = newK; + if (newK != oldK) planner.set_advance_k(newK, tool_index); #if ENABLED(SMOOTH_LIN_ADVANCE) - if (newU != oldU) stepper.set_advance_tau(newU); + if (newU != oldU) stepper.set_advance_tau(newU, tool_index); #endif } @@ -136,11 +136,11 @@ void GcodeSuite::M900() { #if ENABLED(ADVANCE_K_EXTRA) #if DISABLED(DISTINCT_E_FACTORS) - SERIAL_ECHOLNPGM("Advance S", new_slot, " K", kref, "(S", !new_slot, " K", lref, ")"); + SERIAL_ECHOLNPGM("Advance S", new_slot, " K", newK, "(S", !new_slot, " K", lref, ")"); #else EXTRUDER_LOOP() { const bool slot = TEST(lin_adv_slot, e); - SERIAL_ECHOLNPGM("Advance T", e, " S", slot, " K", planner.extruder_advance_K[e], + SERIAL_ECHOLNPGM("Advance T", e, " S", slot, " K", planner.get_advance_k(e), "(S", !slot, " K", other_extruder_advance_K[e], ")"); } #endif @@ -149,14 +149,14 @@ void GcodeSuite::M900() { SERIAL_ECHO_START(); #if DISABLED(DISTINCT_E_FACTORS) - SERIAL_ECHOPGM("Advance K=", planner.extruder_advance_K[0]); + SERIAL_ECHOPGM("Advance K=", planner.get_advance_k()); #if ENABLED(SMOOTH_LIN_ADVANCE) SERIAL_ECHOPGM(" TAU=", stepper.get_advance_tau()); #endif SERIAL_EOL(); #else SERIAL_ECHOPGM("Advance K"); - EXTRUDER_LOOP() SERIAL_ECHO(C(' '), C('0' + e), C(':'), planner.extruder_advance_K[e]); + EXTRUDER_LOOP() SERIAL_ECHO(C(' '), C('0' + e), C(':'), planner.get_advance_k(e)); SERIAL_EOL(); #if ENABLED(SMOOTH_LIN_ADVANCE) SERIAL_ECHOPGM("Advance TAU"); @@ -174,23 +174,21 @@ void GcodeSuite::M900_report(const bool forReplay/*=true*/) { TERN_(MARLIN_SMALL_BUILD, return); report_heading(forReplay, F(STR_LINEAR_ADVANCE)); - #if DISABLED(DISTINCT_E_FACTORS) + DISTINCT_E_LOOP() { report_echo_start(forReplay); - SERIAL_ECHOPGM(" M900 K", planner.extruder_advance_K[0]); + SERIAL_ECHOPGM( + #if ENABLED(DISTINCT_E_FACTORS) + " M900 T", e, " K" + #else + " M900 K" + #endif + ); + SERIAL_ECHO(planner.get_advance_k(e)); #if ENABLED(SMOOTH_LIN_ADVANCE) - SERIAL_ECHOPGM(" M900 U", stepper.get_advance_tau()); + SERIAL_ECHOPGM(" U", stepper.get_advance_tau(e)); #endif SERIAL_EOL(); - #else - EXTRUDER_LOOP() { - report_echo_start(forReplay); - SERIAL_ECHOPGM(" M900 T", e, " K", planner.extruder_advance_K[e]); - #if ENABLED(SMOOTH_LIN_ADVANCE) - SERIAL_ECHOPGM(" U", stepper.get_advance_tau(e)); - #endif - SERIAL_EOL(); - } - #endif + } } #endif // LIN_ADVANCE diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index ff75824673..97cc2ed198 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -3725,7 +3725,7 @@ static_assert(NUM_SERVOS <= NUM_SERVO_PLUGS, "NUM_SERVOS (or some servo index) i * Check per-axis initializers for errors */ -#define __PLUS_TEST(I,A) && (sanity_arr_##A[_MIN(I,signed(COUNT(sanity_arr_##A)-1))] > 0) +#define __PLUS_TEST(I,A) && (sanity_arr_##A[ALIM(I,sanity_arr_##A)] > 0) #define _PLUS_TEST(A) (1 REPEAT2(14,__PLUS_TEST,A)) #if HAS_MULTI_EXTRUDER #define _EXTRA_NOTE " (Did you forget to enable DISTINCT_E_FACTORS?)" diff --git a/Marlin/src/lcd/e3v2/jyersui/dwin.cpp b/Marlin/src/lcd/e3v2/jyersui/dwin.cpp index aa087cefc4..f2c54da745 100644 --- a/Marlin/src/lcd/e3v2/jyersui/dwin.cpp +++ b/Marlin/src/lcd/e3v2/jyersui/dwin.cpp @@ -2398,10 +2398,13 @@ void JyersDWIN::menuItemHandler(const uint8_t menu, const uint8_t item, bool dra case MOTION_LA: if (draw) { drawMenuItem(row, ICON_MaxAccelerated, GET_TEXT_F(MSG_ADVANCE_K)); - drawFloat(planner.extruder_advance_K[0], row, false, 100); + drawFloat(planner.get_advance_k(), row, false, 100); } - else - modifyValue(planner.extruder_advance_K[0], 0, 10, 100); + else { + static float k = planner.get_advance_k(); + modifyValue(k, 0, 10, 100, []{ planner.set_advance_k(k); }); + } + break; #endif } @@ -2914,10 +2917,12 @@ void JyersDWIN::menuItemHandler(const uint8_t menu, const uint8_t item, bool dra case ADVANCED_LA: if (draw) { drawMenuItem(row, ICON_MaxAccelerated, GET_TEXT_F(MSG_ADVANCE_K)); - drawFloat(planner.extruder_advance_K[0], row, false, 100); + drawFloat(planner.get_advance_k(), row, false, 100); + } + else { + static float k = planner.get_advance_k(); + modifyValue(k, 0, 10, 100, []{ planner.set_advance_k(k); }); } - else - modifyValue(planner.extruder_advance_K[0], 0, 10, 100); break; #endif @@ -3925,10 +3930,12 @@ void JyersDWIN::menuItemHandler(const uint8_t menu, const uint8_t item, bool dra case TUNE_LA: if (draw) { drawMenuItem(row, ICON_MaxAccelerated, GET_TEXT_F(MSG_ADVANCE_K)); - drawFloat(planner.extruder_advance_K[0], row, false, 100); + drawFloat(planner.get_advance_k(), row, false, 100); + } + else { + static float k = planner.get_advance_k(); + modifyValue(k, 0, 10, 100, []{ planner.set_advance_k(k); }); } - else - modifyValue(planner.extruder_advance_K[0], 0, 10, 100); break; #endif diff --git a/Marlin/src/lcd/e3v2/proui/dwin.cpp b/Marlin/src/lcd/e3v2/proui/dwin.cpp index c3a69c1c66..7574439051 100644 --- a/Marlin/src/lcd/e3v2/proui/dwin.cpp +++ b/Marlin/src/lcd/e3v2/proui/dwin.cpp @@ -2686,7 +2686,8 @@ void applyMaxAccel() { planner.set_max_acceleration(hmiValue.axis, menuData.valu #endif #if ENABLED(LIN_ADVANCE) - void setLA_K() { setPFloatOnClick(0, 10, 3); } + void applyLA_K() { planner.set_advance_k(menuData.value / MINUNITMULT); } + void setLA_K() { setPFloatOnClick(0, 10, 3, applyLA_K); } #endif #if HAS_X_AXIS @@ -3545,7 +3546,7 @@ void drawTuneMenu() { EDIT_ITEM(ICON_JDmm, MSG_JUNCTION_DEVIATION, onDrawPFloat3Menu, setJDmm, &planner.junction_deviation_mm); #endif #if ENABLED(PROUI_ITEM_ADVK) - EDIT_ITEM(ICON_MaxAccelerated, MSG_ADVANCE_K, onDrawPFloat3Menu, setLA_K, &planner.extruder_advance_K[0]); + EDIT_ITEM(ICON_MaxAccelerated, MSG_ADVANCE_K, onDrawPFloat3Menu, setLA_K, &planner.get_advance_k()); #endif #if HAS_LOCKSCREEN MENU_ITEM(ICON_Lock, MSG_LOCKSCREEN, onDrawMenuItem, dwinLockScreen); @@ -3683,7 +3684,7 @@ void drawMotionMenu() { MENU_ITEM(ICON_Homing, MSG_HOMING_FEEDRATE, onDrawSubMenu, drawHomingFRMenu); #endif #if ENABLED(LIN_ADVANCE) - EDIT_ITEM(ICON_MaxAccelerated, MSG_ADVANCE_K, onDrawPFloat3Menu, setLA_K, &planner.extruder_advance_K[0]); + EDIT_ITEM(ICON_MaxAccelerated, MSG_ADVANCE_K, onDrawPFloat3Menu, setLA_K, &planner.get_advance_k()); #endif #if ENABLED(SHAPING_MENU) MENU_ITEM(ICON_InputShaping, MSG_INPUT_SHAPING, onDrawSubMenu, drawInputShaping_menu); diff --git a/Marlin/src/lcd/extui/ui_api.cpp b/Marlin/src/lcd/extui/ui_api.cpp index b3f4c39c24..5380b05596 100644 --- a/Marlin/src/lcd/extui/ui_api.cpp +++ b/Marlin/src/lcd/extui/ui_api.cpp @@ -643,12 +643,12 @@ namespace ExtUI { #if ENABLED(LIN_ADVANCE) float getLinearAdvance_mm_mm_s(const extruder_t extruder) { - return (extruder < EXTRUDERS) ? planner.extruder_advance_K[E_INDEX_N(extruder - E0)] : 0; + return (extruder < EXTRUDERS) ? planner.get_advance_k(E_INDEX_N(extruder - E0)) : 0; } void setLinearAdvance_mm_mm_s(const_float_t value, const extruder_t extruder) { if (extruder < EXTRUDERS) - planner.extruder_advance_K[E_INDEX_N(extruder - E0)] = constrain(value, 0, 10); + planner.set_advance_k(constrain(value, 0, 10), E_INDEX_N(extruder - E0)); } #endif diff --git a/Marlin/src/lcd/menu/menu_advanced.cpp b/Marlin/src/lcd/menu/menu_advanced.cpp index 92f2f51536..b15a21fc7b 100644 --- a/Marlin/src/lcd/menu/menu_advanced.cpp +++ b/Marlin/src/lcd/menu/menu_advanced.cpp @@ -117,10 +117,13 @@ void menu_backlash(); #if ENABLED(LIN_ADVANCE) #if DISABLED(DISTINCT_E_FACTORS) - EDIT_ITEM(float42_52, MSG_ADVANCE_K, &planner.extruder_advance_K[0], 0, 10); + editable.decimal = planner.get_advance_k(); + EDIT_ITEM(float42_52, MSG_ADVANCE_K, &editable.decimal, 0.0f, 10.0f, []{ planner.set_advance_k(editable.decimal); }); #else - EXTRUDER_LOOP() - EDIT_ITEM_N(float42_52, e, MSG_ADVANCE_K_E, &planner.extruder_advance_K[e], 0, 10); + EXTRUDER_LOOP() { + editable.decimal = planner.get_advance_k(e); + EDIT_ITEM_N(float42_52, e, MSG_ADVANCE_K_E, &editable.decimal, 0.0f, 10.0f, []{ planner.set_advance_k(editable.decimal, MenuItemBase::itemIndex); }); + } #endif #if ENABLED(SMOOTH_LIN_ADVANCE) #if DISABLED(DISTINCT_E_FACTORS) @@ -745,15 +748,19 @@ void menu_advanced_settings() { #endif #if HAS_ADV_FILAMENT_MENU - SUBMENU(MSG_FILAMENT, menu_advanced_filament); - #endif - #if ENABLED(LIN_ADVANCE) && DISABLED(HAS_ADV_FILAMENT_MENU) + SUBMENU(MSG_FILAMENT, menu_advanced_filament); + + #elif ENABLED(LIN_ADVANCE) + #if DISABLED(DISTINCT_E_FACTORS) - EDIT_ITEM(float42_52, MSG_ADVANCE_K, &planner.extruder_advance_K[0], 0, 10); + editable.decimal = planner.get_advance_k(); + EDIT_ITEM(float42_52, MSG_ADVANCE_K, &editable.decimal, 0.0f, 10.0f, []{ planner.set_advance_k(editable.decimal); }); #else - EXTRUDER_LOOP() - EDIT_ITEM_N(float42_52, e, MSG_ADVANCE_K_E, &planner.extruder_advance_K[e], 0, 10); + EXTRUDER_LOOP() { + editable.decimal = planner.get_advance_k(e); + EDIT_ITEM_N(float42_52, e, MSG_ADVANCE_K_E, &editable.decimal, 0.0f, 10.0f, []{ planner.set_advance_k(editable.decimal, MenuItemBase::itemIndex); }); + } #endif #if ENABLED(SMOOTH_LIN_ADVANCE) #if DISABLED(DISTINCT_E_FACTORS) @@ -766,7 +773,8 @@ void menu_advanced_settings() { } #endif #endif - #endif + + #endif // LIN_ADVANCE && !HAS_ADV_FILAMENT_MENU // M540 S - Abort on endstop hit when SD printing #if ENABLED(SD_ABORT_ON_ENDSTOP_HIT) diff --git a/Marlin/src/lcd/menu/menu_tune.cpp b/Marlin/src/lcd/menu/menu_tune.cpp index d5cb805244..7f4696a3f1 100644 --- a/Marlin/src/lcd/menu/menu_tune.cpp +++ b/Marlin/src/lcd/menu/menu_tune.cpp @@ -216,10 +216,13 @@ void menu_tune() { // #if ENABLED(LIN_ADVANCE) && DISABLED(SLIM_LCD_MENUS) #if DISABLED(DISTINCT_E_FACTORS) - EDIT_ITEM(float42_52, MSG_ADVANCE_K, &planner.extruder_advance_K[0], 0, 10); + editable.decimal = planner.get_advance_k(); + EDIT_ITEM(float42_52, MSG_ADVANCE_K, &editable.decimal, 0.0f, 10.0f, []{ planner.set_advance_k(editable.decimal); }); #else - EXTRUDER_LOOP() - EDIT_ITEM_N(float42_52, e, MSG_ADVANCE_K_E, &planner.extruder_advance_K[e], 0, 10); + EXTRUDER_LOOP() { + editable.decimal = planner.get_advance_k(e); + EDIT_ITEM_N(float42_52, e, MSG_ADVANCE_K_E, &editable.decimal, 0.0f, 10.0f, []{ planner.set_advance_k(editable.decimal, MenuItemBase::itemIndex); }); + } #endif #if ENABLED(SMOOTH_LIN_ADVANCE) #if DISABLED(DISTINCT_E_FACTORS) diff --git a/Marlin/src/lcd/sovol_rts/sovol_rts.cpp b/Marlin/src/lcd/sovol_rts/sovol_rts.cpp index bea95be96a..3c09838684 100644 --- a/Marlin/src/lcd/sovol_rts/sovol_rts.cpp +++ b/Marlin/src/lcd/sovol_rts/sovol_rts.cpp @@ -894,7 +894,7 @@ void RTS::handleData() { break; case 4: // Go to Advanced Settings - TERN_(LIN_ADVANCE, sendData(planner.extruder_advance_K[0] * 100, Advance_K_VP)); + TERN_(LIN_ADVANCE, sendData(planner.get_advance_k() * 100, Advance_K_VP)); gotoPage(ID_AdvWarn_L, ID_AdvWarn_D); break; @@ -1292,7 +1292,7 @@ void RTS::handleData() { #if ENABLED(LIN_ADVANCE) case 7: // Confirm - sendData(planner.extruder_advance_K[0] * 100, Advance_K_VP); + sendData(planner.get_advance_k() * 100, Advance_K_VP); gotoPage(ID_Advanced_L, ID_Advanced_D); break; #endif @@ -1350,7 +1350,7 @@ void RTS::handleData() { #endif case A_Retract: planner.settings.retract_acceleration = recdat.data[0]; break; #if ENABLED(LIN_ADVANCE) - case Advance_K: planner.extruder_advance_K[0] = float(recdat.data[0]) / 100.0f; break; + case Advance_K: planner.set_advance_k(float(recdat.data[0]) / 100.0f); break; #endif #endif case Accel: planner.settings.acceleration = recdat.data[0]; break; diff --git a/Marlin/src/lcd/tft/touch.cpp b/Marlin/src/lcd/tft/touch.cpp index bb226e50c6..fbba927a86 100644 --- a/Marlin/src/lcd/tft/touch.cpp +++ b/Marlin/src/lcd/tft/touch.cpp @@ -181,44 +181,51 @@ void Touch::touch(touch_control_t *control) { case SLIDER: hold(control); ui.encoderPosition = (x - control->x) * control->data / control->width; break; case INCREASE: hold(control, repeat_delay - 5); TERN(AUTO_BED_LEVELING_UBL, ui.external_control ? bedlevel.encoder_diff++ : ui.encoderPosition++, ui.encoderPosition++); break; case DECREASE: hold(control, repeat_delay - 5); TERN(AUTO_BED_LEVELING_UBL, ui.external_control ? bedlevel.encoder_diff-- : ui.encoderPosition--, ui.encoderPosition--); break; - case HEATER: - int8_t heater; - heater = control->data; + case HEATER: { ui.clear_for_drawing(); - #if HAS_HOTEND - if (heater >= 0) { // HotEnd - #if HOTENDS == 1 - MenuItem_int3::action(GET_TEXT_F(MSG_NOZZLE), &thermalManager.temp_hotend[0].target, 0, thermalManager.hotend_max_target(0), []{ thermalManager.start_watching_hotend(0); }); - #else - MenuItemBase::itemIndex = heater; - MenuItem_int3::action(GET_TEXT_F(MSG_NOZZLE_N), &thermalManager.temp_hotend[heater].target, 0, thermalManager.hotend_max_target(heater), []{ thermalManager.start_watching_hotend(MenuItemBase::itemIndex); }); + const int8_t heater = control->data; + switch (heater) { + default: // Hotend + #if HAS_HOTEND + #define HOTEND_HEATER(N) TERN0(HAS_MULTI_HOTEND, N) + TERN_(HAS_MULTI_HOTEND, MenuItemBase::itemIndex = heater); + MenuItem_int3::action(GET_TEXT_F(TERN(HAS_MULTI_HOTEND, MSG_NOZZLE_N, MSG_NOZZLE)), + &thermalManager.temp_hotend[HOTEND_HEATER(heater)].target, 0, thermalManager.hotend_max_target(HOTEND_HEATER(heater)), + []{ thermalManager.start_watching_hotend(HOTEND_HEATER(MenuItemBase::itemIndex)); } + ); #endif - } - #endif - #if HAS_HEATED_BED - else if (heater == H_BED) { - MenuItem_int3::action(GET_TEXT_F(MSG_BED), &thermalManager.temp_bed.target, 0, BED_MAX_TARGET, thermalManager.start_watching_bed); - } - #endif - #if HAS_HEATED_CHAMBER - else if (heater == H_CHAMBER) { - MenuItem_int3::action(GET_TEXT_F(MSG_CHAMBER), &thermalManager.temp_chamber.target, 0, CHAMBER_MAX_TARGET, thermalManager.start_watching_chamber); - } - #endif - #if HAS_COOLER - else if (heater == H_COOLER) { - MenuItem_int3::action(GET_TEXT_F(MSG_COOLER), &thermalManager.temp_cooler.target, 0, COOLER_MAX_TARGET, thermalManager.start_watching_cooler); - } - #endif + break; - break; - case FAN: + #if HAS_HEATED_BED + case H_BED: + MenuItem_int3::action(GET_TEXT_F(MSG_BED), &thermalManager.temp_bed.target, 0, BED_MAX_TARGET, thermalManager.start_watching_bed); + break; + #endif + + #if HAS_HEATED_CHAMBER + case H_CHAMBER: + MenuItem_int3::action(GET_TEXT_F(MSG_CHAMBER), &thermalManager.temp_chamber.target, 0, CHAMBER_MAX_TARGET, thermalManager.start_watching_chamber); + break; + #endif + + #if HAS_COOLER + case H_COOLER: + MenuItem_int3::action(GET_TEXT_F(MSG_COOLER), &thermalManager.temp_cooler.target, 0, COOLER_MAX_TARGET, thermalManager.start_watching_cooler); + break; + #endif + + } // switch + + } break; + + case FAN: { ui.clear_for_drawing(); static uint8_t fan, fan_speed; fan = 0; fan_speed = thermalManager.fan_speed[fan]; MenuItem_percent::action(GET_TEXT_F(MSG_FIRST_FAN_SPEED), &fan_speed, 0, 255, []{ thermalManager.set_fan_speed(fan, fan_speed); TERN_(LASER_SYNCHRONOUS_M106_M107, planner.buffer_sync_block(BLOCK_BIT_SYNC_FANS));}); - break; + } break; + case FEEDRATE: ui.clear_for_drawing(); MenuItem_int3::action(GET_TEXT_F(MSG_SPEED), &feedrate_percentage, SPEED_EDIT_MIN, SPEED_EDIT_MAX); @@ -228,11 +235,10 @@ void Touch::touch(touch_control_t *control) { case FLOWRATE: ui.clear_for_drawing(); MenuItemBase::itemIndex = control->data; - #if EXTRUDERS == 1 - MenuItem_int3::action(GET_TEXT_F(MSG_FLOW), &planner.flow_percentage[MenuItemBase::itemIndex], FLOW_EDIT_MIN, FLOW_EDIT_MAX, []{ planner.refresh_e_factor(MenuItemBase::itemIndex); }); - #else - MenuItem_int3::action(GET_TEXT_F(MSG_FLOW_N), &planner.flow_percentage[MenuItemBase::itemIndex], FLOW_EDIT_MIN, FLOW_EDIT_MAX, []{ planner.refresh_e_factor(MenuItemBase::itemIndex); }); - #endif + MenuItem_int3::action(GET_TEXT_F(TERN(HAS_MULTI_EXTRUDER, MSG_FLOW_N, MSG_FLOW)), + &planner.flow_percentage[MenuItemBase::itemIndex], FLOW_EDIT_MIN, FLOW_EDIT_MAX, + []{ planner.refresh_e_factor(MenuItemBase::itemIndex); } + ); break; #endif diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index 87cb4cd21b..fe497058d9 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -236,6 +236,9 @@ float Planner::previous_nominal_speed; #if ENABLED(LIN_ADVANCE) float Planner::extruder_advance_K[DISTINCT_E]; // Initialized by settings.load + #if ENABLED(SMOOTH_LIN_ADVANCE) + uint32_t Planner::extruder_advance_K_q27[DISTINCT_E]; + #endif #endif #if HAS_POSITION_FLOAT @@ -2457,7 +2460,7 @@ bool Planner::_populate_block( block->acceleration_steps_per_s2 = accel; block->acceleration = accel / steps_per_mm; #if DISABLED(S_CURVE_ACCELERATION) - block->acceleration_rate = uint32_t(accel * (float(1UL << 24) / (STEPPER_TIMER_RATE))); + block->acceleration_rate = uint32_t(accel * (float(_BV32(24)) / (STEPPER_TIMER_RATE))); #endif #if HAS_ROUGH_LIN_ADVANCE @@ -2478,7 +2481,13 @@ bool Planner::_populate_block( } #elif ENABLED(SMOOTH_LIN_ADVANCE) block->use_advance_lead = use_advance_lead; - block->e_step_ratio = (block->direction_bits.e ? 1 : -1) * float(block->steps.e) / block->step_event_count; + const uint32_t ratio = (uint64_t(block->steps.e) * _BV32(30)) / block->step_event_count; + block->e_step_ratio_q30 = block->direction_bits.e ? ratio : -ratio; + + #if ENABLED(INPUT_SHAPING_E_SYNC) + const uint32_t xy_steps = TERN0(INPUT_SHAPING_X, block->steps.x) + TERN0(INPUT_SHAPING_Y, block->steps.y); + block->xy_length_inv_q30 = xy_steps ? (_BV32(30) / xy_steps) : 0; + #endif #endif // Formula for the average speed over a 1 step worth of distance if starting from zero and diff --git a/Marlin/src/module/planner.h b/Marlin/src/module/planner.h index 1c23f95cb1..ead39a8bd4 100644 --- a/Marlin/src/module/planner.h +++ b/Marlin/src/module/planner.h @@ -247,7 +247,10 @@ typedef struct PlannerBlock { #if ENABLED(SMOOTH_LIN_ADVANCE) uint32_t cruise_time; // Cruise time in STEP timer counts - float e_step_ratio; + int32_t e_step_ratio_q30; // Ratio of e steps to block steps. + #if ENABLED(INPUT_SHAPING_E_SYNC) + uint32_t xy_length_inv_q30; // inverse of block->steps.x + block.steps.y + #endif #endif #if ANY(S_CURVE_ACCELERATION, SMOOTH_LIN_ADVANCE) uint32_t cruise_rate, // The actual cruise rate to use, between end of the acceleration phase and start of deceleration phase @@ -359,9 +362,8 @@ typedef struct PlannerSettings { #if ENABLED(EDITABLE_STEPS_PER_UNIT) float axis_steps_per_mm[DISTINCT_AXES]; #else - #define _DLIM(I) ALIM(I, _dasu) - #define _DASU(N) _dasu[_DLIM(N)], - #define _EASU(N) _dasu[_DLIM(E_AXIS + N)], + #define _DASU(N) _dasu[ALIM(N, _dasu)], + #define _EASU(N) _dasu[ALIM(E_AXIS + N, _dasu)], static constexpr float axis_steps_per_mm[DISTINCT_AXES] = { REPEAT(NUM_AXES, _DASU) TERN_(HAS_EXTRUDERS, REPEAT(DISTINCT_E, _EASU)) @@ -526,6 +528,23 @@ class Planner { #if ENABLED(LIN_ADVANCE) static float extruder_advance_K[DISTINCT_E]; + static void set_advance_k(const_float_t k, const uint8_t e=active_extruder) { + UNUSED(e); + extruder_advance_K[E_INDEX_N(e)] = k; + #if ENABLED(SMOOTH_LIN_ADVANCE) + extruder_advance_K_q27[E_INDEX_N(e)] = k * (1UL << 27); + #endif + } + static float get_advance_k(const uint8_t e=active_extruder) { + UNUSED(e); + return extruder_advance_K[E_INDEX_N(e)]; + } + #if ENABLED(SMOOTH_LIN_ADVANCE) + static uint32_t get_advance_k_q27(const uint8_t e=active_extruder) { + UNUSED(e); + return extruder_advance_K_q27[E_INDEX_N(e)]; + } + #endif #endif /** @@ -602,6 +621,10 @@ class Planner { volatile static uint32_t block_buffer_runtime_us; // Theoretical block buffer runtime in µs #endif + #if ENABLED(SMOOTH_LIN_ADVANCE) + static uint32_t extruder_advance_K_q27[DISTINCT_E]; + #endif + public: /** diff --git a/Marlin/src/module/settings.cpp b/Marlin/src/module/settings.cpp index 1a46c6cc2a..59cb7244e9 100644 --- a/Marlin/src/module/settings.cpp +++ b/Marlin/src/module/settings.cpp @@ -126,7 +126,7 @@ #endif #if ENABLED(ADVANCE_K_EXTRA) - extern float other_extruder_advance_K[DISTINCT_E]; + extern float other_extruder_advance_K[EXTRUDERS]; #endif #if HAS_MULTI_EXTRUDER @@ -2641,18 +2641,14 @@ void MarlinSettings::postprocess() { _FIELD_TEST(planner_extruder_advance_K); EEPROM_READ(extruder_advance_K); if (!validating) - COPY(planner.extruder_advance_K, extruder_advance_K); + DISTINCT_E_LOOP() planner.set_advance_k(extruder_advance_K[e], e); + #if ENABLED(SMOOTH_LIN_ADVANCE) _FIELD_TEST(stepper_extruder_advance_tau); float tau[DISTINCT_E]; EEPROM_READ(tau); - if (!validating) { - #if ENABLED(DISTINCT_E_FACTORS) - EXTRUDER_LOOP() stepper.set_advance_tau(tau[e], e); - #else - stepper.set_advance_tau(tau[0]); - #endif - } + if (!validating) + DISTINCT_E_LOOP() stepper.set_advance_tau(tau[e], e); #endif } #endif @@ -3615,21 +3611,23 @@ void MarlinSettings::reset() { #if ENABLED(DISTINCT_E_FACTORS) constexpr float linAdvanceK[] = ADVANCE_K; - EXTRUDER_LOOP() { - const float a = linAdvanceK[ALIM(e, linAdvanceK)]; - planner.extruder_advance_K[e] = a; - TERN_(ADVANCE_K_EXTRA, other_extruder_advance_K[e] = a); - } - #else - planner.extruder_advance_K[0] = ADVANCE_K; - #endif - #if ENABLED(SMOOTH_LIN_ADVANCE) - #if ENABLED(DISTINCT_E_FACTORS) + #if ENABLED(SMOOTH_LIN_ADVANCE) constexpr float linAdvanceTau[] = ADVANCE_TAU; - EXTRUDER_LOOP() - stepper.set_advance_tau(linAdvanceTau[ALIM(e, linAdvanceTau)], e); - #else - stepper.set_advance_tau(ADVANCE_TAU); + #endif + + EXTRUDER_LOOP() { + const float k = linAdvanceK[ALIM(e, linAdvanceK)]; + planner.set_advance_k(k, e); + TERN_(SMOOTH_LIN_ADVANCE, stepper.set_advance_tau(linAdvanceTau[ALIM(e, linAdvanceTau)], e)); + TERN_(ADVANCE_K_EXTRA, other_extruder_advance_K[e] = k); + } + + #else // !DISTINCT_E_FACTORS + + planner.set_advance_k(ADVANCE_K); + TERN_(SMOOTH_LIN_ADVANCE, stepper.set_advance_tau(ADVANCE_TAU)); + #if ENABLED(ADVANCE_K_EXTRA) + EXTRUDER_LOOP() other_extruder_advance_K[e] = ADVANCE_K; #endif #endif diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp index e9f83aa532..04c796acb3 100644 --- a/Marlin/src/module/stepper.cpp +++ b/Marlin/src/module/stepper.cpp @@ -1510,6 +1510,10 @@ HAL_STEP_TIMER_ISR() { #define STEP_MULTIPLY(A,B) MultiU24X32toH16(A, B) #endif +#if ENABLED(SMOOTH_LIN_ADVANCE) + FORCE_INLINE static constexpr int32_t MULT_Q(uint8_t q, int32_t x, int32_t y) { return (int64_t(x) * y) >> q; } +#endif + void Stepper::isr() { static hal_timer_t nextMainISR = 0; // Interval until the next main Stepper Pulse phase (0 = Now) @@ -2877,9 +2881,9 @@ hal_timer_t Stepper::block_phase_isr() { #if ENABLED(SMOOTH_LIN_ADVANCE) - float Stepper::extruder_advance_tau[DISTINCT_E], - Stepper::extruder_advance_tau_ticks[DISTINCT_E], - Stepper::extruder_advance_alpha[DISTINCT_E]; + float Stepper::extruder_advance_tau[DISTINCT_E]; + uint32_t Stepper::extruder_advance_tau_ticks[DISTINCT_E], + Stepper::extruder_advance_alpha_q30[DISTINCT_E]; void Stepper::set_la_interval(const int32_t rate) { if (rate == 0) { @@ -2904,117 +2908,119 @@ hal_timer_t Stepper::block_phase_isr() { constexpr uint16_t IS_COMPENSATION_BUFFER_SIZE = uint16_t(float(SMOOTH_LIN_ADV_HZ) / float(SHAPING_MIN_FREQ) / 2.0f + 0.5f); typedef struct { - xy_float_t buffer[IS_COMPENSATION_BUFFER_SIZE]; + xy_long_t buffer[IS_COMPENSATION_BUFFER_SIZE]; uint16_t index; + FORCE_INLINE void add(const xy_long_t &input) { + buffer[index] = input; + if (++index == IS_COMPENSATION_BUFFER_SIZE) index = 0; + } + FORCE_INLINE xy_long_t past_item(const uint16_t n) { + const int16_t i = int16_t(index) - n; + return buffer[i >= 0 ? i : i + IS_COMPENSATION_BUFFER_SIZE]; + } } DelayBuffer; DelayBuffer delayBuffer; - void add_to_buffer(xy_float_t input) { - delayBuffer.buffer[delayBuffer.index++] = input; - if (delayBuffer.index == IS_COMPENSATION_BUFFER_SIZE) - delayBuffer.index = 0; - } - - xy_float_t lookback(shaping_time_t t /* in stepper timer ticks */) { - constexpr float ADV_TICKS_PER_STEPPER_TICKS = float(SMOOTH_LIN_ADV_HZ) / (STEPPER_TIMER_RATE); - uint32_t delay_steps = t * ADV_TICKS_PER_STEPPER_TICKS + 0.5f; // Convert time to steps - uint16_t past_i; - if (delay_steps>= IS_COMPENSATION_BUFFER_SIZE) { - // this means the buffer is too small. TODO: how to inform user? - past_i = delayBuffer.index; - } - else { - past_i = (delayBuffer.index + IS_COMPENSATION_BUFFER_SIZE - delay_steps) % IS_COMPENSATION_BUFFER_SIZE; - } - return delayBuffer.buffer[past_i]; + xy_long_t smooth_lin_adv_lookback(const shaping_time_t stepper_ticks) { + constexpr uint32_t ADV_TICKS_PER_STEPPER_TICKS_Q30 = (uint64_t(SMOOTH_LIN_ADV_HZ) * _BV32(30)) / STEPPER_TIMER_RATE; + const uint16_t delay_steps = MULT_Q(30, stepper_ticks, ADV_TICKS_PER_STEPPER_TICKS_Q30); + return delayBuffer.past_item(delay_steps); } #endif // INPUT_SHAPING_E_SYNC - float lookahead(uint32_t t) { + int32_t smooth_lin_adv_lookahead(uint32_t stepper_ticks) { for (uint8_t i = 0; block_t *block = planner.get_future_block(i); i++) { if (block->is_sync()) continue; - if (t <= block->acceleration_time) { - if (!block->use_advance_lead) return 0.0f; - uint32_t rate = STEP_MULTIPLY(t, block->acceleration_rate) + block->initial_rate; + if (stepper_ticks <= block->acceleration_time) { + if (!block->use_advance_lead) return 0; + uint32_t rate = STEP_MULTIPLY(stepper_ticks, block->acceleration_rate) + block->initial_rate; NOMORE(rate, block->nominal_rate); - return rate * block->e_step_ratio; + return MULT_Q(30, rate, block->e_step_ratio_q30); } - t -= block->acceleration_time; + stepper_ticks -= block->acceleration_time; - if (t <= block->cruise_time) { - if (!block->use_advance_lead) return 0.0f; - return block->cruise_rate * block->e_step_ratio; + if (stepper_ticks <= block->cruise_time) { + if (!block->use_advance_lead) return 0; + return MULT_Q(30, block->cruise_rate, block->e_step_ratio_q30); } - t -= block->cruise_time; + stepper_ticks -= block->cruise_time; - if (t <= block->deceleration_time) { - if (!block->use_advance_lead) return 0.0f; - uint32_t rate = STEP_MULTIPLY(t, block->acceleration_rate); + if (stepper_ticks <= block->deceleration_time) { + if (!block->use_advance_lead) return 0; + uint32_t rate = STEP_MULTIPLY(stepper_ticks, block->acceleration_rate); if (rate < block->cruise_rate) { rate = block->cruise_rate - rate; NOLESS(rate, block->final_rate); } else rate = block->final_rate; - return rate * block->e_step_ratio; + return MULT_Q(30, rate, block->e_step_ratio_q30); } - t -= block->deceleration_time; + stepper_ticks -= block->deceleration_time; } - return 0.0f; + return 0; } hal_timer_t Stepper::smooth_lin_adv_isr() { - float target_adv_steps = 0; + int32_t target_adv_steps = 0; if (current_block) { - const uint32_t t = extruder_advance_tau_ticks[0] + curr_timer_tick; - target_adv_steps = lookahead(t) * planner.extruder_advance_K[0]; + const uint32_t stepper_ticks = extruder_advance_tau_ticks[E_INDEX_N(active_extruder)] + curr_timer_tick; + target_adv_steps = MULT_Q(27, smooth_lin_adv_lookahead(stepper_ticks), planner.get_advance_k_q27()); } else { curr_step_rate = 0; } - static float last_target_adv_steps = 0; - constexpr float dt_inv = SMOOTH_LIN_ADV_HZ; - float la_step_rate = (target_adv_steps - last_target_adv_steps) * dt_inv; + static int32_t last_target_adv_steps = 0; + constexpr uint16_t dt_inv = SMOOTH_LIN_ADV_HZ; + int32_t la_step_rate = (target_adv_steps - last_target_adv_steps) * dt_inv; last_target_adv_steps = target_adv_steps; - static float smoothed_vals[SMOOTH_LIN_ADV_EXP_ORDER] = {0}; + static int32_t smoothed_vals[SMOOTH_LIN_ADV_EXP_ORDER] = {0}; + for (uint8_t i = 0; i < SMOOTH_LIN_ADV_EXP_ORDER; i++) { // Approximate gaussian smoothing via higher order exponential smoothing - la_step_rate = extruder_advance_alpha[0] * la_step_rate + (1 - extruder_advance_alpha[0]) * smoothed_vals[i]; - smoothed_vals[i] = la_step_rate; + smoothed_vals[i] += MULT_Q(30, la_step_rate - smoothed_vals[i], extruder_advance_alpha_q30[E_INDEX_N(active_extruder)]); + la_step_rate = smoothed_vals[i]; } - const float planned_step_rate = current_block ? curr_step_rate * current_block->e_step_ratio : 0; - float total_step_rate = la_step_rate + planned_step_rate; + + const int32_t planned_step_rate = current_block + ? MULT_Q(30, curr_step_rate, current_block->e_step_ratio_q30) + : 0; + + int32_t total_step_rate = la_step_rate + planned_step_rate; #if ENABLED(INPUT_SHAPING_E_SYNC) - xy_float_t pre_shaping_rate = xy_float_t({0, 0}), - first_pulse_rate = xy_float_t({0, 0}); - float unshaped_rate_e = total_step_rate; + xy_long_t pre_shaping_rate = xy_long_t({0, 0}), + first_pulse_rate = xy_long_t({0, 0}); + int32_t unshaped_rate_e = total_step_rate; if (current_block) { - const float xy_length = TERN0(INPUT_SHAPING_X, current_block->steps.x) + TERN0(INPUT_SHAPING_Y, current_block->steps.y); - if (xy_length > 0) { + if (current_block->xy_length_inv_q30 > 0) { unshaped_rate_e = 0; - pre_shaping_rate = xy_float_t({ - TERN0(INPUT_SHAPING_X, total_step_rate * current_block->steps.x / xy_length), - TERN0(INPUT_SHAPING_Y, total_step_rate * current_block->steps.y / xy_length) + + pre_shaping_rate = xy_long_t({ + TERN0(INPUT_SHAPING_X, MULT_Q(30, total_step_rate * current_block->steps.x, current_block->xy_length_inv_q30)), + TERN0(INPUT_SHAPING_Y, MULT_Q(30, total_step_rate * current_block->steps.y, current_block->xy_length_inv_q30)) }); - first_pulse_rate = xy_float_t({ - TERN0(INPUT_SHAPING_X, pre_shaping_rate.x * Stepper::shaping_x.factor1 / 128.0f), - TERN0(INPUT_SHAPING_Y, pre_shaping_rate.y * Stepper::shaping_y.factor1 / 128.0f) + + first_pulse_rate = xy_long_t({ + TERN0(INPUT_SHAPING_X, (pre_shaping_rate.x * Stepper::shaping_x.factor1) >> 7), + TERN0(INPUT_SHAPING_Y, (pre_shaping_rate.y * Stepper::shaping_y.factor1) >> 7) }); } } - const xy_float_t second_pulse_rate = { - TERN0(INPUT_SHAPING_X, lookback(ShapingQueue::get_delay_x()).x * Stepper::shaping_x.factor2 / 128.0f), - TERN0(INPUT_SHAPING_Y, lookback(ShapingQueue::get_delay_y()).y * Stepper::shaping_y.factor2 / 128.0f) - }; - add_to_buffer(pre_shaping_rate); - const float x = TERN0(INPUT_SHAPING_X, first_pulse_rate.x + second_pulse_rate.x), - y = TERN0(INPUT_SHAPING_Y, first_pulse_rate.y + second_pulse_rate.y); + const xy_long_t second_pulse_rate = { + TERN0(INPUT_SHAPING_X, (smooth_lin_adv_lookback(ShapingQueue::get_delay_x()).x * Stepper::shaping_x.factor2)) >> 7, + TERN0(INPUT_SHAPING_Y, (smooth_lin_adv_lookback(ShapingQueue::get_delay_y()).y * Stepper::shaping_y.factor2)) >> 7 + }; + + delayBuffer.add(pre_shaping_rate); + + const int32_t x = TERN0(INPUT_SHAPING_X, first_pulse_rate.x + second_pulse_rate.x), + y = TERN0(INPUT_SHAPING_Y, first_pulse_rate.y + second_pulse_rate.y); total_step_rate = unshaped_rate_e + x + y; @@ -3025,6 +3031,7 @@ hal_timer_t Stepper::block_phase_isr() { curr_timer_tick += SMOOTH_LIN_ADV_INTERVAL; return SMOOTH_LIN_ADV_INTERVAL; } + #endif // SMOOTH_LIN_ADVANCE // Timer interrupt for E. LA_steps is set in the main routine diff --git a/Marlin/src/module/stepper.h b/Marlin/src/module/stepper.h index 1c06d83351..3fb0b44884 100644 --- a/Marlin/src/module/stepper.h +++ b/Marlin/src/module/stepper.h @@ -352,13 +352,18 @@ class Stepper { #endif #if ENABLED(SMOOTH_LIN_ADVANCE) - static void set_advance_tau(const_float_t tau, const uint8_t e=E_INDEX_N(active_extruder)) { - extruder_advance_tau[e] = tau; - extruder_advance_tau_ticks[e] = tau * (STEPPER_TIMER_RATE); // i.e., <= STEPPER_TIMER_RATE / 2 + static float extruder_advance_tau[DISTINCT_E]; // Smoothing time; also the lookahead time of the smoother + static void set_advance_tau(const_float_t tau, const uint8_t e=active_extruder) { + const uint8_t i = E_INDEX_N(e); + extruder_advance_tau[i] = tau; + extruder_advance_tau_ticks[i] = tau * STEPPER_TIMER_RATE; // α=1−exp(−dt/τ) - extruder_advance_alpha[e] = 1.0f - expf(-(SMOOTH_LIN_ADV_INTERVAL) * (SMOOTH_LIN_ADV_EXP_ORDER) / extruder_advance_tau_ticks[e]); + const float alpha_float = 1.0f - expf(-float(SMOOTH_LIN_ADV_INTERVAL) * (SMOOTH_LIN_ADV_EXP_ORDER) / extruder_advance_tau_ticks[i]); + extruder_advance_alpha_q30[i] = int32_t(alpha_float * _BV32(30)); + } + static float get_advance_tau(const uint8_t e=active_extruder) { + return extruder_advance_tau[E_INDEX_N(e)]; } - static float get_advance_tau(const uint8_t e=E_INDEX_N(active_extruder)) { return extruder_advance_tau[e]; } #endif private: @@ -449,12 +454,11 @@ class Stepper { static hal_timer_t nextAdvanceISR, la_interval; // Interval between ISR calls for LA #if ENABLED(SMOOTH_LIN_ADVANCE) - static uint32_t curr_timer_tick, // Current tick relative to block start - curr_step_rate; // Current motion step rate - static float extruder_advance_tau[DISTINCT_E], // Smoothing time; also the lookahead time of the smoother - extruder_advance_tau_ticks[DISTINCT_E], // Same as extruder_advance_tau but in in stepper timer ticks - extruder_advance_alpha[DISTINCT_E]; // The smoothing factor of each stage of the high-order exponential - // smoothing filter (calculated from tau) + static uint32_t curr_timer_tick, // Current tick relative to block start + curr_step_rate; // Current motion step rate + static uint32_t extruder_advance_tau_ticks[DISTINCT_E], // Same as extruder_advance_tau but in in stepper timer ticks + extruder_advance_alpha_q30[DISTINCT_E]; // The smoothing factor of each stage of the high-order exponential + // smoothing filter (calculated from tau) #else static int32_t la_delta_error, // Analogue of delta_error.e for E steps in LA ISR la_dividend, // Analogue of advance_dividend.e for E steps in LA ISR diff --git a/Marlin/src/module/tool_change.cpp b/Marlin/src/module/tool_change.cpp index fcaa64cefe..980f9327b5 100644 --- a/Marlin/src/module/tool_change.cpp +++ b/Marlin/src/module/tool_change.cpp @@ -1587,7 +1587,7 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) { #endif // Migrate Linear Advance K factor to the new extruder - TERN_(LIN_ADVANCE, planner.extruder_advance_K[active_extruder] = planner.extruder_advance_K[migration_extruder]); + TERN_(LIN_ADVANCE, planner.set_advance_k(planner.get_advance_k(migration_extruder), active_extruder)); // Temporary migration toolchange_settings restored on exit. i.e., before next tool_change(). #if defined(MIGRATION_FS_EXTRA_PRIME) \ From 5a88a806909ca1c1942511d4e3c2bdcfbd3f02b1 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 13 May 2025 16:50:41 -0500 Subject: [PATCH 306/787] =?UTF-8?q?=F0=9F=9A=B8=20Extend=20M360=20(a=20Rep?= =?UTF-8?q?etier=20code)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/gcode/host/M360.cpp | 179 +++++++++++++++++++++------------ 1 file changed, 115 insertions(+), 64 deletions(-) diff --git a/Marlin/src/gcode/host/M360.cpp b/Marlin/src/gcode/host/M360.cpp index 63071f6113..a3f86d615d 100644 --- a/Marlin/src/gcode/host/M360.cpp +++ b/Marlin/src/gcode/host/M360.cpp @@ -22,6 +22,10 @@ #include "../../inc/MarlinConfig.h" +/** + * M360 Report Printer Configuration - Repetier Firmware + * See https://github.com/repetier/Repetier-Firmware/blob/master/src/ArduinoAVR/Repetier/Printer.cpp + */ #if ENABLED(REPETIER_GCODE_M360) #include "../gcode.h" @@ -33,74 +37,112 @@ #include "../../module/temperature.h" #endif -static void config_prefix(PGM_P const name, PGM_P const pref=nullptr, const int8_t ind=-1) { +#include + +struct ProgStr { + PGM_P ptr; + constexpr ProgStr(PGM_P p) : ptr(p) {} + ProgStr(FSTR_P f) : ptr(FTOP(f)) {} + ProgStr(std::nullptr_t) : ptr(nullptr) {} + + constexpr operator PGM_P() const { return ptr; } + constexpr explicit operator bool() const { return ptr != nullptr; } +}; + +static void config_prefix(ProgStr name, ProgStr pref=nullptr, int8_t ind=-1) { SERIAL_ECHOPGM("Config:"); - if (pref) SERIAL_ECHOPGM_P(pref); + if (pref) SERIAL_ECHOPGM_P(static_cast(pref)); if (ind >= 0) { SERIAL_ECHO(ind); SERIAL_CHAR(':'); } - SERIAL_ECHOPGM_P(name, C(':')); + SERIAL_ECHOPGM_P(static_cast(name), C(':')); } -static void config_line(PGM_P const name, const float val, PGM_P const pref=nullptr, const int8_t ind=-1) { + +template +static void config_line(ProgStr name, const T val, ProgStr pref=nullptr, int8_t ind=-1) { config_prefix(name, pref, ind); SERIAL_ECHOLN(val); } -static void config_line(FSTR_P const name, const float val, FSTR_P const pref=nullptr, const int8_t ind=-1) { - config_line(FTOP(name), val, FTOP(pref), ind); -} -static void config_line_e(const int8_t e, PGM_P const name, const float val) { + +template +static void config_line_e(int8_t e, ProgStr name, const T val) { config_line(name, val, PSTR("Extr."), e + 1); } -static void config_line_e(const int8_t e, FSTR_P const name, const float val) { - config_line_e(e, FTOP(name), val); -} - /** * M360: Report Firmware configuration * in RepRapFirmware-compatible format */ void GcodeSuite::M360() { - PGMSTR(X_STR, "X"); - PGMSTR(Y_STR, "Y"); - PGMSTR(Z_STR, "Z"); - #if ANY(CLASSIC_JERK, HAS_LINEAR_E_JERK) - PGMSTR(JERK_STR, "Jerk"); - #endif - // // Basics and Enabled items // config_line(F("Baudrate"), BAUDRATE); config_line(F("InputBuffer"), MAX_CMD_SIZE); config_line(F("PrintlineCache"), BUFSIZE); - config_line(F("MixingExtruder"), ENABLED(MIXING_EXTRUDER)); - config_line(F("SDCard"), ENABLED(HAS_MEDIA)); - config_line(F("Fan"), ENABLED(HAS_FAN)); - config_line(F("LCD"), ENABLED(HAS_DISPLAY)); + config_line(F("MixingExtruder"), bool(ENABLED(MIXING_EXTRUDER))); + config_line(F("SDCard"), bool(ENABLED(HAS_MEDIA))); + config_line(F("Fan"), bool(ENABLED(HAS_FAN))); + config_line(F("LCD"), bool(ENABLED(HAS_DISPLAY))); config_line(F("SoftwarePowerSwitch"), 1); - config_line(F("SupportLocalFilamentchange"), ENABLED(ADVANCED_PAUSE_FEATURE)); - config_line(F("CaseLights"), ENABLED(CASE_LIGHT_ENABLE)); - config_line(F("ZProbe"), ENABLED(HAS_BED_PROBE)); - config_line(F("Autolevel"), ENABLED(HAS_LEVELING)); - config_line(F("EEPROM"), ENABLED(EEPROM_SETTINGS)); + config_line(F("SupportLocalFilamentchange"), bool(ENABLED(ADVANCED_PAUSE_FEATURE))); + config_line(F("CaseLights"), bool(ENABLED(CASE_LIGHT_ENABLE))); + config_line(F("ZProbe"), bool(ENABLED(HAS_BED_PROBE))); + config_line(F("Autolevel"), bool(ENABLED(HAS_LEVELING))); + config_line(F("EEPROM"), bool(ENABLED(EEPROM_SETTINGS))); + + // + // Axis letters, in PROGMEM + // + #define _DEFINE_A_STR(Q) PGMSTR(Q##_STR, STR_##Q); + MAIN_AXIS_MAP(_DEFINE_A_STR); // // Homing Directions // PGMSTR(H_DIR_STR, "HomeDir"); - config_line(H_DIR_STR, X_HOME_DIR, X_STR); - config_line(H_DIR_STR, Y_HOME_DIR, Y_STR); - config_line(H_DIR_STR, Z_HOME_DIR, Z_STR); + #if X_HOME_DIR + config_line(H_DIR_STR, X_HOME_DIR, X_STR); + #endif + #if Y_HOME_DIR + config_line(H_DIR_STR, Y_HOME_DIR, Y_STR); + #endif + #if Z_HOME_DIR + config_line(H_DIR_STR, Z_HOME_DIR, Z_STR); + #endif + #if I_HOME_DIR + config_line(H_DIR_STR, I_HOME_DIR, I_STR); + #endif + #if J_HOME_DIR + config_line(H_DIR_STR, J_HOME_DIR, J_STR); + #endif + #if K_HOME_DIR + config_line(H_DIR_STR, K_HOME_DIR, K_STR); + #endif + #if U_HOME_DIR + config_line(H_DIR_STR, U_HOME_DIR, U_STR); + #endif + #if V_HOME_DIR + config_line(H_DIR_STR, V_HOME_DIR, V_STR); + #endif + #if W_HOME_DIR + config_line(H_DIR_STR, W_HOME_DIR, W_STR); + #endif + + #if ANY(CLASSIC_JERK, HAS_LINEAR_E_JERK) + PGMSTR(JERK_STR, "Jerk"); + #endif // // XYZ Axis Jerk // #if ENABLED(CLASSIC_JERK) - if (planner.max_jerk.x == planner.max_jerk.y) - config_line(F("XY"), planner.max_jerk.x, FPSTR(JERK_STR)); + #define _REPORT_JERK(Q) config_line(Q##_STR, planner.max_jerk.Q, JERK_STR); + if (TERN0(HAS_Y_AXIS, planner.max_jerk.x == planner.max_jerk.y)) + config_line(F("XY"), planner.max_jerk.x, JERK_STR); else { - config_line(X_STR, planner.max_jerk.x, JERK_STR); - config_line(Y_STR, planner.max_jerk.y, JERK_STR); + TERN_(HAS_X_AXIS, _REPORT_JERK(X)); + TERN_(HAS_Y_AXIS, _REPORT_JERK(Y)); } - config_line(Z_STR, planner.max_jerk.z, JERK_STR); + TERN_(HAS_Z_AXIS, config_line(Z_STR, planner.max_jerk.z, JERK_STR)); + SECONDARY_AXIS_MAP(_REPORT_JERK); #endif // @@ -112,53 +154,62 @@ void GcodeSuite::M360() { PGMSTR(UNRET_STR, "RetractionUndo"); PGMSTR(SPEED_STR, "Speed"); // M10 Retract with swap (long) moves - config_line(F("Length"), fwretract.settings.retract_length, FPSTR(RET_STR)); + config_line(F("Length"), fwretract.settings.retract_length, RET_STR); + config_line(F("LongLength"), fwretract.settings.swap_retract_length, RET_STR); config_line(SPEED_STR, fwretract.settings.retract_feedrate_mm_s, RET_STR); - config_line(F("ZLift"), fwretract.settings.retract_zraise, FPSTR(RET_STR)); - config_line(F("LongLength"), fwretract.settings.swap_retract_length, FPSTR(RET_STR)); + config_line(F("ZLift"), fwretract.settings.retract_zraise, RET_STR); // M11 Recover (undo) with swap (long) moves + config_line(F("ExtraLength"), fwretract.settings.retract_recover_extra, UNRET_STR); + config_line(F("ExtraLongLength"), fwretract.settings.swap_retract_recover_extra, UNRET_STR); config_line(SPEED_STR, fwretract.settings.retract_recover_feedrate_mm_s, UNRET_STR); - config_line(F("ExtraLength"), fwretract.settings.retract_recover_extra, FPSTR(UNRET_STR)); - config_line(F("ExtraLongLength"), fwretract.settings.swap_retract_recover_extra, FPSTR(UNRET_STR)); - config_line(F("LongSpeed"), fwretract.settings.swap_retract_recover_feedrate_mm_s, FPSTR(UNRET_STR)); + config_line(F("LongSpeed"), fwretract.settings.swap_retract_recover_feedrate_mm_s, UNRET_STR); #endif // // Workspace boundaries // - const xyz_pos_t dmin = { X_MIN_POS, Y_MIN_POS, Z_MIN_POS }, - dmax = { X_MAX_POS, Y_MAX_POS, Z_MAX_POS }; + const xyz_pos_t dmin = NUM_AXIS_ARRAY(X_MIN_POS, Y_MIN_POS, Z_MIN_POS, I_MIN_POS, J_MIN_POS, K_MIN_POS, U_MIN_POS, V_MIN_POS, W_MIN_POS), + dmax = NUM_AXIS_ARRAY(X_MAX_POS, Y_MAX_POS, Z_MAX_POS, I_MAX_POS, J_MAX_POS, K_MAX_POS, U_MAX_POS, V_MAX_POS, W_MAX_POS); xyz_pos_t cmin = dmin, cmax = dmax; apply_motion_limits(cmin); apply_motion_limits(cmax); const xyz_pos_t wmin = cmin.asLogical(), wmax = cmax.asLogical(); PGMSTR(MIN_STR, "Min"); + #define _REPORT_MIN(Q) config_line(MIN_STR, wmin.Q, Q##_STR); + MAIN_AXIS_MAP(_REPORT_MIN); + PGMSTR(MAX_STR, "Max"); + #define _REPORT_MAX(Q) config_line(MAX_STR, wmax.Q, Q##_STR); + MAIN_AXIS_MAP(_REPORT_MAX); + PGMSTR(SIZE_STR, "Size"); - config_line(MIN_STR, wmin.x, X_STR); - config_line(MIN_STR, wmin.y, Y_STR); - config_line(MIN_STR, wmin.z, Z_STR); - config_line(MAX_STR, wmax.x, X_STR); - config_line(MAX_STR, wmax.y, Y_STR); - config_line(MAX_STR, wmax.z, Z_STR); - config_line(SIZE_STR, wmax.x - wmin.x, X_STR); - config_line(SIZE_STR, wmax.y - wmin.y, Y_STR); - config_line(SIZE_STR, wmax.z - wmin.z, Z_STR); + #define _REPORT_SIZE(Q) config_line(SIZE_STR, wmax.Q - wmin.Q, Q##_STR); + MAIN_AXIS_MAP(_REPORT_SIZE); + + // + // Axis Steps per mm + // + PGMSTR(S_MM_STR, "Steps/mm"); + #define _REPORT_S_MM(Q) config_line(S_MM_STR, planner.settings.axis_steps_per_mm[_AXIS(Q)], Q##_STR); + MAIN_AXIS_MAP(_REPORT_S_MM); // // Print and Travel Acceleration // - #define _ACCEL(A,B) _MIN(planner.settings.max_acceleration_mm_per_s2[A##_AXIS], planner.settings.B) - PGMSTR(P_ACC_STR, "PrintAccel"); - PGMSTR(T_ACC_STR, "TravelAccel"); - config_line(P_ACC_STR, _ACCEL(X, acceleration), X_STR); - config_line(P_ACC_STR, _ACCEL(Y, acceleration), Y_STR); - config_line(P_ACC_STR, _ACCEL(Z, acceleration), Z_STR); - config_line(T_ACC_STR, _ACCEL(X, travel_acceleration), X_STR); - config_line(T_ACC_STR, _ACCEL(Y, travel_acceleration), Y_STR); - config_line(T_ACC_STR, _ACCEL(Z, travel_acceleration), Z_STR); + #define _ACCEL(Q,B) _MIN(planner.settings.max_acceleration_mm_per_s2[Q##_AXIS], planner.settings.B) + PGMSTR(P_ACC_STR, "PrintAccel"); + #define _REPORT_P_ACC(Q) config_line(P_ACC_STR, _ACCEL(Q, acceleration), Q##_STR); + MAIN_AXIS_MAP(_REPORT_P_ACC); + + PGMSTR(T_ACC_STR, "TravelAccel"); + #define _REPORT_T_ACC(Q) config_line(T_ACC_STR, _ACCEL(Q, travel_acceleration), Q##_STR); + MAIN_AXIS_MAP(_REPORT_T_ACC); + + // + // Printer Type + // config_prefix(PSTR("PrinterType")); SERIAL_ECHOLNPGM( TERN_(DELTA, "Delta") @@ -189,12 +240,12 @@ void GcodeSuite::M360() { #elif ENABLED(CLASSIC_JERK) config_line_e(e, JERK_STR, planner.max_jerk.e); #endif - config_line_e(e, F("MaxSpeed"), planner.settings.max_feedrate_mm_s[E_AXIS_N(e)]); config_line_e(e, F("Acceleration"), planner.settings.max_acceleration_mm_per_s2[E_AXIS_N(e)]); + config_line_e(e, F("MaxSpeed"), planner.settings.max_feedrate_mm_s[E_AXIS_N(e)]); config_line_e(e, F("Diameter"), TERN(NO_VOLUMETRICS, DEFAULT_NOMINAL_FILAMENT_DIA, planner.filament_size[e])); config_line_e(e, F("MaxTemp"), thermalManager.hotend_maxtemp[e]); } #endif } -#endif +#endif // REPETIER_GCODE_M360 From eaa836b6fc89835b1e18f3e92b2f646deff306e8 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 13 May 2025 16:51:48 -0500 Subject: [PATCH 307/787] =?UTF-8?q?=F0=9F=8E=A8=20May=2013=20code=20format?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/module/motion.h | 10 +++++----- Marlin/src/module/planner.h | 12 ++++++------ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Marlin/src/module/motion.h b/Marlin/src/module/motion.h index 18376cf773..4245331010 100644 --- a/Marlin/src/module/motion.h +++ b/Marlin/src/module/motion.h @@ -141,11 +141,11 @@ inline int8_t pgm_read_any(const int8_t *p) { return TERN(__IMXRT1062__, *p, pgm static const XYZval NAME##_P DEFS_PROGMEM = NUM_AXIS_ARRAY(X_##OPT, Y_##OPT, Z_##OPT, I_##OPT, J_##OPT, K_##OPT, U_##OPT, V_##OPT, W_##OPT); \ return pgm_read_any(&NAME##_P[axis]); \ } -XYZ_DEFS(float, base_min_pos, MIN_POS); -XYZ_DEFS(float, base_max_pos, MAX_POS); -XYZ_DEFS(float, base_home_pos, HOME_POS); -XYZ_DEFS(float, max_length, MAX_LENGTH); -XYZ_DEFS(int8_t, home_dir, HOME_DIR); +XYZ_DEFS(float, base_min_pos, MIN_POS); // base_min_pos(axis) +XYZ_DEFS(float, base_max_pos, MAX_POS); // base_max_pos(axis) +XYZ_DEFS(float, base_home_pos, HOME_POS); // base_home_pos(axis) +XYZ_DEFS(float, max_length, MAX_LENGTH); // max_length(axis) +XYZ_DEFS(int8_t, home_dir, HOME_DIR); // home_dir(axis) // Flags for rotational axes constexpr AxisFlags rotational{0 LOGICAL_AXIS_GANG( diff --git a/Marlin/src/module/planner.h b/Marlin/src/module/planner.h index ead39a8bd4..0a3a35d922 100644 --- a/Marlin/src/module/planner.h +++ b/Marlin/src/module/planner.h @@ -373,12 +373,12 @@ typedef struct PlannerSettings { #undef _DLIM #endif - feedRate_t max_feedrate_mm_s[DISTINCT_AXES]; // (mm/s) M203 XYZE - Max speeds - float acceleration, // (mm/s^2) M204 S - Normal acceleration. DEFAULT ACCELERATION for all printing moves. - retract_acceleration, // (mm/s^2) M204 R - Retract acceleration. Filament pull-back and push-forward while standing still in the other axes - travel_acceleration; // (mm/s^2) M204 T - Travel acceleration. DEFAULT ACCELERATION for all NON printing moves. - feedRate_t min_feedrate_mm_s, // (mm/s) M205 S - Minimum linear feedrate - min_travel_feedrate_mm_s; // (mm/s) M205 T - Minimum travel feedrate + feedRate_t max_feedrate_mm_s[DISTINCT_AXES]; // (mm/s) M203 XYZE - Max speeds + float acceleration, // (mm/s^2) M204 S - Normal acceleration. DEFAULT ACCELERATION for all printing moves. + retract_acceleration, // (mm/s^2) M204 R - Retract acceleration. Filament pull-back and push-forward while standing still in the other axes + travel_acceleration; // (mm/s^2) M204 T - Travel acceleration. DEFAULT ACCELERATION for all NON printing moves. + feedRate_t min_feedrate_mm_s, // (mm/s) M205 S - Minimum linear feedrate + min_travel_feedrate_mm_s; // (mm/s) M205 T - Minimum travel feedrate } planner_settings_t; #if ENABLED(IMPROVE_HOMING_RELIABILITY) From c8265d61d571ba20eacfb3a57587072d005746ec Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 13 May 2025 17:14:57 -0500 Subject: [PATCH 308/787] =?UTF-8?q?=F0=9F=9A=B8=20Include=20'R'=20in=20M20?= =?UTF-8?q?8=20report?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Followup to #21335 --- Marlin/src/feature/fwretract.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Marlin/src/feature/fwretract.cpp b/Marlin/src/feature/fwretract.cpp index fff2a1ed39..8944d2bd35 100644 --- a/Marlin/src/feature/fwretract.cpp +++ b/Marlin/src/feature/fwretract.cpp @@ -244,6 +244,7 @@ void FWRetract::M208_report() { " M208 S", LINEAR_UNIT(settings.retract_recover_extra) , " W", LINEAR_UNIT(settings.swap_retract_recover_extra) , " F", LINEAR_UNIT(MMS_TO_MMM(settings.retract_recover_feedrate_mm_s)) + , " R", LINEAR_UNIT(MMS_TO_MMM(settings.swap_retract_recover_feedrate_mm_s)) ); } From 7a841cd8cff5683fd318e84e30e0c652f8c85af8 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Wed, 14 May 2025 00:31:35 +0000 Subject: [PATCH 309/787] [cron] Bump distribution date (2025-05-14) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 3c4711b876..bc68976ee3 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-05-10" +//#define STRING_DISTRIBUTION_DATE "2025-05-14" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 64a498179d..75995aa92a 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-05-10" + #define STRING_DISTRIBUTION_DATE "2025-05-14" #endif /** From 10ecea62c189d4bd8a7158bfd1d1347add2bf217 Mon Sep 17 00:00:00 2001 From: ellensp <530024+ellensp@users.noreply.github.com> Date: Thu, 15 May 2025 06:54:48 +1200 Subject: [PATCH 310/787] =?UTF-8?q?=F0=9F=A9=B9=20Fix=20'PIN=5FEXIST'=20ty?= =?UTF-8?q?po=20(#27856)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/lcd/marlinui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/src/lcd/marlinui.cpp b/Marlin/src/lcd/marlinui.cpp index 28697affab..991a4f549c 100644 --- a/Marlin/src/lcd/marlinui.cpp +++ b/Marlin/src/lcd/marlinui.cpp @@ -1224,7 +1224,7 @@ void MarlinUI::init() { #ifdef NEOPIXEL_BKGD_INDEX_FIRST neo.set_background_off(); neo.show(); - #elif PIN_EXIST(LCD_BACKLIGHT) + #elif PIN_EXISTS(LCD_BACKLIGHT) WRITE(LCD_BACKLIGHT_PIN, LOW); // Backlight off #endif backlight_off_ms = 0; From 8f13c1ecb213afb2bb2d91e164061bdab3a5e1ef Mon Sep 17 00:00:00 2001 From: Giuliano <3684609+GMagician@users.noreply.github.com> Date: Wed, 14 May 2025 20:55:45 +0200 Subject: [PATCH 311/787] =?UTF-8?q?=F0=9F=8C=90=20Shorten=20Italian=20mess?= =?UTF-8?q?ages=20(#27855)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/lcd/language/language_it.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Marlin/src/lcd/language/language_it.h b/Marlin/src/lcd/language/language_it.h index 4bcde87859..0e8689cb0f 100644 --- a/Marlin/src/lcd/language/language_it.h +++ b/Marlin/src/lcd/language/language_it.h @@ -945,9 +945,9 @@ namespace LanguageWide_it { using namespace LanguageNarrow_it; #if LCD_WIDTH >= 20 || HAS_DWIN_E3V2 LSTR MSG_HOST_START_PRINT = _UxGT("Avvio stampa host"); - LSTR MSG_PRINTING_OBJECT = _UxGT("Sto stampando l'oggetto"); - LSTR MSG_CANCEL_OBJECT = _UxGT("Cancella l'oggetto"); - LSTR MSG_CANCEL_OBJECT_N = _UxGT("Cancella l'oggetto {"); + LSTR MSG_PRINTING_OBJECT = _UxGT("Stampa oggetto"); + LSTR MSG_CANCEL_OBJECT = _UxGT("Cancella oggetto"); + LSTR MSG_CANCEL_OBJECT_N = _UxGT("Cancella oggetto {"); LSTR MSG_CONTINUE_PRINT_JOB = _UxGT("Continua il job di stampa"); LSTR MSG_MEDIA_MENU = _UxGT("Selez.da supporto"); LSTR MSG_TURN_OFF = _UxGT("Spegni la stampante"); From 8e0f271f558b95a1f4993209cf92586693d7051d Mon Sep 17 00:00:00 2001 From: ellensp <530024+ellensp@users.noreply.github.com> Date: Thu, 15 May 2025 06:57:18 +1200 Subject: [PATCH 312/787] =?UTF-8?q?=F0=9F=94=A8=20ESP3DLib=20update=20for?= =?UTF-8?q?=20compatibility=20(#27851)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ini/features.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ini/features.ini b/ini/features.ini index e51ad0bda3..5bd955dd0a 100644 --- a/ini/features.ini +++ b/ini/features.ini @@ -378,7 +378,7 @@ HAS_SERVOS = build_src_filter=+ HAS_MICROSTEPS = build_src_filter=+ (ESP3D_)?WIFISUPPORT = esp32async/AsyncTCP@3.3.3, mathieucarbou/ESP Async WebServer@3.0.6 - ESP3DLib=https://github.com/luc-github/ESP3DLib/archive/dc0f3d96c6.zip + ESP3DLib=https://github.com/luc-github/ESP3DLib/archive/6d62f76c3f.zip arduinoWebSockets=links2004/WebSockets@2.3.4 luc-github/ESP32SSDP@1.1.1 lib_ignore=ESPAsyncTCP From 4a0b3d1c9b68b0c412e6bba5a03044b5d2ffacb5 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Wed, 14 May 2025 15:17:58 -0500 Subject: [PATCH 313/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Con?= =?UTF-8?q?solidate=20MIN/MAX/STOP=20endstop=20pin=20assign=20(#27839)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_3.h | 71 +++---------------- Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_4.h | 59 ++------------- Marlin/src/pins/lpc1768/pins_MKS_SGEN_L.h | 41 ++--------- Marlin/src/pins/lpc1769/pins_MKS_SGEN_L_V2.h | 41 ++--------- Marlin/src/pins/pins.h | 51 ------------- Marlin/src/pins/pins_postprocess.h | 60 +++++++++++++--- Marlin/src/pins/rambo/pins_EINSY_RAMBO.h | 24 ++++--- Marlin/src/pins/rambo/pins_EINSY_RETRO.h | 34 +++++---- Marlin/src/pins/ramps/pins_TRIGORILLA_14.h | 2 +- Marlin/src/pins/sam/pins_ARCHIM2.h | 16 ++--- Marlin/src/pins/stm32f1/pins_CHITU3D_V9.h | 4 +- Marlin/src/pins/stm32f1/pins_CREALITY_V521.h | 8 +-- Marlin/src/pins/stm32f4/pins_ARTILLERY_RUBY.h | 25 ++----- Marlin/src/pins/stm32f4/pins_BTT_GTR_V1_0.h | 32 +++------ .../pins/stm32f4/pins_BTT_OCTOPUS_V1_common.h | 59 ++------------- .../pins/stm32f4/pins_BTT_SKR_PRO_common.h | 41 ++--------- .../pins/stm32f4/pins_BTT_SKR_V2_0_common.h | 61 ++-------------- Marlin/src/pins/stm32f4/pins_I3DBEEZ9.h | 53 ++------------ .../src/pins/stm32f4/pins_MELLOW_FLY_E3_V2.h | 22 ++---- Marlin/src/pins/stm32f4/pins_MKS_SKIPR_V1_0.h | 50 +++---------- Marlin/src/pins/stm32f7/pins_REMRAM_V1.h | 57 +++++++++------ .../pins/stm32g0/pins_BTT_MANTA_M8P_common.h | 40 ++--------- Marlin/src/pins/stm32g0/pins_BTT_SKRAT_V1_0.h | 61 +++------------- .../src/pins/stm32h7/pins_BTT_KRAKEN_V1_0.h | 59 ++------------- .../pins/stm32h7/pins_BTT_MANTA_M8P_V2_0.h | 59 ++------------- .../pins/stm32h7/pins_BTT_OCTOPUS_MAX_EZ.h | 59 ++------------- .../stm32h7/pins_BTT_OCTOPUS_PRO_V1_common.h | 59 ++------------- .../pins/stm32h7/pins_BTT_SKR_V3_0_common.h | 64 +++-------------- 28 files changed, 257 insertions(+), 955 deletions(-) diff --git a/Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_3.h b/Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_3.h index e6b4baddaf..3afb7fe072 100644 --- a/Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_3.h +++ b/Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_3.h @@ -43,71 +43,18 @@ // // Limit Switches // -#ifdef X_STALL_SENSITIVITY - #ifndef X_STOP_PIN - #define X_STOP_PIN X_DIAG_PIN - #endif - #if X_HOME_TO_MIN - #ifndef X_MAX_PIN - #define X_MAX_PIN P1_28 // X+ - #endif - #else - #ifndef X_MIN_PIN - #define X_MIN_PIN P1_28 // X+ - #endif - #endif -#else - #ifndef X_MIN_PIN - #define X_MIN_PIN P1_29 // X- - #endif - #ifndef X_MAX_PIN - #define X_MAX_PIN P1_28 // X+ - #endif +#ifndef X_STOP_PIN + #define X_STOP_PIN X_DIAG_PIN #endif - -#ifdef Y_STALL_SENSITIVITY - #ifndef Y_STOP_PIN - #define Y_STOP_PIN Y_DIAG_PIN - #endif - #if Y_HOME_TO_MIN - #ifndef Y_MAX_PIN - #define Y_MAX_PIN P1_26 // Y+ - #endif - #else - #ifndef Y_MIN_PIN - #define Y_MIN_PIN P1_26 // Y+ - #endif - #endif -#else - #ifndef Y_MIN_PIN - #define Y_MIN_PIN P1_27 // Y- - #endif - #ifndef Y_MAX_PIN - #define Y_MAX_PIN P1_26 // Y+ - #endif +#define X_OTHR_PIN P1_28 // X+ +#ifndef Y_STOP_PIN + #define Y_STOP_PIN Y_DIAG_PIN #endif - -#ifdef Z_STALL_SENSITIVITY - #ifndef Z_STOP_PIN - #define Z_STOP_PIN Z_DIAG_PIN - #endif - #if Z_HOME_TO_MIN - #ifndef Z_MAX_PIN - #define Z_MAX_PIN P1_24 // Z+ - #endif - #else - #ifndef Z_MIN_PIN - #define Z_MIN_PIN P1_24 // Z+ - #endif - #endif -#else - #ifndef Z_MIN_PIN - #define Z_MIN_PIN P1_25 // Z- - #endif - #ifndef Z_MAX_PIN - #define Z_MAX_PIN P1_24 // Z+ - #endif +#define Y_OTHR_PIN P1_26 // Y+ +#ifndef Z_STOP_PIN + #define Z_STOP_PIN Z_DIAG_PIN #endif +#define Z_OTHR_PIN P1_24 // Z+ #define ONBOARD_ENDSTOPPULLUPS // Board has built-in pullups diff --git a/Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_4.h b/Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_4.h index 65718bbf45..dbb8210fd1 100644 --- a/Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_4.h +++ b/Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_4.h @@ -70,61 +70,14 @@ // // Limit Switches // -#ifdef X_STALL_SENSITIVITY - #define X_STOP_PIN X_DIAG_PIN - #if X_HOME_TO_MIN - #define X_MAX_PIN P1_26 // E0DET - #else - #define X_MIN_PIN P1_26 // E0DET - #endif -#elif ENABLED(X_DUAL_ENDSTOPS) - #ifndef X_MIN_PIN - #define X_MIN_PIN P1_29 // X-STOP - #endif - #ifndef X_MAX_PIN - #define X_MAX_PIN P1_26 // E0DET - #endif -#else - #define X_STOP_PIN P1_29 // X-STOP -#endif - -#ifdef Y_STALL_SENSITIVITY - #define Y_STOP_PIN Y_DIAG_PIN - #if Y_HOME_TO_MIN - #define Y_MAX_PIN P1_25 // E1DET - #else - #define Y_MIN_PIN P1_25 // E1DET - #endif -#elif ENABLED(Y_DUAL_ENDSTOPS) - #ifndef Y_MIN_PIN - #define Y_MIN_PIN P1_28 // Y-STOP - #endif - #ifndef Y_MAX_PIN - #define Y_MAX_PIN P1_25 // E1DET - #endif -#else - #define Y_STOP_PIN P1_28 // Y-STOP -#endif - -#ifdef Z_STALL_SENSITIVITY +#define X_STOP_PIN X_DIAG_PIN +#define X_OTHR_PIN P1_26 // E0DET +#define Y_STOP_PIN Y_DIAG_PIN +#define Y_OTHR_PIN P1_25 // E1DET +#ifndef Z_STOP_PIN #define Z_STOP_PIN Z_DIAG_PIN - #if Z_HOME_TO_MIN - #define Z_MAX_PIN P1_00 // PWRDET - #else - #define Z_MIN_PIN P1_00 // PWRDET - #endif -#elif ENABLED(Z_MULTI_ENDSTOPS) - #ifndef Z_MIN_PIN - #define Z_MIN_PIN P1_27 // Z-STOP - #endif - #ifndef Z_MAX_PIN - #define Z_MAX_PIN P1_00 // PWRDET - #endif -#else - #ifndef Z_STOP_PIN - #define Z_STOP_PIN P1_27 // Z-STOP - #endif #endif +#define Z_OTHR_PIN P1_00 // PWRDET // // Z Probe (when not Z_MIN_PIN) diff --git a/Marlin/src/pins/lpc1768/pins_MKS_SGEN_L.h b/Marlin/src/pins/lpc1768/pins_MKS_SGEN_L.h index 9b1258bec2..d3451665ac 100644 --- a/Marlin/src/pins/lpc1768/pins_MKS_SGEN_L.h +++ b/Marlin/src/pins/lpc1768/pins_MKS_SGEN_L.h @@ -51,41 +51,12 @@ // // Limit Switches // -#ifdef X_STALL_SENSITIVITY - #define X_STOP_PIN X_DIAG_PIN - #if X_HOME_TO_MIN - #define X_MAX_PIN P1_28 // X+ - #else - #define X_MIN_PIN P1_28 // X+ - #endif -#else - #define X_MIN_PIN P1_29 // X- - #define X_MAX_PIN P1_28 // X+ -#endif - -#ifdef Y_STALL_SENSITIVITY - #define Y_STOP_PIN Y_DIAG_PIN - #if Y_HOME_TO_MIN - #define Y_MAX_PIN P1_26 // Y+ - #else - #define Y_MIN_PIN P1_26 // Y+ - #endif -#else - #define Y_MIN_PIN P1_27 // Y- - #define Y_MAX_PIN P1_26 // Y+ -#endif - -#ifdef Z_STALL_SENSITIVITY - #define Z_STOP_PIN Z_DIAG_PIN - #if Z_HOME_TO_MIN - #define Z_MAX_PIN P1_24 // Z+ - #else - #define Z_MIN_PIN P1_24 // Z+ - #endif -#else - #define Z_MIN_PIN P1_25 // Z- - #define Z_MAX_PIN P1_24 // Z+ -#endif +#define X_STOP_PIN X_DIAG_PIN +#define X_OTHR_PIN P1_28 // X+ +#define Y_STOP_PIN Y_DIAG_PIN +#define Y_OTHR_PIN P1_26 // Y+ +#define Z_STOP_PIN Z_DIAG_PIN +#define Z_OTHR_PIN P1_24 // Z+ // // Z Probe (when not Z_MIN_PIN) diff --git a/Marlin/src/pins/lpc1769/pins_MKS_SGEN_L_V2.h b/Marlin/src/pins/lpc1769/pins_MKS_SGEN_L_V2.h index eb2f31cbcb..f98449ff53 100644 --- a/Marlin/src/pins/lpc1769/pins_MKS_SGEN_L_V2.h +++ b/Marlin/src/pins/lpc1769/pins_MKS_SGEN_L_V2.h @@ -59,41 +59,12 @@ // // Limit Switches // -#if X_STALL_SENSITIVITY - #define X_STOP_PIN X_DIAG_PIN - #if X_HOME_TO_MIN - #define X_MAX_PIN P1_28 // X+ - #else - #define X_MIN_PIN P1_28 // X+ - #endif -#else - #define X_MIN_PIN P1_29 // X- - #define X_MAX_PIN P1_28 // X+ -#endif - -#if Y_STALL_SENSITIVITY - #define Y_STOP_PIN Y_DIAG_PIN - #if Y_HOME_TO_MIN - #define Y_MAX_PIN P1_26 // Y+ - #else - #define Y_MIN_PIN P1_26 // Y+ - #endif -#else - #define Y_MIN_PIN P1_27 // Y- - #define Y_MAX_PIN P1_26 // Y+ -#endif - -#if Z_STALL_SENSITIVITY - #define Z_STOP_PIN Z_DIAG_PIN - #if Z_HOME_TO_MIN - #define Z_MAX_PIN P1_24 // Z+ - #else - #define Z_MIN_PIN P1_24 // Z+ - #endif -#else - #define Z_MIN_PIN P1_25 // Z- - #define Z_MAX_PIN P1_24 // Z+ -#endif +#define X_STOP_PIN X_DIAG_PIN // X- +#define X_OTHR_PIN P1_28 // X+ +#define Y_STOP_PIN Y_DIAG_PIN // Y- +#define Y_OTHR_PIN P1_26 // Y+ +#define Z_STOP_PIN Z_DIAG_PIN // Z- +#define Z_OTHR_PIN P1_24 // Z+ // // Z Probe (when not Z_MIN_PIN) diff --git a/Marlin/src/pins/pins.h b/Marlin/src/pins/pins.h index 7b2daae1ea..4a05b72a23 100644 --- a/Marlin/src/pins/pins.h +++ b/Marlin/src/pins/pins.h @@ -65,57 +65,6 @@ #define HAS_FREE_AUX2_PINS 1 #endif -// -// Check for additional used endstop pins -// -#ifndef X_MIN_PIN - #define X_MIN_PIN 1001 -#endif -#ifndef Y_MIN_PIN - #define Y_MIN_PIN 1002 -#endif -#ifndef Z_MIN_PIN - #define Z_MIN_PIN 1003 -#endif -#ifndef X_MAX_PIN - #define X_MAX_PIN 1004 -#endif -#ifndef Y_MAX_PIN - #define Y_MAX_PIN 1005 -#endif -#ifndef Z_MAX_PIN - #define Z_MAX_PIN 1006 -#endif -#define _ENDSTOP_IS_ANY(P) (HAS_EXTRA_ENDSTOPS && (X2_STOP_PIN == P || Y2_STOP_PIN == P || Z2_STOP_PIN == P || Z3_STOP_PIN == P || Z4_STOP_PIN == P)) -#if ENABLED(DUAL_X_CARRIAGE) || _ENDSTOP_IS_ANY(X_MIN_PIN) || _ENDSTOP_IS_ANY(X_MAX_PIN) - #define NEEDS_X_MINMAX 1 -#endif -#if _ENDSTOP_IS_ANY(Y_MIN_PIN) || _ENDSTOP_IS_ANY(Y_MAX_PIN) - #define NEEDS_Y_MINMAX 1 -#endif -#if _ENDSTOP_IS_ANY(Z_MIN_PIN) || _ENDSTOP_IS_ANY(Z_MAX_PIN) || ALL(Z_HOME_TO_MAX, Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN) - #define NEEDS_Z_MINMAX 1 -#endif -#undef _ENDSTOP_IS_ANY -#if X_MIN_PIN > 1000 - #undef X_MIN_PIN -#endif -#if Y_MIN_PIN > 1000 - #undef Y_MIN_PIN -#endif -#if Z_MIN_PIN > 1000 - #undef Z_MIN_PIN -#endif -#if X_MAX_PIN > 1000 - #undef X_MAX_PIN -#endif -#if Y_MAX_PIN > 1000 - #undef Y_MAX_PIN -#endif -#if Z_MAX_PIN > 1000 - #undef Z_MAX_PIN -#endif - // Test the target within the included pins file #ifdef __MARLIN_DEPS__ #define NOT_TARGET(V...) 0 diff --git a/Marlin/src/pins/pins_postprocess.h b/Marlin/src/pins/pins_postprocess.h index a18c099196..2c29cf4d8c 100644 --- a/Marlin/src/pins/pins_postprocess.h +++ b/Marlin/src/pins/pins_postprocess.h @@ -604,14 +604,30 @@ #define NUM_SERVO_PLUGS 0 #endif -// Only used within pins files -#undef NEEDS_X_MINMAX -#undef NEEDS_Y_MINMAX -#undef NEEDS_Z_MINMAX +/** + * Endstop Pins + * + * The general idea is to provide STOP and MIN|MAX pins as needed... + * + * - Standard Homing : X_STOP_PIN with alias X_(MIN|MAX)_PIN. Same for Y, Z, etc. + * - DUAL_X_CARRIAGE : Asserts both X_MIN_PIN and X_MAX_PIN must be defined. + * - X_DUAL_ENDSTOPS : Also define X2_STOP_PIN with alias X2_(MIN|MAX)_PIN. + * - Y_DUAL_ENDSTOPS : Also define Y2_STOP_PIN with alias Y2_(MIN|MAX)_PIN. + * - Z_MULTI_ENDSTOPS : Also define Z2_STOP_PIN with alias Z2_(MIN|MAX)_PIN. Same for Z3, Z4. + * + * Pins files should define pins according to usability: + * - Define X_STOP_PIN for boards with a preferred endstop plug, including Sensorless. + * - Define X_OTHR_PIN for the "other" endstop pin on the axis. + * - Define X_MIN_PIN and/or X_MAX_PIN as preferred connectors. + * - Allow user override of these pins for easier swapping. + * + * See also Conditionals-5-post.h >> "Endstop and probe flags" + */ // // Assign endstop pins, with handling for boards that have only 3 connectors // + #if HAS_X_AXIS #ifdef X_STOP_PIN #if X_HOME_TO_MIN @@ -624,8 +640,19 @@ #elif X_HOME_TO_MAX #define X_STOP_PIN X_MAX_PIN #endif - #if !defined(X2_STOP_PIN) && ENABLED(X_DUAL_ENDSTOPS) && PIN_EXISTS(X_STOP) - #define X2_STOP_PIN X_STOP_PIN + #if ENABLED(X_DUAL_ENDSTOPS) && PIN_EXISTS(X_STOP) + #ifndef X_MIN_PIN + #define X_MIN_PIN X_STOP_PIN + #endif + #ifndef X2_STOP_PIN + #define X2_STOP_PIN X_STOP_PIN + #endif + #endif + #if !defined(X_MIN_PIN) && X_HOME_TO_MAX && defined(X_OTHR_PIN) + #define X_MIN_PIN X_OTHR_PIN + #endif + #if !defined(X_MAX_PIN) && X_HOME_TO_MIN && defined(X_OTHR_PIN) + #define X_MAX_PIN X_OTHR_PIN #endif #endif @@ -641,8 +668,19 @@ #elif Y_HOME_TO_MAX #define Y_STOP_PIN Y_MAX_PIN #endif - #if !defined(Y2_STOP_PIN) && ENABLED(Y_DUAL_ENDSTOPS) && PIN_EXISTS(Y_STOP) - #define Y2_STOP_PIN Y_STOP_PIN + #if ENABLED(Y_DUAL_ENDSTOPS) && PIN_EXISTS(Y_STOP) + #ifndef Y_MIN_PIN + #define Y_MIN_PIN Y_STOP_PIN + #endif + #ifndef Y2_STOP_PIN + #define Y2_STOP_PIN Y_STOP_PIN + #endif + #endif + #if !defined(Y_MIN_PIN) && Y_HOME_TO_MAX && defined(Y_OTHR_PIN) + #define Y_MIN_PIN Y_OTHR_PIN + #endif + #if !defined(Y_MAX_PIN) && Y_HOME_TO_MIN && defined(Y_OTHR_PIN) + #define Y_MAX_PIN Y_OTHR_PIN #endif #endif @@ -654,6 +692,12 @@ #define Z_MAX_PIN Z_STOP_PIN #endif #endif + #if !defined(Z_MIN_PIN) && Z_HOME_TO_MAX && defined(Z_OTHR_PIN) + #define Z_MIN_PIN Z_OTHR_PIN + #endif + #if !defined(Z_MAX_PIN) && Z_HOME_TO_MIN && defined(Z_OTHR_PIN) + #define Z_MAX_PIN Z_OTHR_PIN + #endif #if ENABLED(Z_MULTI_ENDSTOPS) #if ((Z_HOME_TO_MIN && !defined(Z2_MIN_PIN)) || (Z_HOME_TO_MAX && !defined(Z2_MAX_PIN))) && !defined(Z2_STOP_PIN) #error "Z2_STOP_PIN is required for Z_MULTI_ENDSTOPS. Define Z2_STOP_PIN in Configuration_adv.h." diff --git a/Marlin/src/pins/rambo/pins_EINSY_RAMBO.h b/Marlin/src/pins/rambo/pins_EINSY_RAMBO.h index 98a16764af..ff36b4ac54 100644 --- a/Marlin/src/pins/rambo/pins_EINSY_RAMBO.h +++ b/Marlin/src/pins/rambo/pins_EINSY_RAMBO.h @@ -40,7 +40,9 @@ #error "For EinsyRambo you must set all *_DRIVER_TYPE to TMC2130 in Configuration.h." #endif -// TMC2130 Diag Pins (currently just for reference) +// +// Trinamic TMC2130 distinct DIAG pins +// #define X_DIAG_PIN 64 #define Y_DIAG_PIN 69 #define Z_DIAG_PIN 68 @@ -55,31 +57,31 @@ // SERVO0_PIN and Z_MIN_PIN configuration for BLTOUCH sensor when combined with SENSORLESS_HOMING. // -#if DISABLED(SENSORLESS_HOMING) - - #define X_STOP_PIN 12 - #define Y_STOP_PIN 11 - #define Z_STOP_PIN 10 - -#else +#if ENABLED(SENSORLESS_HOMING) #define X_STOP_PIN X_DIAG_PIN #define Y_STOP_PIN Y_DIAG_PIN #if ENABLED(BLTOUCH) + #define SERVO0_PIN 10 // PROBE-S #define Z_STOP_PIN 11 // Y-MIN - #define SERVO0_PIN 10 // Z-MIN #else - #define Z_STOP_PIN 10 + #define Z_STOP_PIN 10 // PROBE-S #endif +#else + + #define X_STOP_PIN 12 // X-MIN + #define Y_STOP_PIN 11 // Y-MIN + #define Z_STOP_PIN 10 // PROBE-S + #endif // // Z Probe (when not Z_MIN_PIN) // #ifndef Z_MIN_PROBE_PIN - #define Z_MIN_PROBE_PIN 10 + #define Z_MIN_PROBE_PIN 10 // PROBE-S #endif // diff --git a/Marlin/src/pins/rambo/pins_EINSY_RETRO.h b/Marlin/src/pins/rambo/pins_EINSY_RETRO.h index ca681b8174..99cee17cc1 100644 --- a/Marlin/src/pins/rambo/pins_EINSY_RETRO.h +++ b/Marlin/src/pins/rambo/pins_EINSY_RETRO.h @@ -53,29 +53,20 @@ // SERVO0_PIN and Z_MIN_PIN configuration for BLTOUCH sensor when combined with SENSORLESS_HOMING. // -#if DISABLED(SENSORLESS_HOMING) - - #define X_MIN_PIN 12 // X- - #define Y_MIN_PIN 11 // Y- - #define X_MAX_PIN 81 // X+ - #define Y_MAX_PIN 57 // Y+ - -#else +#if ENABLED(SENSORLESS_HOMING) + #define X_STOP_PIN X_DIAG_PIN #if X_HOME_TO_MIN - #define X_MIN_PIN X_DIAG_PIN - #define X_MAX_PIN 81 // X+ + #define X_OTHR_PIN 81 // X+ #else - #define X_MIN_PIN 12 // X- - #define X_MAX_PIN X_DIAG_PIN + #define X_OTHR_PIN 12 // X- #endif + #define Y_STOP_PIN Y_DIAG_PIN #if Y_HOME_TO_MIN - #define Y_MIN_PIN Y_DIAG_PIN - #define Y_MAX_PIN 57 // Y+ + #define Y_OTHR_PIN 57 // Y+ #else - #define Y_MIN_PIN 11 // Y- - #define Y_MAX_PIN Y_DIAG_PIN + #define Y_OTHR_PIN 11 // Y- #endif #if ENABLED(BLTOUCH) @@ -83,9 +74,16 @@ #define SERVO0_PIN 10 // Z- #endif +#else + + #define X_MIN_PIN 12 // X- + #define Y_MIN_PIN 11 // Y- + #define X_MAX_PIN 81 // X+ + #define Y_MAX_PIN 57 // Y+ + #endif -#define Z_MAX_PIN 7 +#define Z_MAX_PIN 7 // Z+ #ifndef Z_MIN_PIN #define Z_MIN_PIN 10 // Z- #endif @@ -94,7 +92,7 @@ // Z Probe (when not Z_MIN_PIN) // #ifndef Z_MIN_PROBE_PIN - #define Z_MIN_PROBE_PIN 10 + #define Z_MIN_PROBE_PIN 10 // Z- #endif // diff --git a/Marlin/src/pins/ramps/pins_TRIGORILLA_14.h b/Marlin/src/pins/ramps/pins_TRIGORILLA_14.h index d3c921a5f6..7c01c8aba8 100644 --- a/Marlin/src/pins/ramps/pins_TRIGORILLA_14.h +++ b/Marlin/src/pins/ramps/pins_TRIGORILLA_14.h @@ -120,7 +120,7 @@ #define Y_STOP_PIN 42 // AUX (1) #define Z_STOP_PIN 43 // AUX (2) #ifndef Z2_STOP_PIN - #define Z2_STOP_PIN 18 // Z- + #define Z2_STOP_PIN 18 // Z- #endif #ifndef Z_MIN_PROBE_PIN diff --git a/Marlin/src/pins/sam/pins_ARCHIM2.h b/Marlin/src/pins/sam/pins_ARCHIM2.h index 2d0a42c03d..38722326cd 100644 --- a/Marlin/src/pins/sam/pins_ARCHIM2.h +++ b/Marlin/src/pins/sam/pins_ARCHIM2.h @@ -71,20 +71,18 @@ #define E0_DIAG_PIN 78 // PB23 #define E1_DIAG_PIN 25 // PD0 + #define X_STOP_PIN X_DIAG_PIN #if X_HOME_TO_MIN - #define X_MIN_PIN X_DIAG_PIN - #define X_MAX_PIN 32 + #define X_OTHR_PIN 32 // PD10 MAX ES1 #else - #define X_MIN_PIN 14 - #define X_MAX_PIN X_DIAG_PIN + #define X_OTHR_PIN 14 // PD4 MIN ES1 #endif + #define Y_STOP_PIN Y_DIAG_PIN #if Y_HOME_TO_MIN - #define Y_MIN_PIN Y_DIAG_PIN - #define Y_MAX_PIN 15 + #define Y_OTHR_PIN 15 // PD5 MAX ES2 #else - #define Y_MIN_PIN 29 - #define Y_MAX_PIN Y_DIAG_PIN + #define Y_OTHR_PIN 29 // PD6 MIN ES2 #endif #else @@ -103,7 +101,7 @@ // Z Probe (when not Z_MIN_PIN) // #ifndef Z_MIN_PROBE_PIN - #define Z_MIN_PROBE_PIN 32 + #define Z_MIN_PROBE_PIN 32 // PD10 MAX ES1 #endif // diff --git a/Marlin/src/pins/stm32f1/pins_CHITU3D_V9.h b/Marlin/src/pins/stm32f1/pins_CHITU3D_V9.h index 0d02e1d5d9..7c6b75a082 100755 --- a/Marlin/src/pins/stm32f1/pins_CHITU3D_V9.h +++ b/Marlin/src/pins/stm32f1/pins_CHITU3D_V9.h @@ -23,11 +23,11 @@ #define BOARD_INFO_NAME "Chitu3D V9" -#define Z_STOP_PIN PA14 - #define Z2_ENABLE_PIN PF3 #define Z2_STEP_PIN PF5 #define Z2_DIR_PIN PF1 + +#define Z_STOP_PIN PA14 #define Z2_STOP_PIN PA13 #ifndef Z_MIN_PROBE_PIN diff --git a/Marlin/src/pins/stm32f1/pins_CREALITY_V521.h b/Marlin/src/pins/stm32f1/pins_CREALITY_V521.h index 60a0062621..0717506fff 100644 --- a/Marlin/src/pins/stm32f1/pins_CREALITY_V521.h +++ b/Marlin/src/pins/stm32f1/pins_CREALITY_V521.h @@ -67,11 +67,11 @@ // // Limit Switches // -#define X_STOP_PIN PD10 // X -#define X2_STOP_PIN PE15 // X2 +#define X_MIN_PIN PD10 // X +#define X_MAX_PIN PE15 // X2 #define Y_STOP_PIN PE0 // Y -#define Z_STOP_PIN PE1 // Z -#define Z2_STOP_PIN PE2 // Z2 +#define Z_MIN_PIN PE1 // Z +#define Z_MAX_PIN PE2 // Z2 #ifndef Z_MIN_PROBE_PIN #define Z_MIN_PROBE_PIN PD12 // BLTouch IN diff --git a/Marlin/src/pins/stm32f4/pins_ARTILLERY_RUBY.h b/Marlin/src/pins/stm32f4/pins_ARTILLERY_RUBY.h index 8b60b234cd..6dd25ad464 100644 --- a/Marlin/src/pins/stm32f4/pins_ARTILLERY_RUBY.h +++ b/Marlin/src/pins/stm32f4/pins_ARTILLERY_RUBY.h @@ -40,27 +40,10 @@ // // Limit Switches // -#if (X_HOME_DIR == 1) - #define X_MIN_PIN -1 - #define X_MAX_PIN PA2 -#else - #define X_MIN_PIN PA2 - #define X_MAX_PIN -1 -#endif -#if (Y_HOME_DIR == 1) - #define Y_MIN_PIN -1 - #define Y_MAX_PIN PA1 -#else - #define Y_MIN_PIN PA1 - #define Y_MAX_PIN -1 -#endif -#if (Z_HOME_DIR == 1) - #define Z_MIN_PIN PC2 - #define Z_MAX_PIN PA0 -#else - #define Z_MIN_PIN PA0 - #define Z_MAX_PIN PC2 -#endif +#define X_STOP_PIN PA2 +#define Y_STOP_PIN PA1 +#define Z_STOP_PIN PA0 +#define Z_OTHR_PIN PC2 // // Steppers diff --git a/Marlin/src/pins/stm32f4/pins_BTT_GTR_V1_0.h b/Marlin/src/pins/stm32f4/pins_BTT_GTR_V1_0.h index be98edd605..1d3975ab8f 100644 --- a/Marlin/src/pins/stm32f4/pins_BTT_GTR_V1_0.h +++ b/Marlin/src/pins/stm32f4/pins_BTT_GTR_V1_0.h @@ -68,38 +68,24 @@ // #ifdef X_STALL_SENSITIVITY #define X_STOP_PIN X_DIAG_PIN - #if X_HOME_TO_MIN - #define X_MAX_PIN E0_DIAG_PIN // X+ - #else - #define X_MIN_PIN E0_DIAG_PIN // X+ - #endif + #define X_OTHR_PIN PG14 // X+ #else - #define X_MIN_PIN X_DIAG_PIN // X- - #define X_MAX_PIN E0_DIAG_PIN // X+ + #define X_MIN_PIN PF2 // X- + #define X_MAX_PIN PG14 // X+ #endif - #ifdef Y_STALL_SENSITIVITY #define Y_STOP_PIN Y_DIAG_PIN - #if Y_HOME_TO_MIN - #define Y_MAX_PIN E1_DIAG_PIN // Y+ - #else - #define Y_MIN_PIN E1_DIAG_PIN // Y+ - #endif + #define Y_OTHR_PIN PG9 // Y+ #else - #define Y_MIN_PIN Y_DIAG_PIN // Y- - #define Y_MAX_PIN E1_DIAG_PIN // Y+ + #define Y_MIN_PIN PC13 // Y- + #define Y_MAX_PIN PG9 // Y+ #endif - #ifdef Z_STALL_SENSITIVITY #define Z_STOP_PIN Z_DIAG_PIN - #if Z_HOME_TO_MIN - #define Z_MAX_PIN E2_DIAG_PIN // Z+ - #else - #define Z_MIN_PIN E2_DIAG_PIN // Z+ - #endif + #define Z_OTHR_PIN PD3 // Z+ #else - #define Z_MIN_PIN Z_DIAG_PIN // Z- - #define Z_MAX_PIN E2_DIAG_PIN // Z+ + #define Z_MIN_PIN PE0 // Z- + #define Z_MAX_PIN PD3 // Z+ #endif // diff --git a/Marlin/src/pins/stm32f4/pins_BTT_OCTOPUS_V1_common.h b/Marlin/src/pins/stm32f4/pins_BTT_OCTOPUS_V1_common.h index ac96042b23..9388c8a1f4 100644 --- a/Marlin/src/pins/stm32f4/pins_BTT_OCTOPUS_V1_common.h +++ b/Marlin/src/pins/stm32f4/pins_BTT_OCTOPUS_V1_common.h @@ -65,59 +65,12 @@ // // Limit Switches // -#ifdef X_STALL_SENSITIVITY - #define X_STOP_PIN X_DIAG_PIN - #if X_HOME_TO_MIN - #define X_MAX_PIN E0_DIAG_PIN // E0DET - #else - #define X_MIN_PIN E0_DIAG_PIN // E0DET - #endif -#elif NEEDS_X_MINMAX - #ifndef X_MIN_PIN - #define X_MIN_PIN X_DIAG_PIN // X-STOP - #endif - #ifndef X_MAX_PIN - #define X_MAX_PIN E0_DIAG_PIN // E0DET - #endif -#else - #define X_STOP_PIN X_DIAG_PIN // X-STOP -#endif - -#ifdef Y_STALL_SENSITIVITY - #define Y_STOP_PIN Y_DIAG_PIN - #if Y_HOME_TO_MIN - #define Y_MAX_PIN E1_DIAG_PIN // E1DET - #else - #define Y_MIN_PIN E1_DIAG_PIN // E1DET - #endif -#elif NEEDS_Y_MINMAX - #ifndef Y_MIN_PIN - #define Y_MIN_PIN Y_DIAG_PIN // Y-STOP - #endif - #ifndef Y_MAX_PIN - #define Y_MAX_PIN E1_DIAG_PIN // E1DET - #endif -#else - #define Y_STOP_PIN Y_DIAG_PIN // Y-STOP -#endif - -#ifdef Z_STALL_SENSITIVITY - #define Z_STOP_PIN Z_DIAG_PIN - #if Z_HOME_TO_MIN - #define Z_MAX_PIN E2_DIAG_PIN // PWRDET - #else - #define Z_MIN_PIN E2_DIAG_PIN // PWRDET - #endif -#elif NEEDS_Z_MINMAX - #ifndef Z_MIN_PIN - #define Z_MIN_PIN Z_DIAG_PIN // Z-STOP - #endif - #ifndef Z_MAX_PIN - #define Z_MAX_PIN E2_DIAG_PIN // PWRDET - #endif -#else - #define Z_STOP_PIN Z_DIAG_PIN // Z-STOP -#endif +#define X_STOP_PIN X_DIAG_PIN // X-STOP +#define Y_STOP_PIN Y_DIAG_PIN // Y-STOP +#define Z_STOP_PIN Z_DIAG_PIN // Z-STOP +#define X_OTHR_PIN E0_DIAG_PIN // E0DET +#define Y_OTHR_PIN E1_DIAG_PIN // E1DET +#define Z_OTHR_PIN E2_DIAG_PIN // E2DET // // Z Probe (when not Z_MIN_PIN) diff --git a/Marlin/src/pins/stm32f4/pins_BTT_SKR_PRO_common.h b/Marlin/src/pins/stm32f4/pins_BTT_SKR_PRO_common.h index 943c0ed761..5b42a05c70 100644 --- a/Marlin/src/pins/stm32f4/pins_BTT_SKR_PRO_common.h +++ b/Marlin/src/pins/stm32f4/pins_BTT_SKR_PRO_common.h @@ -70,41 +70,12 @@ // // Limit Switches // -#ifdef X_STALL_SENSITIVITY - #define X_STOP_PIN X_DIAG_PIN - #if X_HOME_TO_MIN - #define X_MAX_PIN PE15 // E0 - #else - #define X_MIN_PIN PE15 // E0 - #endif -#else - #define X_MIN_PIN PB10 // X- - #define X_MAX_PIN PE15 // E0 -#endif - -#ifdef Y_STALL_SENSITIVITY - #define Y_STOP_PIN Y_DIAG_PIN - #if Y_HOME_TO_MIN - #define Y_MAX_PIN PE10 // E1 - #else - #define Y_MIN_PIN PE10 // E1 - #endif -#else - #define Y_MIN_PIN PE12 // Y- - #define Y_MAX_PIN PE10 // E1 -#endif - -#ifdef Z_STALL_SENSITIVITY - #define Z_STOP_PIN Z_DIAG_PIN - #if Z_HOME_TO_MIN - #define Z_MAX_PIN PG5 // E2 - #else - #define Z_MIN_PIN PG5 // E2 - #endif -#else - #define Z_MIN_PIN PG8 // Z- - #define Z_MAX_PIN PG5 // E2 -#endif +#define X_STOP_PIN X_DIAG_PIN // X- +#define Y_STOP_PIN Y_DIAG_PIN // Y- +#define Z_STOP_PIN Z_DIAG_PIN // Z- +#define X_OTHR_PIN PE15 // E0 +#define Y_OTHR_PIN PE10 // E1 +#define Z_OTHR_PIN PG5 // E2 // // Z Probe must be this pin diff --git a/Marlin/src/pins/stm32f4/pins_BTT_SKR_V2_0_common.h b/Marlin/src/pins/stm32f4/pins_BTT_SKR_V2_0_common.h index 51b27efa39..fa0e1ed516 100644 --- a/Marlin/src/pins/stm32f4/pins_BTT_SKR_V2_0_common.h +++ b/Marlin/src/pins/stm32f4/pins_BTT_SKR_V2_0_common.h @@ -71,61 +71,12 @@ // // Limit Switches // -#ifdef X_STALL_SENSITIVITY - #define X_STOP_PIN X_DIAG_PIN - #if X_HOME_TO_MIN - #define X_MAX_PIN PC2 // E0DET - #else - #define X_MIN_PIN PC2 // E0DET - #endif -#elif ENABLED(X_DUAL_ENDSTOPS) - #ifndef X_MIN_PIN - #define X_MIN_PIN PC1 // X-STOP - #endif - #ifndef X_MAX_PIN - #define X_MAX_PIN PC2 // E0DET - #endif -#else - #define X_STOP_PIN PC1 // X-STOP -#endif - -#ifdef Y_STALL_SENSITIVITY - #define Y_STOP_PIN Y_DIAG_PIN - #if Y_HOME_TO_MIN - #define Y_MAX_PIN PA0 // E1DET - #else - #define Y_MIN_PIN PA0 // E1DET - #endif -#elif ENABLED(Y_DUAL_ENDSTOPS) - #ifndef Y_MIN_PIN - #define Y_MIN_PIN PC3 // Y-STOP - #endif - #ifndef Y_MAX_PIN - #define Y_MAX_PIN PA0 // E1DET - #endif -#else - #define Y_STOP_PIN PC3 // Y-STOP -#endif - -#ifdef Z_STALL_SENSITIVITY - #define Z_STOP_PIN Z_DIAG_PIN - #if Z_HOME_TO_MIN - #define Z_MAX_PIN PC15 // PWRDET - #else - #define Z_MIN_PIN PC15 // PWRDET - #endif -#elif ENABLED(Z_MULTI_ENDSTOPS) - #ifndef Z_MIN_PIN - #define Z_MIN_PIN PC0 // Z-STOP - #endif - #ifndef Z_MAX_PIN - #define Z_MAX_PIN PC15 // PWRDET - #endif -#else - #ifndef Z_STOP_PIN - #define Z_STOP_PIN PC0 // Z-STOP - #endif -#endif +#define X_STOP_PIN X_DIAG_PIN // X-STOP +#define Y_STOP_PIN Y_DIAG_PIN // Y-STOP +#define Z_STOP_PIN Z_DIAG_PIN // Z-STOP +#define X_OTHR_PIN PC2 // E0DET +#define Y_OTHR_PIN PA0 // E1DET +#define Z_OTHR_PIN PC15 // PWRDET // // Z Probe (when not Z_MIN_PIN) diff --git a/Marlin/src/pins/stm32f4/pins_I3DBEEZ9.h b/Marlin/src/pins/stm32f4/pins_I3DBEEZ9.h index 1620c86bed..13dc536cfa 100644 --- a/Marlin/src/pins/stm32f4/pins_I3DBEEZ9.h +++ b/Marlin/src/pins/stm32f4/pins_I3DBEEZ9.h @@ -77,53 +77,12 @@ // // Limit Switches // -#ifdef X_STALL_SENSITIVITY - #define X_STOP_PIN X_DIAG_PIN - #if X_HOME_TO_MIN - #define X_MAX_PIN PE15 // E0 - #else - #define X_MIN_PIN PE15 // E0 - #endif -#else - #define X_MIN_PIN PB10 // X- - #define X_MAX_PIN PE15 // E0 -#endif - -#ifdef Y_STALL_SENSITIVITY - #define Y_STOP_PIN Y_DIAG_PIN - #if Y_HOME_TO_MIN - #define Y_MAX_PIN PE10 // E1 - #else - #define Y_MIN_PIN PE10 // E1 - #endif -#else - #define Y_MIN_PIN PE12 // Y- - #define Y_MAX_PIN PE10 // E1 -#endif - -#ifdef Z_STALL_SENSITIVITY - #define Z_STOP_PIN Z_DIAG_PIN - #if Z_HOME_TO_MIN - #define Z_MAX_PIN PG5 // E2 - #else - #define Z_MIN_PIN PG5 // E2 - #endif -#else - #define Z_MIN_PIN PG8 // Z- - #define Z_MAX_PIN PG5 // E2 -#endif - -#ifdef Z2_STALL_SENSITIVITY - #define Z2_STOP_PIN E1_DIAG_PIN - #if Z2_HOME_TO_MIN - #define Z2_MAX_PIN PD0 // E3 - #else - #define Z2_MIN_PIN PD0 // E3 - #endif -#else - #define Z2_MIN_PIN PD0 // Z2- [E3] - #define Z2_MAX_PIN PD6 // E4 -#endif +#define X_STOP_PIN X_DIAG_PIN // X- +#define Y_STOP_PIN Y_DIAG_PIN // Y- +#define Z_STOP_PIN Z_DIAG_PIN // Z- +#define X_OTHR_PIN PE15 // E0 +#define Y_OTHR_PIN PE10 // E1 +#define Z_OTHR_PIN PG5 // E2 // // Z Probe must be this pin diff --git a/Marlin/src/pins/stm32f4/pins_MELLOW_FLY_E3_V2.h b/Marlin/src/pins/stm32f4/pins_MELLOW_FLY_E3_V2.h index 4626176a99..d6b5c31bbf 100644 --- a/Marlin/src/pins/stm32f4/pins_MELLOW_FLY_E3_V2.h +++ b/Marlin/src/pins/stm32f4/pins_MELLOW_FLY_E3_V2.h @@ -66,24 +66,14 @@ // // Limit Switches // -#ifdef X_STALL_SENSITIVITY - #define X_STOP_PIN X_DIAG_PIN -#else - #define X_STOP_PIN PE7 // X-STOP +#ifndef X_STOP_PIN + #define X_STOP_PIN X_DIAG_PIN // X-STOP #endif - -#ifdef Y_STALL_SENSITIVITY - #define Y_STOP_PIN Y_DIAG_PIN -#else - #define Y_STOP_PIN PE8 // Y-STOP +#ifndef Y_STOP_PIN + #define Y_STOP_PIN Y_DIAG_PIN // Y-STOP #endif - -#ifdef Z_STALL_SENSITIVITY - #define Z_STOP_PIN Z_DIAG_PIN -#else - #ifndef Z_STOP_PIN - #define Z_STOP_PIN PE9 // Z-STOP - #endif +#ifndef Z_STOP_PIN + #define Z_STOP_PIN Z_DIAG_PIN // Z-STOP #endif // diff --git a/Marlin/src/pins/stm32f4/pins_MKS_SKIPR_V1_0.h b/Marlin/src/pins/stm32f4/pins_MKS_SKIPR_V1_0.h index b0eb8bf24f..b060ac56e5 100644 --- a/Marlin/src/pins/stm32f4/pins_MKS_SKIPR_V1_0.h +++ b/Marlin/src/pins/stm32f4/pins_MKS_SKIPR_V1_0.h @@ -56,49 +56,15 @@ // // Limit Switches // -#ifdef X_STALL_SENSITIVITY - #define X_STOP_PIN X_DIAG_PIN // X- -#elif NEEDS_X_MINMAX - #ifndef X_MIN_PIN - #define X_MIN_PIN X_DIAG_PIN // X- - #endif - #ifndef X_MAX_PIN - #define X_MAX_PIN E0_DIAG_PIN // MT-DET - #endif -#else - #define X_STOP_PIN X_DIAG_PIN // X- -#endif +#define X_STOP_PIN X_DIAG_PIN // X- +#define Y_STOP_PIN Y_DIAG_PIN // Y- +#define Z_STOP_PIN Z_DIAG_PIN // Z+ +#define X_OTHR_PIN E0_DIAG_PIN // MT-DET +#define Y_OTHR_PIN E1_DIAG_PIN // NEOPIXEL +#define Z_OTHR_PIN E2_DIAG_PIN // PWRDET -#ifdef Y_STALL_SENSITIVITY - #define Y_STOP_PIN Y_DIAG_PIN // Y- -#elif NEEDS_Y_MINMAX - #ifndef Y_MIN_PIN - #define Y_MIN_PIN Y_DIAG_PIN // Y- - #endif - #ifndef Y_MAX_PIN - #define Y_MAX_PIN E1_DIAG_PIN // NEOPIXEL - #endif -#else - #define Y_STOP_PIN Y_DIAG_PIN // Y- -#endif - -#ifdef Z_STALL_SENSITIVITY - #define Z_STOP_PIN Z_DIAG_PIN // Z- -#elif NEEDS_Z_MINMAX - #ifndef Z_MIN_PIN - #define Z_MIN_PIN Z_DIAG_PIN // Z- - #endif - #ifndef Z_MAX_PIN - #define Z_MAX_PIN E2_DIAG_PIN // Z+ - #endif -#else - #define Z_STOP_PIN Z_DIAG_PIN // Z- -#endif - -#if DISABLED(Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN) || ENABLED(USE_PROBE_FOR_Z_HOMING) - #ifndef Z_MIN_PROBE_PIN - #define Z_MIN_PROBE_PIN E2_DIAG_PIN // defaults to 'Z+' connector - #endif +#ifndef Z_MIN_PROBE_PIN + #define Z_MIN_PROBE_PIN E2_DIAG_PIN // Z+ #endif // diff --git a/Marlin/src/pins/stm32f7/pins_REMRAM_V1.h b/Marlin/src/pins/stm32f7/pins_REMRAM_V1.h index 7cf8d813a0..8aeec7bc95 100644 --- a/Marlin/src/pins/stm32f7/pins_REMRAM_V1.h +++ b/Marlin/src/pins/stm32f7/pins_REMRAM_V1.h @@ -36,21 +36,44 @@ #error "RemRam only supports 1 hotend / E stepper." #endif +// +// Timers +// +#define STEP_TIMER 2 + +// +// Servos +// +#define SERVO0_PIN 26 // PWM_EXT1 +#define SERVO1_PIN 27 // PWM_EXT2 + // // Limit Switches // -#if DISABLED(SENSORLESS_HOMING) - #define X_MIN_PIN 58 - #define X_MAX_PIN 59 - #define Y_MIN_PIN 60 - #define Y_MAX_PIN 61 - #define Z_MAX_PIN 63 +#define X_DIAG_PIN 36 +#define Y_DIAG_PIN 39 +#define Z_DIAG_PIN 42 + +// Direct endstop pin references +#define _X_MIN_PIN 58 +#define _X_MAX_PIN 59 +#define _Y_MIN_PIN 60 +#define _Y_MAX_PIN 61 +#define _Z_MIN_PIN 62 +#define _Z_MAX_PIN 63 + +#if ENABLED(SENSORLESS_HOMING) + #define X_STOP_PIN X_DIAG_PIN + #define Y_STOP_PIN Y_DIAG_PIN + #define Z_STOP_PIN Z_DIAG_PIN #else - #define X_STOP_PIN 36 - #define Y_STOP_PIN 39 - #define Z_MAX_PIN 42 + #define X_MIN_PIN _X_MIN_PIN + #define X_MAX_PIN _X_MAX_PIN + #define Y_MIN_PIN _Y_MIN_PIN + #define Y_MAX_PIN _Y_MAX_PIN + #define Z_MIN_PIN _Z_MIN_PIN + #define Z_MAX_PIN _Z_MAX_PIN #endif -#define Z_MIN_PIN 62 // // Z Probe (when not Z_MIN_PIN) @@ -105,19 +128,17 @@ #endif // -// Servos +// SD Card // -#define SERVO0_PIN 26 // PWM_EXT1 -#define SERVO1_PIN 27 // PWM_EXT2 - +#define SD_DETECT_PIN 56 // SD_CARD_DET #define SD_SS_PIN 57 // Onboard SD card reader //#define SD_SS_PIN 9 // LCD SD card reader + #define LED_PIN 21 // STATUS_LED // // LCD / Controller // -#define SD_DETECT_PIN 56 // SD_CARD_DET #define BEEPER_PIN 46 // LCD_BEEPER #define LCD_PINS_RS 49 // LCD_RS #define LCD_PINS_EN 48 // LCD_EN @@ -128,9 +149,3 @@ #define BTN_EN1 54 // BTN_EN1 #define BTN_EN2 55 // BTN_EN2 #define BTN_ENC 47 // BTN_ENC - -// -// Timers -// - -#define STEP_TIMER 2 diff --git a/Marlin/src/pins/stm32g0/pins_BTT_MANTA_M8P_common.h b/Marlin/src/pins/stm32g0/pins_BTT_MANTA_M8P_common.h index 0af45e6645..901f1c8919 100644 --- a/Marlin/src/pins/stm32g0/pins_BTT_MANTA_M8P_common.h +++ b/Marlin/src/pins/stm32g0/pins_BTT_MANTA_M8P_common.h @@ -76,43 +76,11 @@ // // Limit Switches // -#ifdef X_STALL_SENSITIVITY - #define X_STOP_PIN X_DIAG_PIN - #if X_HOME_TO_MIN - #define X_MAX_PIN E0_DIAG_PIN // MIN5 - #else - #define X_MIN_PIN E0_DIAG_PIN // MIN5 - #endif -#elif NEEDS_X_MINMAX - #ifndef X_MIN_PIN - #define X_MIN_PIN X_DIAG_PIN // MIN1 - #endif - #ifndef X_MAX_PIN - #define X_MAX_PIN E0_DIAG_PIN // MIN5 - #endif -#else - #define X_STOP_PIN X_DIAG_PIN // MIN1 -#endif - -#ifdef Y_STALL_SENSITIVITY - #define Y_STOP_PIN Y_DIAG_PIN - #if Y_HOME_TO_MIN - #define Y_MAX_PIN E1_DIAG_PIN // MIN6 - #else - #define Y_MIN_PIN E1_DIAG_PIN // MIN6 - #endif -#elif NEEDS_Y_MINMAX - #ifndef Y_MIN_PIN - #define Y_MIN_PIN Y_DIAG_PIN // MIN2 - #endif - #ifndef Y_MAX_PIN - #define Y_MAX_PIN E1_DIAG_PIN // MIN6 - #endif -#else - #define Y_STOP_PIN Y_DIAG_PIN // MIN2 -#endif - +#define X_STOP_PIN X_DIAG_PIN // MIN1 +#define Y_STOP_PIN Y_DIAG_PIN // MIN2 #define Z_STOP_PIN Z_DIAG_PIN // MIN3 +#define X_OTHR_PIN E0_DIAG_PIN // MIN5 +#define Y_OTHR_PIN E1_DIAG_PIN // MIN6 // // Filament Runout Sensors diff --git a/Marlin/src/pins/stm32g0/pins_BTT_SKRAT_V1_0.h b/Marlin/src/pins/stm32g0/pins_BTT_SKRAT_V1_0.h index 2a112f34b1..e760306780 100644 --- a/Marlin/src/pins/stm32g0/pins_BTT_SKRAT_V1_0.h +++ b/Marlin/src/pins/stm32g0/pins_BTT_SKRAT_V1_0.h @@ -79,61 +79,18 @@ // // Limit Switches // -#ifdef X_STALL_SENSITIVITY - #define X_STOP_PIN X_DIAG_PIN - #if X_HOME_TO_MIN - #define X_MAX_PIN PF4 // E0_DET - #else - #define X_MIN_PIN PF4 // E0_DET - #endif -#elif ENABLED(X_DUAL_ENDSTOPS) - #ifndef X_MIN_PIN - #define X_MIN_PIN PB5 // X-STOP - #endif - #ifndef X_MAX_PIN - #define X_MAX_PIN PF4 // E0_DET - #endif -#else - #define X_STOP_PIN PB5 // X-STOP +#ifndef X_STOP_PIN + #define X_STOP_PIN X_DIAG_PIN // X-STOP #endif - -#ifdef Y_STALL_SENSITIVITY - #define Y_STOP_PIN Y_DIAG_PIN - #if Y_HOME_TO_MIN - #define Y_MAX_PIN PF5 // E1_DET - #else - #define Y_MIN_PIN PF5 // E1_DET - #endif -#elif ENABLED(Y_DUAL_ENDSTOPS) - #ifndef Y_MIN_PIN - #define Y_MIN_PIN PC1 // Y-STOP - #endif - #ifndef Y_MAX_PIN - #define Y_MAX_PIN PF5 // E1_DET - #endif -#else - #define Y_STOP_PIN PC1 // Y-STOP +#ifndef Y_STOP_PIN + #define Y_STOP_PIN Y_DIAG_PIN // Y-STOP #endif - -#ifdef Z_STALL_SENSITIVITY - #define Z_STOP_PIN Z_DIAG_PIN - #if Z_HOME_TO_MIN - #define Z_MAX_PIN PE12 // PWR_DET - #else - #define Z_MIN_PIN PE12 // PWR_DET - #endif -#elif ENABLED(Z_MULTI_ENDSTOPS) - #ifndef Z_MIN_PIN - #define Z_MIN_PIN PC0 // Z-STOP - #endif - #ifndef Z_MAX_PIN - #define Z_MAX_PIN PE12 // PWR_DET - #endif -#else - #ifndef Z_STOP_PIN - #define Z_STOP_PIN PC0 // Z-STOP - #endif +#ifndef Z_STOP_PIN + #define Z_STOP_PIN Z_DIAG_PIN // Z-STOP #endif +#define X_OTHR_PIN PF4 // E0_DET +#define Y_OTHR_PIN E1_DIAG_PIN // E1_DET +#define Z_OTHR_PIN PE12 // PWR_DET // // Z Probe (when not Z_MIN_PIN) diff --git a/Marlin/src/pins/stm32h7/pins_BTT_KRAKEN_V1_0.h b/Marlin/src/pins/stm32h7/pins_BTT_KRAKEN_V1_0.h index 3a0cc346e5..8ed780b6c7 100644 --- a/Marlin/src/pins/stm32h7/pins_BTT_KRAKEN_V1_0.h +++ b/Marlin/src/pins/stm32h7/pins_BTT_KRAKEN_V1_0.h @@ -65,59 +65,12 @@ // // Limit Switches // -#ifdef X_STALL_SENSITIVITY - #define X_STOP_PIN X_DIAG_PIN - #if X_HOME_TO_MIN - #define X_MAX_PIN E0_DIAG_PIN // MIN4 - #else - #define X_MIN_PIN E0_DIAG_PIN // MIN4 - #endif -#elif NEEDS_X_MINMAX - #ifndef X_MIN_PIN - #define X_MIN_PIN X_DIAG_PIN // MIN1 - #endif - #ifndef X_MAX_PIN - #define X_MAX_PIN E0_DIAG_PIN // MIN4 - #endif -#else - #define X_STOP_PIN X_DIAG_PIN // MIN1 -#endif - -#ifdef Y_STALL_SENSITIVITY - #define Y_STOP_PIN Y_DIAG_PIN - #if Y_HOME_TO_MIN - #define Y_MAX_PIN E1_DIAG_PIN // MIN5 - #else - #define Y_MIN_PIN E1_DIAG_PIN // MIN5 - #endif -#elif NEEDS_Y_MINMAX - #ifndef Y_MIN_PIN - #define Y_MIN_PIN Y_DIAG_PIN // MIN2 - #endif - #ifndef Y_MAX_PIN - #define Y_MAX_PIN E1_DIAG_PIN // MIN5 - #endif -#else - #define Y_STOP_PIN Y_DIAG_PIN // MIN2 -#endif - -#ifdef Z_STALL_SENSITIVITY - #define Z_STOP_PIN Z_DIAG_PIN - #if Z_HOME_TO_MIN - #define Z_MAX_PIN E2_DIAG_PIN // MIN6 - #else - #define Z_MIN_PIN E2_DIAG_PIN // MIN6 - #endif -#elif NEEDS_Z_MINMAX - #ifndef Z_MIN_PIN - #define Z_MIN_PIN Z_DIAG_PIN // MIN3 - #endif - #ifndef Z_MAX_PIN - #define Z_MAX_PIN E2_DIAG_PIN // MIN6 - #endif -#else - #define Z_STOP_PIN Z_DIAG_PIN // MIN3 -#endif +#define X_STOP_PIN X_DIAG_PIN // MIN1 +#define Y_STOP_PIN Y_DIAG_PIN // MIN2 +#define Z_STOP_PIN Z_DIAG_PIN // MIN3 +#define X_OTHR_PIN E0_DIAG_PIN // MIN4 +#define Y_OTHR_PIN E1_DIAG_PIN // MIN5 +#define Z_OTHR_PIN E2_DIAG_PIN // MIN6 // // Z Probe (when not Z_MIN_PIN) diff --git a/Marlin/src/pins/stm32h7/pins_BTT_MANTA_M8P_V2_0.h b/Marlin/src/pins/stm32h7/pins_BTT_MANTA_M8P_V2_0.h index 941d6ab068..29e57b42a2 100644 --- a/Marlin/src/pins/stm32h7/pins_BTT_MANTA_M8P_V2_0.h +++ b/Marlin/src/pins/stm32h7/pins_BTT_MANTA_M8P_V2_0.h @@ -64,59 +64,12 @@ // // Limit Switches // -#ifdef X_STALL_SENSITIVITY - #define X_STOP_PIN X_DIAG_PIN // M1-STOP - #if X_HOME_TO_MIN - #define X_MAX_PIN E0_DIAG_PIN // M4-STOP - #else - #define X_MIN_PIN E0_DIAG_PIN // M4-STOP - #endif -#elif NEEDS_X_MINMAX - #ifndef X_MIN_PIN - #define X_MIN_PIN X_DIAG_PIN // M1-STOP - #endif - #ifndef X_MAX_PIN - #define X_MAX_PIN E0_DIAG_PIN // M4-STOP - #endif -#else - #define X_STOP_PIN X_DIAG_PIN // M1-STOP -#endif - -#ifdef Y_STALL_SENSITIVITY - #define Y_STOP_PIN Y_DIAG_PIN // M2-STOP - #if Y_HOME_TO_MIN - #define Y_MAX_PIN E1_DIAG_PIN // M5-STOP - #else - #define Y_MIN_PIN E1_DIAG_PIN // M5-STOP - #endif -#elif NEEDS_Y_MINMAX - #ifndef Y_MIN_PIN - #define Y_MIN_PIN Y_DIAG_PIN // M2-STOP - #endif - #ifndef Y_MAX_PIN - #define Y_MAX_PIN E1_DIAG_PIN // M5-STOP - #endif -#else - #define Y_STOP_PIN Y_DIAG_PIN // M2-STOP -#endif - -#ifdef Z_STALL_SENSITIVITY - #define Z_STOP_PIN Z_DIAG_PIN // M3-STOP - #if Z_HOME_TO_MIN - #define Z_MAX_PIN E2_DIAG_PIN // M6-STOP - #else - #define Z_MIN_PIN E2_DIAG_PIN // M6-STOP - #endif -#elif NEEDS_Z_MINMAX - #ifndef Z_MIN_PIN - #define Z_MIN_PIN Z_DIAG_PIN // M3-STOP - #endif - #ifndef Z_MAX_PIN - #define Z_MAX_PIN E2_DIAG_PIN // M6-STOP - #endif -#else - #define Z_STOP_PIN Z_DIAG_PIN // M3-STOP -#endif +#define X_STOP_PIN X_DIAG_PIN // M1-STOP +#define Y_STOP_PIN Y_DIAG_PIN // M2-STOP +#define Z_STOP_PIN Z_DIAG_PIN // M3-STOP +#define X_OTHR_PIN E0_DIAG_PIN // M4-STOP +#define Y_OTHR_PIN E1_DIAG_PIN // M5-STOP +#define Z_OTHR_PIN E2_DIAG_PIN // M6-STOP // // Z Probe (when not Z_MIN_PIN) diff --git a/Marlin/src/pins/stm32h7/pins_BTT_OCTOPUS_MAX_EZ.h b/Marlin/src/pins/stm32h7/pins_BTT_OCTOPUS_MAX_EZ.h index b995b2269e..a60b3bdf43 100644 --- a/Marlin/src/pins/stm32h7/pins_BTT_OCTOPUS_MAX_EZ.h +++ b/Marlin/src/pins/stm32h7/pins_BTT_OCTOPUS_MAX_EZ.h @@ -59,59 +59,12 @@ // // Limit Switches // -#ifdef X_STALL_SENSITIVITY - #define X_STOP_PIN X_DIAG_PIN - #if X_HOME_TO_MIN - #define X_MAX_PIN E0_DIAG_PIN // M4-DET - #else - #define X_MIN_PIN E0_DIAG_PIN // M4-DET - #endif -#elif NEEDS_X_MINMAX - #ifndef X_MIN_PIN - #define X_MIN_PIN X_DIAG_PIN // X-STOP - #endif - #ifndef X_MAX_PIN - #define X_MAX_PIN E0_DIAG_PIN // M4-DET - #endif -#else - #define X_STOP_PIN X_DIAG_PIN // X-STOP -#endif - -#ifdef Y_STALL_SENSITIVITY - #define Y_STOP_PIN Y_DIAG_PIN - #if Y_HOME_TO_MIN - #define Y_MAX_PIN E1_DIAG_PIN // M5-DET - #else - #define Y_MIN_PIN E1_DIAG_PIN // M5-DET - #endif -#elif NEEDS_Y_MINMAX - #ifndef Y_MIN_PIN - #define Y_MIN_PIN Y_DIAG_PIN // Y-STOP - #endif - #ifndef Y_MAX_PIN - #define Y_MAX_PIN E1_DIAG_PIN // M5-DET - #endif -#else - #define Y_STOP_PIN Y_DIAG_PIN // Y-STOP -#endif - -#ifdef Z_STALL_SENSITIVITY - #define Z_STOP_PIN Z_DIAG_PIN - #if Z_HOME_TO_MIN - #define Z_MAX_PIN E2_DIAG_PIN // PWRDET - #else - #define Z_MIN_PIN E2_DIAG_PIN // PWRDET - #endif -#elif NEEDS_Z_MINMAX - #ifndef Z_MIN_PIN - #define Z_MIN_PIN Z_DIAG_PIN // Z-STOP - #endif - #ifndef Z_MAX_PIN - #define Z_MAX_PIN E2_DIAG_PIN // PWRDET - #endif -#else - #define Z_STOP_PIN Z_DIAG_PIN // Z-STOP -#endif +#define X_STOP_PIN X_DIAG_PIN // M1-STOP +#define Y_STOP_PIN Y_DIAG_PIN // M2-STOP +#define Z_STOP_PIN Z_DIAG_PIN // M3-STOP +#define X_OTHR_PIN E0_DIAG_PIN // M5-STOP +#define Y_OTHR_PIN E1_DIAG_PIN // M6-STOP +#define Z_OTHR_PIN E2_DIAG_PIN // M7-STOP // // Z Probe (when not Z_MIN_PIN) diff --git a/Marlin/src/pins/stm32h7/pins_BTT_OCTOPUS_PRO_V1_common.h b/Marlin/src/pins/stm32h7/pins_BTT_OCTOPUS_PRO_V1_common.h index 8c8cd1d8a1..7339d74376 100644 --- a/Marlin/src/pins/stm32h7/pins_BTT_OCTOPUS_PRO_V1_common.h +++ b/Marlin/src/pins/stm32h7/pins_BTT_OCTOPUS_PRO_V1_common.h @@ -59,59 +59,12 @@ // // Limit Switches // -#ifdef X_STALL_SENSITIVITY - #define X_STOP_PIN X_DIAG_PIN - #if X_HOME_TO_MIN - #define X_MAX_PIN E0_DIAG_PIN // E0DET - #else - #define X_MIN_PIN E0_DIAG_PIN // E0DET - #endif -#elif NEEDS_X_MINMAX - #ifndef X_MIN_PIN - #define X_MIN_PIN X_DIAG_PIN // X-STOP - #endif - #ifndef X_MAX_PIN - #define X_MAX_PIN E0_DIAG_PIN // E0DET - #endif -#else - #define X_STOP_PIN X_DIAG_PIN // X-STOP -#endif - -#ifdef Y_STALL_SENSITIVITY - #define Y_STOP_PIN Y_DIAG_PIN - #if Y_HOME_TO_MIN - #define Y_MAX_PIN E1_DIAG_PIN // E1DET - #else - #define Y_MIN_PIN E1_DIAG_PIN // E1DET - #endif -#elif NEEDS_Y_MINMAX - #ifndef Y_MIN_PIN - #define Y_MIN_PIN Y_DIAG_PIN // Y-STOP - #endif - #ifndef Y_MAX_PIN - #define Y_MAX_PIN E1_DIAG_PIN // E1DET - #endif -#else - #define Y_STOP_PIN Y_DIAG_PIN // Y-STOP -#endif - -#ifdef Z_STALL_SENSITIVITY - #define Z_STOP_PIN Z_DIAG_PIN - #if Z_HOME_TO_MIN - #define Z_MAX_PIN E2_DIAG_PIN // PWRDET - #else - #define Z_MIN_PIN E2_DIAG_PIN // PWRDET - #endif -#elif NEEDS_Z_MINMAX - #ifndef Z_MIN_PIN - #define Z_MIN_PIN Z_DIAG_PIN // Z-STOP - #endif - #ifndef Z_MAX_PIN - #define Z_MAX_PIN E2_DIAG_PIN // PWRDET - #endif -#else - #define Z_STOP_PIN Z_DIAG_PIN // Z-STOP -#endif +#define X_STOP_PIN X_DIAG_PIN // X-STOP +#define Y_STOP_PIN Y_DIAG_PIN // Y-STOP +#define Z_STOP_PIN Z_DIAG_PIN // Z-STOP +#define X_OTHR_PIN E0_DIAG_PIN // E0DET +#define Y_OTHR_PIN E1_DIAG_PIN // E1DET +#define Z_OTHR_PIN E2_DIAG_PIN // E2DET // // Z Probe (when not Z_MIN_PIN) diff --git a/Marlin/src/pins/stm32h7/pins_BTT_SKR_V3_0_common.h b/Marlin/src/pins/stm32h7/pins_BTT_SKR_V3_0_common.h index 7456236669..320d396d76 100644 --- a/Marlin/src/pins/stm32h7/pins_BTT_SKR_V3_0_common.h +++ b/Marlin/src/pins/stm32h7/pins_BTT_SKR_V3_0_common.h @@ -70,61 +70,19 @@ // // Limit Switches // -#ifdef X_STALL_SENSITIVITY - #define X_STOP_PIN X_DIAG_PIN - #if X_HOME_TO_MIN - #define X_MAX_PIN PC2 // E0DET - #else - #define X_MIN_PIN PC2 // E0DET - #endif -#elif ENABLED(X_DUAL_ENDSTOPS) - #ifndef X_MIN_PIN - #define X_MIN_PIN PC1 // X-STOP - #endif - #ifndef X_MAX_PIN - #define X_MAX_PIN PC2 // E0DET - #endif -#else - #define X_STOP_PIN PC1 // X-STOP +#ifndef X_STOP_PIN + #define X_STOP_PIN X_DIAG_PIN // X-STOP #endif +#ifndef Y_STOP_PIN + #define Y_STOP_PIN Y_DIAG_PIN // Y-STOP +#endif +#ifndef Z_STOP_PIN + #define Z_STOP_PIN Z_DIAG_PIN // Z-STOP +#endif +#define X_OTHR_PIN PC2 // E0DET +#define Y_OTHR_PIN PA0 // E1DET +#define Z_OTHR_PIN PC15 // PWRDET -#ifdef Y_STALL_SENSITIVITY - #define Y_STOP_PIN Y_DIAG_PIN - #if Y_HOME_TO_MIN - #define Y_MAX_PIN PA0 // E1DET - #else - #define Y_MIN_PIN PA0 // E1DET - #endif -#elif ENABLED(Y_DUAL_ENDSTOPS) - #ifndef Y_MIN_PIN - #define Y_MIN_PIN PC3 // Y-STOP - #endif - #ifndef Y_MAX_PIN - #define Y_MAX_PIN PA0 // E1DET - #endif -#else - #define Y_STOP_PIN PC3 // Y-STOP -#endif - -#ifdef Z_STALL_SENSITIVITY - #define Z_STOP_PIN Z_DIAG_PIN - #if Z_HOME_TO_MIN - #define Z_MAX_PIN PC15 // PWRDET - #else - #define Z_MIN_PIN PC15 // PWRDET - #endif -#elif ENABLED(Z_MULTI_ENDSTOPS) - #ifndef Z_MIN_PIN - #define Z_MIN_PIN PC0 // Z-STOP - #endif - #ifndef Z_MAX_PIN - #define Z_MAX_PIN PC15 // PWRDET - #endif -#else - #ifndef Z_STOP_PIN - #define Z_STOP_PIN PC0 // Z-STOP - #endif -#endif #define ONBOARD_ENDSTOPPULLUPS // Board has built-in pullups // From fbea4c604812dd5f7ee0f3066c4bcd34fafad4ab Mon Sep 17 00:00:00 2001 From: Keith Bennett <13375512+thisiskeithb@users.noreply.github.com> Date: Wed, 14 May 2025 13:18:53 -0700 Subject: [PATCH 314/787] =?UTF-8?q?=E2=9C=8F=EF=B8=8F=20Fix=20variant=20do?= =?UTF-8?q?cs=20typo=20(#27850)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- buildroot/share/PlatformIO/variants/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildroot/share/PlatformIO/variants/README.md b/buildroot/share/PlatformIO/variants/README.md index ae64b1b439..0217e2ebd9 100644 --- a/buildroot/share/PlatformIO/variants/README.md +++ b/buildroot/share/PlatformIO/variants/README.md @@ -3,7 +3,7 @@ This `buildroot/share/PlatformIO/variants` folder contains Marlin custom variants for both generic and custom boards. Marlin specifies board variants in PlatformIO INI files in one of two ways: -- The `board_build.variant = VARIANT_MAME` field specifies the variant subfolder name directly. +- The `board_build.variant = VARIANT_NAME` field specifies the variant subfolder name directly. - The `board = board_name` field names a custom board JSON file that contains a `build.variant` field. ## Variant File Naming From 0927e49756ca41587088adffdf84ec5a1c87328f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matheus=20M=C3=B6sken=20Diegues?= Date: Wed, 14 May 2025 17:23:04 -0300 Subject: [PATCH 315/787] =?UTF-8?q?=F0=9F=8C=90=20README=20in=20Portuguese?= =?UTF-8?q?=20(Brazil)=20(#27854)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README-PT-BR.md | 81 +++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 4 +++ 2 files changed, 85 insertions(+) create mode 100644 README-PT-BR.md diff --git a/README-PT-BR.md b/README-PT-BR.md new file mode 100644 index 0000000000..8d8b18828f --- /dev/null +++ b/README-PT-BR.md @@ -0,0 +1,81 @@ + +

Logo do MarlinFirmware

+ +

Firmware de Impressora 3D Marlin

+ +
+ +Documentação adicional pode ser encontrada na [Página Inicial do Marlin](//marlinfw.org/). +Por favor, teste este firmware e nos avise se encontrar algum problema. Voluntários estão prontos para ajudar! + +## Branch de Correções do Marlin 2.1 + +__Não é para uso em produção. Use com cautela!__ + +O Marlin 2.1 continua oferecendo suporte a placas ARM 32 bits e AVR 8 bits, além de adicionar suporte para até 9 eixos coordenados e até 8 extrusoras. + +Este branch é para correções da versão mais recente 2.1.x. Periodicamente, ele servirá de base para o próximo lançamento menor da linha 2.1.x. + +Versões anteriores do Marlin podem ser baixadas na [página de lançamentos](//github.com/MarlinFirmware/Marlin/releases). + +## Configurações de Exemplo + +Antes de compilar o Marlin para sua máquina, você precisará de uma configuração específica para o seu hardware. Ao solicitar, seu fornecedor deve fornecer o código-fonte completo e as configurações da sua máquina. No entanto, se quiser instalar uma versão mais recente do Marlin, você precisará de arquivos de configuração atualizados. Felizmente, a comunidade do Marlin já contribuiu com dezenas de configurações testadas para ajudar no início. Visite o repositório [MarlinFirmware/Configurations](//github.com/MarlinFirmware/Configurations) para encontrar a configuração mais próxima da sua impressora. + +## Compilando o Marlin 2.1 + +Para compilar e enviar o Marlin você pode usar uma destas ferramentas: + +- O [Visual Studio Code](//code.visualstudio.com/download) com a extensão [Auto Build Marlin](//marlinfw.org/docs/basics/auto_build_marlin.html). +- A [IDE do Arduino](//www.arduino.cc/en/main/software): Veja [Compilando Marlin com Arduino](//marlinfw.org/docs/basics/install_arduino.html). +- Também é possível usar VSCode com devcontainer: Veja [Instalando Marlin (VSCode devcontainer)](http://marlinfw.org/docs/basics/install_devcontainer_vscode.html). + +O Marlin é otimizado para ser compilado com a extensão **PlatformIO IDE** no **Visual Studio Code**. Ainda é possível compilar com a **IDE do Arduino**, e temos planos para melhorar essa experiência, mas por enquanto o PlatformIO é a melhor escolha. + +## Placas AVR 8 Bits + +Pretendemos continuar oferecendo suporte às placas AVR 8 bits indefinidamente, mantendo uma base de código única que possa ser aplicada a todas as máquinas. Queremos que hobbystas, experimentadores e donos de máquinas antigas também se beneficiem das inovações da comunidade tanto quanto os donos de equipamentos mais modernos. Além disso, essas máquinas baseadas em AVR costumam ser ideais para testes e feedbacks! + +## Camada de Abstração de Hardware (HAL) + +O Marlin inclui uma camada de abstração de hardware para portar o firmware para uma grande variedade de chips. Essa camada trata das diferenças entre chips de forma modular, permitindo que as funcionalidades do Marlin sejam aproveitadas ao máximo. + +## Licença + +Marlin é publicado sob a licença GPL, então você pode usar, redistribuir e modificar o código-fonte, desde que o código derivado também seja publicado sob a mesma licença. Consulte o arquivo [LICENSE](https://github.com/MarlinFirmware/Marlin/blob/bugfix-2.1.x/LICENSE) para mais detalhes. + +## Ajude o Marlin! + +Você pode ajudar o projeto Marlin contribuindo com código, traduções, testes ou apoiando financeiramente no [GitHub Sponsors](https://github.com/sponsors/thinkyhead). + +...Marlin para diferentes plataformas de hardware. O HAL define as interfaces entre o núcleo do Marlin e o hardware da plataforma. O Marlin suporta atualmente as seguintes arquiteturas: + +- AVR +- SAM (Arduino Due) +- SAMD (Arduino Zero, etc.) +- STM32F1, STM32F4, STM32F7, STM32H7 +- LPC176x (Smoothieboard, ReARM, Archim, MKS Sbase, etc.) +- Teensy 3.5 e 3.6 (ARM Cortex-M4) +- ESP32 (experimental) + +## Comunicação Serial + +- **Baudrates suportados:** 250000, 115200, 57600, 38400, 19200, 9600 +- O baudrate padrão é 250000 para maior velocidade e estabilidade + +## Atualizações e Contribuições + +Aceitamos correções de bugs, melhorias de desempenho e novas funcionalidades. Veja as instruções de contribuição na [Wiki do Marlin](https://github.com/MarlinFirmware/Marlin/wiki/Contributing). + +## Licença + +Marlin é um software livre licenciado sob a [GNU General Public License v3.0](https://www.gnu.org/licenses/gpl-3.0.html). Você pode redistribuí-lo e/ou modificá-lo sob os termos da GPL. Para mais detalhes, veja o arquivo [LICENSE](LICENSE). diff --git a/README.md b/README.md index 50b86d3213..50dfddda9a 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,10 @@ Additional documentation can be found at the [Marlin Home Page](//marlinfw.org/). Please test this firmware and let us know if it misbehaves in any way. Volunteers are standing by! +--- +This README is available in other languages +> **Versão em português:** [README-PT-BR.md](README-PT-BR.md) + ## Marlin 2.1 Bugfix Branch __Not for production use. Use with caution!__ From b79f7f203ab3335c8b2d01d4ab1ab058530785cb Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Thu, 15 May 2025 00:30:52 +0000 Subject: [PATCH 316/787] [cron] Bump distribution date (2025-05-15) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index bc68976ee3..5e346f4260 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-05-14" +//#define STRING_DISTRIBUTION_DATE "2025-05-15" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 75995aa92a..0390d41cfc 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-05-14" + #define STRING_DISTRIBUTION_DATE "2025-05-15" #endif /** From 487542083b7920a797e1df8c288fa05b40c73bf3 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Thu, 15 May 2025 14:08:32 -0500 Subject: [PATCH 317/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Upd?= =?UTF-8?q?ate=20Sim,=20fix=20Mac=20native=20gcc?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- buildroot/bin/mac_gcc | 45 ++++++++++++++++++++++++------------------- ini/native.ini | 4 ++-- 2 files changed, 27 insertions(+), 22 deletions(-) diff --git a/buildroot/bin/mac_gcc b/buildroot/bin/mac_gcc index 6c5d7ea24a..14ae3c4500 100755 --- a/buildroot/bin/mac_gcc +++ b/buildroot/bin/mac_gcc @@ -10,30 +10,29 @@ which port >/dev/null && HAS_MACPORTS=1 which brew >/dev/null && HAS_HOMEBREW=1 -MACPORTS_PATH=$(dirname "$(which port)") +if ((HAS_MACPORTS)); then + MACPORTS_PATH=$(dirname "$(which port)") + cd $MACPORTS_PATH + sudo rm -f cpp gcc g++ cc ld + cd - +fi + if ((HAS_HOMEBREW)); then HOMEBREW_PATH="$(brew --prefix)/bin" + cd $HOMEBREW_PATH + rm -f cpp gcc g++ cc ld + cd - fi if [[ $1 == "apple" || $1 == "darwin" || $1 == "system" ]]; then - if ((HAS_MACPORTS)); then - cd $MACPORTS_PATH - sudo rm -f gcc g++ cc ld - cd - - fi - - if ((HAS_HOMEBREW)); then - cd $HOMEBREW_PATH - sudo rm -f gcc g++ cc - cd - - fi + # Nothing to do elif [[ $1 =~ ".*ports" ]]; then ((HAS_MACPORTS)) || { echo "MacPorts is not installed"; exit 1; } - GCCV=$( find $MACPORTS_PATH -name "gcc-mp-*" | sort -r | head -1 | sed 's/.*gcc-mp-//' ) + GCCV=$( find $MACPORTS_PATH -name "cpp-mp-*" | sort -r | head -1 | sed 's/.*cpp-mp-//' ) [[ $GCCV -ge 11 ]] || GCCV=14 getport() { port installed $1 | grep $1 || sudo port install $1; } @@ -42,7 +41,7 @@ elif [[ $1 =~ ".*ports" ]]; then getports "gcc$GCCV" glm mesa libsdl2 libsdl2_net cd $MACPORTS_PATH - sudo rm -f gcc g++ cc ld + sudo ln -s "cpp-mp-$GCCV" cpp sudo ln -s "gcc-mp-$GCCV" gcc sudo ln -s "g++-mp-$GCCV" g++ sudo ln -s g++ cc @@ -53,16 +52,22 @@ elif [[ $1 =~ ".*brew" ]]; then ((HAS_HOMEBREW)) || { echo "Homebrew is not installed"; exit 1; } - GCCV=$( find $HOMEBREW_PATH -name "gcc-*" | sort -r | head -1 | sed 's/.*gcc-//' ) - [[ $GCCV -ge 11 ]] || { brew install gcc@14 ; GCCV=14 } + GCCV=$( find $HOMEBREW_PATH -name "cpp-*" | sort -r | head -1 | sed 's/.*cpp-//' ) + [[ $GCCV -ge 11 ]] || brew install gcc + GCCV=$( find $HOMEBREW_PATH -name "cpp-*" | sort -r | head -1 | sed 's/.*cpp-//' ) brew install glm mesa sdl2 sdl2_net cd $HOMEBREW_PATH - sudo rm -f gcc g++ cc - sudo ln -s "gcc-$GCCV" gcc - sudo ln -s "g++-$GCCV" g++ - sudo ln -s g++ cc + ln -s "cpp-$GCCV" cpp + ln -s "gcc-$GCCV" gcc + ln -s "g++-$GCCV" g++ + ln -s g++ cc + if [[ -f "$MACPORTS_PATH/ld-classic" ]]; then + ln -s "$MACPORTS_PATH/ld-classic" ld + else + echo "MacPorts may be required for a compatible 'ld' linker!" + fi cd - else diff --git a/ini/native.ini b/ini/native.ini index f27285e83a..5f56b1c843 100644 --- a/ini/native.ini +++ b/ini/native.ini @@ -58,7 +58,7 @@ debug_build_flags = -fstack-protector-strong -g -g3 -ggdb lib_compat_mode = off build_src_filter = ${common.default_src_filter} + lib_deps = ${common.lib_deps} - MarlinSimUI=https://github.com/p3p/MarlinSimUI/archive/dd9c41f1b2.zip + MarlinSimUI=https://github.com/p3p/MarlinSimUI/archive/af62611296.zip Adafruit NeoPixel=https://github.com/p3p/Adafruit_NeoPixel/archive/c6b319f447.zip LiquidCrystal=https://github.com/p3p/LiquidCrystal/archive/322fb5fc23.zip extra_scripts = ${common.extra_scripts} @@ -115,7 +115,7 @@ build_flags = -g2 -DHAS_LIBBSD -I/opt/local/include -I/opt/local/include/freetype2 - -I/opt/local/include/SDL2/ + -I/opt/local/include/SDL2 -L/opt/local/lib -Wl,-framework,OpenGl -Wl,-framework,CoreFoundation From 8643fa0afb6498ac9eb111a5f6a4cf0481bb95db Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Fri, 16 May 2025 00:32:02 +0000 Subject: [PATCH 318/787] [cron] Bump distribution date (2025-05-16) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 5e346f4260..5c920216d1 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-05-15" +//#define STRING_DISTRIBUTION_DATE "2025-05-16" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 0390d41cfc..570a8c03d8 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-05-15" + #define STRING_DISTRIBUTION_DATE "2025-05-16" #endif /** From bd4900d6cd0074f3d709bbd93d30db5375a4def9 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sun, 18 May 2025 16:35:23 -0500 Subject: [PATCH 319/787] =?UTF-8?q?=E2=9C=85=20Pre-fetch=20configs=20for?= =?UTF-8?q?=20CI=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci-build-tests.yml | 10 +++++ buildroot/bin/use_example_configs | 65 +++++++++++++++++++++++----- 2 files changed, 64 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci-build-tests.yml b/.github/workflows/ci-build-tests.yml index f80417c0fe..b65a71ab56 100644 --- a/.github/workflows/ci-build-tests.yml +++ b/.github/workflows/ci-build-tests.yml @@ -36,6 +36,9 @@ jobs: runs-on: ubuntu-22.04 + env: + CONFIG_BRANCH: ${{ github.base_ref || github.ref_name }} + strategy: fail-fast: true matrix: @@ -205,6 +208,13 @@ jobs: sudo apt-get install libsdl2-net-dev sudo apt-get install libglm-dev + - name: Checkout Configurations + uses: actions/checkout@v4 + with: + repository: MarlinFirmware/Configurations + ref: ${{ env.CONFIG_BRANCH }} + path: ConfigurationsRepo + - name: Run ${{ matrix.test-platform }} Tests run: | make tests-single-ci TEST_TARGET=${{ matrix.test-platform }} diff --git a/buildroot/bin/use_example_configs b/buildroot/bin/use_example_configs index 193da74901..9a3a7a34d4 100755 --- a/buildroot/bin/use_example_configs +++ b/buildroot/bin/use_example_configs @@ -15,6 +15,9 @@ # import os, subprocess, sys, urllib.request +from pathlib import Path + +CONFIG_FILES = ("Configuration.h", "Configuration_adv.h", "_Bootscreen.h", "_Statusscreen.h") def get_current_branch(): try: @@ -25,19 +28,45 @@ def get_current_branch(): except subprocess.CalledProcessError: return None -def fetch_configs(branch, config_path): - print(f"Fetching {config_path} configurations from {branch}...") - base_url = f"https://raw.githubusercontent.com/MarlinFirmware/Configurations/{branch}/config/{config_path}" - files = ["Configuration.h", "Configuration_adv.h", "_Bootscreen.h", "_Statusscreen.h"] - marlin_dir = os.path.join(os.getcwd(), "Marlin") - if not os.path.exists(marlin_dir): - print(f"Directory {marlin_dir} does not exist.") - sys.exit(1) - for file in files: +def sparse_checkout(branch, config_path, repo_url="https://github.com/MarlinFirmware/Configurations.git"): + configs_dir = Path("ConfigurationsRepo") + config_subdir = f"config/{config_path}" + + if not configs_dir.exists(): + # Step 1: Clone with no checkout + subprocess.run([ + "git", "clone", "--depth", "1", "--filter=blob:none", "--sparse", + "--branch", branch, repo_url, str(configs_dir) + ], check=True) + + # Step 2: Enable sparse checkout and set the folder + subprocess.run(["git", "sparse-checkout", "set", config_subdir], cwd=str(configs_dir), check=True) + # Step 3: Pull the latest for that branch/folder + subprocess.run(["git", "pull"], cwd=str(configs_dir), check=True) + +def copy_config_files(branch, config_path, dest_dir): + sparse_checkout(branch, config_path) + + src_dir = Path("ConfigurationsRepo") / "config" / config_path + for fname in CONFIG_FILES: + src_file = src_dir / fname + if src_file.exists(): + dest_file = dest_dir / fname + print(f"Copying {src_file} to {dest_file}") + dest_file.write_bytes(src_file.read_bytes()) + else: + print(f"{fname} not found in {src_dir}") + +def fetch_config_files(branch, config_path, dest_dir): + config_path_url = config_path.replace(' ', '%20') + base_url = f"https://raw.githubusercontent.com/MarlinFirmware/Configurations/{branch}/config/{config_path_url}" + + for file in CONFIG_FILES: url = f"{base_url}/{file}" - dest_file = os.path.join(marlin_dir, file) + dest_file = dest_dir / file if os.getenv('DEBUG', '0') == '1': print(f"Fetching {file} from {url} to {dest_file}") + try: urllib.request.urlretrieve(url, dest_file) except urllib.error.HTTPError as e: @@ -47,6 +76,19 @@ def fetch_configs(branch, config_path): else: raise +def fetch_configs(branch, config_path): + print(f"Fetching {config_path} configurations from {branch}...") + + marlin_dir = Path("Marlin") + if not marlin_dir.exists(): + print(f"Directory 'Marlin' not found at the current location.") + sys.exit(1) + + if os.environ.get('GITHUB_ACTIONS'): # Running on GitHub ? + copy_config_files(branch, config_path, marlin_dir) + else: + fetch_config_files(branch, config_path, marlin_dir) + def main(): branch = get_current_branch() if not branch: @@ -74,7 +116,7 @@ def main(): branch = part1 else: config_path = arg - config_path = 'examples/'+config_path.replace(' ', '%20') + config_path = 'examples/'+config_path else: config_path = "default" @@ -82,6 +124,7 @@ def main(): subprocess.run(['restore_configs'], check=True) except FileNotFoundError: print("restore_configs not found, skipping.") + fetch_configs(branch, config_path) if __name__ == "__main__": From fe747ae4bf4173e5947bbf41b6bc77ad9be571e0 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Mon, 19 May 2025 00:37:46 +0000 Subject: [PATCH 320/787] [cron] Bump distribution date (2025-05-19) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 5c920216d1..1deb2d2109 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-05-16" +//#define STRING_DISTRIBUTION_DATE "2025-05-19" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 570a8c03d8..8c62809731 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-05-16" + #define STRING_DISTRIBUTION_DATE "2025-05-19" #endif /** From 88a8e2127d80abb46a11261073cd11a80e17c476 Mon Sep 17 00:00:00 2001 From: Fly3DTeam Date: Mon, 19 May 2025 10:12:07 +0800 Subject: [PATCH 321/787] =?UTF-8?q?=F0=9F=94=A7=20TMC=20Baud=20Rate=20for?= =?UTF-8?q?=20FLY=20D5/D7=20(#27860)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/pins/stm32f0/pins_FLY_D5.h | 6 ++++++ Marlin/src/pins/stm32f0/pins_FLY_D7.h | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/Marlin/src/pins/stm32f0/pins_FLY_D5.h b/Marlin/src/pins/stm32f0/pins_FLY_D5.h index c98dcb0b7e..b3b51f6bde 100644 --- a/Marlin/src/pins/stm32f0/pins_FLY_D5.h +++ b/Marlin/src/pins/stm32f0/pins_FLY_D5.h @@ -114,6 +114,12 @@ #define Z_SERIAL_TX_PIN PA3 #define E0_SERIAL_TX_PIN PA7 #define E1_SERIAL_TX_PIN PB1 + +// Reduce baud rate to improve software serial reliability +#ifndef TMC_BAUD_RATE + #define TMC_BAUD_RATE 9600 +#endif + #endif // diff --git a/Marlin/src/pins/stm32f0/pins_FLY_D7.h b/Marlin/src/pins/stm32f0/pins_FLY_D7.h index 78ce01d385..136b2c5f9c 100644 --- a/Marlin/src/pins/stm32f0/pins_FLY_D7.h +++ b/Marlin/src/pins/stm32f0/pins_FLY_D7.h @@ -133,6 +133,12 @@ #define E1_SERIAL_TX_PIN PB1 #define E2_SERIAL_TX_PIN PB6 #define E3_SERIAL_TX_PIN PC10 + +// Reduce baud rate to improve software serial reliability +#ifndef TMC_BAUD_RATE + #define TMC_BAUD_RATE 9600 +#endif + #endif // From ade6dbf01eb2c1d58bf526e0f7bc993f190f38ef Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sun, 18 May 2025 21:13:30 -0500 Subject: [PATCH 322/787] =?UTF-8?q?=F0=9F=94=A7=20Fix=20Speed/Flow=20edit?= =?UTF-8?q?=20options=20(#27863)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #27849 --- Marlin/Configuration_adv.h | 5 +++-- Marlin/src/inc/Conditionals-2-LCD.h | 3 --- Marlin/src/inc/Conditionals-3-etc.h | 5 ----- Marlin/src/inc/Conditionals-4-adv.h | 4 ++++ Marlin/src/lcd/extui/ui_api.cpp | 4 ++-- Marlin/src/lcd/menu/menu_bed_tramming.cpp | 15 ++++++++------- Marlin/src/module/motion.cpp | 2 +- Marlin/src/module/motion.h | 5 ++++- Marlin/src/module/probe.cpp | 2 +- 9 files changed, 23 insertions(+), 22 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 762ae2aa81..60e5378c30 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -1673,11 +1673,12 @@ #endif // HAS_DISPLAY -#if HAS_FEEDRATE_EDIT +// Some displays offer Feedrate / Flow editing. +#if ANY(HAS_MARLINUI_MENU, DWIN_CREALITY_LCD, DWIN_LCD_PROUI, MALYAN_LCD, TOUCH_SCREEN, ULTIPANEL_FEEDMULTIPLY) #define SPEED_EDIT_MIN 10 // (%) Feedrate percentage edit range minimum #define SPEED_EDIT_MAX 999 // (%) Feedrate percentage edit range maximum #endif -#if HAS_FLOW_EDIT +#if ANY(HAS_MARLINUI_MENU, DWIN_CREALITY_LCD, DWIN_LCD_PROUI, MALYAN_LCD, TOUCH_SCREEN) #define FLOW_EDIT_MIN 10 // (%) Flow percentage edit range minimum #define FLOW_EDIT_MAX 999 // (%) Flow percentage edit range maximum #endif diff --git a/Marlin/src/inc/Conditionals-2-LCD.h b/Marlin/src/inc/Conditionals-2-LCD.h index 2bf663b6f0..362ca7a714 100644 --- a/Marlin/src/inc/Conditionals-2-LCD.h +++ b/Marlin/src/inc/Conditionals-2-LCD.h @@ -667,9 +667,6 @@ #if HAS_EXTRUDERS && ANY(HAS_MARLINUI_MENU, DWIN_CREALITY_LCD, DWIN_LCD_PROUI, MALYAN_LCD, TOUCH_SCREEN) #define HAS_FLOW_EDIT 1 #endif -#if ANY(HAS_MARLINUI_MENU, ULTIPANEL_FEEDMULTIPLY, DWIN_CREALITY_LCD, DWIN_LCD_PROUI, MALYAN_LCD, TOUCH_SCREEN) - #define HAS_FEEDRATE_EDIT 1 -#endif /** * TFT Displays diff --git a/Marlin/src/inc/Conditionals-3-etc.h b/Marlin/src/inc/Conditionals-3-etc.h index b361a50a58..00bff0e072 100644 --- a/Marlin/src/inc/Conditionals-3-etc.h +++ b/Marlin/src/inc/Conditionals-3-etc.h @@ -560,11 +560,6 @@ #undef Z_CLEARANCE_DEPLOY_PROBE #endif -#if !(ANY(HAS_BED_PROBE, BACKLASH_GCODE) || (ENABLED(EXTENSIBLE_UI) && ANY(MESH_BED_LEVELING, AUTO_BED_LEVELING_UBL))) - #undef Z_PROBE_FEEDRATE_FAST - #undef Z_PROBE_FEEDRATE_SLOW -#endif - /** * Z_CLEARANCE_FOR_HOMING */ diff --git a/Marlin/src/inc/Conditionals-4-adv.h b/Marlin/src/inc/Conditionals-4-adv.h index 629ee98273..a0eaa7081c 100644 --- a/Marlin/src/inc/Conditionals-4-adv.h +++ b/Marlin/src/inc/Conditionals-4-adv.h @@ -105,6 +105,10 @@ #endif #endif +#if !(ANY(HAS_BED_PROBE, BACKLASH_GCODE) || (ENABLED(EXTENSIBLE_UI) && ANY(MESH_BED_LEVELING, AUTO_BED_LEVELING_UBL))) + #undef Z_PROBE_FEEDRATE_FAST + #undef Z_PROBE_FEEDRATE_SLOW +#endif #if !HAS_BED_PROBE #undef BABYSTEP_ZPROBE_OFFSET #undef PROBING_USE_CURRENT_HOME diff --git a/Marlin/src/lcd/extui/ui_api.cpp b/Marlin/src/lcd/extui/ui_api.cpp index 5380b05596..badb3335a3 100644 --- a/Marlin/src/lcd/extui/ui_api.cpp +++ b/Marlin/src/lcd/extui/ui_api.cpp @@ -887,14 +887,14 @@ namespace ExtUI { y_target = MESH_MIN_Y + pos.y * (MESH_Y_DIST); if (x_target != current_position.x || y_target != current_position.y) { // If moving across bed, raise nozzle to safe height over bed - feedrate_mm_s = MMM_TO_MMS(Z_PROBE_FEEDRATE_FAST); + feedrate_mm_s = z_probe_fast_mm_s; destination.set(current_position.x, current_position.y, Z_CLEARANCE_BETWEEN_PROBES); prepare_line_to_destination(); if (XY_PROBE_FEEDRATE_MM_S) feedrate_mm_s = XY_PROBE_FEEDRATE_MM_S; destination.set(x_target, y_target); prepare_line_to_destination(); } - feedrate_mm_s = MMM_TO_MMS(Z_PROBE_FEEDRATE_FAST); + feedrate_mm_s = z_probe_fast_mm_s; destination.z = z; prepare_line_to_destination(); #else diff --git a/Marlin/src/lcd/menu/menu_bed_tramming.cpp b/Marlin/src/lcd/menu/menu_bed_tramming.cpp index d749763808..0d5feddce6 100644 --- a/Marlin/src/lcd/menu/menu_bed_tramming.cpp +++ b/Marlin/src/lcd/menu/menu_bed_tramming.cpp @@ -230,11 +230,12 @@ static void _lcd_goto_next_corner() { ); } + // Probe down and return 'true' if the probe triggered bool _lcd_bed_tramming_probe(const bool verify=false) { - if (verify) line_to_z(current_position.z + (BED_TRAMMING_Z_HOP)); // do clearance if needed - TERN_(BLTOUCH, if (!bltouch.high_speed_mode) bltouch.deploy()); // Deploy in LOW SPEED MODE on every probe action - do_blocking_move_to_z(last_z - BED_TRAMMING_PROBE_TOLERANCE, MMM_TO_MMS(Z_PROBE_FEEDRATE_SLOW)); // Move down to lower tolerance - if (TEST(endstops.trigger_state(), Z_MIN_PROBE)) { // check if probe triggered + if (verify) line_to_z(current_position.z + (BED_TRAMMING_Z_HOP)); // Do clearance if needed + TERN_(BLTOUCH, if (!bltouch.high_speed_mode) bltouch.deploy()); // Deploy in LOW SPEED MODE on every probe action + do_blocking_move_to_z(last_z - BED_TRAMMING_PROBE_TOLERANCE, z_probe_slow_mm_s); // Move down to lower tolerance + if (TEST(endstops.trigger_state(), Z_MIN_PROBE)) { // Probe triggered? endstops.hit_on_purpose(); set_current_from_steppers_for_axis(Z_AXIS); sync_plan_position(); @@ -251,10 +252,10 @@ static void _lcd_goto_next_corner() { if (TERN0(NEEDS_PROBE_DEPLOY, good_points == nr_edge_points - 1)) do_z_clearance(BED_TRAMMING_Z_HOP); - return true; // probe triggered + return true; // Triggered } - line_to_z(last_z); // go back to tolerance middle point before raise - return false; // probe not triggered + line_to_z(last_z); // Go back to tolerance middle point before raise + return false; // Not triggered } bool _lcd_bed_tramming_raise() { diff --git a/Marlin/src/module/motion.cpp b/Marlin/src/module/motion.cpp index fcaaf613e4..f2f27ee6a9 100644 --- a/Marlin/src/module/motion.cpp +++ b/Marlin/src/module/motion.cpp @@ -1990,7 +1990,7 @@ void prepare_line_to_destination() { */ feedRate_t get_homing_bump_feedrate(const AxisEnum axis) { #if HOMING_Z_WITH_PROBE - if (axis == Z_AXIS) return MMM_TO_MMS(Z_PROBE_FEEDRATE_SLOW); + if (axis == Z_AXIS) return z_probe_slow_mm_s; #endif static const uint8_t homing_bump_divisor[] PROGMEM = HOMING_BUMP_DIVISOR; uint8_t hbd = pgm_read_byte(&homing_bump_divisor[axis]); diff --git a/Marlin/src/module/motion.h b/Marlin/src/module/motion.h index 4245331010..edee41a903 100644 --- a/Marlin/src/module/motion.h +++ b/Marlin/src/module/motion.h @@ -71,7 +71,10 @@ extern xyz_pos_t cartes; #define XY_PROBE_FEEDRATE_MM_S PLANNER_XY_FEEDRATE_MM_S #endif -#if HAS_BED_PROBE +#ifdef Z_PROBE_FEEDRATE_SLOW + constexpr feedRate_t z_probe_slow_mm_s = MMM_TO_MMS(Z_PROBE_FEEDRATE_SLOW); +#endif +#ifdef Z_PROBE_FEEDRATE_FAST constexpr feedRate_t z_probe_fast_mm_s = MMM_TO_MMS(Z_PROBE_FEEDRATE_FAST); #endif diff --git a/Marlin/src/module/probe.cpp b/Marlin/src/module/probe.cpp index 9a998ec569..b1f1f2cf40 100644 --- a/Marlin/src/module/probe.cpp +++ b/Marlin/src/module/probe.cpp @@ -854,7 +854,7 @@ float Probe::run_z_probe(const bool sanity_check/*=true*/, const_float_t z_min_p // Probe downward slowly to find the bed if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Slow Probe:"); - if (try_to_probe(PSTR("SLOW"), z_probe_low_point, MMM_TO_MMS(Z_PROBE_FEEDRATE_SLOW), sanity_check)) return NAN; + if (try_to_probe(PSTR("SLOW"), z_probe_low_point, z_probe_slow_mm_s, sanity_check)) return NAN; TERN_(MEASURE_BACKLASH_WHEN_PROBING, backlash.measure_with_probe()); From 3cd945ab5dd9d4adcb2a130328f700f3f553ff4e Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Tue, 20 May 2025 00:32:44 +0000 Subject: [PATCH 323/787] [cron] Bump distribution date (2025-05-20) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 1deb2d2109..61232e769a 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-05-19" +//#define STRING_DISTRIBUTION_DATE "2025-05-20" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 8c62809731..8f8c30dbfa 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-05-19" + #define STRING_DISTRIBUTION_DATE "2025-05-20" #endif /** From af553d5fbd1e4217d38f5e0f629682d79570e438 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Mon, 19 May 2025 19:36:20 -0500 Subject: [PATCH 324/787] =?UTF-8?q?=F0=9F=94=A8=20Solve=20a=20linker=20err?= =?UTF-8?q?or?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #27864 --- Marlin/src/lcd/marlinui.cpp | 11 ++++++----- Marlin/src/lcd/marlinui.h | 6 +++++- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/Marlin/src/lcd/marlinui.cpp b/Marlin/src/lcd/marlinui.cpp index 991a4f549c..ab932adfcd 100644 --- a/Marlin/src/lcd/marlinui.cpp +++ b/Marlin/src/lcd/marlinui.cpp @@ -62,6 +62,10 @@ MarlinUI ui; #include "../module/printcounter.h" #endif +#if HAS_WIRED_LCD || HAS_PREHEAT + #include "../module/temperature.h" +#endif + #if LCD_HAS_WAIT_FOR_MOVE bool MarlinUI::wait_for_move; // = false #endif @@ -136,8 +140,6 @@ constexpr uint8_t epps = ENCODER_PULSES_PER_STEP; #endif #if HAS_PREHEAT - #include "../module/temperature.h" - preheat_t MarlinUI::material_preset[PREHEAT_COUNT]; // Initialized by settings.load void MarlinUI::reset_material_presets() { @@ -331,7 +333,6 @@ void MarlinUI::init() { #include "lcdprint.h" - #include "../module/temperature.h" #include "../module/planner.h" #include "../module/motion.h" @@ -1883,7 +1884,7 @@ uint8_t expand_u8str_P(char * const outstr, PGM_P const ptpl, const int8_t ind, ); } - #if LCD_WITH_BLINK && HAS_EXTRA_PROGRESS + #if HAS_ROTATE_PROGRESS // Renew and redraw all enabled progress strings void MarlinUI::rotate_progress() { @@ -1903,7 +1904,7 @@ uint8_t expand_u8str_P(char * const outstr, PGM_P const ptpl, const int8_t ind, } } - #endif // LCD_WITH_BLINK && HAS_EXTRA_PROGRESS + #endif // HAS_ROTATE_PROGRESS #endif // HAS_PRINT_PROGRESS diff --git a/Marlin/src/lcd/marlinui.h b/Marlin/src/lcd/marlinui.h index 578d143d96..adfecdbaf5 100644 --- a/Marlin/src/lcd/marlinui.h +++ b/Marlin/src/lcd/marlinui.h @@ -95,6 +95,10 @@ typedef bool (*statusResetFunc_t)(); #define LCD_UPDATE_INTERVAL DIV_TERN(DOUBLE_LCD_FRAMERATE, TERN(HAS_TOUCH_BUTTONS, 50, 100), 2) #endif +#if LCD_WITH_BLINK && HAS_EXTRA_PROGRESS && !IS_DWIN_MARLINUI + #define HAS_ROTATE_PROGRESS 1 +#endif + #if HAS_MARLINUI_U8GLIB enum MarlinFont : uint8_t { FONT_STATUSMENU = 1, @@ -347,7 +351,7 @@ public: FORCE_INLINE static uint16_t get_progress_permyriad() { return _get_progress(); } #endif static uint8_t get_progress_percent() { return uint8_t(_get_progress() / (PROGRESS_SCALE)); } - #if LCD_WITH_BLINK && HAS_EXTRA_PROGRESS + #if HAS_ROTATE_PROGRESS #if ENABLED(SHOW_PROGRESS_PERCENT) static void drawPercent(); #endif From d5723fcafd200a55fcc1fc1c37aab39da7fde12d Mon Sep 17 00:00:00 2001 From: Vovodroid Date: Tue, 20 May 2025 22:52:51 +0300 Subject: [PATCH 325/787] =?UTF-8?q?=F0=9F=94=A7=20Allow=20SMOOTH=5FLIN=5FA?= =?UTF-8?q?DVANCE=20+=20NONLINEAR=5FEXTRUSION=20(#27861)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/HAL/GD32_MFL/timers.h | 6 +- Marlin/src/gcode/feature/nonlinear/M592.cpp | 6 ++ Marlin/src/inc/SanityCheck.h | 2 - Marlin/src/module/planner.cpp | 4 ++ Marlin/src/module/planner.h | 4 +- Marlin/src/module/stepper.cpp | 73 ++++++++++++--------- Marlin/src/module/stepper.h | 25 +++++-- README-PT-BR.md | 2 +- 8 files changed, 74 insertions(+), 48 deletions(-) diff --git a/Marlin/src/HAL/GD32_MFL/timers.h b/Marlin/src/HAL/GD32_MFL/timers.h index 49d005b8cd..a5d36d9eca 100644 --- a/Marlin/src/HAL/GD32_MFL/timers.h +++ b/Marlin/src/HAL/GD32_MFL/timers.h @@ -44,9 +44,9 @@ extern uint32_t GetStepperTimerClkFreq(); // Timer prescaler calculations -#define STEPPER_TIMER_PRESCALE (GetStepperTimerClkFreq() / STEPPER_TIMER_RATE) // Prescaler = 30 +#define STEPPER_TIMER_PRESCALE (GetStepperTimerClkFreq() / STEPPER_TIMER_RATE) // Prescaler = 30 #define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE -#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000) // Stepper timer ticks per µs +#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000) // Stepper timer ticks per µs #define PULSE_TIMER_RATE STEPPER_TIMER_RATE #define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US @@ -57,7 +57,7 @@ extern uint32_t GetStepperTimerClkFreq(); #define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_STEP) #define DISABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_STEP) #define STEPPER_ISR_ENABLED() HAL_timer_interrupt_enabled(MF_TIMER_STEP) -#define ENABLE_TEMPERATURE_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_TEMP) +#define ENABLE_TEMPERATURE_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_TEMP) #define DISABLE_TEMPERATURE_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_TEMP) extern void Step_Handler(); diff --git a/Marlin/src/gcode/feature/nonlinear/M592.cpp b/Marlin/src/gcode/feature/nonlinear/M592.cpp index 77a6258ddc..78c15443f8 100644 --- a/Marlin/src/gcode/feature/nonlinear/M592.cpp +++ b/Marlin/src/gcode/feature/nonlinear/M592.cpp @@ -49,6 +49,12 @@ void GcodeSuite::M592() { if (parser.seenval('A')) stepper.ne.A = parser.value_float(); if (parser.seenval('B')) stepper.ne.B = parser.value_float(); if (parser.seenval('C')) stepper.ne.C = parser.value_float(); + + #if ENABLED(SMOOTH_LIN_ADVANCE) + stepper.ne_q30.A = _BV32(30) * (stepper.ne.A * planner.mm_per_step[E_AXIS_N(0)] * planner.mm_per_step[E_AXIS_N(0)]); + stepper.ne_q30.B = _BV32(30) * (stepper.ne.B * planner.mm_per_step[E_AXIS_N(0)]); + stepper.ne_q30.C = _BV32(30) * stepper.ne.C; + #endif } #endif // NONLINEAR_EXTRUSION diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index 97cc2ed198..c70c5ce0ec 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -868,8 +868,6 @@ static_assert(COUNT(arm) == LOGICAL_AXES, "AXIS_RELATIVE_MODES must contain " _L #error "SMOOTH_LIN_ADVANCE requires a 32-bit CPU." #elif ENABLED(S_CURVE_ACCELERATION) #error "SMOOTH_LIN_ADVANCE is not compatible with S_CURVE_ACCELERATION." - #elif ENABLED(NONLINEAR_EXTRUSION) - #error "SMOOTH_LIN_ADVANCE doesn't currently support NONLINEAR_EXTRUSION." #elif ENABLED(INPUT_SHAPING_E_SYNC) && NONE(INPUT_SHAPING_X, INPUT_SHAPING_Y) #error "INPUT_SHAPING_E_SYNC requires INPUT_SHAPING_X or INPUT_SHAPING_Y." #endif diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index fe497058d9..5e1c08f863 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -3252,6 +3252,10 @@ void Planner::refresh_acceleration_rates() { void Planner::refresh_positioning() { #if ENABLED(EDITABLE_STEPS_PER_UNIT) LOOP_DISTINCT_AXES(i) mm_per_step[i] = 1.0f / settings.axis_steps_per_mm[i]; + #if ALL(NONLINEAR_EXTRUSION, SMOOTH_LIN_ADVANCE) + stepper.ne_q30.A = _BV32(30) * (stepper.ne.A * mm_per_step[E_AXIS_N(0)] * mm_per_step[E_AXIS_N(0)]); + stepper.ne_q30.B = _BV32(30) * (stepper.ne.B * mm_per_step[E_AXIS_N(0)]); + #endif #endif set_position_mm(current_position); refresh_acceleration_rates(); diff --git a/Marlin/src/module/planner.h b/Marlin/src/module/planner.h index 0a3a35d922..c71a73c5be 100644 --- a/Marlin/src/module/planner.h +++ b/Marlin/src/module/planner.h @@ -531,9 +531,7 @@ class Planner { static void set_advance_k(const_float_t k, const uint8_t e=active_extruder) { UNUSED(e); extruder_advance_K[E_INDEX_N(e)] = k; - #if ENABLED(SMOOTH_LIN_ADVANCE) - extruder_advance_K_q27[E_INDEX_N(e)] = k * (1UL << 27); - #endif + TERN_(SMOOTH_LIN_ADVANCE, extruder_advance_K_q27[E_INDEX_N(e)] = k * _BV32(27)); } static float get_advance_k(const uint8_t e=active_extruder) { UNUSED(e); diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp index 04c796acb3..a6931c8d0d 100644 --- a/Marlin/src/module/stepper.cpp +++ b/Marlin/src/module/stepper.cpp @@ -257,9 +257,16 @@ uint32_t Stepper::advance_divisor = 0, #if ENABLED(NONLINEAR_EXTRUSION) ne_coeff_t Stepper::ne; - ne_fix_t Stepper::ne_fix; - int32_t Stepper::ne_edividend; - uint32_t Stepper::ne_scale; + #if NONLINEAR_EXTRUSION_Q24 + ne_q24_t Stepper::ne_q24; + #else + ne_q30_t Stepper::ne_q30; + #endif + // private: + #if NONLINEAR_EXTRUSION_Q24 + int32_t Stepper::ne_edividend; + uint32_t Stepper::ne_scale_q24; + #endif #endif #if HAS_ZV_SHAPING @@ -2241,13 +2248,13 @@ hal_timer_t Stepper::calc_timer_interval(uint32_t step_rate) { #endif // !CPU_32_BIT } -#if ENABLED(NONLINEAR_EXTRUSION) - void Stepper::calc_nonlinear_e(uint32_t step_rate) { - const uint32_t velocity = ne_scale * step_rate; // Scale step_rate first so all intermediate values stay in range of 8.24 fixed point math - int32_t vd = (((((int64_t)ne_fix.A * velocity) >> 24) * velocity) >> 24) + (((int64_t)ne_fix.B * velocity) >> 24); - NOLESS(vd, 0); +#if NONLINEAR_EXTRUSION_Q24 + void Stepper::calc_nonlinear_e(const uint32_t step_rate) { + const uint32_t velocity_q24 = ne_scale_q24 * step_rate; // Scale step_rate first so all intermediate values stay in range of 8.24 fixed point math + int32_t vd_q24 = (((((int64_t)ne_q24.A * velocity_q24) >> 24) * velocity_q24) >> 24) + (((int64_t)ne_q24.B * velocity_q24) >> 24); + NOLESS(vd_q24, 0); - advance_dividend.e = (uint64_t(ne_fix.C + vd) * ne_edividend) >> 24; + advance_dividend.e = (uint64_t(ne_q24.C + vd_q24) * ne_edividend) >> 24; } #endif @@ -2463,9 +2470,7 @@ hal_timer_t Stepper::block_phase_isr() { acceleration_time += interval; deceleration_time = 0; // Reset since we're doing acceleration first. - #if ENABLED(NONLINEAR_EXTRUSION) - calc_nonlinear_e(acc_step_rate << oversampling_factor); - #endif + calc_nonlinear_e(acc_step_rate << oversampling_factor); #if HAS_ROUGH_LIN_ADVANCE if (la_active) { @@ -2529,9 +2534,7 @@ hal_timer_t Stepper::block_phase_isr() { interval = calc_multistep_timer_interval(step_rate << oversampling_factor); deceleration_time += interval; - #if ENABLED(NONLINEAR_EXTRUSION) - calc_nonlinear_e(step_rate << oversampling_factor); - #endif + calc_nonlinear_e(step_rate << oversampling_factor); #if HAS_ROUGH_LIN_ADVANCE if (la_active) { @@ -2584,9 +2587,7 @@ hal_timer_t Stepper::block_phase_isr() { TERN_(SMOOTH_LIN_ADVANCE, curr_step_rate = current_block->nominal_rate;) deceleration_time = ticks_nominal / 2; - #if ENABLED(NONLINEAR_EXTRUSION) - calc_nonlinear_e(current_block->nominal_rate << oversampling_factor); - #endif + calc_nonlinear_e(current_block->nominal_rate << oversampling_factor); #if HAS_ROUGH_LIN_ADVANCE if (la_active) @@ -2836,18 +2837,18 @@ hal_timer_t Stepper::block_phase_isr() { acc_step_rate = current_block->initial_rate; #endif - #if ENABLED(NONLINEAR_EXTRUSION) + #if NONLINEAR_EXTRUSION_Q24 ne_edividend = advance_dividend.e; const float scale = (float(ne_edividend) / advance_divisor) * planner.mm_per_step[E_AXIS_N(current_block->extruder)]; - ne_scale = (1L << 24) * scale; + ne_scale_q24 = _BV32(24) * scale; if (current_block->direction_bits.e && ANY_AXIS_MOVES(current_block)) { - ne_fix.A = (1L << 24) * ne.A; - ne_fix.B = (1L << 24) * ne.B; - ne_fix.C = (1L << 24) * ne.C; + ne_q24.A = _BV32(24) * ne.A; + ne_q24.B = _BV32(24) * ne.B; + ne_q24.C = _BV32(24) * ne.C; } else { - ne_fix.A = ne_fix.B = 0; - ne_fix.C = (1L << 24); + ne_q24.A = ne_q24.B = 0; + ne_q24.C = _BV32(24); } #endif @@ -2856,9 +2857,7 @@ hal_timer_t Stepper::block_phase_isr() { // Initialize ac/deceleration time as if half the time passed. acceleration_time = deceleration_time = interval / 2; - #if ENABLED(NONLINEAR_EXTRUSION) - calc_nonlinear_e(current_block->initial_rate << oversampling_factor); - #endif + calc_nonlinear_e(current_block->initial_rate << oversampling_factor); #if ENABLED(LIN_ADVANCE) #if ENABLED(SMOOTH_LIN_ADVANCE) @@ -2885,13 +2884,23 @@ hal_timer_t Stepper::block_phase_isr() { uint32_t Stepper::extruder_advance_tau_ticks[DISTINCT_E], Stepper::extruder_advance_alpha_q30[DISTINCT_E]; - void Stepper::set_la_interval(const int32_t rate) { - if (rate == 0) { + void Stepper::set_la_interval(int32_t step_rate) { + if (step_rate == 0) { la_interval = LA_ADV_NEVER; } else { - const bool forward_e = rate > 0; - la_interval = calc_timer_interval(uint32_t(ABS(rate))); + const bool forward_e = step_rate > 0; + + #if ENABLED(NONLINEAR_EXTRUSION) + if (forward_e && ANY_AXIS_MOVES(current_block)) { + // Maximum polynomial value is just above 1, like 1.05..1.2, less than 2 anyway, so we can use 30 bits for fractional part + int32_t vd_q30 = ne_q30.A*step_rate*step_rate + ne_q30.B*step_rate; + NOLESS(vd_q30, 0); + step_rate = (int64_t(step_rate) * (ne_q30.C + vd_q30)) >> 30; + } + #endif + + la_interval = calc_timer_interval(uint32_t(ABS(step_rate))); if (forward_e != motor_direction(E_AXIS)) { last_direction_bits.toggle(E_AXIS); count_direction.e = -count_direction.e; diff --git a/Marlin/src/module/stepper.h b/Marlin/src/module/stepper.h index 3fb0b44884..9495a18139 100644 --- a/Marlin/src/module/stepper.h +++ b/Marlin/src/module/stepper.h @@ -285,7 +285,12 @@ constexpr ena_mask_t enable_overlap[] = { #if ENABLED(NONLINEAR_EXTRUSION) typedef struct { float A, B, C; void reset() { A = B = 0.0f; C = 1.0f; } } ne_coeff_t; - typedef struct { int32_t A, B, C; } ne_fix_t; + #if DISABLED(SMOOTH_LIN_ADVANCE) + #define NONLINEAR_EXTRUSION_Q24 1 + typedef struct { int32_t A, B, C; } ne_q24_t; + #else + typedef struct { int32_t A, B, C; } ne_q30_t; + #endif #endif // @@ -343,6 +348,11 @@ class Stepper { #if ENABLED(NONLINEAR_EXTRUSION) static ne_coeff_t ne; + #if NONLINEAR_EXTRUSION_Q24 + static ne_q24_t ne_q24; + #else + static ne_q30_t ne_q30; + #endif #endif #if ENABLED(ADAPTIVE_STEP_SMOOTHING_TOGGLE) @@ -467,10 +477,9 @@ class Stepper { #endif #endif - #if ENABLED(NONLINEAR_EXTRUSION) + #if NONLINEAR_EXTRUSION_Q24 static int32_t ne_edividend; - static uint32_t ne_scale; - static ne_fix_t ne_fix; + static uint32_t ne_scale_q24; #endif #if ENABLED(BABYSTEPPING) @@ -531,7 +540,7 @@ class Stepper { // The Linear advance ISR phase static void advance_isr(); #if ENABLED(SMOOTH_LIN_ADVANCE) - static void set_la_interval(const int32_t rate); + static void set_la_interval(int32_t step_rate); static hal_timer_t smooth_lin_adv_isr(); #endif #endif @@ -738,8 +747,10 @@ class Stepper { // Evaluate axis motions and set bits in axis_did_move static void set_axis_moved_for_current_block(); - #if ENABLED(NONLINEAR_EXTRUSION) - static void calc_nonlinear_e(uint32_t step_rate); + #if NONLINEAR_EXTRUSION_Q24 + static void calc_nonlinear_e(const uint32_t step_rate); + #else + static void calc_nonlinear_e(const uint32_t) {} #endif #if ENABLED(S_CURVE_ACCELERATION) diff --git a/README-PT-BR.md b/README-PT-BR.md index 8d8b18828f..3c730967ae 100644 --- a/README-PT-BR.md +++ b/README-PT-BR.md @@ -14,7 +14,7 @@ Siga MarlinFirmware no Mastodon

-Documentação adicional pode ser encontrada na [Página Inicial do Marlin](//marlinfw.org/). +Documentação adicional pode ser encontrada na [Página Inicial do Marlin](//marlinfw.org/). Por favor, teste este firmware e nos avise se encontrar algum problema. Voluntários estão prontos para ajudar! ## Branch de Correções do Marlin 2.1 From a4382b4dcdcf136908b1bc739fd310f9c4f4c9c5 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 20 May 2025 16:24:13 -0500 Subject: [PATCH 326/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Fix?= =?UTF-8?q?=20max=5Fisr=5Frate=20sign=20warnings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/module/stepper.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/src/module/stepper.h b/Marlin/src/module/stepper.h index 9495a18139..73fd28fe85 100644 --- a/Marlin/src/module/stepper.h +++ b/Marlin/src/module/stepper.h @@ -147,7 +147,7 @@ constexpr ena_mask_t enable_overlap[] = { TERN0(INPUT_SHAPING_Z, _ISDMF[Z_AXIS] * _ISDASU[Z_AXIS]); #if defined(__AVR__) || !defined(ADAPTIVE_STEP_SMOOTHING) // min_step_isr_frequency is known at compile time on AVRs and any reduction in SRAM is welcome - template constexpr float max_isr_rate() { + template constexpr float max_isr_rate() { return _MAX(_ISDMF[ALIM(INDEX - 1, _ISDMF)] * _ISDASU[ALIM(INDEX - 1, _ISDASU)], max_isr_rate()); } template<> constexpr float max_isr_rate<0>() { From 9c9ed690f787395e3dc464e9b1c8a22239dfcf8b Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Wed, 21 May 2025 00:32:16 +0000 Subject: [PATCH 327/787] [cron] Bump distribution date (2025-05-21) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 61232e769a..98e9fc410e 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-05-20" +//#define STRING_DISTRIBUTION_DATE "2025-05-21" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 8f8c30dbfa..a987b6d9ae 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-05-20" + #define STRING_DISTRIBUTION_DATE "2025-05-21" #endif /** From e7662920a621961254a681eaa732f01ebdd17cc8 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Thu, 22 May 2025 13:41:28 -0500 Subject: [PATCH 328/787] =?UTF-8?q?=F0=9F=A9=B9=20Fix=20delay=20=C2=B5s=20?= =?UTF-8?q?>=2032767?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #27753 --- Marlin/src/HAL/shared/Delay.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Marlin/src/HAL/shared/Delay.h b/Marlin/src/HAL/shared/Delay.h index 4751d7a5e2..eeaf4c59fc 100644 --- a/Marlin/src/HAL/shared/Delay.h +++ b/Marlin/src/HAL/shared/Delay.h @@ -100,7 +100,7 @@ void calibrate_delay_loop(); // For delay in microseconds, no smart delay selection is required, directly call the delay function // Teensy compiler is too old and does not accept smart delay compile-time / run-time selection correctly - #define DELAY_US(x) DelayCycleFnc((x) * ((F_CPU) / 1000000UL)) + #define DELAY_US(x) DelayCycleFnc((unsigned long)(x) * ((F_CPU) / 1000000UL)) #elif defined(__AVR__) FORCE_INLINE static void __delay_up_to_3c(uint8_t cycles) { @@ -164,7 +164,7 @@ void calibrate_delay_loop(); } // Delay in microseconds - #define DELAY_US(x) DELAY_CYCLES((x) * ((F_CPU) / 1000000UL)) + #define DELAY_US(x) DELAY_CYCLES((unsigned long)(x) * ((F_CPU) / 1000000UL)) #define DELAY_CYCLES_VAR DELAY_CYCLES @@ -173,7 +173,7 @@ void calibrate_delay_loop(); // DELAY_CYCLES specified inside platform // Delay in microseconds - #define DELAY_US(x) DELAY_CYCLES((x) * ((F_CPU) / 1000000UL)) + #define DELAY_US(x) DELAY_CYCLES((unsigned long)(x) * ((F_CPU) / 1000000UL)) #define DELAY_CYCLES_VAR DELAY_CYCLES From aa02bb05d3e28d3a38008d12784bab68611e92e6 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Fri, 23 May 2025 00:32:07 +0000 Subject: [PATCH 329/787] [cron] Bump distribution date (2025-05-23) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 98e9fc410e..71c2b31b6b 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-05-21" +//#define STRING_DISTRIBUTION_DATE "2025-05-23" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index a987b6d9ae..fabb554890 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-05-21" + #define STRING_DISTRIBUTION_DATE "2025-05-23" #endif /** From f49e730b23f4bcfc6162dad9dae03b164d4df198 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sun, 24 Nov 2024 22:17:34 -0600 Subject: [PATCH 330/787] =?UTF-8?q?=F0=9F=94=A7=20Allow=20TMCStepper=20wit?= =?UTF-8?q?h=20Zonestar=20ZM3=20E2xx?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ini/stm32f1-maple.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ini/stm32f1-maple.ini b/ini/stm32f1-maple.ini index ddd75549c8..17bcb2eb60 100644 --- a/ini/stm32f1-maple.ini +++ b/ini/stm32f1-maple.ini @@ -389,7 +389,7 @@ build_flags = ${STM32F1_maple.build_flags} -D__STM32F1__=1 -DDEBUG_LEVEL=0 -DSS_TIMER=4 -DSERIAL_USB lib_deps = ${STM32F1_maple.lib_deps} USBComposite for STM32F1@0.91 -lib_ignore = Adafruit NeoPixel, SPI, SailfishLCD, SailfishRGB_LED, SlowSoftI2CMaster, TMCStepper +lib_ignore = Adafruit NeoPixel, SPI, SailfishLCD, SailfishRGB_LED, SlowSoftI2CMaster [env:STM32F103RC_ZM3E2_USB_maple] extends = ZONESTAR_ZM3E_maple From 1258657b8d428f2e28463b6bc46f551193c31bb1 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Sat, 24 May 2025 00:30:50 +0000 Subject: [PATCH 331/787] [cron] Bump distribution date (2025-05-24) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 71c2b31b6b..cb96070cc4 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-05-23" +//#define STRING_DISTRIBUTION_DATE "2025-05-24" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index fabb554890..51a13f1947 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-05-23" + #define STRING_DISTRIBUTION_DATE "2025-05-24" #endif /** From 202ec4b58f76edfff0376306c46ca8529971340a Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Fri, 23 May 2025 21:11:50 -0500 Subject: [PATCH 332/787] =?UTF-8?q?=E2=9C=A8=20Trinamic=20TMC2240=20(SPI)?= =?UTF-8?q?=20(#25974)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: David Buezas Co-Authored-By: z1996xm <102506464+z1996xm@users.noreply.github.com> --- Marlin/Configuration.h | 6 +- Marlin/Configuration_adv.h | 23 ++-- Marlin/src/core/drivers.h | 34 ++++-- Marlin/src/feature/tmc_util.cpp | 76 ++++++++++++ Marlin/src/feature/tmc_util.h | 77 +++++++++++- .../src/gcode/feature/trinamic/M911-M914.cpp | 6 +- Marlin/src/gcode/gcode.h | 12 +- Marlin/src/inc/SanityCheck.h | 64 +++++----- Marlin/src/module/stepper/trinamic.cpp | 114 +++++++++++++++--- Marlin/src/module/stepper/trinamic.h | 1 + buildroot/tests/BTT_BTT002 | 3 +- 11 files changed, 335 insertions(+), 81 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index dc042ff1cb..859f0bbd33 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -148,9 +148,9 @@ * Options: A4988, A5984, DRV8825, LV8729, TB6560, TB6600, TMC2100, * TMC2130, TMC2130_STANDALONE, TMC2160, TMC2160_STANDALONE, * TMC2208, TMC2208_STANDALONE, TMC2209, TMC2209_STANDALONE, - * TMC2660, TMC2660_STANDALONE, TMC5130, TMC5130_STANDALONE, - * TMC5160, TMC5160_STANDALONE - * :['A4988', 'A5984', 'DRV8825', 'LV8729', 'TB6560', 'TB6600', 'TMC2100', 'TMC2130', 'TMC2130_STANDALONE', 'TMC2160', 'TMC2160_STANDALONE', 'TMC2208', 'TMC2208_STANDALONE', 'TMC2209', 'TMC2209_STANDALONE', 'TMC2660', 'TMC2660_STANDALONE', 'TMC5130', 'TMC5130_STANDALONE', 'TMC5160', 'TMC5160_STANDALONE'] + * TMC2240, TMC2240_STANDALONE, TMC2660, TMC2660_STANDALONE, + * TMC5130, TMC5130_STANDALONE, TMC5160, TMC5160_STANDALONE + * :['A4988', 'A5984', 'DRV8825', 'LV8729', 'TB6560', 'TB6600', 'TMC2100', 'TMC2130', 'TMC2130_STANDALONE', 'TMC2160', 'TMC2160_STANDALONE', 'TMC2208', 'TMC2208_STANDALONE', 'TMC2209', 'TMC2209_STANDALONE', 'TMC2240', 'TMC2240_STANDALONE', 'TMC2660', 'TMC2660_STANDALONE', 'TMC5130', 'TMC5130_STANDALONE', 'TMC5160', 'TMC5160_STANDALONE'] */ #define X_DRIVER_TYPE A4988 #define Y_DRIVER_TYPE A4988 diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 60e5378c30..93d84d8d9c 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -3027,6 +3027,15 @@ */ #define INTERPOLATE true + #if HAS_DRIVER(TMC2240) + #define TMC2240_CURRENT_RANGE 1 // RMS: { 0:'690mA', 1:'1410mA', 2:'2120mA', 3:'2110mA' } + // PEAK:{ 0:'1A', 1:'2A', 2:'3A', 3:'3A' } + // Determines max current. Lower is more internal current resolution. Higher runs cooler. + #define TMC2240_Rref 12000 // ('rref', 12000, minval=12000, maxval=60000) + #define TMC2240_SLOPE_CONTROL 0 // :{ 0:'100V/us', 1:'200V/us', 2:'400V/us', 3:'800V/us' } + // Lower is more silent. Higher runs cooler. + #endif + #if AXIS_IS_TMC_CONFIG(X) #define X_CURRENT 800 // (mA) RMS current. Multiply by 1.414 for peak current. #define X_CURRENT_HOME X_CURRENT // (mA) RMS current for homing. (Typically lower than *_CURRENT.) @@ -3335,7 +3344,7 @@ // @section tmc/stealthchop /** - * TMC2130, TMC2160, TMC2208, TMC2209, TMC5130 and TMC5160 only + * TMC2130, TMC2160, TMC2208, TMC2209, TMC2240, TMC5130 and TMC5160 only * Use Trinamic's ultra quiet stepping mode. * When disabled, Marlin will use spreadCycle stepping mode. */ @@ -3414,7 +3423,7 @@ // @section tmc/hybrid /** - * TMC2130, TMC2160, TMC2208, TMC2209, TMC5130 and TMC5160 only + * TMC2130, TMC2160, TMC2208, TMC2209, TMC2240, TMC5130 and TMC5160 only * The driver will switch to spreadCycle when stepper speed is over HYBRID_THRESHOLD. * This mode allows for faster movements at the expense of higher noise levels. * STEALTHCHOP_(XY|Z|E) must be enabled to use HYBRID_THRESHOLD. @@ -3448,16 +3457,16 @@ /** * Use StallGuard to home / probe X, Y, Z. * - * TMC2130, TMC2160, TMC2209, TMC2660, TMC5130, and TMC5160 only + * TMC2130, TMC2160, TMC2209, TMC2240, TMC2660, TMC5130, and TMC5160 only * Connect the stepper driver's DIAG1 pin to the X/Y endstop pin. * X, Y, and Z homing will always be done in spreadCycle mode. * * X/Y/Z_STALL_SENSITIVITY is the default stall threshold. * Use M914 X Y Z to set the stall threshold at runtime: * - * Sensitivity TMC2209 Others - * HIGHEST 255 -64 (Too sensitive => False positive) - * LOWEST 0 63 (Too insensitive => No trigger) + * Sensitivity TMC2209/2240 Others + * HIGHEST 255 -64 (Too sensitive => False positive) + * LOWEST 0 63 (Too insensitive => No trigger) * * It is recommended to set HOMING_BUMP_MM to { 0, 0, 0 }. * @@ -3474,7 +3483,7 @@ //#define SENSORLESS_HOMING // StallGuard capable drivers only #if ANY(SENSORLESS_HOMING, SENSORLESS_PROBING) - // TMC2209: 0...255. TMC2130: -64...63 + // TMC2209/2240: 0...255. TMC2130: -64...63 #define X_STALL_SENSITIVITY 8 #define X2_STALL_SENSITIVITY X_STALL_SENSITIVITY #define Y_STALL_SENSITIVITY 8 diff --git a/Marlin/src/core/drivers.h b/Marlin/src/core/drivers.h index c54e42c8fe..6b1a70202c 100644 --- a/Marlin/src/core/drivers.h +++ b/Marlin/src/core/drivers.h @@ -41,6 +41,8 @@ #define _TMC2208_STANDALONE 0x2208B #define _TMC2209 0x2209A #define _TMC2209_STANDALONE 0x2209B +#define _TMC2240 0x2240A +#define _TMC2240_STANDALONE 0x2240B #define _TMC2660 0x2660A #define _TMC2660_STANDALONE 0x2660B #define _TMC5130 0x5130A @@ -96,7 +98,7 @@ // Does not match standalone configurations #if ( HAS_DRIVER(TMC2130) || HAS_DRIVER(TMC2160) \ || HAS_DRIVER(TMC2208) || HAS_DRIVER(TMC2209) \ - || HAS_DRIVER(TMC2660) \ + || HAS_DRIVER(TMC2240) || HAS_DRIVER(TMC2660) \ || HAS_DRIVER(TMC5130) || HAS_DRIVER(TMC5160) ) #define HAS_TRINAMIC_CONFIG 1 #endif @@ -106,22 +108,30 @@ #if ( HAS_DRIVER(TMC2100) \ || HAS_DRIVER(TMC2130_STANDALONE) || HAS_DRIVER(TMC2160_STANDALONE) \ || HAS_DRIVER(TMC2208_STANDALONE) || HAS_DRIVER(TMC2209_STANDALONE) \ - || HAS_DRIVER(TMC2660_STANDALONE) || HAS_DRIVER(TMC5130_STANDALONE) \ - || HAS_DRIVER(TMC5160_STANDALONE) ) + || HAS_DRIVER(TMC2240_STANDALONE) || HAS_DRIVER(TMC2660_STANDALONE) \ + || HAS_DRIVER(TMC5130_STANDALONE) || HAS_DRIVER(TMC5160_STANDALONE) ) #define HAS_TRINAMIC_STANDALONE 1 #endif -#if HAS_DRIVER(TMC2130) || HAS_DRIVER(TMC2160) || HAS_DRIVER(TMC5130) || HAS_DRIVER(TMC5160) +#if HAS_DRIVER(TMC2130) || HAS_DRIVER(TMC2160) || HAS_DRIVER(TMC5130) || HAS_DRIVER(TMC5160) || HAS_DRIVER(TMC2240) #define HAS_TMCX1X0 1 #endif - #if HAS_DRIVER(TMC2208) || HAS_DRIVER(TMC2209) #define HAS_TMC220x 1 #endif +//#if HAS_TMC_220x || HAS_DRIVER(TMC2240) +// #define HAS_TMC22xx 1 +//#endif +//#if HAS_TMCX1X0 || HAS_TMC220x +// #define HAS_TMC_CS_ACTUAL 1 +//#endif +//#if HAS_TMCX1X0 || HAS_DRIVER(TMC2209) +// #define HAS_TMC_SG_RESULT 1 +//#endif #define AXIS_IS_TMC(A) ( AXIS_DRIVER_TYPE(A,TMC2130) || AXIS_DRIVER_TYPE(A,TMC2160) \ || AXIS_DRIVER_TYPE(A,TMC2208) || AXIS_DRIVER_TYPE(A,TMC2209) \ - || AXIS_DRIVER_TYPE(A,TMC2660) \ + || AXIS_DRIVER_TYPE(A,TMC2240) || AXIS_DRIVER_TYPE(A,TMC2660) \ || AXIS_DRIVER_TYPE(A,TMC5130) || AXIS_DRIVER_TYPE(A,TMC5160) ) #define AXIS_IS_TMC_CONFIG AXIS_IS_TMC @@ -129,8 +139,8 @@ // Test for a driver that uses SPI - this allows checking whether a _CS_ pin // is considered sensitive #define AXIS_HAS_SPI(A) ( AXIS_DRIVER_TYPE(A,TMC2130) || AXIS_DRIVER_TYPE(A,TMC2160) \ - || AXIS_DRIVER_TYPE(A,TMC2660) || AXIS_DRIVER_TYPE(A,TMC5130) \ - || AXIS_DRIVER_TYPE(A,TMC5160) ) + || AXIS_DRIVER_TYPE(A,TMC2240) || AXIS_DRIVER_TYPE(A,TMC2660) \ + || AXIS_DRIVER_TYPE(A,TMC5130) || AXIS_DRIVER_TYPE(A,TMC5160) ) #define AXIS_HAS_UART(A) ( AXIS_DRIVER_TYPE(A,TMC2208) || AXIS_DRIVER_TYPE(A,TMC2209) ) @@ -140,19 +150,21 @@ #define AXIS_HAS_SW_SERIAL(A) ( AXIS_HAS_UART(A) && !defined(A##_HARDWARE_SERIAL) ) #define AXIS_HAS_STALLGUARD(A) ( AXIS_DRIVER_TYPE(A,TMC2130) || AXIS_DRIVER_TYPE(A,TMC2160) \ - || AXIS_DRIVER_TYPE(A,TMC2209) \ + || AXIS_DRIVER_TYPE(A,TMC2209) || AXIS_DRIVER_TYPE(A,TMC2240) \ || AXIS_DRIVER_TYPE(A,TMC2660) \ || AXIS_DRIVER_TYPE(A,TMC5130) || AXIS_DRIVER_TYPE(A,TMC5160) ) #define AXIS_HAS_STEALTHCHOP(A) ( AXIS_DRIVER_TYPE(A,TMC2130) || AXIS_DRIVER_TYPE(A,TMC2160) \ || AXIS_DRIVER_TYPE(A,TMC2208) || AXIS_DRIVER_TYPE(A,TMC2209) \ + || AXIS_DRIVER_TYPE(A,TMC2240) \ || AXIS_DRIVER_TYPE(A,TMC5130) || AXIS_DRIVER_TYPE(A,TMC5160) ) #define AXIS_HAS_SG_RESULT(A) ( AXIS_DRIVER_TYPE(A,TMC2130) || AXIS_DRIVER_TYPE(A,TMC2160) \ - || AXIS_DRIVER_TYPE(A,TMC2208) || AXIS_DRIVER_TYPE(A,TMC2209) ) + || AXIS_DRIVER_TYPE(A,TMC2208) || AXIS_DRIVER_TYPE(A,TMC2209) \ + || AXIS_DRIVER_TYPE(A,TMC2240) ) #define AXIS_HAS_COOLSTEP(A) ( AXIS_DRIVER_TYPE(A,TMC2130) \ - || AXIS_DRIVER_TYPE(A,TMC2209) \ + || AXIS_DRIVER_TYPE(A,TMC2209) || AXIS_DRIVER_TYPE(A,TMC2240) \ || AXIS_DRIVER_TYPE(A,TMC5130) || AXIS_DRIVER_TYPE(A,TMC5160) ) #define _OR_EAH(N,T) || AXIS_HAS_##T(E##N) diff --git a/Marlin/src/feature/tmc_util.cpp b/Marlin/src/feature/tmc_util.cpp index 753cb003ff..d920c3a604 100644 --- a/Marlin/src/feature/tmc_util.cpp +++ b/Marlin/src/feature/tmc_util.cpp @@ -142,6 +142,67 @@ #endif // HAS_TMCX1X0 + #if HAS_DRIVER(TMC2240) + + #if ENABLED(TMC_DEBUG) + static uint32_t get_pwm_scale(TMC2240Stepper &st) { return st.PWM_SCALE(); } + #endif + + static TMC_driver_data get_driver_data(TMC2240Stepper &st) { + constexpr uint8_t OT_bp = 25, OTPW_bp = 26; + constexpr uint32_t S2G_bm = 0x18000000; + #if ENABLED(TMC_DEBUG) + constexpr uint16_t SG_RESULT_bm = 0x3FF; // 0:9 + constexpr uint8_t STEALTH_bp = 14; + constexpr uint32_t CS_ACTUAL_bm = 0x1F0000; // 16:20 + constexpr uint8_t STALL_GUARD_bp = 24; + constexpr uint8_t STST_bp = 31; + #endif + TMC_driver_data data; + const auto ds = data.drv_status = st.DRV_STATUS(); + #ifdef __AVR__ + + // 8-bit optimization saves up to 70 bytes of PROGMEM per axis + uint8_t spart; + #if ENABLED(TMC_DEBUG) + data.sg_result = ds & SG_RESULT_bm; + spart = ds >> 8; + data.is_stealth = TEST(spart, STEALTH_bp - 8); + spart = ds >> 16; + data.cs_actual = spart & (CS_ACTUAL_bm >> 16); + #endif + spart = ds >> 24; + data.is_ot = TEST(spart, OT_bp - 24); + data.is_otpw = TEST(spart, OTPW_bp - 24); + data.is_s2g = !!(spart & (S2G_bm >> 24)); + #if ENABLED(TMC_DEBUG) + data.is_stall = TEST(spart, STALL_GUARD_bp - 24); + data.is_standstill = TEST(spart, STST_bp - 24); + data.sg_result_reasonable = !data.is_standstill; // sg_result has no reasonable meaning while standstill + #endif + + #else // !__AVR__ + + data.is_ot = TEST(ds, OT_bp); + data.is_otpw = TEST(ds, OTPW_bp); + data.is_s2g = !!(ds & S2G_bm); + #if ENABLED(TMC_DEBUG) + constexpr uint8_t CS_ACTUAL_sb = 16; + data.sg_result = ds & SG_RESULT_bm; + data.is_stealth = TEST(ds, STEALTH_bp); + data.cs_actual = (ds & CS_ACTUAL_bm) >> CS_ACTUAL_sb; + data.is_stall = TEST(ds, STALL_GUARD_bp); + data.is_standstill = TEST(ds, STST_bp); + data.sg_result_reasonable = !data.is_standstill; // sg_result has no reasonable meaning while standstill + #endif + + #endif // !__AVR__ + + return data; + } + + #endif // TMC2240 + #if HAS_TMC220x #if ENABLED(TMC_DEBUG) @@ -1025,6 +1086,21 @@ st.TCOOLTHRS(0); } + bool tmc_enable_stallguard(TMC2240Stepper &st) { + const bool stealthchop_was_enabled = st.en_pwm_mode(); + + st.TCOOLTHRS(0xFFFFF); + st.en_pwm_mode(false); + st.diag0_stall(true); + + return stealthchop_was_enabled; + } + void tmc_disable_stallguard(TMC2240Stepper &st, const bool restore_stealth) { + st.TCOOLTHRS(0); + st.en_pwm_mode(restore_stealth); + st.diag0_stall(false); + } + bool tmc_enable_stallguard(TMC2660Stepper) { // TODO return false; diff --git a/Marlin/src/feature/tmc_util.h b/Marlin/src/feature/tmc_util.h index 4cac2969a7..55a4eb02aa 100644 --- a/Marlin/src/feature/tmc_util.h +++ b/Marlin/src/feature/tmc_util.h @@ -95,7 +95,7 @@ class TMCMarlin : public TMC, public TMCStorage { TMC(CS, RS, pinMOSI, pinMISO, pinSCK) {} TMCMarlin(const uint16_t CS, const float RS, const uint16_t pinMOSI, const uint16_t pinMISO, const uint16_t pinSCK, const uint8_t axis_chain_index) : - TMC(CS, RS, pinMOSI, pinMISO, pinSCK, axis_chain_index) + TMC(CS, RS, pinMOSI, pinMISO, pinSCK, axis_chain_index) {} uint16_t rms_current() { return TMC::rms_current(); } void rms_current(uint16_t mA) { @@ -124,7 +124,7 @@ class TMCMarlin : public TMC, public TMCStorage { #if ENABLED(HYBRID_THRESHOLD) uint32_t get_pwm_thrs() { - return _tmc_thrs(this->microsteps(), this->TPWMTHRS(), planner.settings.axis_steps_per_mm[AXIS_ID]); + return _tmc_thrs(this->microsteps(), TMC::TPWMTHRS(), planner.settings.axis_steps_per_mm[AXIS_ID]); } void set_pwm_thrs(const uint32_t thrs) { TMC::TPWMTHRS(_tmc_thrs(this->microsteps(), thrs, planner.settings.axis_steps_per_mm[AXIS_ID])); @@ -197,7 +197,7 @@ class TMCMarlin : public TMC220 #if ENABLED(HYBRID_THRESHOLD) uint32_t get_pwm_thrs() { - return _tmc_thrs(this->microsteps(), this->TPWMTHRS(), planner.settings.axis_steps_per_mm[AXIS_ID]); + return _tmc_thrs(this->microsteps(), TMC2208Stepper::TPWMTHRS(), planner.settings.axis_steps_per_mm[AXIS_ID]); } void set_pwm_thrs(const uint32_t thrs) { TMC2208Stepper::TPWMTHRS(_tmc_thrs(this->microsteps(), thrs, planner.settings.axis_steps_per_mm[AXIS_ID])); @@ -249,13 +249,14 @@ class TMCMarlin : public TMC220 #if ENABLED(HYBRID_THRESHOLD) uint32_t get_pwm_thrs() { - return _tmc_thrs(this->microsteps(), this->TPWMTHRS(), planner.settings.axis_steps_per_mm[AXIS_ID]); + return _tmc_thrs(this->microsteps(), TMC2209Stepper::TPWMTHRS(), planner.settings.axis_steps_per_mm[AXIS_ID]); } void set_pwm_thrs(const uint32_t thrs) { TMC2209Stepper::TPWMTHRS(_tmc_thrs(this->microsteps(), thrs, planner.settings.axis_steps_per_mm[AXIS_ID])); TERN_(HAS_MARLINUI_MENU, this->stored.hybrid_thrs = thrs); } #endif + #if USE_SENSORLESS int16_t homing_threshold() { return TMC2209Stepper::SGTHRS(); } void homing_threshold(int16_t sgt_val) { @@ -278,6 +279,74 @@ class TMCMarlin : public TMC220 sgt_max = 255; }; +template +class TMCMarlin : public TMC2240Stepper, public TMCStorage { + public: + TMCMarlin(const uint16_t cs_pin, const uint8_t axis_chain_index) : + TMC2240Stepper(cs_pin, axis_chain_index) + {} + TMCMarlin(const uint16_t CS, const uint16_t pinMOSI, const uint16_t pinMISO, const uint16_t pinSCK, const uint8_t axis_chain_index) : + TMC2240Stepper(CS, pinMOSI, pinMISO, pinSCK, axis_chain_index ) + {} + + //uint8_t get_address() { return slave_address; } + uint16_t get_microstep_counter() { return microsteps(); } + + uint16_t rms_current() { return TMC2240Stepper::rms_current(); } + void rms_current(const uint16_t mA) { + this->val_mA = mA; + TMC2240Stepper::rms_current(mA); + } + void rms_current(const uint16_t mA, const float mult) { + this->val_mA = mA; + TMC2240Stepper::rms_current(mA, mult); + } + + #if HAS_STEALTHCHOP + bool get_stealthChop() { return this->en_pwm_mode(); } + bool get_stored_stealthChop() { return this->stored.stealthChop_enabled; } + void refresh_stepping_mode() { this->en_pwm_mode(this->stored.stealthChop_enabled); } + void set_stealthChop(const bool stch) { this->stored.stealthChop_enabled = stch; refresh_stepping_mode(); } + bool toggle_stepping_mode() { set_stealthChop(!this->stored.stealthChop_enabled); return get_stealthChop(); } + #endif + + void set_chopper_times(const chopper_timing_t &ct) { + TMC2240Stepper::toff(ct.toff); + TMC2240Stepper::hysteresis_end(ct.hend); + TMC2240Stepper::hysteresis_start(ct.hstrt); + } + + #if ENABLED(HYBRID_THRESHOLD) + uint32_t get_pwm_thrs() { + return _tmc_thrs(this->microsteps(), TMC2240Stepper::TPWMTHRS(), planner.settings.axis_steps_per_mm[AXIS_ID]); + } + void set_pwm_thrs(const uint32_t thrs) { + TMC2240Stepper::TPWMTHRS(_tmc_thrs(this->microsteps(), thrs, planner.settings.axis_steps_per_mm[AXIS_ID])); + TERN_(HAS_MARLINUI_MENU, this->stored.hybrid_thrs = thrs); + } + #endif + + #if USE_SENSORLESS + int16_t homing_threshold() { return TMC2240Stepper::sgt(); } + void homing_threshold(int16_t sgt_val) { + sgt_val = (int16_t)constrain(sgt_val, sgt_min, sgt_max); + TMC2240Stepper::sgt(sgt_val); + TERN_(HAS_MARLINUI_MENU, this->stored.homing_thrs = sgt_val); + } + #endif + + void refresh_stepper_current() { rms_current(this->val_mA); } + #if ENABLED(HYBRID_THRESHOLD) + void refresh_hybrid_thrs() { set_pwm_thrs(this->stored.hybrid_thrs); } + #endif + #if USE_SENSORLESS + void refresh_homing_thrs() { homing_threshold(this->stored.homing_thrs); } + #endif + + static constexpr int8_t sgt_min = -64, + sgt_max = 63; +}; + template class TMCMarlin : public TMC2660Stepper, public TMCStorage { public: diff --git a/Marlin/src/gcode/feature/trinamic/M911-M914.cpp b/Marlin/src/gcode/feature/trinamic/M911-M914.cpp index f4b0ac3670..52622a5e7e 100644 --- a/Marlin/src/gcode/feature/trinamic/M911-M914.cpp +++ b/Marlin/src/gcode/feature/trinamic/M911-M914.cpp @@ -32,7 +32,9 @@ #if ENABLED(MONITOR_DRIVER_STATUS) - #define M91x_USE(ST) (AXIS_DRIVER_TYPE(ST, TMC2130) || AXIS_DRIVER_TYPE(ST, TMC2160) || AXIS_DRIVER_TYPE(ST, TMC2208) || AXIS_DRIVER_TYPE(ST, TMC2209) || AXIS_DRIVER_TYPE(ST, TMC2660) || AXIS_DRIVER_TYPE(ST, TMC5130) || AXIS_DRIVER_TYPE(ST, TMC5160)) + #define M91x_USE(ST) (AXIS_DRIVER_TYPE(ST, TMC2130) || AXIS_DRIVER_TYPE(ST, TMC2160) \ + || AXIS_DRIVER_TYPE(ST, TMC2208) || AXIS_DRIVER_TYPE(ST, TMC2209) || AXIS_DRIVER_TYPE(ST, TMC2240) \ + || AXIS_DRIVER_TYPE(ST, TMC2660) || AXIS_DRIVER_TYPE(ST, TMC5130) || AXIS_DRIVER_TYPE(ST, TMC5160)) #define M91x_USE_E(N) (E_STEPPERS > N && M91x_USE(E##N)) #if HAS_X_AXIS && (M91x_USE(X) || M91x_USE(X2)) @@ -68,7 +70,7 @@ #endif #if !M91x_SOME_X && !M91x_SOME_Y && !M91x_SOME_Z && !M91x_USE_I && !M91x_USE_J && !M91x_USE_K && !M91x_USE_U && !M91x_USE_V && !M91x_USE_W && !M91x_SOME_E - #error "MONITOR_DRIVER_STATUS requires at least one TMC2130, 2160, 2208, 2209, 2660, 5130, or 5160." + #error "MONITOR_DRIVER_STATUS requires at least one TMC2130, 2160, 2208, 2209, 2240, 2660, 5130, or 5160." #endif template diff --git a/Marlin/src/gcode/gcode.h b/Marlin/src/gcode/gcode.h index 706a7387db..cfe0ec056f 100644 --- a/Marlin/src/gcode/gcode.h +++ b/Marlin/src/gcode/gcode.h @@ -159,7 +159,7 @@ * M120 - Enable endstops detection. * M121 - Disable endstops detection. * - * M122 - Debug stepper (Requires *_DRIVER_TYPE TMC(2130|2160|5130|5160|2208|2209|2660)) + * M122 - Debug stepper (Requires *_DRIVER_TYPE TMC(2130|2160|5130|5160|2208|2209|2240|2660)) * M123 - Report fan tachometers. (Requires En_FAN_TACHO_PIN) Optionally set auto-report interval. (Requires AUTO_REPORT_FANS) * M125 - Save current position and move to filament change position. (Requires PARK_HEAD_ON_PAUSE) * @@ -265,7 +265,7 @@ * M552 - Get or set IP address. Enable/disable network interface. (Requires enabled Ethernet port) * M553 - Get or set IP netmask. (Requires enabled Ethernet port) * M554 - Get or set IP gateway. (Requires enabled Ethernet port) - * M569 - Enable stealthChop on an axis. (Requires *_DRIVER_TYPE TMC(2130|2160|2208|2209|5130|5160)) + * M569 - Enable stealthChop on an axis. (Requires *_DRIVER_TYPE TMC(2130|2160|2208|2209|2240|5130|5160)) * M575 - Change the serial baud rate. (Requires BAUD_RATE_GCODE) * M592 - Get or set Nonlinear Extrusion parameters. (Requires NONLINEAR_EXTRUSION) * M593 - Get or set input shaping parameters. (Requires INPUT_SHAPING_[XY]) @@ -309,17 +309,17 @@ * M871 - Print/reset/clear first layer temperature offset values. (Requires PTC_PROBE, PTC_BED, or PTC_HOTEND) * M876 - Handle Prompt Response. (Requires HOST_PROMPT_SUPPORT and not EMERGENCY_PARSER) * M900 - Set or Report Linear Advance K-factor. (Requires LIN_ADVANCE) - * M906 - Set or Report motor current in milliamps using axis codes XYZE, etc. Report values if no axis codes given. (Requires *_DRIVER_TYPE TMC(2130|2160|5130|5160|2208|2209|2660)) + * M906 - Set or Report motor current in milliamps using axis codes XYZE, etc. Report values if no axis codes given. (Requires *_DRIVER_TYPE TMC(2130|2160|5130|5160|2208|2209|2240|2660)) * M907 - Set digital trimpot motor current using axis codes. (Requires a board with digital trimpots) * M908 - Control digital trimpot directly. (Requires HAS_MOTOR_CURRENT_DAC or DIGIPOTSS_PIN) * M909 - Print digipot/DAC current value. (Requires HAS_MOTOR_CURRENT_DAC) * M910 - Commit digipot/DAC value to external EEPROM via I2C. (Requires HAS_MOTOR_CURRENT_DAC) - * M911 - Report stepper driver overtemperature pre-warn condition. (Requires *_DRIVER_TYPE TMC(2130|2160|5130|5160|2208|2209|2660)) - * M912 - Clear stepper driver overtemperature pre-warn condition flag. (Requires *_DRIVER_TYPE TMC(2130|2160|5130|5160|2208|2209|2660)) + * M911 - Report stepper driver overtemperature pre-warn condition. (Requires *_DRIVER_TYPE TMC(2130|2160|5130|5160|2208|2209|2240|2660)) + * M912 - Clear stepper driver overtemperature pre-warn condition flag. (Requires *_DRIVER_TYPE TMC(2130|2160|5130|5160|2208|2209|2240|2660)) * M913 - Set HYBRID_THRESHOLD speed. (Requires HYBRID_THRESHOLD) * M914 - Set StallGuard sensitivity. (Requires SENSORLESS_HOMING or SENSORLESS_PROBING) * M919 - Set or Report motor Chopper Times (time_off, hysteresis_end, hysteresis_start) using axis codes XYZE, etc. - * If no parameters are given, report. (Requires *_DRIVER_TYPE TMC(2130|2160|5130|5160|2208|2209|2660)) + * If no parameters are given, report. (Requires *_DRIVER_TYPE TMC(2130|2160|5130|5160|2208|2209|2240|2660)) * M920 - Set Homing Current. (Requires distinct *_CURRENT_HOME settings) * M936 - OTA update firmware. (Requires OTA_FIRMWARE_UPDATE) * M951 - Set Magnetic Parking Extruder parameters. (Requires MAGNETIC_PARKING_EXTRUDER) diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index c70c5ce0ec..5d427e7e08 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -3378,19 +3378,19 @@ static_assert(NUM_SERVOS <= NUM_SERVO_PLUGS, "NUM_SERVOS (or some servo index) i #error "SPI_ENDSTOPS requires stepper drivers with SPI support." #endif #else // !SPI_ENDSTOPS - // Stall detection DIAG = HIGH : TMC2209 - // Stall detection DIAG = LOW : TMC2130/TMC2160/TMC2660/TMC5130/TMC5160 + // Stall detection DIAG = HIGH : TMC2209/2240 + // Stall detection DIAG = LOW : TMC2130/2160/2660/5130/5160 #if X_SENSORLESS - #define _HIT_STATE AXIS_DRIVER_TYPE(X,TMC2209) + #define _HIT_STATE AXIS_DRIVER_TYPE(X,TMC2209) || AXIS_DRIVER_TYPE(X,TMC2240) #if X_HOME_TO_MIN && X_MIN_ENDSTOP_HIT_STATE != _HIT_STATE #if _HIT_STATE - #error "SENSORLESS_HOMING requires X_MIN_ENDSTOP_HIT_STATE HIGH for X MIN homing with TMC2209." + #error "SENSORLESS_HOMING requires X_MIN_ENDSTOP_HIT_STATE HIGH for X MIN homing with TMC2209/2240." #else #error "SENSORLESS_HOMING requires X_MIN_ENDSTOP_HIT_STATE LOW for X MIN homing." #endif #elif X_HOME_TO_MAX && X_MAX_ENDSTOP_HIT_STATE != _HIT_STATE #if _HIT_STATE - #error "SENSORLESS_HOMING requires X_MAX_ENDSTOP_HIT_STATE HIGH for X MAX homing with TMC2209." + #error "SENSORLESS_HOMING requires X_MAX_ENDSTOP_HIT_STATE HIGH for X MAX homing with TMC2209/2240." #else #error "SENSORLESS_HOMING requires X_MAX_ENDSTOP_HIT_STATE LOW for X MAX homing." #endif @@ -3399,16 +3399,16 @@ static_assert(NUM_SERVOS <= NUM_SERVO_PLUGS, "NUM_SERVOS (or some servo index) i #endif #if Y_SENSORLESS - #define _HIT_STATE AXIS_DRIVER_TYPE(Y,TMC2209) + #define _HIT_STATE AXIS_DRIVER_TYPE(Y,TMC2209) || AXIS_DRIVER_TYPE(Y,TMC2240) #if Y_HOME_TO_MIN && Y_MIN_ENDSTOP_HIT_STATE != _HIT_STATE #if _HIT_STATE - #error "SENSORLESS_HOMING requires Y_MIN_ENDSTOP_HIT_STATE HIGH for Y MIN homing with TMC2209." + #error "SENSORLESS_HOMING requires Y_MIN_ENDSTOP_HIT_STATE HIGH for Y MIN homing with TMC2209/2240." #else #error "SENSORLESS_HOMING requires Y_MIN_ENDSTOP_HIT_STATE LOW for Y MIN homing." #endif #elif Y_HOME_TO_MAX && Y_MAX_ENDSTOP_HIT_STATE != _HIT_STATE #if _HIT_STATE - #error "SENSORLESS_HOMING requires Y_MAX_ENDSTOP_HIT_STATE HIGH for Y MAX homing with TMC2209." + #error "SENSORLESS_HOMING requires Y_MAX_ENDSTOP_HIT_STATE HIGH for Y MAX homing with TMC2209/2240." #else #error "SENSORLESS_HOMING requires Y_MAX_ENDSTOP_HIT_STATE LOW for Y MAX homing." #endif @@ -3417,16 +3417,16 @@ static_assert(NUM_SERVOS <= NUM_SERVO_PLUGS, "NUM_SERVOS (or some servo index) i #endif #if Z_SENSORLESS - #define _HIT_STATE AXIS_DRIVER_TYPE(Z,TMC2209) + #define _HIT_STATE AXIS_DRIVER_TYPE(Z,TMC2209) || AXIS_DRIVER_TYPE(Z,TMC2240) #if Z_HOME_TO_MIN && Z_MIN_ENDSTOP_HIT_STATE != _HIT_STATE #if _HIT_STATE - #error "SENSORLESS_HOMING requires Z_MIN_ENDSTOP_HIT_STATE HIGH for Z MIN homing with TMC2209." + #error "SENSORLESS_HOMING requires Z_MIN_ENDSTOP_HIT_STATE HIGH for Z MIN homing with TMC2209/2240." #else #error "SENSORLESS_HOMING requires Z_MIN_ENDSTOP_HIT_STATE LOW for Z MIN homing." #endif #elif Z_HOME_TO_MAX && Z_MAX_ENDSTOP_HIT_STATE != _HIT_STATE #if _HIT_STATE - #error "SENSORLESS_HOMING requires Z_MAX_ENDSTOP_HIT_STATE HIGH for Z MAX homing with TMC2209." + #error "SENSORLESS_HOMING requires Z_MAX_ENDSTOP_HIT_STATE HIGH for Z MAX homing with TMC2209/2240." #else #error "SENSORLESS_HOMING requires Z_MAX_ENDSTOP_HIT_STATE LOW for Z MAX homing." #endif @@ -3435,16 +3435,16 @@ static_assert(NUM_SERVOS <= NUM_SERVO_PLUGS, "NUM_SERVOS (or some servo index) i #endif #if I_SENSORLESS - #define _HIT_STATE AXIS_DRIVER_TYPE(I,TMC2209) + #define _HIT_STATE AXIS_DRIVER_TYPE(I,TMC2209) || AXIS_DRIVER_TYPE(I,TMC2240) #if I_HOME_TO_MIN && I_MIN_ENDSTOP_HIT_STATE != _HIT_STATE #if _HIT_STATE - #error "SENSORLESS_HOMING requires I_MIN_ENDSTOP_HIT_STATE HIGH for I MIN homing with TMC2209." + #error "SENSORLESS_HOMING requires I_MIN_ENDSTOP_HIT_STATE HIGH for I MIN homing with TMC2209/2240." #else #error "SENSORLESS_HOMING requires I_MIN_ENDSTOP_HIT_STATE LOW for I MIN homing." #endif #elif I_HOME_TO_MAX && I_MAX_ENDSTOP_HIT_STATE != _HIT_STATE #if _HIT_STATE - #error "SENSORLESS_HOMING requires I_MAX_ENDSTOP_HIT_STATE HIGH for I MAX homing with TMC2209." + #error "SENSORLESS_HOMING requires I_MAX_ENDSTOP_HIT_STATE HIGH for I MAX homing with TMC2209/2240." #else #error "SENSORLESS_HOMING requires I_MAX_ENDSTOP_HIT_STATE LOW for I MAX homing." #endif @@ -3453,16 +3453,16 @@ static_assert(NUM_SERVOS <= NUM_SERVO_PLUGS, "NUM_SERVOS (or some servo index) i #endif #if J_SENSORLESS - #define _HIT_STATE AXIS_DRIVER_TYPE(J,TMC2209) + #define _HIT_STATE AXIS_DRIVER_TYPE(J,TMC2209) || AXIS_DRIVER_TYPE(J,TMC2240) #if J_HOME_TO_MIN && J_MIN_ENDSTOP_HIT_STATE != _HIT_STATE #if _HIT_STATE - #error "SENSORLESS_HOMING requires J_MIN_ENDSTOP_HIT_STATE HIGH for J MIN homing with TMC2209." + #error "SENSORLESS_HOMING requires J_MIN_ENDSTOP_HIT_STATE HIGH for J MIN homing with TMC2209/2240." #else #error "SENSORLESS_HOMING requires J_MIN_ENDSTOP_HIT_STATE LOW for J MIN homing." #endif #elif J_HOME_TO_MAX && J_MAX_ENDSTOP_HIT_STATE != _HIT_STATE #if _HIT_STATE - #error "SENSORLESS_HOMING requires J_MAX_ENDSTOP_HIT_STATE HIGH for J MAX homing with TMC2209." + #error "SENSORLESS_HOMING requires J_MAX_ENDSTOP_HIT_STATE HIGH for J MAX homing with TMC2209/2240." #else #error "SENSORLESS_HOMING requires J_MAX_ENDSTOP_HIT_STATE LOW for J MAX homing." #endif @@ -3471,16 +3471,16 @@ static_assert(NUM_SERVOS <= NUM_SERVO_PLUGS, "NUM_SERVOS (or some servo index) i #endif #if K_SENSORLESS - #define _HIT_STATE AXIS_DRIVER_TYPE(K,TMC2209) + #define _HIT_STATE AXIS_DRIVER_TYPE(K,TMC2209) || AXIS_DRIVER_TYPE(K,TMC2240) #if K_HOME_TO_MIN && K_MIN_ENDSTOP_HIT_STATE != _HIT_STATE #if _HIT_STATE - #error "SENSORLESS_HOMING requires K_MIN_ENDSTOP_HIT_STATE HIGH for K MIN homing with TMC2209." + #error "SENSORLESS_HOMING requires K_MIN_ENDSTOP_HIT_STATE HIGH for K MIN homing with TMC2209/2240." #else #error "SENSORLESS_HOMING requires K_MIN_ENDSTOP_HIT_STATE LOW for K MIN homing." #endif #elif K_HOME_TO_MAX && K_MAX_ENDSTOP_HIT_STATE != _HIT_STATE #if _HIT_STATE - #error "SENSORLESS_HOMING requires K_MAX_ENDSTOP_HIT_STATE HIGH for K MAX homing with TMC2209." + #error "SENSORLESS_HOMING requires K_MAX_ENDSTOP_HIT_STATE HIGH for K MAX homing with TMC2209/2240." #else #error "SENSORLESS_HOMING requires K_MAX_ENDSTOP_HIT_STATE LOW for K MAX homing." #endif @@ -3489,16 +3489,16 @@ static_assert(NUM_SERVOS <= NUM_SERVO_PLUGS, "NUM_SERVOS (or some servo index) i #endif #if U_SENSORLESS - #define _HIT_STATE AXIS_DRIVER_TYPE(U,TMC2209) + #define _HIT_STATE AXIS_DRIVER_TYPE(U,TMC2209) || AXIS_DRIVER_TYPE(U,TMC2240) #if U_HOME_TO_MIN && U_MIN_ENDSTOP_HIT_STATE != _HIT_STATE #if _HIT_STATE - #error "SENSORLESS_HOMING requires U_MIN_ENDSTOP_HIT_STATE HIGH for U MIN homing with TMC2209." + #error "SENSORLESS_HOMING requires U_MIN_ENDSTOP_HIT_STATE HIGH for U MIN homing with TMC2209/2240." #else #error "SENSORLESS_HOMING requires U_MIN_ENDSTOP_HIT_STATE LOW for U MIN homing." #endif #elif U_HOME_TO_MAX && U_MAX_ENDSTOP_HIT_STATE != _HIT_STATE #if _HIT_STATE - #error "SENSORLESS_HOMING requires U_MAX_ENDSTOP_HIT_STATE HIGH for U MAX homing with TMC2209." + #error "SENSORLESS_HOMING requires U_MAX_ENDSTOP_HIT_STATE HIGH for U MAX homing with TMC2209/2240." #else #error "SENSORLESS_HOMING requires U_MAX_ENDSTOP_HIT_STATE LOW for U MAX homing." #endif @@ -3507,16 +3507,16 @@ static_assert(NUM_SERVOS <= NUM_SERVO_PLUGS, "NUM_SERVOS (or some servo index) i #endif #if V_SENSORLESS - #define _HIT_STATE AXIS_DRIVER_TYPE(V,TMC2209) + #define _HIT_STATE AXIS_DRIVER_TYPE(V,TMC2209) || AXIS_DRIVER_TYPE(V,TMC2240) #if V_HOME_TO_MIN && V_MIN_ENDSTOP_HIT_STATE != _HIT_STATE #if _HIT_STATE - #error "SENSORLESS_HOMING requires V_MIN_ENDSTOP_HIT_STATE HIGH for V MIN homing with TMC2209." + #error "SENSORLESS_HOMING requires V_MIN_ENDSTOP_HIT_STATE HIGH for V MIN homing with TMC2209/2240." #else #error "SENSORLESS_HOMING requires V_MIN_ENDSTOP_HIT_STATE LOW for V MIN homing." #endif #elif V_HOME_TO_MAX && V_MAX_ENDSTOP_HIT_STATE != _HIT_STATE #if _HIT_STATE - #error "SENSORLESS_HOMING requires V_MAX_ENDSTOP_HIT_STATE HIGH for V MAX homing with TMC2209." + #error "SENSORLESS_HOMING requires V_MAX_ENDSTOP_HIT_STATE HIGH for V MAX homing with TMC2209/2240." #else #error "SENSORLESS_HOMING requires V_MAX_ENDSTOP_HIT_STATE LOW for V MAX homing." #endif @@ -3525,16 +3525,16 @@ static_assert(NUM_SERVOS <= NUM_SERVO_PLUGS, "NUM_SERVOS (or some servo index) i #endif #if W_SENSORLESS - #define _HIT_STATE AXIS_DRIVER_TYPE(W,TMC2209) + #define _HIT_STATE AXIS_DRIVER_TYPE(W,TMC2209) || AXIS_DRIVER_TYPE(W,TMC2240) #if W_HOME_TO_MIN && W_MIN_ENDSTOP_HIT_STATE != _HIT_STATE #if _HIT_STATE - #error "SENSORLESS_HOMING requires W_MIN_ENDSTOP_HIT_STATE HIGH for W MIN homing with TMC2209." + #error "SENSORLESS_HOMING requires W_MIN_ENDSTOP_HIT_STATE HIGH for W MIN homing with TMC2209/2240." #else #error "SENSORLESS_HOMING requires W_MIN_ENDSTOP_HIT_STATE LOW for W MIN homing." #endif #elif W_HOME_TO_MAX && W_MAX_ENDSTOP_HIT_STATE != _HIT_STATE #if _HIT_STATE - #error "SENSORLESS_HOMING requires W_MAX_ENDSTOP_HIT_STATE HIGH for W MAX homing with TMC2209." + #error "SENSORLESS_HOMING requires W_MAX_ENDSTOP_HIT_STATE HIGH for W MAX homing with TMC2209/2240." #else #error "SENSORLESS_HOMING requires W_MAX_ENDSTOP_HIT_STATE LOW for W MAX homing." #endif @@ -3631,11 +3631,11 @@ static_assert(NUM_SERVOS <= NUM_SERVO_PLUGS, "NUM_SERVOS (or some servo index) i // Other TMC feature requirements #if ENABLED(SENSORLESS_HOMING) && !HAS_STALLGUARD - #error "SENSORLESS_HOMING requires TMC2130, TMC2160, TMC2209, TMC2660, or TMC5160 stepper drivers." + #error "SENSORLESS_HOMING requires TMC2130, TMC2160, TMC2209, TMC2240, TMC2660, or TMC5160 stepper drivers." #elif ENABLED(SENSORLESS_PROBING) && !HAS_STALLGUARD - #error "SENSORLESS_PROBING requires TMC2130, TMC2160, TMC2209, TMC2660, or TMC5160 stepper drivers." + #error "SENSORLESS_PROBING requires TMC2130, TMC2160, TMC2209, TMC2240, TMC2660, or TMC5160 stepper drivers." #elif STEALTHCHOP_ENABLED && !HAS_STEALTHCHOP - #error "STEALTHCHOP requires TMC2130, TMC2160, TMC2208, TMC2209, or TMC5160 stepper drivers." + #error "STEALTHCHOP requires TMC2130, TMC2160, TMC2208, TMC2209, TMC2240, or TMC5160 stepper drivers." #endif /** diff --git a/Marlin/src/module/stepper/trinamic.cpp b/Marlin/src/module/stepper/trinamic.cpp index 3ec8ff4325..0f4a8aa89c 100644 --- a/Marlin/src/module/stepper/trinamic.cpp +++ b/Marlin/src/module/stepper/trinamic.cpp @@ -40,15 +40,37 @@ enum StealthIndex : uint8_t { }; #define TMC_INIT(ST, STEALTH_INDEX) tmc_init(stepper##ST, ST##_CURRENT, ST##_MICROSTEPS, ST##_HYBRID_THRESHOLD, stealthchop_by_axis[STEALTH_INDEX], chopper_timing_##ST, ST##_INTERPOLATE, ST##_HOLD_MULTIPLIER) +// // IC = TMC model number // ST = Stepper object letter // L = Label characters // AI = Axis Enum Index // SWHW = SW/SH UART selection +// + #if ENABLED(TMC_USE_SW_SPI) - #define __TMC_SPI_DEFINE(IC, ST, L, AI) TMCMarlin stepper##ST(ST##_CS_PIN, float(ST##_RSENSE), TMC_SPI_MOSI, TMC_SPI_MISO, TMC_SPI_SCK, ST##_CHAIN_POS) + #define __TMC_SPI_RSENSE_DEFINE(IC, ST, L, LI, AI) TMCMarlin stepper##ST(ST##_CS_PIN, float(ST##_RSENSE), TMC_SPI_MOSI, TMC_SPI_MISO, TMC_SPI_SCK, ST##_CHAIN_POS) + #define __TMC_SPI_DEFINE_TMC2240(IC, ST, L, LI, AI) TMCMarlin stepper##ST(ST##_CS_PIN, TMC_SPI_MOSI, TMC_SPI_MISO, TMC_SPI_SCK, ST##_CHAIN_POS) #else - #define __TMC_SPI_DEFINE(IC, ST, L, AI) TMCMarlin stepper##ST(ST##_CS_PIN, float(ST##_RSENSE), ST##_CHAIN_POS) + #define __TMC_SPI_RSENSE_DEFINE(IC, ST, L, LI, AI) TMCMarlin stepper##ST(ST##_CS_PIN, float(ST##_RSENSE), ST##_CHAIN_POS) + #define __TMC_SPI_DEFINE_TMC2240(IC, ST, L, LI, AI) TMCMarlin stepper##ST(ST##_CS_PIN, ST##_CHAIN_POS) +#endif +#define __TMC_SPI_DEFINE_TMC2100 __TMC_SPI_RSENSE_DEFINE +#define __TMC_SPI_DEFINE_TMC2130 __TMC_SPI_RSENSE_DEFINE +#define __TMC_SPI_DEFINE_TMC2160 __TMC_SPI_RSENSE_DEFINE +#define __TMC_SPI_DEFINE_TMC2208 __TMC_SPI_RSENSE_DEFINE +#define __TMC_SPI_DEFINE_TMC2209 __TMC_SPI_RSENSE_DEFINE +#define __TMC_SPI_DEFINE_TMC2660 __TMC_SPI_RSENSE_DEFINE +#define __TMC_SPI_DEFINE_TMC5130 __TMC_SPI_RSENSE_DEFINE +#define __TMC_SPI_DEFINE_TMC5160 __TMC_SPI_RSENSE_DEFINE + +#define __TMC_SPI_DEFINE(IC, ST, LandI, AI) __TMC_SPI_DEFINE_##IC(IC, ST, LandI, AI) +#define _TMC_SPI_DEFINE(IC, ST, AI) __TMC_SPI_DEFINE(IC, ST, TMC_##ST##_LABEL, AI) +#define TMC_SPI_DEFINE(ST, AI) _TMC_SPI_DEFINE(ST##_DRIVER_TYPE, ST, AI##_AXIS) +#if ENABLED(DISTINCT_E_FACTORS) + #define TMC_SPI_DEFINE_E(AI) TMC_SPI_DEFINE(E##AI, E##AI) +#else + #define TMC_SPI_DEFINE_E(AI) TMC_SPI_DEFINE(E##AI, E) #endif #if ENABLED(TMC_SERIAL_MULTIPLEXER) @@ -59,17 +81,11 @@ enum StealthIndex : uint8_t { #define TMC_UART_SW_DEFINE(IC, ST, L, AI) TMCMarlin stepper##ST(ST##_SERIAL_RX_PIN, ST##_SERIAL_TX_PIN, float(ST##_RSENSE), ST##_SLAVE_ADDRESS) -#define _TMC_SPI_DEFINE(IC, ST, AI) __TMC_SPI_DEFINE(IC, ST, TMC_##ST##_LABEL, AI) -#define TMC_SPI_DEFINE(ST, AI) _TMC_SPI_DEFINE(ST##_DRIVER_TYPE, ST, AI##_AXIS) - #define _TMC_UART_DEFINE(SWHW, IC, ST, AI) TMC_UART_##SWHW##_DEFINE(IC, ST, TMC_##ST##_LABEL, AI) #define TMC_UART_DEFINE(SWHW, ST, AI) _TMC_UART_DEFINE(SWHW, ST##_DRIVER_TYPE, ST, AI##_AXIS) - #if ENABLED(DISTINCT_E_FACTORS) - #define TMC_SPI_DEFINE_E(AI) TMC_SPI_DEFINE(E##AI, E##AI) #define TMC_UART_DEFINE_E(SWHW, AI) TMC_UART_DEFINE(SWHW, E##AI, E##AI) #else - #define TMC_SPI_DEFINE_E(AI) TMC_SPI_DEFINE(E##AI, E) #define TMC_UART_DEFINE_E(SWHW, AI) TMC_UART_DEFINE(SWHW, E##AI, E) #endif @@ -219,7 +235,10 @@ enum StealthIndex : uint8_t { #if HAS_DRIVER(TMC2130) template - void tmc_init(TMCMarlin &st, const uint16_t mA, const uint16_t microsteps, const uint32_t hyb_thrs, const bool stealth, const chopper_timing_t &chop_init, const bool interpolate, float hold_multiplier) { + void tmc_init(TMCMarlin &st, + const uint16_t mA, const uint16_t microsteps, const uint32_t hyb_thrs, const bool stealth, + const chopper_timing_t &chop_init, const bool interpolate, float hold_multiplier + ) { st.begin(); CHOPCONF_t chopconf{0}; @@ -254,7 +273,10 @@ enum StealthIndex : uint8_t { #if HAS_DRIVER(TMC2160) template - void tmc_init(TMCMarlin &st, const uint16_t mA, const uint16_t microsteps, const uint32_t hyb_thrs, const bool stealth, const chopper_timing_t &chop_init, const bool interpolate, float hold_multiplier) { + void tmc_init(TMCMarlin &st, + const uint16_t mA, const uint16_t microsteps, const uint32_t hyb_thrs, const bool stealth, + const chopper_timing_t &chop_init, const bool interpolate, float hold_multiplier + ) { st.begin(); CHOPCONF_t chopconf{0}; @@ -670,7 +692,10 @@ enum StealthIndex : uint8_t { #if HAS_DRIVER(TMC2208) template - void tmc_init(TMCMarlin &st, const uint16_t mA, const uint16_t microsteps, const uint32_t hyb_thrs, const bool stealth, const chopper_timing_t &chop_init, const bool interpolate, float hold_multiplier) { + void tmc_init(TMCMarlin &st, + const uint16_t mA, const uint16_t microsteps, const uint32_t hyb_thrs, const bool stealth, + const chopper_timing_t &chop_init, const bool interpolate, float hold_multiplier + ) { TMC2208_n::GCONF_t gconf{0}; gconf.pdn_disable = true; // Use UART gconf.mstep_reg_select = true; // Select microsteps with UART @@ -712,7 +737,10 @@ enum StealthIndex : uint8_t { #if HAS_DRIVER(TMC2209) template - void tmc_init(TMCMarlin &st, const uint16_t mA, const uint16_t microsteps, const uint32_t hyb_thrs, const bool stealth, const chopper_timing_t &chop_init, const bool interpolate, float hold_multiplier) { + void tmc_init(TMCMarlin &st, + const uint16_t mA, const uint16_t microsteps, const uint32_t hyb_thrs, const bool stealth, + const chopper_timing_t &chop_init, const bool interpolate, float hold_multiplier + ) { TMC2208_n::GCONF_t gconf{0}; gconf.pdn_disable = true; // Use UART gconf.mstep_reg_select = true; // Select microsteps with UART @@ -752,9 +780,58 @@ enum StealthIndex : uint8_t { } #endif // TMC2209 +#if HAS_DRIVER(TMC2240) + template + void tmc_init(TMCMarlin &st, + const uint16_t mA, const uint16_t microsteps, const uint32_t hyb_thrs, const bool stealth, + const chopper_timing_t &chop_init, const bool interpolate, float hold_multiplier + ) { + st.begin(); + + st.Rref = TMC2240_Rref; + TMC2240_n::DRV_CONF_t drv_conf{0}; + drv_conf.current_range = TMC2240_CURRENT_RANGE; + drv_conf.slope_control = TMC2240_SLOPE_CONTROL; + st.DRV_CONF(drv_conf.sr); + + CHOPCONF_t chopconf{0}; + chopconf.tbl = 0b01; + chopconf.toff = chop_init.toff; + chopconf.intpol = interpolate; + chopconf.hend = chop_init.hend + 3; + chopconf.hstrt = chop_init.hstrt - 1; + TERN_(EDGE_STEPPING, chopconf.dedge = true); + st.CHOPCONF(chopconf.sr); + + st.rms_current(mA, hold_multiplier); + st.microsteps(microsteps); + st.iholddelay(10); + st.TPOWERDOWN(128); // ~2s until driver lowers to hold current + + st.en_pwm_mode(stealth); + st.stored.stealthChop_enabled = stealth; + + TMC2240_n::PWMCONF_t pwmconf{0}; + pwmconf.pwm_lim = 12; + pwmconf.pwm_reg = 8; + pwmconf.pwm_autograd = true; + pwmconf.pwm_autoscale = true; + pwmconf.pwm_freq = 0b01; + pwmconf.pwm_grad = 14; + pwmconf.pwm_ofs = 36; + st.PWMCONF(pwmconf.sr); + + TERN(HYBRID_THRESHOLD, st.set_pwm_thrs(hyb_thrs), UNUSED(hyb_thrs)); + st.GSTAT(); // Clear GSTAT + } +#endif // TMC2240 + #if HAS_DRIVER(TMC2660) template - void tmc_init(TMCMarlin &st, const uint16_t mA, const uint16_t microsteps, const uint32_t, const bool, const chopper_timing_t &chop_init, const bool interpolate, float hold_multiplier) { + void tmc_init(TMCMarlin &st, + const uint16_t mA, const uint16_t microsteps, const uint32_t, const bool, + const chopper_timing_t &chop_init, const bool interpolate, float hold_multiplier + ) { st.begin(); TMC2660_n::CHOPCONF_t chopconf{0}; @@ -776,7 +853,10 @@ enum StealthIndex : uint8_t { #if HAS_DRIVER(TMC5130) template - void tmc_init(TMCMarlin &st, const uint16_t mA, const uint16_t microsteps, const uint32_t hyb_thrs, const bool stealth, const chopper_timing_t &chop_init, const bool interpolate, float hold_multiplier) { + void tmc_init(TMCMarlin &st, + const uint16_t mA, const uint16_t microsteps, const uint32_t hyb_thrs, const bool stealth, + const chopper_timing_t &chop_init, const bool interpolate, float hold_multiplier + ) { st.begin(); CHOPCONF_t chopconf{0}; @@ -811,7 +891,10 @@ enum StealthIndex : uint8_t { #if HAS_DRIVER(TMC5160) template - void tmc_init(TMCMarlin &st, const uint16_t mA, const uint16_t microsteps, const uint32_t hyb_thrs, const bool stealth, const chopper_timing_t &chop_init, const bool interpolate, float hold_multiplier) { + void tmc_init(TMCMarlin &st, + const uint16_t mA, const uint16_t microsteps, const uint32_t hyb_thrs, const bool stealth, + const chopper_timing_t &chop_init, const bool interpolate, float hold_multiplier + ) { st.begin(); CHOPCONF_t chopconf{0}; @@ -842,6 +925,7 @@ enum StealthIndex : uint8_t { st.PWMCONF(pwmconf.sr); TERN(HYBRID_THRESHOLD, st.set_pwm_thrs(hyb_thrs), UNUSED(hyb_thrs)); + st.GSTAT(); // Clear GSTAT } #endif // TMC5160 diff --git a/Marlin/src/module/stepper/trinamic.h b/Marlin/src/module/stepper/trinamic.h index 0fd48f18cb..d43a1d231b 100644 --- a/Marlin/src/module/stepper/trinamic.h +++ b/Marlin/src/module/stepper/trinamic.h @@ -38,6 +38,7 @@ #define CLASS_TMC2160 TMC2160Stepper #define CLASS_TMC2208 TMC2208Stepper #define CLASS_TMC2209 TMC2209Stepper +#define CLASS_TMC2240 TMC2240Stepper #define CLASS_TMC2660 TMC2660Stepper #define CLASS_TMC5130 TMC5130Stepper #define CLASS_TMC5160 TMC5160Stepper diff --git a/buildroot/tests/BTT_BTT002 b/buildroot/tests/BTT_BTT002 index 121aace895..054b179bfe 100755 --- a/buildroot/tests/BTT_BTT002 +++ b/buildroot/tests/BTT_BTT002 @@ -12,7 +12,8 @@ set -e restore_configs opt_set MOTHERBOARD BOARD_BTT_BTT002_V1_0 \ SERIAL_PORT 1 \ - X_DRIVER_TYPE TMC2209 Y_DRIVER_TYPE TMC2130 + X_DRIVER_TYPE TMC2209 Y_DRIVER_TYPE TMC2130 Z_DRIVER_TYPE TMC2240 \ + X_CURRENT_HOME '(X_CURRENT - 100)' Y_CURRENT_HOME '(Y_CURRENT - 100)' opt_enable SENSORLESS_HOMING X_STALL_SENSITIVITY Y_STALL_SENSITIVITY SPI_ENDSTOPS exec_test $1 $2 "BigTreeTech BTT002 Default Configuration plus TMC steppers" "$3" From db137df6df5e27dc23d68ef31a6be20ea185bd74 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sat, 24 May 2025 03:12:25 -0500 Subject: [PATCH 333/787] =?UTF-8?q?=F0=9F=94=A8=20TMC2240=20Makefile=20upd?= =?UTF-8?q?ate?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/Makefile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Marlin/Makefile b/Marlin/Makefile index ce26bd3572..9acab53673 100644 --- a/Marlin/Makefile +++ b/Marlin/Makefile @@ -798,10 +798,10 @@ endif ifeq ($(TMC), 1) LIB_CXXSRC += TMCStepper.cpp COOLCONF.cpp DRV_STATUS.cpp IHOLD_IRUN.cpp \ - CHOPCONF.cpp GCONF.cpp PWMCONF.cpp DRV_CONF.cpp DRVCONF.cpp DRVCTRL.cpp \ - DRVSTATUS.cpp ENCMODE.cpp RAMP_STAT.cpp SGCSCONF.cpp SHORT_CONF.cpp \ - SMARTEN.cpp SW_MODE.cpp SW_SPI.cpp TMC2130Stepper.cpp TMC2208Stepper.cpp \ - TMC2209Stepper.cpp TMC2660Stepper.cpp TMC5130Stepper.cpp TMC5160Stepper.cpp + CHOPCONF.cpp GCONF.cpp PWMCONF.cpp DRV_CONF.cpp DRVCONF.cpp DRVCTRL.cpp DRVSTATUS.cpp \ + GLOBAL_SCALER.cpp SLAVECONF.cpp IOIN.cpp ENCMODE.cpp RAMP_STAT.cpp SGCSCONF.cpp \ + SHORT_CONF.cpp SMARTEN.cpp SW_MODE.cpp SW_SPI.cpp TMC2130Stepper.cpp TMC2208Stepper.cpp \ + TMC2209Stepper.cpp TMC2240Stepper.cpp TMC2660Stepper.cpp TMC5130Stepper.cpp TMC5160Stepper.cpp endif ifeq ($(RELOC_WORKAROUND), 1) From 86c564121e111c94a9bc4d2488ccbf336ba7184c Mon Sep 17 00:00:00 2001 From: Keith Bennett <13375512+thisiskeithb@users.noreply.github.com> Date: Sat, 24 May 2025 13:38:51 -0700 Subject: [PATCH 334/787] =?UTF-8?q?=F0=9F=A9=B9=20Fix=20Bluesky=20badge=20?= =?UTF-8?q?(#27879)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 50dfddda9a..69979f4884 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ CI Status GitHub Sponsors
- Follow marlinfw.org on Bluesky + Follow marlinfw.org on Bluesky Follow MarlinFirmware on Mastodon

From d76c8c1fbd8d1d1e9fd186d6a2f42f3d0b8d76be Mon Sep 17 00:00:00 2001 From: ellensp <530024+ellensp@users.noreply.github.com> Date: Sun, 25 May 2025 09:49:44 +1200 Subject: [PATCH 335/787] =?UTF-8?q?=F0=9F=A9=B9=20Fix=20ProUI=20Linear=20A?= =?UTF-8?q?dvance=20menu=20(#27878)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Followup to #27818 --- Marlin/src/lcd/e3v2/proui/dwin.cpp | 6 ++++-- buildroot/tests/STM32F103RE_creality | 5 +++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Marlin/src/lcd/e3v2/proui/dwin.cpp b/Marlin/src/lcd/e3v2/proui/dwin.cpp index 7574439051..08782553ba 100644 --- a/Marlin/src/lcd/e3v2/proui/dwin.cpp +++ b/Marlin/src/lcd/e3v2/proui/dwin.cpp @@ -3546,7 +3546,8 @@ void drawTuneMenu() { EDIT_ITEM(ICON_JDmm, MSG_JUNCTION_DEVIATION, onDrawPFloat3Menu, setJDmm, &planner.junction_deviation_mm); #endif #if ENABLED(PROUI_ITEM_ADVK) - EDIT_ITEM(ICON_MaxAccelerated, MSG_ADVANCE_K, onDrawPFloat3Menu, setLA_K, &planner.get_advance_k()); + float editable_decimal = planner.get_advance_k(); + EDIT_ITEM(ICON_MaxAccelerated, MSG_ADVANCE_K, onDrawPFloat3Menu, setLA_K, &editable_decimal); #endif #if HAS_LOCKSCREEN MENU_ITEM(ICON_Lock, MSG_LOCKSCREEN, onDrawMenuItem, dwinLockScreen); @@ -3684,7 +3685,8 @@ void drawMotionMenu() { MENU_ITEM(ICON_Homing, MSG_HOMING_FEEDRATE, onDrawSubMenu, drawHomingFRMenu); #endif #if ENABLED(LIN_ADVANCE) - EDIT_ITEM(ICON_MaxAccelerated, MSG_ADVANCE_K, onDrawPFloat3Menu, setLA_K, &planner.get_advance_k()); + float editable_decimal = planner.get_advance_k(); + EDIT_ITEM(ICON_MaxAccelerated, MSG_ADVANCE_K, onDrawPFloat3Menu, setLA_K, &editable_decimal); #endif #if ENABLED(SHAPING_MENU) MENU_ITEM(ICON_InputShaping, MSG_INPUT_SHAPING, onDrawSubMenu, drawInputShaping_menu); diff --git a/buildroot/tests/STM32F103RE_creality b/buildroot/tests/STM32F103RE_creality index 0a1b1bc79d..5681688929 100755 --- a/buildroot/tests/STM32F103RE_creality +++ b/buildroot/tests/STM32F103RE_creality @@ -26,9 +26,10 @@ exec_test $1 $2 "Ender-3 V2 - MarlinUI (Games, UBL+BLTOUCH, MPCTEMP, LCD_ENDSTOP use_example_configs "Creality/Ender-3 S1/STM32F1" opt_disable DWIN_CREALITY_LCD Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN AUTO_BED_LEVELING_BILINEAR CANCEL_OBJECTS FWRETRACT EVENT_GCODE_SD_ABORT -opt_enable DWIN_LCD_PROUI INDIVIDUAL_AXIS_HOMING_SUBMENU SET_PROGRESS_MANUALLY SET_PROGRESS_PERCENT STATUS_MESSAGE_SCROLLING \ +opt_enable DWIN_LCD_PROUI INDIVIDUAL_AXIS_HOMING_SUBMENU PID_AUTOTUNE_MENU PID_EDIT_MENU \ + SET_PROGRESS_MANUALLY SET_PROGRESS_PERCENT STATUS_MESSAGE_SCROLLING \ SOUND_MENU_ITEM PRINTCOUNTER NOZZLE_PARK_FEATURE ADVANCED_PAUSE_FEATURE FILAMENT_RUNOUT_SENSOR \ - BLTOUCH Z_SAFE_HOMING AUTO_BED_LEVELING_UBL MESH_EDIT_MENU LCD_BED_TRAMMING \ + BLTOUCH Z_SAFE_HOMING AUTO_BED_LEVELING_UBL MESH_EDIT_MENU LCD_BED_TRAMMING LIN_ADVANCE \ LIMITED_MAX_FR_EDITING LIMITED_MAX_ACCEL_EDITING LIMITED_JERK_EDITING BAUD_RATE_GCODE \ CASE_LIGHT_ENABLE CASE_LIGHT_MENU CASE_LIGHT_NO_BRIGHTNESS opt_set PREHEAT_3_LABEL '"CUSTOM"' PREHEAT_3_TEMP_HOTEND 240 PREHEAT_3_TEMP_BED 60 PREHEAT_3_FAN_SPEED 128 BOOTSCREEN_TIMEOUT 1100 CASE_LIGHT_PIN 4 From 4f93f31af0183af5a89d7ceb095d20924ea9b91e Mon Sep 17 00:00:00 2001 From: ellensp <530024+ellensp@users.noreply.github.com> Date: Sun, 25 May 2025 09:53:52 +1200 Subject: [PATCH 336/787] =?UTF-8?q?=F0=9F=94=A8=20Fix=20Windows/ReARM=20up?= =?UTF-8?q?load=20(#27872)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/HAL/LPC1768/upload_extra_script.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/Marlin/src/HAL/LPC1768/upload_extra_script.py b/Marlin/src/HAL/LPC1768/upload_extra_script.py index ce241c4658..f9be140592 100755 --- a/Marlin/src/HAL/LPC1768/upload_extra_script.py +++ b/Marlin/src/HAL/LPC1768/upload_extra_script.py @@ -54,18 +54,25 @@ if pioutil.is_pio_build(): final_drive_name = drive + ':' # print ('disc check: {}'.format(final_drive_name)) try: - volume_info = str(subprocess.check_output('cmd /C dir ' + final_drive_name, stderr=subprocess.STDOUT)) + volume_info = str(subprocess.check_output('cmd /C vol ' + final_drive_name, stderr=subprocess.STDOUT)) except Exception as e: print ('error:{}'.format(e)) continue else: - if target_drive in volume_info and not target_file_found: # set upload if not found target file yet - target_drive_found = True + if target_drive in volume_info: # set upload upload_disk = PureWindowsPath(final_drive_name) - if target_filename in volume_info: - if not target_file_found: + target_drive_found = True + break + try: + dir_info = str(subprocess.check_output('cmd /C dir ' + final_drive_name, stderr=subprocess.STDOUT)) + except Exception as e: + print ('error:{}'.format(e)) + continue + else: + if target_filename in dir_info: upload_disk = PureWindowsPath(final_drive_name) - target_file_found = True + target_file_found = True + break elif current_OS == 'Linux': # From 2976bb48ede7834512551a921b04e260f73acf07 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sat, 24 May 2025 16:57:03 -0500 Subject: [PATCH 337/787] =?UTF-8?q?=F0=9F=94=A8=20Better=20FT=20Motion=20m?= =?UTF-8?q?enu=20string=20code?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/lcd/menu/menu_motion.cpp | 96 ++++++++++++++++++++++------- 1 file changed, 74 insertions(+), 22 deletions(-) diff --git a/Marlin/src/lcd/menu/menu_motion.cpp b/Marlin/src/lcd/menu/menu_motion.cpp index e2adbfded2..956b58c633 100644 --- a/Marlin/src/lcd/menu/menu_motion.cpp +++ b/Marlin/src/lcd/menu/menu_motion.cpp @@ -401,19 +401,48 @@ void menu_move() { #endif // HAS_DYNAMIC_FREQ + // Suppress warning about storing a stack address in a static string pointer + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wdangling-pointer" + + #if ALL(__AVR__, HAS_MARLINUI_U8GLIB) && DISABLED(REDUCE_CODE_SIZE_FOR_FT_MOTION_ON_AVR) + #define CACHE_PREV_STRING + #endif + void menu_ft_motion() { // Define stuff ahead of the menu loop - MString<20> shaper_name[NUM_AXES_SHAPED] {}; - #if HAS_X_AXIS - for (uint_fast8_t a = X_AXIS; a < NUM_AXES_SHAPED; ++a) - shaper_name[a] = get_shaper_name(AxisEnum(a)); - #endif - #if HAS_DYNAMIC_FREQ - MString<20> dmode = get_dyn_freq_mode_name(); - #endif - ft_config_t &c = ftMotion.cfg; + #ifdef __AVR__ + // Copy Flash strings to RAM for C-string substitution + // For U8G paged rendering check and skip extra string copy + #if HAS_X_AXIS + MString<20> shaper_name; + TERN_(CACHE_PREV_STRING, int8_t prev_a = -1); + auto _shaper_name = [&](const AxisEnum a) { + if (TERN1(CACHE_PREV_STRING, a != prev_a)) { + TERN_(CACHE_PREV_STRING, prev_a = a); + shaper_name = get_shaper_name(a); + } + return shaper_name; + }; + #endif + #if HAS_DYNAMIC_FREQ + MString<20> dmode; + TERN_(CACHE_PREV_STRING, bool got_d = false); + auto _dmode = [&]{ + if (TERN1(CACHE_PREV_STRING, !got_d)) { + TERN_(CACHE_PREV_STRING, got_d = true); + dmode = get_dyn_freq_mode_name(); + } + return dmode; + }; + #endif + #else + auto _shaper_name = [](const AxisEnum a) { return get_shaper_name(a); }; + auto _dmode = []{ return get_dyn_freq_mode_name(); }; + #endif + START_MENU(); BACK_ITEM(MSG_MOTION); @@ -426,7 +455,7 @@ void menu_move() { // Show only when FT Motion is active (or optionally always show) if (c.active || ENABLED(FT_MOTION_NO_MENU_TOGGLE)) { #if HAS_X_AXIS - SUBMENU_N_S(X_AXIS, shaper_name[X_AXIS], MSG_FTM_CMPN_MODE, menu_ftm_shaper_x); + SUBMENU_N_S(X_AXIS, _shaper_name(X_AXIS), MSG_FTM_CMPN_MODE, menu_ftm_shaper_x); if (AXIS_HAS_SHAPER(X)) { EDIT_ITEM_FAST_N(float42_52, X_AXIS, MSG_FTM_BASE_FREQ_N, &c.baseFreq.x, FTM_MIN_SHAPE_FREQ, (FTM_FS) / 2, ftMotion.update_shaping_params); @@ -436,7 +465,7 @@ void menu_move() { } #endif #if HAS_Y_AXIS - SUBMENU_N_S(Y_AXIS, shaper_name[Y_AXIS], MSG_FTM_CMPN_MODE, menu_ftm_shaper_y); + SUBMENU_N_S(Y_AXIS, _shaper_name(Y_AXIS), MSG_FTM_CMPN_MODE, menu_ftm_shaper_y); if (AXIS_HAS_SHAPER(Y)) { EDIT_ITEM_FAST_N(float42_52, Y_AXIS, MSG_FTM_BASE_FREQ_N, &c.baseFreq.y, FTM_MIN_SHAPE_FREQ, (FTM_FS) / 2, ftMotion.update_shaping_params); @@ -447,7 +476,7 @@ void menu_move() { #endif #if HAS_DYNAMIC_FREQ - SUBMENU_S(dmode, MSG_FTM_DYN_MODE, menu_ftm_dyn_mode); + SUBMENU_S(_dmode(), MSG_FTM_DYN_MODE, menu_ftm_dyn_mode); if (c.dynFreqMode != dynFreqMode_DISABLED) { #if HAS_X_AXIS EDIT_ITEM_FAST_N(float42_52, X_AXIS, MSG_FTM_DFREQ_K_N, &c.dynFreqK.x, 0.0f, 20.0f); @@ -469,13 +498,34 @@ void menu_move() { void menu_tune_ft_motion() { // Define stuff ahead of the menu loop - MString<20> shaper_name[NUM_AXES_SHAPED] {}; - #if HAS_X_AXIS - for (uint_fast8_t a = X_AXIS; a < NUM_AXES_SHAPED; ++a) - shaper_name[a] = get_shaper_name(AxisEnum(a)); - #endif - #if HAS_DYNAMIC_FREQ - MString<20> dmode = get_dyn_freq_mode_name(); + #ifdef __AVR__ + // Copy Flash strings to RAM for C-string substitution + // For U8G paged rendering check and skip extra string copy + #if HAS_X_AXIS + MString<20> shaper_name; + TERN_(CACHE_PREV_STRING, int8_t prev_a = -1); + auto _shaper_name = [&](const AxisEnum a) { + if (TERN1(CACHE_PREV_STRING, a != prev_a)) { + TERN_(CACHE_PREV_STRING, prev_a = a); + shaper_name = get_shaper_name(a); + } + return shaper_name; + }; + #endif + #if HAS_DYNAMIC_FREQ + MString<20> dmode; + TERN_(CACHE_PREV_STRING, bool got_d = false); + auto _dmode = [&]{ + if (TERN1(CACHE_PREV_STRING, !got_d)) { + TERN_(CACHE_PREV_STRING, got_d = true); + dmode = get_dyn_freq_mode_name(); + } + return dmode; + }; + #endif + #else + auto _shaper_name = [](const AxisEnum a) { return get_shaper_name(a); }; + auto _dmode = []{ return get_dyn_freq_mode_name(); }; #endif #if HAS_EXTRUDERS @@ -486,13 +536,13 @@ void menu_move() { BACK_ITEM(MSG_TUNE); #if HAS_X_AXIS - SUBMENU_N_S(X_AXIS, shaper_name[X_AXIS], MSG_FTM_CMPN_MODE, menu_ftm_shaper_x); + SUBMENU_N_S(X_AXIS, _shaper_name(X_AXIS), MSG_FTM_CMPN_MODE, menu_ftm_shaper_x); #endif #if HAS_Y_AXIS - SUBMENU_N_S(Y_AXIS, shaper_name[Y_AXIS], MSG_FTM_CMPN_MODE, menu_ftm_shaper_y); + SUBMENU_N_S(Y_AXIS, _shaper_name(Y_AXIS), MSG_FTM_CMPN_MODE, menu_ftm_shaper_y); #endif #if HAS_DYNAMIC_FREQ - SUBMENU_S(dmode, MSG_FTM_DYN_MODE, menu_ftm_dyn_mode); + SUBMENU_S(_dmode(), MSG_FTM_DYN_MODE, menu_ftm_dyn_mode); #endif #if HAS_EXTRUDERS EDIT_ITEM(bool, MSG_LINEAR_ADVANCE, &c.linearAdvEna); @@ -503,6 +553,8 @@ void menu_move() { END_MENU(); } + #pragma GCC diagnostic pop + #endif // FT_MOTION_MENU void menu_motion() { From bd9d7a3c4d6b5b974e9dcf2ba90180fb91f6502d Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sat, 24 May 2025 17:17:49 -0500 Subject: [PATCH 338/787] =?UTF-8?q?=F0=9F=A9=B9=20Fix=20MKS=20UI=20E=20Max?= =?UTF-8?q?=20Feedrate=20items?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/lcd/extui/mks_ui/draw_number_key.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/src/lcd/extui/mks_ui/draw_number_key.cpp b/Marlin/src/lcd/extui/mks_ui/draw_number_key.cpp index c44cabd10a..a117775793 100644 --- a/Marlin/src/lcd/extui/mks_ui/draw_number_key.cpp +++ b/Marlin/src/lcd/extui/mks_ui/draw_number_key.cpp @@ -243,10 +243,10 @@ static void set_value_confirm() { #if HAS_Z_AXIS case ZMaxFeedRate: planner.settings.max_feedrate_mm_s[Z_AXIS] = atof(key_value); break; #endif - #if HAS_E0_AXIS + #if HAS_EXTRUDERS case E0MaxFeedRate: planner.settings.max_feedrate_mm_s[E_AXIS] = atof(key_value); break; #endif - #if HAS_E1_AXIS + #if HAS_MULTI_EXTRUDER case E1MaxFeedRate: planner.settings.max_feedrate_mm_s[E_AXIS_N(1)] = atof(key_value); break; #endif From 6a871b2879131c23581a0fdc086240994837ba33 Mon Sep 17 00:00:00 2001 From: B Date: Sat, 24 May 2025 17:21:06 -0700 Subject: [PATCH 339/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Get?= =?UTF-8?q?=20E=20axis=20in=20FTMotion::loadBlockData=20(#27870)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Scott Lahteine --- Marlin/src/module/ft_motion.cpp | 27 ++++++++++++++++++--------- Marlin/src/module/ft_motion.h | 6 ++++++ 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/Marlin/src/module/ft_motion.cpp b/Marlin/src/module/ft_motion.cpp index 88d2fb60b3..cb31525572 100644 --- a/Marlin/src/module/ft_motion.cpp +++ b/Marlin/src/module/ft_motion.cpp @@ -89,6 +89,12 @@ xyze_long_t FTMotion::steps = { 0 }; // Step count accumulator. uint32_t FTMotion::interpIdx = 0; // Index of current data point being interpolated. +#if ENABLED(DISTINCT_E_FACTORS) + uint8_t FTMotion::block_extruder_axis; // Cached E Axis from last-fetched block +#else + constexpr uint8_t FTMotion::block_extruder_axis; +#endif + // Shaping variables. #if HAS_FTM_SHAPING FTMotion::shaping_t FTMotion::shaping = { @@ -143,6 +149,12 @@ void FTMotion::loop() { continue; } loadBlockData(stepper.current_block); + + // If the endstop is already pressed, endstop interrupts won't invoke + // endstop_triggered and the move will grind. So check here for a + // triggered endstop, which shortly marks the block for discard. + endstops.update(); + blockProcRdy = true; // Some kinematics track axis motion in HX, HY, HZ #if ANY(CORE_IS_XY, CORE_IS_XZ, MARKFORGED_XY, MARKFORGED_YX) @@ -389,6 +401,7 @@ void FTMotion::reset() { #endif TERN_(HAS_EXTRUDERS, e_raw_z1 = e_advanced_z1 = 0.0f); + TERN_(DISTINCT_E_FACTORS, block_extruder_axis = E_AXIS); axis_move_end_ti.reset(); } @@ -453,13 +466,15 @@ void FTMotion::init() { // Load / convert block data from planner to fixed-time control variables. void FTMotion::loadBlockData(block_t * const current_block) { + // Cache the extruder index for this block + TERN_(DISTINCT_E_FACTORS, block_extruder_axis = E_AXIS_N(current_block->extruder)); const float totalLength = current_block->millimeters, oneOverLength = 1.0f / totalLength; startPosn = endPosn_prevBlock; const xyze_pos_t moveDist = LOGICAL_AXIS_ARRAY( - current_block->steps.e * planner.mm_per_step[E_AXIS_N(current_block->extruder)] * (current_block->direction_bits.e ? 1 : -1), + current_block->steps.e * planner.mm_per_step[block_extruder_axis] * (current_block->direction_bits.e ? 1 : -1), current_block->steps.x * planner.mm_per_step[X_AXIS] * (current_block->direction_bits.x ? 1 : -1), current_block->steps.y * planner.mm_per_step[Y_AXIS] * (current_block->direction_bits.y ? 1 : -1), current_block->steps.z * planner.mm_per_step[Z_AXIS] * (current_block->direction_bits.z ? 1 : -1), @@ -568,12 +583,6 @@ void FTMotion::loadBlockData(block_t * const current_block) { #endif TERN_(HAS_Z_AXIS, _SET_MOVE_END(Z)); SECONDARY_AXIS_MAP(_SET_MOVE_END); - - // If the endstop is already pressed, endstop interrupts won't invoke - // endstop_triggered and the move will grind. So check here for a - // triggered endstop, which shortly marks the block for discard. - endstops.update(); - } // Generate data points of the trajectory. @@ -721,7 +730,7 @@ void FTMotion::convertToSteps(const uint32_t idx) { #if ENABLED(STEPS_ROUNDING) #define TOSTEPS(A,B) int32_t(trajMod.A[idx] * planner.settings.axis_steps_per_mm[B] + (trajMod.A[idx] < 0.0f ? -0.5f : 0.5f)) const xyze_long_t steps_tar = LOGICAL_AXIS_ARRAY( - TOSTEPS(e, E_AXIS_N(stepper.current_block->extruder)), // May be eliminated if guaranteed positive. + TOSTEPS(e, block_extruder_axis), // May be eliminated if guaranteed positive. TOSTEPS(x, X_AXIS), TOSTEPS(y, Y_AXIS), TOSTEPS(z, Z_AXIS), TOSTEPS(i, I_AXIS), TOSTEPS(j, J_AXIS), TOSTEPS(k, K_AXIS), TOSTEPS(u, U_AXIS), TOSTEPS(v, V_AXIS), TOSTEPS(w, W_AXIS) @@ -730,7 +739,7 @@ void FTMotion::convertToSteps(const uint32_t idx) { #else #define TOSTEPS(A,B) int32_t(trajMod.A[idx] * planner.settings.axis_steps_per_mm[B]) - steps.A xyze_long_t delta = LOGICAL_AXIS_ARRAY( - TOSTEPS(e, E_AXIS_N(stepper.current_block->extruder)), + TOSTEPS(e, block_extruder_axis), TOSTEPS(x, X_AXIS), TOSTEPS(y, Y_AXIS), TOSTEPS(z, Z_AXIS), TOSTEPS(i, I_AXIS), TOSTEPS(j, J_AXIS), TOSTEPS(k, K_AXIS), TOSTEPS(u, U_AXIS), TOSTEPS(v, V_AXIS), TOSTEPS(w, W_AXIS) diff --git a/Marlin/src/module/ft_motion.h b/Marlin/src/module/ft_motion.h index f6ce81af12..4cf8017083 100644 --- a/Marlin/src/module/ft_motion.h +++ b/Marlin/src/module/ft_motion.h @@ -169,6 +169,12 @@ class FTMotion { static xyze_long_t steps; + #if ENABLED(DISTINCT_E_FACTORS) + static uint8_t block_extruder_axis; // Cached extruder axis index + #else + static constexpr uint8_t block_extruder_axis = E_AXIS; + #endif + // Shaping variables. #if HAS_FTM_SHAPING From dbd60fb38e865fcbd51b886f421390e78b0743cc Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Sun, 25 May 2025 00:35:29 +0000 Subject: [PATCH 340/787] [cron] Bump distribution date (2025-05-25) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index cb96070cc4..82979634d4 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-05-24" +//#define STRING_DISTRIBUTION_DATE "2025-05-25" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 51a13f1947..7c80ca1f17 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-05-24" + #define STRING_DISTRIBUTION_DATE "2025-05-25" #endif /** From 7f9eb688adc69ff51c79ecc30acd703643708c21 Mon Sep 17 00:00:00 2001 From: ellensp <530024+ellensp@users.noreply.github.com> Date: Tue, 27 May 2025 03:50:22 +1200 Subject: [PATCH 341/787] =?UTF-8?q?=F0=9F=90=9B=20TMC2240:=20The=20Sequel?= =?UTF-8?q?=20(#27880)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Scott Lahteine --- Marlin/Configuration_adv.h | 8 +-- Marlin/src/core/drivers.h | 6 +- Marlin/src/feature/tmc_util.cpp | 113 +++++++++++++++++++++----------- Marlin/src/feature/tmc_util.h | 3 + Marlin/src/inc/SanityCheck.h | 18 ++--- ini/features.ini | 2 +- 6 files changed, 98 insertions(+), 52 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 93d84d8d9c..fee4c452ab 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -2997,7 +2997,7 @@ /** * Trinamic Smart Drivers * - * To use TMC2130, TMC2160, TMC2660, TMC5130, TMC5160 stepper drivers in SPI mode: + * To use TMC2130, TMC2160, TMC2240, TMC2660, TMC5130, TMC5160 stepper drivers in SPI mode: * - Connect your SPI pins to the Hardware SPI interface on the board. * Some boards have simple jumper connections! See your board's documentation. * - Define the required Stepper CS pins in your `pins_MYBOARD.h` file. @@ -3258,7 +3258,7 @@ // @section tmc/spi /** - * Override default SPI pins for TMC2130, TMC2160, TMC2660, TMC5130 and TMC5160 drivers here. + * Override default SPI pins for TMC2130, TMC2160, TMC2240, TMC2660, TMC5130 and TMC5160 drivers here. * The default pins can be found in your board's pins file. */ //#define X_CS_PIN -1 @@ -3285,7 +3285,7 @@ //#define E7_CS_PIN -1 /** - * Software option for SPI driven drivers (TMC2130, TMC2160, TMC2660, TMC5130 and TMC5160). + * Software option for SPI driven drivers (TMC2130, TMC2160, TMC2240, TMC2660, TMC5130 and TMC5160). * The default SW SPI pins are defined the respective pins files, * but you can override or define them here. */ @@ -3498,7 +3498,7 @@ //#define U_STALL_SENSITIVITY 8 //#define V_STALL_SENSITIVITY 8 //#define W_STALL_SENSITIVITY 8 - //#define SPI_ENDSTOPS // TMC2130/TMC5160 only + //#define SPI_ENDSTOPS // TMC2130, TMC2240, and TMC5160 //#define IMPROVE_HOMING_RELIABILITY #endif diff --git a/Marlin/src/core/drivers.h b/Marlin/src/core/drivers.h index 6b1a70202c..3a53360e26 100644 --- a/Marlin/src/core/drivers.h +++ b/Marlin/src/core/drivers.h @@ -113,9 +113,12 @@ #define HAS_TRINAMIC_STANDALONE 1 #endif -#if HAS_DRIVER(TMC2130) || HAS_DRIVER(TMC2160) || HAS_DRIVER(TMC5130) || HAS_DRIVER(TMC5160) || HAS_DRIVER(TMC2240) +#if HAS_DRIVER(TMC2130) || HAS_DRIVER(TMC2160) || HAS_DRIVER(TMC5130) || HAS_DRIVER(TMC5160) #define HAS_TMCX1X0 1 #endif +#if HAS_TMCX1X0 || HAS_DRIVER(TMC2240) + #define HAS_TMCX1X0_OR_2240 1 +#endif #if HAS_DRIVER(TMC2208) || HAS_DRIVER(TMC2209) #define HAS_TMC220x 1 #endif @@ -207,6 +210,7 @@ #define THRS_TMC2160 255 #define THRS_TMC2208 255 #define THRS_TMC2209 255 +#define THRS_TMC2240 255 #define THRS_TMC2660 65535 #define THRS_TMC5130 65535 #define THRS_TMC5160 65535 diff --git a/Marlin/src/feature/tmc_util.cpp b/Marlin/src/feature/tmc_util.cpp index d920c3a604..fb17e562ad 100644 --- a/Marlin/src/feature/tmc_util.cpp +++ b/Marlin/src/feature/tmc_util.cpp @@ -72,7 +72,7 @@ #endif ; #if ENABLED(TMC_DEBUG) - #if HAS_TMCX1X0 || HAS_TMC220x + #if HAS_TMCX1X0_OR_2240 || HAS_TMC220x uint8_t cs_actual; #endif #if HAS_STALLGUARD @@ -298,7 +298,7 @@ st.printLabel(); SString<60> report(':', pwm_scale); #if ENABLED(TMC_DEBUG) - #if HAS_TMCX1X0 || HAS_TMC220x + #if HAS_TMCX1X0_OR_2240 || HAS_TMC220x report.append('/', data.cs_actual); #endif #if HAS_STALLGUARD @@ -575,6 +575,25 @@ template static void print_vsense(TMC &st) { SERIAL_ECHO(st.vsense() ? F("1=.18") : F("0=.325")); } + #if HAS_DRIVER(TMC2160) + template + void print_vsense(TMCMarlin &) { } + #endif + #if HAS_DRIVER(TMC5160) + template + void print_vsense(TMCMarlin &) { } + #endif + #if HAS_DRIVER(TMC2240) + template + void print_vsense(TMCMarlin &) { } + #endif + + template + void print_cs_actual(TMC &st) { SERIAL_ECHO(st.cs_actual(), F("/31")); } + #if HAS_DRIVER(TMC2240) + template + void print_cs_actual(TMCMarlin &) { } + #endif #if HAS_DRIVER(TMC2130) || HAS_DRIVER(TMC5130) static void _tmc_status(TMC2130Stepper &st, const TMC_debug_enum i) { @@ -600,12 +619,6 @@ #endif #if HAS_DRIVER(TMC2160) || HAS_DRIVER(TMC5160) - template - void print_vsense(TMCMarlin &) { } - - template - void print_vsense(TMCMarlin &) { } - static void _tmc_status(TMC2160Stepper &st, const TMC_debug_enum i) { switch (i) { case TMC_PWM_SCALE: SERIAL_ECHO(st.PWM_SCALE()); break; @@ -676,6 +689,21 @@ #endif // HAS_TMC220x + #if HAS_DRIVER(TMC2240) + static void _tmc_parse_drv_status(TMC2240Stepper, const TMC_drv_status_enum) { } + static void _tmc_status(TMC2240Stepper &st, const TMC_debug_enum i) { + switch (i) { + case TMC_PWM_SCALE_SUM: SERIAL_ECHO(st.pwm_scale_sum()); break; + case TMC_PWM_SCALE_AUTO: SERIAL_ECHO(st.pwm_scale_auto()); break; + case TMC_PWM_OFS_AUTO: SERIAL_ECHO(st.pwm_ofs_auto()); break; + case TMC_PWM_GRAD_AUTO: SERIAL_ECHO(st.pwm_grad_auto()); break; + case TMC_STEALTHCHOP: serialprint_truefalse(st.stealth()); break; + case TMC_INTERPOLATE: serialprint_truefalse(st.intpol()); break; + default: break; + } + } + #endif + #if HAS_DRIVER(TMC2660) static void _tmc_parse_drv_status(TMC2660Stepper, const TMC_drv_status_enum) { } static void _tmc_status(TMC2660Stepper &st, const TMC_debug_enum i) { @@ -686,6 +714,21 @@ } #endif + template + void print_tstep(TMC &st) { + const uint32_t tstep_value = st.TSTEP(); + if (tstep_value != 0xFFFFF) + SERIAL_ECHO(tstep_value); + else + SERIAL_ECHOPGM("max"); + } + void print_tstep(TMC2660Stepper &st) { } + + template + void print_blank_time(TMC &st) { SERIAL_ECHO(st.blank_time()); } + template + void print_blank_time(TMCMarlin &) { } + template static void tmc_status(TMC &st, const TMC_debug_enum i) { SERIAL_CHAR('\t'); @@ -703,16 +746,10 @@ SERIAL_ECHO(st.ihold()); SERIAL_ECHOPGM("/31"); break; - case TMC_CS_ACTUAL: - SERIAL_ECHO(st.cs_actual()); - SERIAL_ECHOPGM("/31"); - break; + case TMC_CS_ACTUAL: print_cs_actual(st); break; case TMC_VSENSE: print_vsense(st); break; case TMC_MICROSTEPS: SERIAL_ECHO(st.microsteps()); break; - case TMC_TSTEP: { - const uint32_t tstep_value = st.TSTEP(); - if (tstep_value != 0xFFFFF) SERIAL_ECHO(tstep_value); else SERIAL_ECHOPGM("max"); - } break; + case TMC_TSTEP: print_tstep(st); break; #if ENABLED(HYBRID_THRESHOLD) case TMC_TPWMTHRS: SERIAL_ECHO(uint32_t(st.TPWMTHRS())); break; case TMC_TPWMTHRS_MMS: { @@ -725,7 +762,7 @@ case TMC_OTPW_TRIGGERED: serialprint_truefalse(st.getOTPW()); break; #endif case TMC_TOFF: SERIAL_ECHO(st.toff()); break; - case TMC_TBL: SERIAL_ECHO(st.blank_time()); break; + case TMC_TBL: print_blank_time(st); break; case TMC_HEND: SERIAL_ECHO(st.hysteresis_end()); break; case TMC_HSTRT: SERIAL_ECHO(st.hysteresis_start()); break; case TMC_MSCNT: SERIAL_ECHO(st.get_microstep_counter()); break; @@ -753,10 +790,10 @@ //case TMC_OTPW_TRIGGERED: serialprint_truefalse(st.getOTPW()); break; case TMC_SGT: SERIAL_ECHO(st.sgt()); break; case TMC_TOFF: SERIAL_ECHO(st.toff()); break; - case TMC_TBL: SERIAL_ECHO(st.blank_time()); break; + case TMC_TBL: print_blank_time(st); break; case TMC_HEND: SERIAL_ECHO(st.hysteresis_end()); break; case TMC_HSTRT: SERIAL_ECHO(st.hysteresis_start()); break; - default: break; + default: _tmc_status(st, i); break; } } #endif @@ -916,10 +953,10 @@ TMC_REPORT("Stallguard thrs", TMC_SGT); TMC_REPORT("uStep count", TMC_MSCNT); DRV_REPORT("DRVSTATUS", TMC_DRV_CODES); - #if HAS_TMCX1X0 || HAS_TMC220x + #if HAS_TMCX1X0_OR_2240 || HAS_TMC220x DRV_REPORT("sg_result", TMC_SG_RESULT); #endif - #if HAS_TMCX1X0 + #if HAS_TMCX1X0_OR_2240 DRV_REPORT("stallguard", TMC_STALLGUARD); DRV_REPORT("fsactive", TMC_FSACTIVE); #endif @@ -944,21 +981,22 @@ #define PRINT_TMC_REGISTER(REG_CASE) case TMC_GET_##REG_CASE: print_hex_long(st.REG_CASE(), ':'); break - #if HAS_TMCX1X0 - static void tmc_get_ic_registers(TMC2130Stepper &st, const TMC_get_registers_enum i) { - switch (i) { - PRINT_TMC_REGISTER(TCOOLTHRS); - PRINT_TMC_REGISTER(THIGH); - PRINT_TMC_REGISTER(COOLCONF); - default: SERIAL_CHAR('\t'); break; - } - } - #endif - #if HAS_TMC220x - static void tmc_get_ic_registers(TMC2208Stepper, const TMC_get_registers_enum) { SERIAL_CHAR('\t'); } - #endif - #if HAS_TRINAMIC_CONFIG + + template + static void tmc_get_ic_registers(TMC &, const TMC_get_registers_enum) { SERIAL_CHAR('\t'); } + + #if HAS_TMCX1X0 + static void tmc_get_ic_registers(TMC2130Stepper &st, const TMC_get_registers_enum i) { + switch (i) { + PRINT_TMC_REGISTER(TCOOLTHRS); + PRINT_TMC_REGISTER(THIGH); + PRINT_TMC_REGISTER(COOLCONF); + default: SERIAL_CHAR('\t'); break; + } + } + #endif + template static void tmc_get_registers(TMC &st, const TMC_get_registers_enum i) { switch (i) { @@ -978,7 +1016,8 @@ } SERIAL_CHAR('\t'); } - #endif + #endif // HAS_TRINAMIC_CONFIG + #if HAS_DRIVER(TMC2660) template static void tmc_get_registers(TMCMarlin &st, const TMC_get_registers_enum i) { @@ -1105,7 +1144,7 @@ // TODO return false; } - void tmc_disable_stallguard(TMC2660Stepper, const bool) {}; + void tmc_disable_stallguard(TMC2660Stepper, const bool) { } #endif // USE_SENSORLESS diff --git a/Marlin/src/feature/tmc_util.h b/Marlin/src/feature/tmc_util.h index 55a4eb02aa..99d9dc4bc1 100644 --- a/Marlin/src/feature/tmc_util.h +++ b/Marlin/src/feature/tmc_util.h @@ -422,6 +422,9 @@ void test_tmc_connection(LOGICAL_AXIS_DECL_LC(const bool, true)); bool tmc_enable_stallguard(TMC2209Stepper &st); void tmc_disable_stallguard(TMC2209Stepper &st, const bool restore_stealth); + bool tmc_enable_stallguard(TMC2240Stepper &st); + void tmc_disable_stallguard(TMC2240Stepper &st, const bool restore_stealth); + bool tmc_enable_stallguard(TMC2660Stepper); void tmc_disable_stallguard(TMC2660Stepper, const bool); diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index 5d427e7e08..98498f4355 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -3381,7 +3381,7 @@ static_assert(NUM_SERVOS <= NUM_SERVO_PLUGS, "NUM_SERVOS (or some servo index) i // Stall detection DIAG = HIGH : TMC2209/2240 // Stall detection DIAG = LOW : TMC2130/2160/2660/5130/5160 #if X_SENSORLESS - #define _HIT_STATE AXIS_DRIVER_TYPE(X,TMC2209) || AXIS_DRIVER_TYPE(X,TMC2240) + #define _HIT_STATE (AXIS_DRIVER_TYPE(X,TMC2209) || AXIS_DRIVER_TYPE(X,TMC2240)) #if X_HOME_TO_MIN && X_MIN_ENDSTOP_HIT_STATE != _HIT_STATE #if _HIT_STATE #error "SENSORLESS_HOMING requires X_MIN_ENDSTOP_HIT_STATE HIGH for X MIN homing with TMC2209/2240." @@ -3399,7 +3399,7 @@ static_assert(NUM_SERVOS <= NUM_SERVO_PLUGS, "NUM_SERVOS (or some servo index) i #endif #if Y_SENSORLESS - #define _HIT_STATE AXIS_DRIVER_TYPE(Y,TMC2209) || AXIS_DRIVER_TYPE(Y,TMC2240) + #define _HIT_STATE (AXIS_DRIVER_TYPE(Y,TMC2209) || AXIS_DRIVER_TYPE(Y,TMC2240)) #if Y_HOME_TO_MIN && Y_MIN_ENDSTOP_HIT_STATE != _HIT_STATE #if _HIT_STATE #error "SENSORLESS_HOMING requires Y_MIN_ENDSTOP_HIT_STATE HIGH for Y MIN homing with TMC2209/2240." @@ -3417,7 +3417,7 @@ static_assert(NUM_SERVOS <= NUM_SERVO_PLUGS, "NUM_SERVOS (or some servo index) i #endif #if Z_SENSORLESS - #define _HIT_STATE AXIS_DRIVER_TYPE(Z,TMC2209) || AXIS_DRIVER_TYPE(Z,TMC2240) + #define _HIT_STATE (AXIS_DRIVER_TYPE(Z,TMC2209) || AXIS_DRIVER_TYPE(Z,TMC2240)) #if Z_HOME_TO_MIN && Z_MIN_ENDSTOP_HIT_STATE != _HIT_STATE #if _HIT_STATE #error "SENSORLESS_HOMING requires Z_MIN_ENDSTOP_HIT_STATE HIGH for Z MIN homing with TMC2209/2240." @@ -3435,7 +3435,7 @@ static_assert(NUM_SERVOS <= NUM_SERVO_PLUGS, "NUM_SERVOS (or some servo index) i #endif #if I_SENSORLESS - #define _HIT_STATE AXIS_DRIVER_TYPE(I,TMC2209) || AXIS_DRIVER_TYPE(I,TMC2240) + #define _HIT_STATE (AXIS_DRIVER_TYPE(I,TMC2209) || AXIS_DRIVER_TYPE(I,TMC2240)) #if I_HOME_TO_MIN && I_MIN_ENDSTOP_HIT_STATE != _HIT_STATE #if _HIT_STATE #error "SENSORLESS_HOMING requires I_MIN_ENDSTOP_HIT_STATE HIGH for I MIN homing with TMC2209/2240." @@ -3453,7 +3453,7 @@ static_assert(NUM_SERVOS <= NUM_SERVO_PLUGS, "NUM_SERVOS (or some servo index) i #endif #if J_SENSORLESS - #define _HIT_STATE AXIS_DRIVER_TYPE(J,TMC2209) || AXIS_DRIVER_TYPE(J,TMC2240) + #define _HIT_STATE (AXIS_DRIVER_TYPE(J,TMC2209) || AXIS_DRIVER_TYPE(J,TMC2240)) #if J_HOME_TO_MIN && J_MIN_ENDSTOP_HIT_STATE != _HIT_STATE #if _HIT_STATE #error "SENSORLESS_HOMING requires J_MIN_ENDSTOP_HIT_STATE HIGH for J MIN homing with TMC2209/2240." @@ -3471,7 +3471,7 @@ static_assert(NUM_SERVOS <= NUM_SERVO_PLUGS, "NUM_SERVOS (or some servo index) i #endif #if K_SENSORLESS - #define _HIT_STATE AXIS_DRIVER_TYPE(K,TMC2209) || AXIS_DRIVER_TYPE(K,TMC2240) + #define _HIT_STATE (AXIS_DRIVER_TYPE(K,TMC2209) || AXIS_DRIVER_TYPE(K,TMC2240)) #if K_HOME_TO_MIN && K_MIN_ENDSTOP_HIT_STATE != _HIT_STATE #if _HIT_STATE #error "SENSORLESS_HOMING requires K_MIN_ENDSTOP_HIT_STATE HIGH for K MIN homing with TMC2209/2240." @@ -3489,7 +3489,7 @@ static_assert(NUM_SERVOS <= NUM_SERVO_PLUGS, "NUM_SERVOS (or some servo index) i #endif #if U_SENSORLESS - #define _HIT_STATE AXIS_DRIVER_TYPE(U,TMC2209) || AXIS_DRIVER_TYPE(U,TMC2240) + #define _HIT_STATE (AXIS_DRIVER_TYPE(U,TMC2209) || AXIS_DRIVER_TYPE(U,TMC2240)) #if U_HOME_TO_MIN && U_MIN_ENDSTOP_HIT_STATE != _HIT_STATE #if _HIT_STATE #error "SENSORLESS_HOMING requires U_MIN_ENDSTOP_HIT_STATE HIGH for U MIN homing with TMC2209/2240." @@ -3507,7 +3507,7 @@ static_assert(NUM_SERVOS <= NUM_SERVO_PLUGS, "NUM_SERVOS (or some servo index) i #endif #if V_SENSORLESS - #define _HIT_STATE AXIS_DRIVER_TYPE(V,TMC2209) || AXIS_DRIVER_TYPE(V,TMC2240) + #define _HIT_STATE (AXIS_DRIVER_TYPE(V,TMC2209) || AXIS_DRIVER_TYPE(V,TMC2240)) #if V_HOME_TO_MIN && V_MIN_ENDSTOP_HIT_STATE != _HIT_STATE #if _HIT_STATE #error "SENSORLESS_HOMING requires V_MIN_ENDSTOP_HIT_STATE HIGH for V MIN homing with TMC2209/2240." @@ -3525,7 +3525,7 @@ static_assert(NUM_SERVOS <= NUM_SERVO_PLUGS, "NUM_SERVOS (or some servo index) i #endif #if W_SENSORLESS - #define _HIT_STATE AXIS_DRIVER_TYPE(W,TMC2209) || AXIS_DRIVER_TYPE(W,TMC2240) + #define _HIT_STATE (AXIS_DRIVER_TYPE(W,TMC2209) || AXIS_DRIVER_TYPE(W,TMC2240)) #if W_HOME_TO_MIN && W_MIN_ENDSTOP_HIT_STATE != _HIT_STATE #if _HIT_STATE #error "SENSORLESS_HOMING requires W_MIN_ENDSTOP_HIT_STATE HIGH for W MIN homing with TMC2209/2240." diff --git a/ini/features.ini b/ini/features.ini index 5bd955dd0a..833fe76510 100644 --- a/ini/features.ini +++ b/ini/features.ini @@ -20,7 +20,7 @@ MARLIN_TEST_BUILD = build_src_filter=+ POSTMORTEM_DEBUGGING = build_src_filter=+ + build_flags=-funwind-tables MKS_WIFI_MODULE = QRCode=https://github.com/makerbase-mks/QRCode/archive/261c5a696a.zip -HAS_TRINAMIC_CONFIG = TMCStepper=https://github.com/MarlinFirmware/TMCStepper/archive/marlin-2.1.3.x.zip +HAS_TRINAMIC_CONFIG = TMCStepper=https://github.com/MarlinFirmware/TMCStepper/archive/v0.8.2.zip build_src_filter=+ + + + + HAS_STEPPER_CONTROL = build_src_filter=+ HAS_T(RINAMIC_CONFIG|MC_SPI) = build_src_filter=+ From c7bcbf944ec366c55b6ebbf2909c0baad36491e3 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Mon, 26 May 2025 11:29:26 -0500 Subject: [PATCH 342/787] =?UTF-8?q?=F0=9F=8C=90=20Specific=20USB-FD=20stri?= =?UTF-8?q?ngs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/lcd/language/language_cz.h | 7 ++++--- Marlin/src/lcd/language/language_de.h | 7 ++++--- Marlin/src/lcd/language/language_el.h | 8 ++++---- Marlin/src/lcd/language/language_en.h | 9 ++++----- Marlin/src/lcd/language/language_es.h | 7 ++++--- Marlin/src/lcd/language/language_fr.h | 7 ++++--- Marlin/src/lcd/language/language_fr_na.h | 7 ++++--- Marlin/src/lcd/language/language_gl.h | 7 ++++--- Marlin/src/lcd/language/language_hu.h | 7 ++++--- Marlin/src/lcd/language/language_it.h | 10 +++++++--- Marlin/src/lcd/language/language_pl.h | 7 ++++--- Marlin/src/lcd/language/language_pt_br.h | 7 ++++--- Marlin/src/lcd/language/language_ro.h | 7 ++++--- Marlin/src/lcd/language/language_ru.h | 7 ++++--- Marlin/src/lcd/language/language_sk.h | 7 ++++--- Marlin/src/lcd/language/language_sv.h | 7 ++++--- Marlin/src/lcd/language/language_tr.h | 7 ++++--- Marlin/src/lcd/language/language_uk.h | 7 ++++--- Marlin/src/lcd/language/language_vi.h | 7 ++++--- Marlin/src/lcd/language/language_zh_CN.h | 7 ++++--- Marlin/src/lcd/language/language_zh_TW.h | 7 ++++--- Marlin/src/lcd/marlinui.cpp | 2 +- Marlin/src/sd/usb_flashdrive/Sd2Card_FlashDrive.cpp | 10 +++++----- 23 files changed, 93 insertions(+), 72 deletions(-) diff --git a/Marlin/src/lcd/language/language_cz.h b/Marlin/src/lcd/language/language_cz.h index ac23bc8daf..2b5fb524d4 100644 --- a/Marlin/src/lcd/language/language_cz.h +++ b/Marlin/src/lcd/language/language_cz.h @@ -45,13 +45,14 @@ namespace LanguageNarrow_cz { LSTR MSG_YES = _UxGT("ANO"); LSTR MSG_NO = _UxGT("NE"); LSTR MSG_BACK = _UxGT("Zpět"); + LSTR MSG_MEDIA_ABORTING = _UxGT("Rušení..."); LSTR MSG_MEDIA_INSERTED = _UxGT("Médium vloženo"); LSTR MSG_MEDIA_REMOVED = _UxGT("Médium vyjmuto"); - LSTR MSG_MEDIA_WAITING = _UxGT("Čekání na médium"); LSTR MSG_MEDIA_READ_ERROR = _UxGT("Chyba čtení média"); - LSTR MSG_MEDIA_USB_REMOVED = _UxGT("USB odstraněno"); - LSTR MSG_MEDIA_USB_FAILED = _UxGT("Chyba USB"); + LSTR MSG_USB_FD_DEVICE_REMOVED = _UxGT("USB odstraněno"); + LSTR MSG_USB_FD_USB_FAILED = _UxGT("Chyba USB"); + LSTR MSG_LCD_ENDSTOPS = _UxGT("Endstopy"); // max 8 znaku LSTR MSG_LCD_SOFT_ENDSTOPS = _UxGT("Soft Endstopy"); LSTR MSG_MAIN_MENU = _UxGT("Hlavní nabídka"); diff --git a/Marlin/src/lcd/language/language_de.h b/Marlin/src/lcd/language/language_de.h index e681317fb8..4f2cdb79ff 100644 --- a/Marlin/src/lcd/language/language_de.h +++ b/Marlin/src/lcd/language/language_de.h @@ -41,15 +41,16 @@ namespace LanguageNarrow_de { LSTR MSG_LOW = _UxGT("RUNTER"); LSTR MSG_BACK = _UxGT("Zurück"); LSTR MSG_ERROR = _UxGT("Fehler"); + LSTR MSG_MEDIA_ABORTING = _UxGT("Abbruch..."); LSTR MSG_MEDIA_INSERTED = _UxGT("Medium erkannt"); LSTR MSG_MEDIA_REMOVED = _UxGT("Medium entfernt"); - LSTR MSG_MEDIA_WAITING = _UxGT("Warten auf Medium"); LSTR MSG_MEDIA_INIT_FAIL = _UxGT("Medium Init fehlgesch."); LSTR MSG_MEDIA_READ_ERROR = _UxGT("Medium Lesefehler"); - LSTR MSG_MEDIA_USB_REMOVED = _UxGT("USB Gerät entfernt"); - LSTR MSG_MEDIA_USB_FAILED = _UxGT("USB Start fehlge."); + LSTR MSG_USB_FD_DEVICE_REMOVED = _UxGT("USB Gerät entfernt"); + LSTR MSG_USB_FD_USB_FAILED = _UxGT("USB Start fehlge."); LSTR MSG_KILL_SUBCALL_OVERFLOW = _UxGT("Subcall überschritten"); + LSTR MSG_LCD_ENDSTOPS = _UxGT("Endstopp"); // Max length 8 characters LSTR MSG_LCD_SOFT_ENDSTOPS = _UxGT("Software-Endstopp"); LSTR MSG_MAIN_MENU = _UxGT("Hauptmenü"); diff --git a/Marlin/src/lcd/language/language_el.h b/Marlin/src/lcd/language/language_el.h index 0d3d355cb0..ab816adae0 100644 --- a/Marlin/src/lcd/language/language_el.h +++ b/Marlin/src/lcd/language/language_el.h @@ -45,12 +45,12 @@ namespace LanguageNarrow_el { LSTR MSG_MEDIA_INSERTED = _UxGT("Κάρτα εισήχθη"); LSTR MSG_MEDIA_REMOVED = _UxGT("Κάρτα αφαιρέθη"); - LSTR MSG_MEDIA_WAITING = _UxGT("Αναμονή για κάρτα"); LSTR MSG_MEDIA_ABORTING = _UxGT("Ματαίωση..."); - LSTR MSG_MEDIA_READ_ERROR = MEDIA_TYPE_EN _UxGT(" σφάλμα ανάγνωσης"); - LSTR MSG_MEDIA_USB_REMOVED = _UxGT("USB αφαιρέθη"); - LSTR MSG_MEDIA_USB_FAILED = _UxGT("Αποτυχία εκκίνησης USB"); LSTR MSG_MEDIA_INIT_FAIL = _UxGT("Αποτυχία αρχικοποίησης SD"); + LSTR MSG_MEDIA_READ_ERROR = MEDIA_TYPE_EN _UxGT(" σφάλμα ανάγνωσης"); + LSTR MSG_USB_FD_DEVICE_REMOVED = _UxGT("USB αφαιρέθη"); + LSTR MSG_USB_FD_USB_FAILED = _UxGT("Αποτυχία εκκίνησης USB"); + LSTR MSG_MAIN_MENU = _UxGT("Αρχική Οθόνη"); LSTR MSG_DISABLE_STEPPERS = _UxGT("Απενεργοποίηση μοτέρ"); LSTR MSG_AUTO_HOME = _UxGT("Αυτόμ. επαναφορά XYZ"); diff --git a/Marlin/src/lcd/language/language_en.h b/Marlin/src/lcd/language/language_en.h index 5ed5b24635..a74d28b82a 100644 --- a/Marlin/src/lcd/language/language_en.h +++ b/Marlin/src/lcd/language/language_en.h @@ -90,17 +90,16 @@ namespace LanguageNarrow_en { LSTR MSG_MEDIA_REMOVED = MEDIA_TYPE_EN _UxGT(" Removed"); LSTR MSG_MEDIA_REMOVED_SD = _UxGT("SD Card Removed"); LSTR MSG_MEDIA_REMOVED_USB = _UxGT("USB Drive Removed"); - LSTR MSG_MEDIA_WAITING = _UxGT("Waiting for ") MEDIA_TYPE_EN; - LSTR MSG_MEDIA_WAITING_SD = _UxGT("Waiting for SD Card"); - LSTR MSG_MEDIA_WAITING_USB = _UxGT("Waiting for USB Drive"); LSTR MSG_MEDIA_INIT_FAIL = MEDIA_TYPE_EN _UxGT(" Init Fail"); LSTR MSG_MEDIA_INIT_FAIL_SD = _UxGT("SD Card Init Fail"); LSTR MSG_MEDIA_INIT_FAIL_USB = _UxGT("USB Drive Init Fail"); LSTR MSG_MEDIA_READ_ERROR = MEDIA_TYPE_EN _UxGT(" read error"); - LSTR MSG_MEDIA_USB_REMOVED = _UxGT("USB device removed"); - LSTR MSG_MEDIA_USB_FAILED = _UxGT("USB start failed"); LSTR MSG_MEDIA_SORT = _UxGT("Sort ") MEDIA_TYPE_EN; LSTR MSG_MEDIA_UPDATE = MEDIA_TYPE_EN _UxGT(" Update"); + LSTR MSG_USB_FD_WAITING_FOR_MEDIA = _UxGT("Wait for USB Drive"); + LSTR MSG_USB_FD_MEDIA_REMOVED = _UxGT("USB Drive Removed"); + LSTR MSG_USB_FD_DEVICE_REMOVED = _UxGT("USB device removed"); + LSTR MSG_USB_FD_USB_FAILED = _UxGT("USB start failed"); LSTR MSG_KILL_SUBCALL_OVERFLOW = _UxGT("Subcall Overflow"); LSTR MSG_LCD_ENDSTOPS = _UxGT("Endstops"); // Max length 8 characters diff --git a/Marlin/src/lcd/language/language_es.h b/Marlin/src/lcd/language/language_es.h index a92efd5389..2646a85f09 100644 --- a/Marlin/src/lcd/language/language_es.h +++ b/Marlin/src/lcd/language/language_es.h @@ -46,15 +46,16 @@ namespace LanguageNarrow_es { LSTR MSG_YES = _UxGT("SI"); LSTR MSG_NO = _UxGT("NO"); LSTR MSG_BACK = _UxGT("Atrás"); + LSTR MSG_MEDIA_ABORTING = _UxGT("Cancelando..."); LSTR MSG_MEDIA_INSERTED = MEDIA_TYPE_ES _UxGT(" insertado"); LSTR MSG_MEDIA_REMOVED = MEDIA_TYPE_ES _UxGT(" retirado"); - LSTR MSG_MEDIA_WAITING = _UxGT("Esperando al ") MEDIA_TYPE_ES; LSTR MSG_MEDIA_INIT_FAIL = _UxGT("Fallo al iniciar ") MEDIA_TYPE_ES; LSTR MSG_MEDIA_READ_ERROR = _UxGT("Error lectura ") MEDIA_TYPE_ES; - LSTR MSG_MEDIA_USB_REMOVED = _UxGT("Disp. USB retirado"); - LSTR MSG_MEDIA_USB_FAILED = _UxGT("Inicio USB fallido"); + LSTR MSG_USB_FD_DEVICE_REMOVED = _UxGT("Disp. USB retirado"); + LSTR MSG_USB_FD_USB_FAILED = _UxGT("Inicio USB fallido"); LSTR MSG_KILL_SUBCALL_OVERFLOW = _UxGT("Desbordamiento de subllamada"); + LSTR MSG_LCD_ENDSTOPS = _UxGT("Endstops"); // Max length 8 characters LSTR MSG_LCD_SOFT_ENDSTOPS = _UxGT("Soft Endstops"); LSTR MSG_MAIN_MENU = _UxGT("Menú principal"); diff --git a/Marlin/src/lcd/language/language_fr.h b/Marlin/src/lcd/language/language_fr.h index 6d9fd3b4f4..6f0e870807 100644 --- a/Marlin/src/lcd/language/language_fr.h +++ b/Marlin/src/lcd/language/language_fr.h @@ -40,13 +40,14 @@ namespace LanguageNarrow_fr { LSTR MSG_YES = _UxGT("Oui"); LSTR MSG_NO = _UxGT("Non"); LSTR MSG_BACK = _UxGT("Retour"); + LSTR MSG_MEDIA_ABORTING = _UxGT("Annulation..."); LSTR MSG_MEDIA_INSERTED = _UxGT("Média inséré"); LSTR MSG_MEDIA_REMOVED = _UxGT("Média retiré"); - LSTR MSG_MEDIA_WAITING = _UxGT("Attente média"); LSTR MSG_MEDIA_READ_ERROR = _UxGT("Err lecture média"); - LSTR MSG_MEDIA_USB_REMOVED = _UxGT("USB débranché"); - LSTR MSG_MEDIA_USB_FAILED = _UxGT("Erreur média USB"); + LSTR MSG_USB_FD_DEVICE_REMOVED = _UxGT("USB débranché"); + LSTR MSG_USB_FD_USB_FAILED = _UxGT("Erreur média USB"); + LSTR MSG_LCD_ENDSTOPS = _UxGT("Butées"); LSTR MSG_LCD_SOFT_ENDSTOPS = _UxGT("Butées SW"); LSTR MSG_MAIN_MENU = _UxGT("Menu principal"); diff --git a/Marlin/src/lcd/language/language_fr_na.h b/Marlin/src/lcd/language/language_fr_na.h index 07f2b86499..ef1e29a6b9 100644 --- a/Marlin/src/lcd/language/language_fr_na.h +++ b/Marlin/src/lcd/language/language_fr_na.h @@ -40,13 +40,14 @@ namespace LanguageNarrow_fr_na { LSTR MSG_YES = _UxGT("Oui"); LSTR MSG_NO = _UxGT("Non"); LSTR MSG_BACK = _UxGT("Retour"); + LSTR MSG_MEDIA_ABORTING = _UxGT("Annulation..."); LSTR MSG_MEDIA_INSERTED = _UxGT("Media insere"); LSTR MSG_MEDIA_REMOVED = _UxGT("Media retire"); - LSTR MSG_MEDIA_WAITING = _UxGT("Attente media"); LSTR MSG_MEDIA_READ_ERROR = _UxGT("Err lecture media"); - LSTR MSG_MEDIA_USB_REMOVED = _UxGT("USB debranche"); - LSTR MSG_MEDIA_USB_FAILED = _UxGT("Erreur media USB"); + LSTR MSG_USB_FD_DEVICE_REMOVED = _UxGT("USB debranche"); + LSTR MSG_USB_FD_USB_FAILED = _UxGT("Erreur media USB"); + LSTR MSG_LCD_ENDSTOPS = _UxGT("Butees"); LSTR MSG_LCD_SOFT_ENDSTOPS = _UxGT("Butees SW"); LSTR MSG_MAIN_MENU = _UxGT("Menu principal"); diff --git a/Marlin/src/lcd/language/language_gl.h b/Marlin/src/lcd/language/language_gl.h index 3b7620de90..6285626625 100644 --- a/Marlin/src/lcd/language/language_gl.h +++ b/Marlin/src/lcd/language/language_gl.h @@ -48,14 +48,15 @@ namespace LanguageNarrow_gl { LSTR MSG_YES = _UxGT("SI"); LSTR MSG_NO = _UxGT("NON"); LSTR MSG_BACK = _UxGT("Atrás"); + LSTR MSG_MEDIA_ABORTING = _UxGT("Cancelando..."); LSTR MSG_MEDIA_INSERTED = _UxGT("Tarxeta inserida"); LSTR MSG_MEDIA_REMOVED = _UxGT("Tarxeta retirada"); - LSTR MSG_MEDIA_WAITING = _UxGT("Agardando ao ") MEDIA_TYPE_GL; LSTR MSG_MEDIA_READ_ERROR = _UxGT("Erro lectura ") MEDIA_TYPE_GL; - LSTR MSG_MEDIA_USB_REMOVED = _UxGT("Disp. USB retirado"); - LSTR MSG_MEDIA_USB_FAILED = _UxGT("Inicio USB fallido"); + LSTR MSG_USB_FD_DEVICE_REMOVED = _UxGT("Disp. USB retirado"); + LSTR MSG_USB_FD_USB_FAILED = _UxGT("Inicio USB fallido"); LSTR MSG_KILL_SUBCALL_OVERFLOW = _UxGT("Desbord. Subch."); + LSTR MSG_LCD_ENDSTOPS = _UxGT("FinCarro"); LSTR MSG_LCD_SOFT_ENDSTOPS = _UxGT("FinCarro SW"); LSTR MSG_MAIN_MENU = _UxGT("Menú principal"); diff --git a/Marlin/src/lcd/language/language_hu.h b/Marlin/src/lcd/language/language_hu.h index 3159b79827..7a3e51539c 100644 --- a/Marlin/src/lcd/language/language_hu.h +++ b/Marlin/src/lcd/language/language_hu.h @@ -43,15 +43,16 @@ namespace LanguageNarrow_hu { LSTR MSG_YES = _UxGT("IGEN"); LSTR MSG_NO = _UxGT("NEM"); LSTR MSG_BACK = _UxGT("Vissza"); + LSTR MSG_MEDIA_ABORTING = _UxGT("Megszakítás..."); LSTR MSG_MEDIA_INSERTED = _UxGT("Tároló behelyezve"); LSTR MSG_MEDIA_REMOVED = _UxGT("Tároló eltávolítva"); - LSTR MSG_MEDIA_WAITING = _UxGT("Várakozás a tárolóra"); LSTR MSG_MEDIA_INIT_FAIL = _UxGT("Tároló-kártya hiba"); LSTR MSG_MEDIA_READ_ERROR = _UxGT("Tároló olvasási hiba"); - LSTR MSG_MEDIA_USB_REMOVED = _UxGT("USB eltávolítva"); - LSTR MSG_MEDIA_USB_FAILED = _UxGT("USB eszköz hiba"); + LSTR MSG_USB_FD_DEVICE_REMOVED = _UxGT("USB eltávolítva"); + LSTR MSG_USB_FD_USB_FAILED = _UxGT("USB eszköz hiba"); LSTR MSG_KILL_SUBCALL_OVERFLOW = _UxGT("Túlfolyás"); + LSTR MSG_LCD_ENDSTOPS = _UxGT("Végállás"); // Maximum 8 karakter LSTR MSG_LCD_SOFT_ENDSTOPS = _UxGT("Szoft. végállás"); LSTR MSG_MAIN_MENU = _UxGT(""); diff --git a/Marlin/src/lcd/language/language_it.h b/Marlin/src/lcd/language/language_it.h index 0e8689cb0f..bdcd0b8ff6 100644 --- a/Marlin/src/lcd/language/language_it.h +++ b/Marlin/src/lcd/language/language_it.h @@ -59,16 +59,19 @@ namespace LanguageNarrow_it { LSTR MSG_LOW = _UxGT("BASSO"); LSTR MSG_BACK = _UxGT("Indietro"); LSTR MSG_ERROR = _UxGT("Errore"); + LSTR MSG_MEDIA_ABORTING = _UxGT("Annullando..."); LSTR MSG_MEDIA_INSERTED = MEDIA_TYPE_IT _UxGT(" inserito"); LSTR MSG_MEDIA_REMOVED = MEDIA_TYPE_IT _UxGT(" rimosso"); - LSTR MSG_MEDIA_WAITING = _UxGT("Aspettando ") MEDIA_TYPE_IT; LSTR MSG_MEDIA_INIT_FAIL = _UxGT("Iniz.") MEDIA_TYPE_IT _UxGT(" fallita"); LSTR MSG_MEDIA_READ_ERROR = _UxGT("Err.leggendo ") MEDIA_TYPE_IT; - LSTR MSG_MEDIA_USB_REMOVED = _UxGT("Dispos.USB rimosso"); - LSTR MSG_MEDIA_USB_FAILED = _UxGT("Avvio USB fallito"); LSTR MSG_MEDIA_SORT = _UxGT("Ordina ") MEDIA_TYPE_IT; LSTR MSG_MEDIA_UPDATE = _UxGT("Aggiorna ") MEDIA_TYPE_IT; + LSTR MSG_USB_FD_WAITING_FOR_MEDIA = _UxGT("In attesa unità USB"); + LSTR MSG_USB_FD_MEDIA_REMOVED = _UxGT("Unità USB rimossa"); + LSTR MSG_USB_FD_DEVICE_REMOVED = _UxGT("Unità USB rimossa"); + LSTR MSG_USB_FD_USB_FAILED = _UxGT("Iniz. USB fallita"); + LSTR MSG_KILL_SUBCALL_OVERFLOW = _UxGT("Overflow sottochiamate"); LSTR MSG_LCD_ENDSTOPS = _UxGT("Finecor."); // Max 8 characters LSTR MSG_LCD_SOFT_ENDSTOPS = _UxGT("Finecorsa soft"); @@ -848,6 +851,7 @@ namespace LanguageNarrow_it { LSTR MSG_FILAMENT_CHANGE_PURGE = _UxGT(MSG_1_LINE("Spurgo filamento")); LSTR MSG_FILAMENT_CHANGE_CONT_PURGE = _UxGT(MSG_1_LINE("Premi x terminare")); LSTR MSG_FILAMENT_CHANGE_RESUME = _UxGT(MSG_1_LINE("Ripresa...")); + LSTR MSG_TMC_DRIVERS = _UxGT("Driver TMC"); LSTR MSG_TMC_CURRENT = _UxGT("Corrente driver"); LSTR MSG_TMC_ACURRENT = _UxGT("Corrente driver ") STR_A; diff --git a/Marlin/src/lcd/language/language_pl.h b/Marlin/src/lcd/language/language_pl.h index 7c7297d184..df0f995416 100644 --- a/Marlin/src/lcd/language/language_pl.h +++ b/Marlin/src/lcd/language/language_pl.h @@ -48,14 +48,15 @@ namespace LanguageNarrow_pl { LSTR MSG_YES = _UxGT("TAK"); LSTR MSG_NO = _UxGT("NIE"); LSTR MSG_BACK = _UxGT("Wstecz"); + LSTR MSG_MEDIA_ABORTING = _UxGT("Przerywanie..."); LSTR MSG_MEDIA_INSERTED = _UxGT("Karta włożona"); LSTR MSG_MEDIA_REMOVED = _UxGT("Karta usunięta"); - LSTR MSG_MEDIA_WAITING = _UxGT("Oczekiwanie na kartę"); LSTR MSG_MEDIA_INIT_FAIL = _UxGT("Błąd inicializacji karty"); LSTR MSG_MEDIA_READ_ERROR = _UxGT("Bład odczytu karty"); - LSTR MSG_MEDIA_USB_REMOVED = _UxGT("Urządzenie USB usunięte"); - LSTR MSG_MEDIA_USB_FAILED = _UxGT("Błąd uruchomienia USB"); + LSTR MSG_USB_FD_DEVICE_REMOVED = _UxGT("Urządzenie USB usunięte"); + LSTR MSG_USB_FD_USB_FAILED = _UxGT("Błąd uruchomienia USB"); + LSTR MSG_LCD_ENDSTOPS = _UxGT("Krańców."); // Max length 8 characters LSTR MSG_LCD_SOFT_ENDSTOPS = _UxGT("Progr. Krańcówki"); LSTR MSG_MAIN_MENU = _UxGT("Menu główne"); diff --git a/Marlin/src/lcd/language/language_pt_br.h b/Marlin/src/lcd/language/language_pt_br.h index 80a8d95bdb..49c52300f9 100644 --- a/Marlin/src/lcd/language/language_pt_br.h +++ b/Marlin/src/lcd/language/language_pt_br.h @@ -38,13 +38,14 @@ namespace LanguageNarrow_pt_br { LSTR MSG_YES = _UxGT("SIM"); LSTR MSG_NO = _UxGT("NÃO"); LSTR MSG_BACK = _UxGT("Voltar"); + LSTR MSG_MEDIA_ABORTING = _UxGT("Abortando..."); LSTR MSG_MEDIA_INSERTED = _UxGT("Cartão inserido"); LSTR MSG_MEDIA_REMOVED = _UxGT("Cartão removido"); - LSTR MSG_MEDIA_WAITING = _UxGT("Aguardando cartão"); LSTR MSG_MEDIA_READ_ERROR = _UxGT("Erro de leitura"); - LSTR MSG_MEDIA_USB_REMOVED = _UxGT("USB removido"); - LSTR MSG_MEDIA_USB_FAILED = _UxGT("USB falhou"); + LSTR MSG_USB_FD_DEVICE_REMOVED = _UxGT("USB removido"); + LSTR MSG_USB_FD_USB_FAILED = _UxGT("USB falhou"); + LSTR MSG_LCD_ENDSTOPS = _UxGT("Fins de curso"); LSTR MSG_LCD_SOFT_ENDSTOPS = _UxGT("Soft Fins curso"); LSTR MSG_MAIN_MENU = _UxGT("Menu principal"); diff --git a/Marlin/src/lcd/language/language_ro.h b/Marlin/src/lcd/language/language_ro.h index 7337862909..3a939c6a3d 100644 --- a/Marlin/src/lcd/language/language_ro.h +++ b/Marlin/src/lcd/language/language_ro.h @@ -39,14 +39,15 @@ namespace LanguageNarrow_ro { LSTR MSG_YES = _UxGT("DA"); LSTR MSG_NO = _UxGT("NU"); LSTR MSG_BACK = _UxGT("Inapoi"); + LSTR MSG_MEDIA_ABORTING = _UxGT("Abandon..."); LSTR MSG_MEDIA_INSERTED = _UxGT("Media Introdus"); LSTR MSG_MEDIA_REMOVED = _UxGT("Media Inlaturat"); - LSTR MSG_MEDIA_WAITING = _UxGT("Astept Media"); LSTR MSG_MEDIA_READ_ERROR = _UxGT("Eroare Citire Media"); - LSTR MSG_MEDIA_USB_REMOVED = _UxGT("Dispozitiv USB Inlaturat"); - LSTR MSG_MEDIA_USB_FAILED = _UxGT("Pornire USB Esuata"); + LSTR MSG_USB_FD_DEVICE_REMOVED = _UxGT("Dispozitiv USB Inlaturat"); + LSTR MSG_USB_FD_USB_FAILED = _UxGT("Pornire USB Esuata"); LSTR MSG_KILL_SUBCALL_OVERFLOW = _UxGT("Eroare:Subcall Overflow"); + LSTR MSG_LCD_ENDSTOPS = _UxGT("Endstops"); // Max length 8 characters LSTR MSG_LCD_SOFT_ENDSTOPS = _UxGT("Soft Endstops"); LSTR MSG_MAIN_MENU = _UxGT("Principal"); diff --git a/Marlin/src/lcd/language/language_ru.h b/Marlin/src/lcd/language/language_ru.h index 40b3a03d3d..37bc17aa0c 100644 --- a/Marlin/src/lcd/language/language_ru.h +++ b/Marlin/src/lcd/language/language_ru.h @@ -39,16 +39,17 @@ namespace LanguageNarrow_ru { LSTR MSG_YES = _UxGT("Да"); LSTR MSG_NO = _UxGT("Нет"); LSTR MSG_BACK = _UxGT("Назад"); + LSTR MSG_MEDIA_ABORTING = _UxGT("Прерывание..."); LSTR MSG_MEDIA_INSERTED = _UxGT("SD карта вставлена"); LSTR MSG_MEDIA_REMOVED = _UxGT("SD карта извлечена"); - LSTR MSG_MEDIA_WAITING = _UxGT("Вставьте SD карту"); LSTR MSG_MEDIA_INIT_FAIL = _UxGT("Сбой инициализ. SD"); LSTR MSG_ADVANCED_SETTINGS = _UxGT("Расшир. настройки"); LSTR MSG_KILL_SUBCALL_OVERFLOW = _UxGT("Переполн. вызова"); LSTR MSG_MEDIA_READ_ERROR = _UxGT("Ошибка чтения"); - LSTR MSG_MEDIA_USB_REMOVED = _UxGT("USB диск удалён"); - LSTR MSG_MEDIA_USB_FAILED = _UxGT("Ошибка USB диска"); + LSTR MSG_USB_FD_DEVICE_REMOVED = _UxGT("USB диск удалён"); + LSTR MSG_USB_FD_USB_FAILED = _UxGT("Ошибка USB диска"); + LSTR MSG_LCD_SOFT_ENDSTOPS = _UxGT("Прогр. концевики"); LSTR MSG_LCD_ENDSTOPS = _UxGT("Концевик"); // Max length 8 characters LSTR MSG_MAIN_MENU = _UxGT("Главное меню"); diff --git a/Marlin/src/lcd/language/language_sk.h b/Marlin/src/lcd/language/language_sk.h index 7a8c228d84..f1efc0e7c3 100644 --- a/Marlin/src/lcd/language/language_sk.h +++ b/Marlin/src/lcd/language/language_sk.h @@ -54,14 +54,15 @@ namespace LanguageNarrow_sk { LSTR MSG_LOW = _UxGT("NÍZKA"); LSTR MSG_BACK = _UxGT("Naspäť"); LSTR MSG_ERROR = _UxGT("Chyba"); + LSTR MSG_MEDIA_ABORTING = _UxGT("Ruším..."); LSTR MSG_MEDIA_INSERTED = _UxGT("Karta vložená"); LSTR MSG_MEDIA_REMOVED = _UxGT("Karta vybraná"); - LSTR MSG_MEDIA_WAITING = _UxGT("Čakám na kartu"); LSTR MSG_MEDIA_INIT_FAIL = _UxGT("Inicial.karty zlyhala"); LSTR MSG_MEDIA_READ_ERROR = _UxGT("Chyba čítania karty"); - LSTR MSG_MEDIA_USB_REMOVED = _UxGT("USB zaria. odstrán."); - LSTR MSG_MEDIA_USB_FAILED = _UxGT("Chyba spúšťania USB"); + LSTR MSG_USB_FD_DEVICE_REMOVED = _UxGT("USB zaria. odstrán."); + LSTR MSG_USB_FD_USB_FAILED = _UxGT("Chyba spúšťania USB"); + LSTR MSG_KILL_SUBCALL_OVERFLOW = _UxGT("Preteč. podprogramu"); LSTR MSG_LCD_ENDSTOPS = _UxGT("Endstopy"); // max 8 znakov LSTR MSG_LCD_SOFT_ENDSTOPS = _UxGT("Soft. endstopy"); diff --git a/Marlin/src/lcd/language/language_sv.h b/Marlin/src/lcd/language/language_sv.h index e2e408391c..33ffe8a77d 100644 --- a/Marlin/src/lcd/language/language_sv.h +++ b/Marlin/src/lcd/language/language_sv.h @@ -40,15 +40,16 @@ namespace LanguageNarrow_sv { LSTR MSG_YES = _UxGT("JA"); LSTR MSG_NO = _UxGT("NEJ"); LSTR MSG_BACK = _UxGT("Bakåt"); + LSTR MSG_MEDIA_ABORTING = _UxGT("Avbryter..."); LSTR MSG_MEDIA_INSERTED = _UxGT("Media Instatt"); LSTR MSG_MEDIA_REMOVED = _UxGT("Media Borttaget"); - LSTR MSG_MEDIA_WAITING = _UxGT("Väntar på media"); LSTR MSG_MEDIA_INIT_FAIL = _UxGT("Media init misslyckades"); LSTR MSG_MEDIA_READ_ERROR = _UxGT("Media läsningsfel"); - LSTR MSG_MEDIA_USB_REMOVED = _UxGT("USB enhet borttagen"); - LSTR MSG_MEDIA_USB_FAILED = _UxGT("USB start misslyckad"); + LSTR MSG_USB_FD_DEVICE_REMOVED = _UxGT("USB enhet borttagen"); + LSTR MSG_USB_FD_USB_FAILED = _UxGT("USB start misslyckad"); LSTR MSG_KILL_SUBCALL_OVERFLOW = _UxGT("Underanrop överskriden"); + LSTR MSG_LCD_ENDSTOPS = _UxGT("Slutstop"); // Max length 8 characters LSTR MSG_LCD_SOFT_ENDSTOPS = _UxGT("Mjuk slutstopp"); LSTR MSG_MAIN_MENU = _UxGT("Huvud"); diff --git a/Marlin/src/lcd/language/language_tr.h b/Marlin/src/lcd/language/language_tr.h index 36fe4188fa..9e4f261271 100644 --- a/Marlin/src/lcd/language/language_tr.h +++ b/Marlin/src/lcd/language/language_tr.h @@ -52,17 +52,18 @@ namespace LanguageNarrow_tr { LSTR MSG_LOW = _UxGT("DÜŞÜK"); LSTR MSG_BACK = _UxGT("Geri"); LSTR MSG_ERROR = _UxGT("Hata"); + LSTR MSG_MEDIA_ABORTING = _UxGT("Durduruluyor..."); LSTR MSG_MEDIA_INSERTED = _UxGT("SD K. Yerleştirildi."); LSTR MSG_MEDIA_REMOVED = _UxGT("SD Kart Çıkarıldı."); - LSTR MSG_MEDIA_WAITING = _UxGT("SD Kart Bekleniyor"); LSTR MSG_MEDIA_INIT_FAIL = _UxGT("SD K. Başlatma Hatası"); LSTR MSG_MEDIA_READ_ERROR = _UxGT("Kart Okuma Hatası"); - LSTR MSG_MEDIA_USB_REMOVED = _UxGT("USB Çıkarıldı"); - LSTR MSG_MEDIA_USB_FAILED = _UxGT("USB Başlat. Hatası"); + LSTR MSG_USB_FD_DEVICE_REMOVED = _UxGT("USB Çıkarıldı"); + LSTR MSG_USB_FD_USB_FAILED = _UxGT("USB Başlat. Hatası"); LSTR MSG_MEDIA_SORT = _UxGT("Medyayı Sırala"); LSTR MSG_MEDIA_UPDATE = _UxGT("Medyayı Güncelle"); LSTR MSG_KILL_SUBCALL_OVERFLOW = _UxGT("Subcall Overflow"); + LSTR MSG_LCD_ENDSTOPS = _UxGT("Endstops"); // Max length 8 characters LSTR MSG_LCD_SOFT_ENDSTOPS = _UxGT("Soft Endstops"); LSTR MSG_MAIN_MENU = _UxGT("Ana"); diff --git a/Marlin/src/lcd/language/language_uk.h b/Marlin/src/lcd/language/language_uk.h index 4d323d6ba7..a6d87e2ae8 100644 --- a/Marlin/src/lcd/language/language_uk.h +++ b/Marlin/src/lcd/language/language_uk.h @@ -40,15 +40,16 @@ namespace LanguageNarrow_uk { LSTR MSG_YES = _UxGT("ТАК"); LSTR MSG_NO = _UxGT("НІ"); LSTR MSG_BACK = _UxGT("Назад"); + LSTR MSG_MEDIA_ABORTING = _UxGT("Переривання..."); LSTR MSG_MEDIA_INSERTED = _UxGT("SD-картка вставлена"); LSTR MSG_MEDIA_REMOVED = _UxGT("SD-картка видалена"); - LSTR MSG_MEDIA_WAITING = _UxGT("Вставте SD-картку"); LSTR MSG_MEDIA_INIT_FAIL = _UxGT("Збій ініціаліз. SD"); LSTR MSG_MEDIA_READ_ERROR = _UxGT("Помилка зчитування"); - LSTR MSG_MEDIA_USB_REMOVED = _UxGT("USB диск видалений"); - LSTR MSG_MEDIA_USB_FAILED = _UxGT("Помилка USB диску"); + LSTR MSG_USB_FD_DEVICE_REMOVED = _UxGT("USB диск видалений"); + LSTR MSG_USB_FD_USB_FAILED = _UxGT("Помилка USB диску"); LSTR MSG_KILL_SUBCALL_OVERFLOW = _UxGT("Переповн. виклику"); + LSTR MSG_LCD_SOFT_ENDSTOPS = _UxGT("Прогр.кінцевики"); LSTR MSG_LCD_ENDSTOPS = _UxGT("Кінцевик"); // Max length 8 characters LSTR MSG_MAIN_MENU = _UxGT("Основне меню"); diff --git a/Marlin/src/lcd/language/language_vi.h b/Marlin/src/lcd/language/language_vi.h index f7f5545bcb..e411668a91 100644 --- a/Marlin/src/lcd/language/language_vi.h +++ b/Marlin/src/lcd/language/language_vi.h @@ -35,13 +35,14 @@ namespace LanguageNarrow_vi { LSTR WELCOME_MSG = MACHINE_NAME_SUBST _UxGT(" Sẵn sàng."); // Ready LSTR MSG_BACK = _UxGT("Trở lại"); // Back + LSTR MSG_MEDIA_ABORTING = _UxGT("Đang hủy bỏ..."); LSTR MSG_MEDIA_INSERTED = _UxGT("Phương tiện được cắm vào"); // Media inserted LSTR MSG_MEDIA_REMOVED = _UxGT("Phương tiện được rút ra"); - LSTR MSG_MEDIA_WAITING = _UxGT("Chờ đợi phương tiện"); LSTR MSG_MEDIA_READ_ERROR = _UxGT("Lỗi đọc phương tiện"); - LSTR MSG_MEDIA_USB_REMOVED = _UxGT("USB được rút ra"); - LSTR MSG_MEDIA_USB_FAILED = _UxGT("USB khởi thất bại"); + LSTR MSG_USB_FD_DEVICE_REMOVED = _UxGT("USB được rút ra"); + LSTR MSG_USB_FD_USB_FAILED = _UxGT("USB khởi thất bại"); + LSTR MSG_LCD_ENDSTOPS = _UxGT("Công tắc"); // Endstops - công tắc hành trình LSTR MSG_LCD_SOFT_ENDSTOPS = _UxGT("Công tắc mềm"); // Soft Endstops LSTR MSG_MAIN_MENU = _UxGT("Chính"); // Main diff --git a/Marlin/src/lcd/language/language_zh_CN.h b/Marlin/src/lcd/language/language_zh_CN.h index 01f9f53d0c..ff095889af 100644 --- a/Marlin/src/lcd/language/language_zh_CN.h +++ b/Marlin/src/lcd/language/language_zh_CN.h @@ -41,14 +41,15 @@ namespace LanguageNarrow_zh_CN { LSTR MSG_LOW = _UxGT("低"); LSTR MSG_BACK = _UxGT("返回"); // ”Back“ LSTR MSG_ERROR = _UxGT("错误"); + LSTR MSG_MEDIA_ABORTING = _UxGT("存储卡中止..."); LSTR MSG_MEDIA_INSERTED = _UxGT("存储卡已插入"); // "Card inserted" LSTR MSG_MEDIA_REMOVED = _UxGT("存储卡被拔出"); // "Card removed" - LSTR MSG_MEDIA_WAITING = _UxGT("等待存储器"); LSTR MSG_MEDIA_READ_ERROR = _UxGT("卡读卡器错误"); - LSTR MSG_MEDIA_USB_REMOVED = _UxGT("USB设备已弹出"); - LSTR MSG_MEDIA_USB_FAILED = _UxGT("USB读取失败"); + LSTR MSG_USB_FD_DEVICE_REMOVED = _UxGT("USB设备已弹出"); + LSTR MSG_USB_FD_USB_FAILED = _UxGT("USB读取失败"); LSTR MSG_KILL_SUBCALL_OVERFLOW = _UxGT("子响应溢出"); + LSTR MSG_LCD_ENDSTOPS = _UxGT("挡块"); // "Endstops" // Max length 8 characters LSTR MSG_LCD_SOFT_ENDSTOPS = _UxGT("软挡块"); LSTR MSG_MAIN_MENU = _UxGT("主菜单"); // "Main" diff --git a/Marlin/src/lcd/language/language_zh_TW.h b/Marlin/src/lcd/language/language_zh_TW.h index 7321252de7..ecacf7e33d 100644 --- a/Marlin/src/lcd/language/language_zh_TW.h +++ b/Marlin/src/lcd/language/language_zh_TW.h @@ -37,13 +37,14 @@ namespace LanguageNarrow_zh_TW { LSTR MSG_YES = _UxGT("是"); // "YES" LSTR MSG_NO = _UxGT("否"); // "NO" LSTR MSG_BACK = _UxGT("返回"); // "Back" + LSTR MSG_MEDIA_ABORTING = _UxGT("正在中止..."); // "Aborting..." LSTR MSG_MEDIA_INSERTED = _UxGT("記憶卡已插入"); // "Card inserted" LSTR MSG_MEDIA_REMOVED = _UxGT("記憶卡被拔出"); // "Card removed" - LSTR MSG_MEDIA_WAITING = _UxGT("等待記憶卡"); // "Waiting for media" LSTR MSG_MEDIA_READ_ERROR = _UxGT("記憶卡讀取錯誤"); //"Media read error" - LSTR MSG_MEDIA_USB_REMOVED = _UxGT("USB裝置已移除"); // "USB device removed" - LSTR MSG_MEDIA_USB_FAILED = _UxGT("USB啟動失敗"); // "USB start failed" + LSTR MSG_USB_FD_DEVICE_REMOVED = _UxGT("USB裝置已移除"); // "USB device removed" + LSTR MSG_USB_FD_USB_FAILED = _UxGT("USB啟動失敗"); // "USB start failed" + LSTR MSG_LCD_ENDSTOPS = _UxGT("擋塊"); // "Endstops" // Max length 8 characters LSTR MSG_LCD_SOFT_ENDSTOPS = _UxGT("軟體擋塊"); // "Soft Endstops" LSTR MSG_MAIN_MENU = _UxGT("主選單"); // "Main" diff --git a/Marlin/src/lcd/marlinui.cpp b/Marlin/src/lcd/marlinui.cpp index ab932adfcd..9cfc6498a8 100644 --- a/Marlin/src/lcd/marlinui.cpp +++ b/Marlin/src/lcd/marlinui.cpp @@ -1957,7 +1957,7 @@ uint8_t expand_u8str_P(char * const outstr, PGM_P const ptpl, const int8_t ind, if ((old_status ^ status) & INSERT_SD) LCD_MESSAGE(MSG_MEDIA_REMOVED_SD); else if ((old_status ^ status) & INSERT_USB) - LCD_MESSAGE(MSG_MEDIA_REMOVED_USB); + LCD_MESSAGE(MSG_USB_FD_MEDIA_REMOVED); else LCD_MESSAGE(MSG_MEDIA_REMOVED); diff --git a/Marlin/src/sd/usb_flashdrive/Sd2Card_FlashDrive.cpp b/Marlin/src/sd/usb_flashdrive/Sd2Card_FlashDrive.cpp index 8b25df16b9..fde697c1f4 100644 --- a/Marlin/src/sd/usb_flashdrive/Sd2Card_FlashDrive.cpp +++ b/Marlin/src/sd/usb_flashdrive/Sd2Card_FlashDrive.cpp @@ -128,7 +128,7 @@ bool DiskIODriver_USBFlash::usbStartup() { SERIAL_ECHOPGM("Starting USB host..."); if (!UHS_START) { SERIAL_ECHOLNPGM(" failed."); - LCD_MESSAGE(MSG_MEDIA_USB_FAILED); + LCD_MESSAGE(MSG_USB_FD_USB_FAILED); return false; } @@ -223,8 +223,8 @@ void DiskIODriver_USBFlash::idle() { #endif #if USB_DEBUG >= 1 SERIAL_ECHOLNPGM("Waiting for media"); + LCD_MESSAGE(MSG_USB_FD_WAITING_FOR_MEDIA); #endif - LCD_MESSAGE(MSG_MEDIA_WAITING); GOTO_STATE_AFTER_DELAY(state, 2000); } break; @@ -237,9 +237,9 @@ void DiskIODriver_USBFlash::idle() { // Handle device removal events #if USB_DEBUG >= 1 SERIAL_ECHOLNPGM("USB device removed"); + if (state != MEDIA_READY) + LCD_MESSAGE(MSG_USB_FD_DEVICE_REMOVED); #endif - if (state != MEDIA_READY) - LCD_MESSAGE(MSG_MEDIA_USB_REMOVED); GOTO_STATE_AFTER_DELAY(WAIT_FOR_DEVICE, 0); } @@ -247,8 +247,8 @@ void DiskIODriver_USBFlash::idle() { // Handle media removal events #if USB_DEBUG >= 1 SERIAL_ECHOLNPGM("Media removed"); + LCD_MESSAGE(MSG_USB_FD_MEDIA_REMOVED); #endif - LCD_MESSAGE(MSG_MEDIA_REMOVED); GOTO_STATE_AFTER_DELAY(WAIT_FOR_DEVICE, 0); } From bc990ccca669e513be71050486f380161dfeee3c Mon Sep 17 00:00:00 2001 From: Giuliano <3684609+GMagician@users.noreply.github.com> Date: Mon, 26 May 2025 18:43:47 +0200 Subject: [PATCH 343/787] =?UTF-8?q?=F0=9F=8C=90=20Update=20Italian=20langu?= =?UTF-8?q?age=20(#27877)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/lcd/language/language_it.h | 103 +++++++++++++++++++++----- 1 file changed, 86 insertions(+), 17 deletions(-) diff --git a/Marlin/src/lcd/language/language_it.h b/Marlin/src/lcd/language/language_it.h index bdcd0b8ff6..dbf093c042 100644 --- a/Marlin/src/lcd/language/language_it.h +++ b/Marlin/src/lcd/language/language_it.h @@ -61,9 +61,15 @@ namespace LanguageNarrow_it { LSTR MSG_ERROR = _UxGT("Errore"); LSTR MSG_MEDIA_ABORTING = _UxGT("Annullando..."); - LSTR MSG_MEDIA_INSERTED = MEDIA_TYPE_IT _UxGT(" inserito"); - LSTR MSG_MEDIA_REMOVED = MEDIA_TYPE_IT _UxGT(" rimosso"); + LSTR MSG_MEDIA_INSERTED = MEDIA_TYPE_IT _UxGT(" inserita"); + LSTR MSG_MEDIA_INSERTED_SD = _UxGT("Scheda SD inserita"); + LSTR MSG_MEDIA_INSERTED_USB = _UxGT("Unità USB inserita"); + LSTR MSG_MEDIA_REMOVED = MEDIA_TYPE_IT _UxGT(" rimossa"); + LSTR MSG_MEDIA_REMOVED_SD = _UxGT("Scheda SD rimossa"); + LSTR MSG_MEDIA_REMOVED_USB = _UxGT("Unità USB rimossa"); LSTR MSG_MEDIA_INIT_FAIL = _UxGT("Iniz.") MEDIA_TYPE_IT _UxGT(" fallita"); + LSTR MSG_MEDIA_INIT_FAIL_SD = _UxGT("Iniz. SD fallita"); + LSTR MSG_MEDIA_INIT_FAIL_USB = _UxGT("Iniz. USB fallita"); LSTR MSG_MEDIA_READ_ERROR = _UxGT("Err.leggendo ") MEDIA_TYPE_IT; LSTR MSG_MEDIA_SORT = _UxGT("Ordina ") MEDIA_TYPE_IT; LSTR MSG_MEDIA_UPDATE = _UxGT("Aggiorna ") MEDIA_TYPE_IT; @@ -136,11 +142,12 @@ namespace LanguageNarrow_it { LSTR MSG_PREHEAT_M = _UxGT("Preriscalda $"); LSTR MSG_PREHEAT_M_H = _UxGT("Preriscalda $ ~"); - LSTR MSG_PREHEAT_M_END = _UxGT("Preris.$ ugello"); - LSTR MSG_PREHEAT_M_END_E = _UxGT("Preris.$ ugello ~"); - LSTR MSG_PREHEAT_M_ALL = _UxGT("Preris.$ tutto"); - LSTR MSG_PREHEAT_M_BEDONLY = _UxGT("Preris.$ piatto"); - LSTR MSG_PREHEAT_M_SETTINGS = _UxGT("Preris.$ conf"); + LSTR MSG_PREHEAT_M_END = _UxGT("Preris.ugello $"); + LSTR MSG_PREHEAT_M_END_E = _UxGT("Preris.ugello ~ $"); + LSTR MSG_PREHEAT_M_ALL = _UxGT("Preris.tutto $"); + LSTR MSG_PREHEAT_M_BEDONLY = _UxGT("Preris.piatto $"); + LSTR MSG_PREHEAT_M_CHAMBER = _UxGT("Preris.camera $"); + LSTR MSG_PREHEAT_M_SETTINGS = _UxGT("Preris.conf $"); LSTR MSG_PREHEAT_HOTEND = _UxGT("Prerisc.ugello"); LSTR MSG_PREHEAT_CUSTOM = _UxGT("Prerisc.personal."); @@ -164,6 +171,7 @@ namespace LanguageNarrow_it { LSTR MSG_SPINDLE_REVERSE = _UxGT("Inverti mandrino"); LSTR MSG_SWITCH_PS_ON = _UxGT("Accendi aliment."); LSTR MSG_SWITCH_PS_OFF = _UxGT("Spegni aliment."); + LSTR MSG_POWER_EDM_FAULT = _UxGT("Anomalia alim.EDM"); LSTR MSG_EXTRUDE = _UxGT("Estrudi"); LSTR MSG_RETRACT = _UxGT("Ritrai"); LSTR MSG_MOVE_AXIS = _UxGT("Muovi asse"); @@ -181,6 +189,7 @@ namespace LanguageNarrow_it { LSTR MSG_MESH_VIEWER = _UxGT("Visualiz. mesh"); LSTR MSG_EDIT_MESH = _UxGT("Modifica mesh"); LSTR MSG_MESH_VIEW = _UxGT("Visualizza mesh"); + LSTR MSG_MESH_VIEW_GRID = _UxGT("Vis.mesh (griglia)"); LSTR MSG_EDITING_STOPPED = _UxGT("Modif. mesh fermata"); LSTR MSG_NO_VALID_MESH = _UxGT("Mesh non valida"); LSTR MSG_ACTIVATE_MESH = _UxGT("Attiva livellamento"); @@ -204,7 +213,9 @@ namespace LanguageNarrow_it { LSTR MSG_M48_TEST = _UxGT("Test sonda M48"); LSTR MSG_M48_POINT = _UxGT("Punto M48"); LSTR MSG_M48_OUT_OF_BOUNDS = _UxGT("Sonda oltre i limiti"); + LSTR MSG_M48_DEV = _UxGT("Dev"); LSTR MSG_M48_DEVIATION = _UxGT("Deviazione"); + LSTR MSG_M48_MAX_DELTA = _UxGT("Delta max"); LSTR MSG_IDEX_MENU = _UxGT("Modo IDEX"); LSTR MSG_OFFSETS_MENU = _UxGT("Strumenti offsets"); LSTR MSG_IDEX_MODE_AUTOPARK = _UxGT("Auto-Park"); @@ -431,6 +442,7 @@ namespace LanguageNarrow_it { LSTR MSG_AMAX_EN = _UxGT("Acc.massima *"); LSTR MSG_A_RETRACT = _UxGT("A-Ritrazione"); LSTR MSG_A_TRAVEL = _UxGT("A-Spostamento"); + LSTR MSG_A_SPINDLE = _UxGT("Acc.mandrino"); LSTR MSG_INPUT_SHAPING = _UxGT("Input shaping"); LSTR MSG_SHAPING_ENABLE_N = _UxGT("Abilita shaping @"); LSTR MSG_SHAPING_DISABLE_N = _UxGT("Disabil. shaping @"); @@ -469,8 +481,10 @@ namespace LanguageNarrow_it { LSTR MSG_DRAW_MAX_Y = _UxGT("Max Y area disegno"); LSTR MSG_MAX_BELT_LEN = _UxGT("Lungh.max cinghia"); LSTR MSG_LINEAR_ADVANCE = _UxGT("Avanzam.lineare"); - LSTR MSG_ADVANCE_K = _UxGT("K Avanzamento"); - LSTR MSG_ADVANCE_K_E = _UxGT("K Avanzamento *"); + LSTR MSG_ADVANCE_K = _UxGT("K advance"); + LSTR MSG_ADVANCE_TAU = _UxGT("Tau advance"); + LSTR MSG_ADVANCE_K_E = _UxGT("K advance *"); + LSTR MSG_ADVANCE_TAU_E = _UxGT("Tau advance *"); LSTR MSG_CONTRAST = _UxGT("Contrasto LCD"); LSTR MSG_BRIGHTNESS = _UxGT("Luminosità LCD"); LSTR MSG_SCREEN_TIMEOUT = _UxGT("Timeout LCD (m)"); @@ -535,10 +549,8 @@ namespace LanguageNarrow_it { LSTR MSG_CANCEL_OBJECT = _UxGT("Cancella oggetto"); LSTR MSG_CANCEL_OBJECT_N = _UxGT("Canc. oggetto {"); LSTR MSG_CONTINUE_PRINT_JOB = _UxGT("Cont.proc.stampa"); - LSTR MSG_MEDIA_MENU = _UxGT("Stampa da ") MEDIA_TYPE_IT; LSTR MSG_TURN_OFF = _UxGT("Spegni stampante"); LSTR MSG_END_LOOPS = _UxGT("Fine cicli di rip."); - LSTR MSG_NO_MEDIA = MEDIA_TYPE_IT _UxGT(" non presente"); LSTR MSG_DWELL = _UxGT("Sospensione..."); LSTR MSG_USERWAIT = _UxGT("Premi tasto.."); LSTR MSG_PRINT_PAUSED = _UxGT("Stampa sospesa"); @@ -592,10 +604,20 @@ namespace LanguageNarrow_it { LSTR MSG_ATTACH_MEDIA = _UxGT("Collega ") MEDIA_TYPE_IT; LSTR MSG_ATTACH_SD = _UxGT("Collega scheda SD"); - LSTR MSG_ATTACH_USB = _UxGT("Collega penna USB"); - LSTR MSG_CHANGE_MEDIA = _UxGT("Cambia ") MEDIA_TYPE_IT; + LSTR MSG_ATTACH_USB = _UxGT("Collega unità USB"); LSTR MSG_RELEASE_MEDIA = _UxGT("Rilascia ") MEDIA_TYPE_IT; - LSTR MSG_RUN_AUTOFILES = _UxGT("Esegui files auto"); + LSTR MSG_RELEASE_SD = _UxGT("Rilascia sceda SD"); + LSTR MSG_RELEASE_USB = _UxGT("Rilascia unità USB"); + LSTR MSG_CHANGE_MEDIA = _UxGT("Selez.") MEDIA_TYPE_IT; + LSTR MSG_CHANGE_SD = _UxGT("Selez. scheda SD"); + LSTR MSG_CHANGE_USB = _UxGT("Selez. unità USB"); + LSTR MSG_RUN_AUTOFILES = _UxGT("Esegui Autofiles"); + LSTR MSG_RUN_AUTOFILES_SD = _UxGT("Esegui Autofiles SD"); + LSTR MSG_RUN_AUTOFILES_USB = _UxGT("Esegui Autofiles USB"); + LSTR MSG_MEDIA_MENU = _UxGT("Stampa da ") MEDIA_TYPE_IT; + LSTR MSG_MEDIA_MENU_SD = _UxGT("Selez. da SD"); + LSTR MSG_MEDIA_MENU_USB = _UxGT("Selez. da USB"); + LSTR MSG_NO_MEDIA = MEDIA_TYPE_IT _UxGT(" non rilevato"); LSTR MSG_ZPROBE_OUT = _UxGT("Z probe fuori piatto"); LSTR MSG_SKEW_FACTOR = _UxGT("Fattore distorsione"); @@ -862,6 +884,7 @@ namespace LanguageNarrow_it { LSTR MSG_TMC_HOMING_THRS = _UxGT("Sensorless homing"); LSTR MSG_TMC_STEPPING_MODE = _UxGT("Modo Stepping"); LSTR MSG_TMC_STEALTHCHOP = _UxGT("StealthChop"); + LSTR MSG_TMC_HOMING_CURRENT = _UxGT("Corrente homing"); LSTR MSG_SERVICE_RESET = _UxGT("Resetta"); LSTR MSG_SERVICE_IN = _UxGT(" tra:"); @@ -901,6 +924,7 @@ namespace LanguageNarrow_it { LSTR MSG_BOTTOM_LEFT = _UxGT("Basso sinistra"); LSTR MSG_TOP_RIGHT = _UxGT("Alto destra"); LSTR MSG_BOTTOM_RIGHT = _UxGT("Basso destra"); + LSTR MSG_TOUCH_CALIBRATION = _UxGT("Calibrazione touch"); LSTR MSG_CALIBRATION_COMPLETED = _UxGT("Calibrazione completata"); LSTR MSG_CALIBRATION_FAILED = _UxGT("Calibrazione fallita"); @@ -911,7 +935,7 @@ namespace LanguageNarrow_it { LSTR MSG_HOST_SHUTDOWN = _UxGT("Arresta host"); -// DGUS-Specific message strings, not used elsewhere + // DGUS-Specific message strings, not used elsewhere LSTR DGUS_MSG_NOT_WHILE_PRINTING = _UxGT("Non ammesso durante la stampa"); LSTR DGUS_MSG_NOT_WHILE_IDLE = _UxGT("Non ammesso mentre è in riposo"); LSTR DGUS_MSG_NO_FILE_SELECTED = _UxGT("Nessun file selezionato"); @@ -943,17 +967,56 @@ namespace LanguageNarrow_it { LSTR MSG_BTN_STOP = _UxGT("Stop"); LSTR MSG_BTN_DISABLE_MMU = _UxGT("Disabilita"); LSTR MSG_BTN_MORE = _UxGT("Più info"); + + // Prusa MMU + LSTR MSG_DONE = _UxGT("Eseguito"); + LSTR MSG_FINISHING_MOVEMENTS = _UxGT("Termina movimenti"); + LSTR MSG_LOADING_FILAMENT = _UxGT("Carica. filamento"); + LSTR MSG_UNLOADING_FILAMENT = _UxGT("Scarico filamento"); + LSTR MSG_TESTING_FILAMENT = _UxGT("Testando filamento"); + LSTR MSG_EJECT_FROM_MMU = _UxGT("Espelli da MMU"); + LSTR MSG_CUT_FILAMENT = _UxGT("Taglia filamento"); + LSTR MSG_OFF = _UxGT("Off"); + LSTR MSG_ON = _UxGT("On"); + LSTR MSG_PROGRESS_OK = _UxGT("OK"); + LSTR MSG_PROGRESS_ENGAGE_IDLER = _UxGT("Innesto idler"); + LSTR MSG_PROGRESS_DISENGAGE_IDLER = _UxGT("Disinnesto idler"); + LSTR MSG_PROGRESS_UNLOAD_FINDA = _UxGT("Scarico a FINDA"); + LSTR MSG_PROGRESS_UNLOAD_PULLEY = _UxGT("Scarico a puleggia"); + LSTR MSG_PROGRESS_FEED_FINDA = _UxGT("Alim. a FINDA"); + LSTR MSG_PROGRESS_FEED_EXTRUDER = _UxGT("Alim. all'estrusore"); + LSTR MSG_PROGRESS_FEED_NOZZLE = _UxGT("Alim. all'ugello"); + LSTR MSG_PROGRESS_AVOID_GRIND = _UxGT("Evita grind"); + LSTR MSG_PROGRESS_WAIT_USER = _UxGT("ERR attesa utente"); + LSTR MSG_PROGRESS_ERR_INTERNAL = _UxGT("ERR interno"); + LSTR MSG_PROGRESS_ERR_HELP_FIL = _UxGT("ERR aiuto filamento"); + LSTR MSG_PROGRESS_ERR_TMC = _UxGT("ERR anomalia TMC"); + LSTR MSG_PROGRESS_SELECT_SLOT = _UxGT("Selez.slot filam."); + LSTR MSG_PROGRESS_PREPARE_BLADE = _UxGT("Preparaz.lama"); + LSTR MSG_PROGRESS_PUSH_FILAMENT = _UxGT("Spinta fialmento"); + LSTR MSG_PROGRESS_PERFORM_CUT = _UxGT("Esecuzione taglio"); + LSTR MSG_PROGRESSPSTRETURN_SELECTOR = _UxGT("Ritorno selettore"); + LSTR MSG_PROGRESS_PARK_SELECTOR = _UxGT("Parcheggio selettore"); + LSTR MSG_PROGRESS_EJECT_FILAMENT = _UxGT("Esplusione filamento"); + LSTR MSG_PROGRESSPSTRETRACT_FINDA = _UxGT("Ritrai a FINDA"); + LSTR MSG_PROGRESS_HOMING = _UxGT("Homing"); + LSTR MSG_PROGRESS_MOVING_SELECTOR = _UxGT("Movim. selettore"); + LSTR MSG_PROGRESS_FEED_FSENSOR = _UxGT("Alim. a FSensor"); } namespace LanguageWide_it { using namespace LanguageNarrow_it; #if LCD_WIDTH >= 20 || HAS_DWIN_E3V2 + LSTR MSG_LIVE_MOVE = _UxGT("Movimento live"); LSTR MSG_HOST_START_PRINT = _UxGT("Avvio stampa host"); LSTR MSG_PRINTING_OBJECT = _UxGT("Stampa oggetto"); LSTR MSG_CANCEL_OBJECT = _UxGT("Cancella oggetto"); LSTR MSG_CANCEL_OBJECT_N = _UxGT("Cancella oggetto {"); LSTR MSG_CONTINUE_PRINT_JOB = _UxGT("Continua il job di stampa"); - LSTR MSG_MEDIA_MENU = _UxGT("Selez.da supporto"); + LSTR MSG_MEDIA_MENU = _UxGT("Seleziona da ") MEDIA_TYPE_IT; + LSTR MSG_MEDIA_MENU_SD = _UxGT("Seleziona da scheda SD"); + LSTR MSG_MEDIA_MENU_USB = _UxGT("Seleziona da unità USB"); + LSTR MSG_NO_MEDIA = MEDIA_TYPE_EN _UxGT(" non trovato"); LSTR MSG_TURN_OFF = _UxGT("Spegni la stampante"); LSTR MSG_END_LOOPS = _UxGT("Termina i cicli di ripetizione"); LSTR MSG_MEDIA_NOT_INSERTED = _UxGT("Nessun supporto inserito."); // ProUI @@ -963,7 +1026,13 @@ namespace LanguageWide_it { LSTR MSG_INFO_PRINT_TIME = _UxGT("Tempo totale"); LSTR MSG_INFO_PRINT_LONGEST = _UxGT("Lavoro più lungo"); LSTR MSG_INFO_PRINT_FILAMENT = _UxGT("Totale estruso"); - LSTR MSG_TEMP_TOO_LOW = _UxGT("Temperatura troppo bassa"); + LSTR MSG_HOMING_FEEDRATE_N = _UxGT("Velocità @ di homing"); + LSTR MSG_HOMING_FEEDRATE_X = _UxGT("Velocità X di homing"); + LSTR MSG_HOMING_FEEDRATE_Y = _UxGT("Velocità Y di homing"); + LSTR MSG_HOMING_FEEDRATE_Z = _UxGT("Velocità Z di homing"); + LSTR MSG_EEPROM_INITIALIZED = _UxGT("Ripristinate impostazioni predefinite"); + LSTR MSG_PREHEAT_M_CHAMBER = _UxGT("Preriscalda camera per $"); + LSTR MSG_PREHEAT_M_SETTINGS = _UxGT("Configurazioni preriscaldo $"); #endif } From af7b126edc3d6fbbbf26b1221f0c2cb5b7a82160 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Mon, 26 May 2025 18:09:01 +0000 Subject: [PATCH 344/787] [cron] Bump distribution date (2025-05-26) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 82979634d4..b46b688339 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-05-25" +//#define STRING_DISTRIBUTION_DATE "2025-05-26" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 7c80ca1f17..06c29974a7 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-05-25" + #define STRING_DISTRIBUTION_DATE "2025-05-26" #endif /** From 0916d325898cba1314e9502690f908547d34fbd6 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Mon, 26 May 2025 14:33:40 -0500 Subject: [PATCH 345/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Ser?= =?UTF-8?q?ial=20ON=5FOFF,=20TRUE=5FFALSE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/core/serial.cpp | 4 --- Marlin/src/core/serial.h | 6 ++-- Marlin/src/feature/meatpack.cpp | 8 +++-- Marlin/src/feature/tmc_util.cpp | 32 ++++++++++--------- Marlin/src/gcode/bedlevel/M420.cpp | 9 ++---- Marlin/src/gcode/bedlevel/mbl/G29.cpp | 2 +- Marlin/src/gcode/control/M211.cpp | 3 +- Marlin/src/gcode/control/M605.cpp | 3 +- Marlin/src/gcode/feature/mixing/M166.cpp | 3 +- Marlin/src/gcode/feature/powerloss/M413.cpp | 5 ++- .../gcode/feature/prusa_MMU2/M704-M709.cpp | 9 +++--- Marlin/src/gcode/feature/runout/M412.cpp | 11 +++---- .../src/gcode/feature/trinamic/M911-M914.cpp | 4 +-- Marlin/src/gcode/probe/M401_M402.cpp | 4 +-- Marlin/src/gcode/temp/M303.cpp | 4 +-- 15 files changed, 45 insertions(+), 62 deletions(-) diff --git a/Marlin/src/core/serial.cpp b/Marlin/src/core/serial.cpp index 8a8378330f..3ddfa6d345 100644 --- a/Marlin/src/core/serial.cpp +++ b/Marlin/src/core/serial.cpp @@ -114,10 +114,6 @@ void serial_ternary(FSTR_P const pre, const bool onoff, FSTR_P const on, FSTR_P if (post) SERIAL_ECHO(post); } -void serialprint_onoff(const bool onoff) { SERIAL_ECHO(onoff ? F(STR_ON) : F(STR_OFF)); } -void serialprintln_onoff(const bool onoff) { serialprint_onoff(onoff); SERIAL_EOL(); } -void serialprint_truefalse(const bool tf) { SERIAL_ECHO(tf ? F("true") : F("false")); } - void print_bin(uint16_t val) { for (uint8_t i = 16; i--;) { SERIAL_CHAR('0' + TEST(val, i)); diff --git a/Marlin/src/core/serial.h b/Marlin/src/core/serial.h index 97f31dea35..8ec8b8db2a 100644 --- a/Marlin/src/core/serial.h +++ b/Marlin/src/core/serial.h @@ -233,9 +233,9 @@ void serial_ternary(FSTR_P const pre, const bool onoff, FSTR_P const on, FSTR_P // Print up to 255 spaces void SERIAL_ECHO_SP(uint8_t count); -void serialprint_onoff(const bool onoff); -void serialprintln_onoff(const bool onoff); -void serialprint_truefalse(const bool tf); +inline FSTR_P const ON_OFF(const bool onoff) { return onoff ? F("ON") : F("OFF"); } +inline FSTR_P const TRUE_FALSE(const bool tf) { return tf ? F("true") : F("false"); } + void serial_offset(const_float_t v, const uint8_t sp=0); // For v==0 draw space (sp==1) or plus (sp==2) void print_bin(const uint16_t val); diff --git a/Marlin/src/feature/meatpack.cpp b/Marlin/src/feature/meatpack.cpp index fe3dabe8da..3b762d4ded 100644 --- a/Marlin/src/feature/meatpack.cpp +++ b/Marlin/src/feature/meatpack.cpp @@ -169,9 +169,11 @@ void MeatPack::handle_command(const MeatPack_Command c) { void MeatPack::report_state() { // NOTE: if any configuration vars are added below, the outgoing sync text for host plugin // should not contain the "PV' substring, as this is used to indicate protocol version - SERIAL_ECHOPGM("[MP] " MeatPack_ProtocolVersion " "); - serialprint_onoff(TEST(state, MPConfig_Bit_Active)); - SERIAL_ECHO(TEST(state, MPConfig_Bit_NoSpaces) ? F(" NSP\n") : F(" ESP\n")); + SERIAL_ECHO( + F("[MP] " MeatPack_ProtocolVersion " "), + ON_OFF(TEST(state, MPConfig_Bit_Active)), + TEST(state, MPConfig_Bit_NoSpaces) ? F(" NSP\n") : F(" ESP\n") + ); } /** diff --git a/Marlin/src/feature/tmc_util.cpp b/Marlin/src/feature/tmc_util.cpp index fb17e562ad..d280b55854 100644 --- a/Marlin/src/feature/tmc_util.cpp +++ b/Marlin/src/feature/tmc_util.cpp @@ -595,13 +595,15 @@ void print_cs_actual(TMCMarlin &) { } #endif + static void print_true_or_false(const bool tf) { SERIAL_ECHO(TRUE_FALSE(tf)); } + #if HAS_DRIVER(TMC2130) || HAS_DRIVER(TMC5130) static void _tmc_status(TMC2130Stepper &st, const TMC_debug_enum i) { switch (i) { case TMC_PWM_SCALE: SERIAL_ECHO(st.PWM_SCALE()); break; case TMC_SGT: SERIAL_ECHO(st.sgt()); break; - case TMC_STEALTHCHOP: serialprint_truefalse(st.en_pwm_mode()); break; - case TMC_INTERPOLATE: serialprint_truefalse(st.intpol()); break; + case TMC_STEALTHCHOP: print_true_or_false(st.en_pwm_mode()); break; + case TMC_INTERPOLATE: print_true_or_false(st.intpol()); break; default: break; } } @@ -623,7 +625,7 @@ switch (i) { case TMC_PWM_SCALE: SERIAL_ECHO(st.PWM_SCALE()); break; case TMC_SGT: SERIAL_ECHO(st.sgt()); break; - case TMC_STEALTHCHOP: serialprint_truefalse(st.en_pwm_mode()); break; + case TMC_STEALTHCHOP: print_true_or_false(st.en_pwm_mode()); break; case TMC_GLOBAL_SCALER: { const uint16_t value = st.GLOBAL_SCALER(); @@ -631,7 +633,7 @@ SERIAL_ECHOPGM("/256"); } break; - case TMC_INTERPOLATE: serialprint_truefalse(st.intpol()); break; + case TMC_INTERPOLATE: print_true_or_false(st.intpol()); break; default: break; } } @@ -645,8 +647,8 @@ case TMC_PWM_SCALE_AUTO: SERIAL_ECHO(st.pwm_scale_auto()); break; case TMC_PWM_OFS_AUTO: SERIAL_ECHO(st.pwm_ofs_auto()); break; case TMC_PWM_GRAD_AUTO: SERIAL_ECHO(st.pwm_grad_auto()); break; - case TMC_STEALTHCHOP: serialprint_truefalse(st.stealth()); break; - case TMC_INTERPOLATE: serialprint_truefalse(st.intpol()); break; + case TMC_STEALTHCHOP: print_true_or_false(st.stealth()); break; + case TMC_INTERPOLATE: print_true_or_false(st.intpol()); break; default: break; } } @@ -697,8 +699,8 @@ case TMC_PWM_SCALE_AUTO: SERIAL_ECHO(st.pwm_scale_auto()); break; case TMC_PWM_OFS_AUTO: SERIAL_ECHO(st.pwm_ofs_auto()); break; case TMC_PWM_GRAD_AUTO: SERIAL_ECHO(st.pwm_grad_auto()); break; - case TMC_STEALTHCHOP: serialprint_truefalse(st.stealth()); break; - case TMC_INTERPOLATE: serialprint_truefalse(st.intpol()); break; + case TMC_STEALTHCHOP: print_true_or_false(st.stealth()); break; + case TMC_INTERPOLATE: print_true_or_false(st.intpol()); break; default: break; } } @@ -708,7 +710,7 @@ static void _tmc_parse_drv_status(TMC2660Stepper, const TMC_drv_status_enum) { } static void _tmc_status(TMC2660Stepper &st, const TMC_debug_enum i) { switch (i) { - case TMC_INTERPOLATE: serialprint_truefalse(st.intpol()); break; + case TMC_INTERPOLATE: print_true_or_false(st.intpol()); break; default: break; } } @@ -734,7 +736,7 @@ SERIAL_CHAR('\t'); switch (i) { case TMC_CODES: st.printLabel(); break; - case TMC_ENABLED: serialprint_truefalse(st.isEnabled()); break; + case TMC_ENABLED: print_true_or_false(st.isEnabled()); break; case TMC_CURRENT: SERIAL_ECHO(st.getMilliamps()); break; case TMC_RMS_CURRENT: SERIAL_ECHO(st.rms_current()); break; case TMC_MAX_CURRENT: SERIAL_ECHO(p_float_t(st.rms_current() * 1.41, 0)); break; @@ -757,9 +759,9 @@ if (tpwmthrs_val) SERIAL_ECHO(tpwmthrs_val); else SERIAL_CHAR('-'); } break; #endif - case TMC_OTPW: serialprint_truefalse(st.otpw()); break; + case TMC_OTPW: print_true_or_false(st.otpw()); break; #if ENABLED(MONITOR_DRIVER_STATUS) - case TMC_OTPW_TRIGGERED: serialprint_truefalse(st.getOTPW()); break; + case TMC_OTPW_TRIGGERED: print_true_or_false(st.getOTPW()); break; #endif case TMC_TOFF: SERIAL_ECHO(st.toff()); break; case TMC_TBL: print_blank_time(st); break; @@ -776,7 +778,7 @@ SERIAL_CHAR('\t'); switch (i) { case TMC_CODES: st.printLabel(); break; - case TMC_ENABLED: serialprint_truefalse(st.isEnabled()); break; + case TMC_ENABLED: print_true_or_false(st.isEnabled()); break; case TMC_CURRENT: SERIAL_ECHO(st.getMilliamps()); break; case TMC_RMS_CURRENT: SERIAL_ECHO(st.rms_current()); break; case TMC_MAX_CURRENT: SERIAL_ECHO(p_float_t(st.rms_current() * 1.41, 0)); break; @@ -786,8 +788,8 @@ break; case TMC_VSENSE: SERIAL_ECHO(st.vsense() ? F("1=.165") : F("0=.310")); break; case TMC_MICROSTEPS: SERIAL_ECHO(st.microsteps()); break; - //case TMC_OTPW: serialprint_truefalse(st.otpw()); break; - //case TMC_OTPW_TRIGGERED: serialprint_truefalse(st.getOTPW()); break; + //case TMC_OTPW: print_true_or_false(st.otpw()); break; + //case TMC_OTPW_TRIGGERED: print_true_or_false(st.getOTPW()); break; case TMC_SGT: SERIAL_ECHO(st.sgt()); break; case TMC_TOFF: SERIAL_ECHO(st.toff()); break; case TMC_TBL: print_blank_time(st); break; diff --git a/Marlin/src/gcode/bedlevel/M420.cpp b/Marlin/src/gcode/bedlevel/M420.cpp index 8711bab9c8..7903cc623c 100644 --- a/Marlin/src/gcode/bedlevel/M420.cpp +++ b/Marlin/src/gcode/bedlevel/M420.cpp @@ -228,9 +228,7 @@ void GcodeSuite::M420() { if (to_enable && !planner.leveling_active) SERIAL_ERROR_MSG(STR_ERR_M420_FAILED); - SERIAL_ECHO_START(); - SERIAL_ECHOPGM("Bed Leveling "); - serialprintln_onoff(planner.leveling_active); + SERIAL_ECHO_MSG("Bed Leveling ", ON_OFF(planner.leveling_active)); #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT) SERIAL_ECHO_START(); @@ -252,14 +250,13 @@ void GcodeSuite::M420_report(const bool forReplay/*=true*/) { report_heading_etc(forReplay, F( TERN(MESH_BED_LEVELING, "Mesh Bed Leveling", TERN(AUTO_BED_LEVELING_UBL, "Unified Bed Leveling", "Auto Bed Leveling")) )); - SERIAL_ECHO( + SERIAL_ECHOLN( F(" M420 S"), planner.leveling_active #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT) , FPSTR(SP_Z_STR), LINEAR_UNIT(planner.z_fade_height) #endif - , F(" ; Leveling ") + , F(" ; Leveling "), ON_OFF(planner.leveling_active) ); - serialprintln_onoff(planner.leveling_active); } #endif // HAS_LEVELING diff --git a/Marlin/src/gcode/bedlevel/mbl/G29.cpp b/Marlin/src/gcode/bedlevel/mbl/G29.cpp index be0e5d7f18..4bd444c5a3 100644 --- a/Marlin/src/gcode/bedlevel/mbl/G29.cpp +++ b/Marlin/src/gcode/bedlevel/mbl/G29.cpp @@ -99,7 +99,7 @@ void GcodeSuite::G29() { case MeshReport: SERIAL_ECHOPGM("Mesh Bed Leveling "); if (leveling_is_valid()) { - serialprintln_onoff(planner.leveling_active); + SERIAL_ECHOLN(ON_OFF(planner.leveling_active)); bedlevel.report_mesh(); } else diff --git a/Marlin/src/gcode/control/M211.cpp b/Marlin/src/gcode/control/M211.cpp index 471ca6c448..e51a9d5297 100644 --- a/Marlin/src/gcode/control/M211.cpp +++ b/Marlin/src/gcode/control/M211.cpp @@ -43,8 +43,7 @@ void GcodeSuite::M211_report(const bool forReplay/*=true*/) { TERN_(MARLIN_SMALL_BUILD, return); report_heading_etc(forReplay, F(STR_SOFT_ENDSTOPS)); - SERIAL_ECHOPGM(" M211 S", AS_DIGIT(soft_endstop._enabled), " ; "); - serialprintln_onoff(soft_endstop._enabled); + SERIAL_ECHOLNPGM(" M211 S", AS_DIGIT(soft_endstop._enabled), " ; ", ON_OFF(soft_endstop._enabled)); report_echo_start(forReplay); const xyz_pos_t l_soft_min = soft_endstop.min.asLogical(), diff --git a/Marlin/src/gcode/control/M605.cpp b/Marlin/src/gcode/control/M605.cpp index 56d7594b08..4679422dfb 100644 --- a/Marlin/src/gcode/control/M605.cpp +++ b/Marlin/src/gcode/control/M605.cpp @@ -173,8 +173,7 @@ set_duplication_enabled(ena && (duplication_e_mask >= 3)); } SERIAL_ECHO_START(); - SERIAL_ECHOPGM(STR_DUPLICATION_MODE); - serialprint_onoff(extruder_duplication_enabled); + SERIAL_ECHOPGM(STR_DUPLICATION_MODE, ON_OFF(extruder_duplication_enabled)); if (ena) { SERIAL_ECHOPGM(" ( "); HOTEND_LOOP() if (TEST(duplication_e_mask, e)) { SERIAL_ECHO(e); SERIAL_CHAR(' '); } diff --git a/Marlin/src/gcode/feature/mixing/M166.cpp b/Marlin/src/gcode/feature/mixing/M166.cpp index f42583d052..29411f2122 100644 --- a/Marlin/src/gcode/feature/mixing/M166.cpp +++ b/Marlin/src/gcode/feature/mixing/M166.cpp @@ -68,8 +68,7 @@ void GcodeSuite::M166() { mixer.refresh_gradient(); - SERIAL_ECHOPGM("Gradient Mix "); - serialprint_onoff(mixer.gradient.enabled); + SERIAL_ECHOPGM("Gradient Mix ", ON_OFF(mixer.gradient.enabled)); if (mixer.gradient.enabled) { #if ENABLED(GRADIENT_VTOOL) diff --git a/Marlin/src/gcode/feature/powerloss/M413.cpp b/Marlin/src/gcode/feature/powerloss/M413.cpp index b12257b4e5..7f0e2e2b9a 100644 --- a/Marlin/src/gcode/feature/powerloss/M413.cpp +++ b/Marlin/src/gcode/feature/powerloss/M413.cpp @@ -67,13 +67,12 @@ void GcodeSuite::M413_report(const bool forReplay/*=true*/) { TERN_(MARLIN_SMALL_BUILD, return); report_heading_etc(forReplay, F(STR_POWER_LOSS_RECOVERY)); - SERIAL_ECHOPGM(" M413 S", AS_DIGIT(recovery.enabled) + SERIAL_ECHOLNPGM(" M413 S", AS_DIGIT(recovery.enabled) #if HAS_PLR_BED_THRESHOLD , " B", recovery.bed_temp_threshold #endif + , " ; ", ON_OFF(recovery.enabled) ); - SERIAL_ECHO(" ; "); - serialprintln_onoff(recovery.enabled); } #endif // POWER_LOSS_RECOVERY diff --git a/Marlin/src/gcode/feature/prusa_MMU2/M704-M709.cpp b/Marlin/src/gcode/feature/prusa_MMU2/M704-M709.cpp index f6af70b8dd..19aea31ff1 100644 --- a/Marlin/src/gcode/feature/prusa_MMU2/M704-M709.cpp +++ b/Marlin/src/gcode/feature/prusa_MMU2/M704-M709.cpp @@ -185,13 +185,12 @@ void GcodeSuite::M709() { void GcodeSuite::MMU3_report(const bool forReplay/*=true*/) { using namespace MMU3; report_heading(forReplay, F("MMU3 Operational Stats")); - SERIAL_ECHOPGM(" MMU "); serialprintln_onoff(mmu3.mmu_hw_enabled); - SERIAL_ECHOPGM(" Stealth Mode "); serialprintln_onoff(mmu3.stealth_mode); + SERIAL_ECHOLNPGM(" MMU ", ON_OFF(mmu3.mmu_hw_enabled)); + SERIAL_ECHOLNPGM(" Stealth Mode ", ON_OFF(mmu3.stealth_mode)); #if ENABLED(MMU3_HAS_CUTTER) - SERIAL_ECHOPGM(" Cutter "); - serialprintln_onoff(mmu3.cutter_mode != 0); + SERIAL_ECHOLNPGM(" Cutter ", ON_OFF(mmu3.cutter_mode != 0)); #endif - SERIAL_ECHOPGM(" SpoolJoin "); serialprintln_onoff(spooljoin.enabled); + SERIAL_ECHOLNPGM(" SpoolJoin ", ON_OFF(spooljoin.enabled)); SERIAL_ECHOLNPGM(" Tool Changes ", operation_statistics.tool_change_counter); SERIAL_ECHOLNPGM(" Total Tool Changes ", operation_statistics.tool_change_total_counter); SERIAL_ECHOLNPGM(" Fails ", operation_statistics.fail_num); diff --git a/Marlin/src/gcode/feature/runout/M412.cpp b/Marlin/src/gcode/feature/runout/M412.cpp index 4cfb238309..1b8936e6bd 100644 --- a/Marlin/src/gcode/feature/runout/M412.cpp +++ b/Marlin/src/gcode/feature/runout/M412.cpp @@ -53,14 +53,12 @@ void GcodeSuite::M412() { } else { SERIAL_ECHO_START(); - SERIAL_ECHOPGM("Filament runout "); - serialprint_onoff(runout.enabled); + SERIAL_ECHOPGM("Filament runout ", ON_OFF(runout.enabled)); #if HAS_FILAMENT_RUNOUT_DISTANCE SERIAL_ECHOPGM(" ; Distance ", runout.runout_distance(), "mm"); #endif #if ENABLED(HOST_ACTION_COMMANDS) - SERIAL_ECHOPGM(" ; Host handling "); - serialprint_onoff(runout.host_handling); + SERIAL_ECHOPGM(" ; Host handling ", ON_OFF(runout.host_handling)); #endif SERIAL_EOL(); } @@ -70,14 +68,13 @@ void GcodeSuite::M412_report(const bool forReplay/*=true*/) { TERN_(MARLIN_SMALL_BUILD, return); report_heading_etc(forReplay, F(STR_FILAMENT_RUNOUT_SENSOR)); - SERIAL_ECHOPGM( + SERIAL_ECHOLNPGM( " M412 S", runout.enabled #if HAS_FILAMENT_RUNOUT_DISTANCE , " D", LINEAR_UNIT(runout.runout_distance()) #endif - , " ; Sensor " + , " ; Sensor ", ON_OFF(runout.enabled) ); - serialprintln_onoff(runout.enabled); } #endif // HAS_FILAMENT_SENSOR diff --git a/Marlin/src/gcode/feature/trinamic/M911-M914.cpp b/Marlin/src/gcode/feature/trinamic/M911-M914.cpp index 52622a5e7e..336e881372 100644 --- a/Marlin/src/gcode/feature/trinamic/M911-M914.cpp +++ b/Marlin/src/gcode/feature/trinamic/M911-M914.cpp @@ -76,9 +76,7 @@ template static void tmc_report_otpw(TMC &st) { st.printLabel(); - SERIAL_ECHOPGM(" temperature prewarn triggered: "); - serialprint_truefalse(st.getOTPW()); - SERIAL_EOL(); + SERIAL_ECHOLNPGM(" temperature prewarn triggered: ", TRUE_FALSE(st.getOTPW())); } template diff --git a/Marlin/src/gcode/probe/M401_M402.cpp b/Marlin/src/gcode/probe/M401_M402.cpp index 05230e05ea..237f841212 100644 --- a/Marlin/src/gcode/probe/M401_M402.cpp +++ b/Marlin/src/gcode/probe/M401_M402.cpp @@ -47,9 +47,7 @@ void GcodeSuite::M401() { seenS = parser.seen('S'); if (seenH || seenS) { if (seenS) bltouch.high_speed_mode = parser.value_bool(); - SERIAL_ECHO_START(); - SERIAL_ECHOPGM("BLTouch HS mode "); - serialprintln_onoff(bltouch.high_speed_mode); + SERIAL_ECHO_MSG("BLTouch HS mode ", ON_OFF(bltouch.high_speed_mode)); return; } #endif diff --git a/Marlin/src/gcode/temp/M303.cpp b/Marlin/src/gcode/temp/M303.cpp index c08b99edc6..ffa4efb699 100644 --- a/Marlin/src/gcode/temp/M303.cpp +++ b/Marlin/src/gcode/temp/M303.cpp @@ -50,9 +50,7 @@ void GcodeSuite::M303() { #if HAS_PID_DEBUG if (parser.seen_test('D')) { FLIP(thermalManager.pid_debug_flag); - SERIAL_ECHO_START(); - SERIAL_ECHOPGM("PID Debug "); - serialprintln_onoff(thermalManager.pid_debug_flag); + SERIAL_ECHO_MSG("PID Debug ", ON_OFF(thermalManager.pid_debug_flag)); return; } #endif From 21559b0c59029524da9eeca24e75863b92874ae7 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Mon, 26 May 2025 16:33:33 -0500 Subject: [PATCH 346/787] =?UTF-8?q?=F0=9F=A9=B9=20Call=20SERIAL=5FIMPL.msg?= =?UTF-8?q?Done()=20after=20M105?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/gcode/gcode.cpp | 4 ++-- Marlin/src/gcode/gcode.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp index 469ab134d3..242972c24b 100644 --- a/Marlin/src/gcode/gcode.cpp +++ b/Marlin/src/gcode/gcode.cpp @@ -319,7 +319,7 @@ void GcodeSuite::dwell(const millis_t time) { /** * Process the parsed command and dispatch it to its handler */ -void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) { +void GcodeSuite::process_parsed_command(bool no_ok/*=false*/) { TERN_(HAS_FANCHECK, fan_check.check_deferred_error()); KEEPALIVE_STATE(IN_HANDLER); @@ -582,7 +582,7 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) { case 109: M109(); break; // M109: Wait for hotend temperature to reach target #endif - case 105: M105(); return; // M105: Report Temperatures (and say "ok") + case 105: M105(); no_ok = true; break; // M105: Report Temperatures (and say "ok") #if HAS_FAN case 106: M106(); break; // M106: Fan On diff --git a/Marlin/src/gcode/gcode.h b/Marlin/src/gcode/gcode.h index cfe0ec056f..ee0ccb9a0f 100644 --- a/Marlin/src/gcode/gcode.h +++ b/Marlin/src/gcode/gcode.h @@ -458,7 +458,7 @@ public: static int8_t get_target_e_stepper_from_command(const int8_t dval=-1); static void get_destination_from_command(); - static void process_parsed_command(const bool no_ok=false); + static void process_parsed_command(bool no_ok=false); static void process_next_command(); // Execute G-code in-place, preserving current G-code parameters From 122c4116f2e2a64017b528cd49f896c166f1dfaf Mon Sep 17 00:00:00 2001 From: Andrew <18502096+classicrocker883@users.noreply.github.com> Date: Mon, 26 May 2025 17:36:55 -0400 Subject: [PATCH 347/787] =?UTF-8?q?=F0=9F=9A=B8=20Misc.=20optimizations,?= =?UTF-8?q?=20cleanup,=20DWIN=20fixes=E2=80=A6=20(#27858)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Scott Lahteine --- .../src/HAL/GD32_MFL/eeprom/eeprom_if_iic.cpp | 2 +- Marlin/src/HAL/HC32/eeprom/eeprom_if_iic.cpp | 2 +- Marlin/src/HAL/STM32/eeprom/eeprom_if_iic.cpp | 2 +- .../src/HAL/STM32F1/eeprom/eeprom_if_iic.cpp | 2 +- Marlin/src/core/types.h | 38 +++++++------- Marlin/src/gcode/bedlevel/G26.cpp | 6 ++- Marlin/src/gcode/calibrate/G33.cpp | 4 +- Marlin/src/gcode/feature/powerloss/M413.cpp | 4 +- Marlin/src/gcode/motion/G0_G1.cpp | 7 +-- Marlin/src/gcode/probe/M951.cpp | 2 +- Marlin/src/gcode/temp/M106_M107.cpp | 5 +- Marlin/src/inc/Changes.h | 12 ++--- Marlin/src/inc/Conditionals-2-LCD.h | 5 -- Marlin/src/lcd/e3v2/proui/dwin.cpp | 50 ++++++++++--------- Marlin/src/module/planner.cpp | 10 ++-- Marlin/src/module/planner.h | 3 +- ini/hc32.ini | 4 +- 17 files changed, 82 insertions(+), 76 deletions(-) diff --git a/Marlin/src/HAL/GD32_MFL/eeprom/eeprom_if_iic.cpp b/Marlin/src/HAL/GD32_MFL/eeprom/eeprom_if_iic.cpp index ea563f742c..765c997e1f 100644 --- a/Marlin/src/HAL/GD32_MFL/eeprom/eeprom_if_iic.cpp +++ b/Marlin/src/HAL/GD32_MFL/eeprom/eeprom_if_iic.cpp @@ -42,7 +42,7 @@ void eeprom_init() { void eeprom_write_byte(uint8_t *pos, uint8_t value) { const unsigned eeprom_address = (unsigned)pos; - return BL24CXX::writeOneByte(eeprom_address, value); + BL24CXX::writeOneByte(eeprom_address, value); } uint8_t eeprom_read_byte(uint8_t *pos) { diff --git a/Marlin/src/HAL/HC32/eeprom/eeprom_if_iic.cpp b/Marlin/src/HAL/HC32/eeprom/eeprom_if_iic.cpp index 85d21a972a..0a161f23f2 100644 --- a/Marlin/src/HAL/HC32/eeprom/eeprom_if_iic.cpp +++ b/Marlin/src/HAL/HC32/eeprom/eeprom_if_iic.cpp @@ -39,7 +39,7 @@ void eeprom_init() { void eeprom_write_byte(uint8_t *pos, unsigned char value) { const unsigned eeprom_address = (unsigned)pos; - return BL24CXX::writeOneByte(eeprom_address, value); + BL24CXX::writeOneByte(eeprom_address, value); } uint8_t eeprom_read_byte(uint8_t *pos) { diff --git a/Marlin/src/HAL/STM32/eeprom/eeprom_if_iic.cpp b/Marlin/src/HAL/STM32/eeprom/eeprom_if_iic.cpp index 9cabdd681b..2733c8f283 100644 --- a/Marlin/src/HAL/STM32/eeprom/eeprom_if_iic.cpp +++ b/Marlin/src/HAL/STM32/eeprom/eeprom_if_iic.cpp @@ -44,7 +44,7 @@ void eeprom_init() { BL24CXX::init(); } void eeprom_write_byte(uint8_t *pos, uint8_t value) { const unsigned eeprom_address = (unsigned)pos; - return BL24CXX::writeOneByte(eeprom_address, value); + BL24CXX::writeOneByte(eeprom_address, value); } uint8_t eeprom_read_byte(uint8_t *pos) { diff --git a/Marlin/src/HAL/STM32F1/eeprom/eeprom_if_iic.cpp b/Marlin/src/HAL/STM32F1/eeprom/eeprom_if_iic.cpp index e1d5e06b68..e7e7fc1db1 100644 --- a/Marlin/src/HAL/STM32F1/eeprom/eeprom_if_iic.cpp +++ b/Marlin/src/HAL/STM32F1/eeprom/eeprom_if_iic.cpp @@ -42,7 +42,7 @@ void eeprom_init() { BL24CXX::init(); } void eeprom_write_byte(uint8_t *pos, uint8_t value) { const unsigned eeprom_address = (unsigned)pos; - return BL24CXX::writeOneByte(eeprom_address, value); + BL24CXX::writeOneByte(eeprom_address, value); } uint8_t eeprom_read_byte(uint8_t *pos) { diff --git a/Marlin/src/core/types.h b/Marlin/src/core/types.h index 0de49771ee..86f6ae69dc 100644 --- a/Marlin/src/core/types.h +++ b/Marlin/src/core/types.h @@ -168,7 +168,7 @@ template struct IF { typedef L type; }; // Helpers #define _RECIP(N) ((N) ? 1.0f / static_cast(N) : 0.0f) -#define _ABS(N) ((N) < 0 ? -(N) : (N)) +#define _ABS(N) ((N) < decltype(N)(0) ? -(N) : (N)) #define _LS(N) T(uint32_t(N) << p) #define _RS(N) T(uint32_t(N) >> p) #define _LSE(N) N = T(uint32_t(N) << p) @@ -640,8 +640,8 @@ struct XYZval { FI void reset() { NUM_AXIS_CODE(x = 0, y = 0, z = 0, i = 0, j = 0, k = 0, u = 0, v = 0, w = 0); } // Setters taking struct types and arrays - FI void set(const XYval pxy) { XY_CODE(x = pxy.x, y = pxy.y); } - FI void set(const XYval pxy, const T pz) { XYZ_CODE(x = pxy.x, y = pxy.y, z = pz); } + FI void set(const XYval &pxy) { XY_CODE(x = pxy.x, y = pxy.y); } + FI void set(const XYval &pxy, const T pz) { XYZ_CODE(x = pxy.x, y = pxy.y, z = pz); } FI void set(const T (&arr)[NUM_AXES]) { NUM_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5], u = arr[6], v = arr[7], w = arr[8]); } #if LOGICAL_AXES > NUM_AXES FI void set(const T (&arr)[LOGICAL_AXES]) { NUM_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5], u = arr[6], v = arr[7], w = arr[8]); } @@ -743,7 +743,7 @@ struct XYZval { // Absolute difference between two objects FI constexpr XYZval diff(const XYZEval &rs) const { return NUM_AXIS_ARRAY(T(_ABS(x - rs.x)), T(_ABS(y - rs.y)), T(_ABS(z - rs.z)), T(_ABS(i - rs.i)), T(_ABS(j - rs.j)), T(_ABS(k - rs.k)), T(_ABS(u - rs.u)), T(_ABS(v - rs.v)), T(_ABS(w - rs.w)) ); } - FI constexpr XYZval diff(const XYZval &rs) const { return NUM_AXIS_ARRAY(T(_ABS(x - rs.x)), T(_ABS(y - rs.y)), T(_ABS(z - rs.z)), T(_ABS(i - rs.i)), T(_ABS(j - rs.j)), T(_ABS(k - rs.k)), T(_ABS(u - rs.u)), T(_ABS(v - rs.v)), T(_ABS(w - rs.w)) ); } + FI constexpr XYZval diff(const XYZval &rs) const { return NUM_AXIS_ARRAY(T(_ABS(x - rs.x)), T(_ABS(y - rs.y)), T(_ABS(z - rs.z)), T(_ABS(i - rs.i)), T(_ABS(j - rs.j)), T(_ABS(k - rs.k)), T(_ABS(u - rs.u)), T(_ABS(v - rs.v)), T(_ABS(w - rs.w)) ); } FI constexpr XYZval diff(const XYval &rs) const { return NUM_AXIS_ARRAY(T(_ABS(x - rs.x)), T(_ABS(y - rs.y)), z, i, j, k, u, v, w ); } // Modifier operators @@ -787,17 +787,17 @@ struct XYZEval { FI void reset() { LOGICAL_AXIS_GANG(e =, x =, y =, z =, i =, j =, k =, u =, v =, w =) 0; } // Setters taking struct types and arrays - FI void set(const XYval pxy) { XY_CODE(x = pxy.x, y = pxy.y); } - FI void set(const XYval pxy, const T pz) { XYZ_CODE(x = pxy.x, y = pxy.y, z = pz); } - FI void set(const XYZval pxyz) { set(NUM_AXIS_ELEM_LC(pxyz)); } - FI void set(const T (&arr)[NUM_AXES]) { NUM_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5], u = arr[6], v = arr[7], w = arr[8]); } + FI void set(const XYval &pxy) { XY_CODE(x = pxy.x, y = pxy.y); } + FI void set(const XYval &pxy, const T pz) { XYZ_CODE(x = pxy.x, y = pxy.y, z = pz); } + FI void set(const XYZval &pxyz) { set(NUM_AXIS_ELEM_LC(pxyz)); } + FI void set(const T (&arr)[NUM_AXES]) { NUM_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5], u = arr[6], v = arr[7], w = arr[8]); } #if LOGICAL_AXES > NUM_AXES - FI void set(const T (&arr)[LOGICAL_AXES]) { LOGICAL_AXIS_CODE(e = arr[LOGICAL_AXES-1], x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5], u = arr[6], v = arr[7], w = arr[8]); } - FI void set(const XYval pxy, const T pz, const T pe) { set(pxy, pz); e = pe; } - FI void set(const XYZval pxyz, const T pe) { set(pxyz); e = pe; } - FI void set(LOGICAL_AXIS_ARGS_LC(const T)) { LOGICAL_AXIS_CODE(_e = e, a = x, b = y, c = z, _i = i, _j = j, _k = k, _u = u, _v = v, _w = w); } + FI void set(const T (&arr)[LOGICAL_AXES]) { LOGICAL_AXIS_CODE(e = arr[LOGICAL_AXES-1], x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5], u = arr[6], v = arr[7], w = arr[8]); } + FI void set(const XYval &pxy, const T pz, const T pe) { set(pxy, pz); e = pe; } + FI void set(const XYZval &pxyz, const T pe) { set(pxyz); e = pe; } + FI void set(LOGICAL_AXIS_ARGS_LC(const T)) { LOGICAL_AXIS_CODE(_e = e, a = x, b = y, c = z, _i = i, _j = j, _k = k, _u = u, _v = v, _w = w); } #if DISTINCT_AXES > LOGICAL_AXES - FI void set(const T (&arr)[DISTINCT_AXES]) { LOGICAL_AXIS_CODE(e = arr[LOGICAL_AXES-1], x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5], u = arr[6], v = arr[7], w = arr[8]); } + FI void set(const T (&arr)[DISTINCT_AXES]) { LOGICAL_AXIS_CODE(e = arr[LOGICAL_AXES-1], x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5], u = arr[6], v = arr[7], w = arr[8]); } #endif #endif @@ -933,9 +933,9 @@ struct XYZarray { }; FI void reset() { ZERO(data); } - FI void set(const int n, const XYval p) { NUM_AXIS_CODE(x[n]=p.x, y[n]=p.y,,,,,,,); } - FI void set(const int n, const XYZval p) { NUM_AXIS_CODE(x[n]=p.x, y[n]=p.y, z[n]=p.z, i[n]=p.i, j[n]=p.j, k[n]=p.k, u[n]=p.u, v[n]=p.v, w[n]=p.w ); } - FI void set(const int n, const XYZEval p) { NUM_AXIS_CODE(x[n]=p.x, y[n]=p.y, z[n]=p.z, i[n]=p.i, j[n]=p.j, k[n]=p.k, u[n]=p.u, v[n]=p.v, w[n]=p.w ); } + FI void set(const int n, const XYval &p) { NUM_AXIS_CODE(x[n]=p.x, y[n]=p.y,,,,,,,); } + FI void set(const int n, const XYZval &p) { NUM_AXIS_CODE(x[n]=p.x, y[n]=p.y, z[n]=p.z, i[n]=p.i, j[n]=p.j, k[n]=p.k, u[n]=p.u, v[n]=p.v, w[n]=p.w ); } + FI void set(const int n, const XYZEval &p) { NUM_AXIS_CODE(x[n]=p.x, y[n]=p.y, z[n]=p.z, i[n]=p.i, j[n]=p.j, k[n]=p.k, u[n]=p.u, v[n]=p.v, w[n]=p.w ); } // Setter for all individual args FI void set(const int n OPTARGS_NUM(const T)) { NUM_AXIS_CODE(a[n] = x, b[n] = y, c[n] = z, _i[n] = i, _j[n] = j, _k[n] = k, _u[n] = u, _v[n] = v, _w[n] = w); } @@ -981,9 +981,9 @@ struct XYZEarray { }; FI void reset() { ZERO(data); } - FI void set(const int n, const XYval p) { NUM_AXIS_CODE(x[n]=p.x, y[n]=p.y,,,,,,,); } - FI void set(const int n, const XYZval p) { NUM_AXIS_CODE(x[n]=p.x, y[n]=p.y, z[n]=p.z, i[n]=p.i, j[n]=p.j, k[n]=p.k, u[n]=p.u, v[n]=p.v, w[n]=p.w ); } - FI void set(const int n, const XYZEval p) { LOGICAL_AXIS_CODE(e[n]=p.e, x[n]=p.x, y[n]=p.y, z[n]=p.z, i[n]=p.i, j[n]=p.j, k[n]=p.k, u[n]=p.u, v[n]=p.v, w[n]=p.w ); } + FI void set(const int n, const XYval &p) { NUM_AXIS_CODE(x[n]=p.x, y[n]=p.y,,,,,,,); } + FI void set(const int n, const XYZval &p) { NUM_AXIS_CODE(x[n]=p.x, y[n]=p.y, z[n]=p.z, i[n]=p.i, j[n]=p.j, k[n]=p.k, u[n]=p.u, v[n]=p.v, w[n]=p.w ); } + FI void set(const int n, const XYZEval &p) { LOGICAL_AXIS_CODE(e[n]=p.e, x[n]=p.x, y[n]=p.y, z[n]=p.z, i[n]=p.i, j[n]=p.j, k[n]=p.k, u[n]=p.u, v[n]=p.v, w[n]=p.w ); } // Setter for all individual args FI void set(const int n OPTARGS_NUM(const T)) { NUM_AXIS_CODE(a[n] = x, b[n] = y, c[n] = z, _i[n] = i, _j[n] = j, _k[n] = k, _u[n] = u, _v[n] = v, _w[n] = w); } diff --git a/Marlin/src/gcode/bedlevel/G26.cpp b/Marlin/src/gcode/bedlevel/G26.cpp index 8c26ca4e8f..94e9b82506 100644 --- a/Marlin/src/gcode/bedlevel/G26.cpp +++ b/Marlin/src/gcode/bedlevel/G26.cpp @@ -268,8 +268,10 @@ typedef struct { // If the end point of the line is closer to the nozzle, flip the direction, // moving from the end to the start. On very small lines the optimization isn't worth it. - if (dist_end < dist_start && (INTERSECTION_CIRCLE_RADIUS) < ABS(line_length)) - return print_line_from_here_to_there(e, s); + if (dist_end < dist_start && (INTERSECTION_CIRCLE_RADIUS) < ABS(line_length)) { + print_line_from_here_to_there(e, s); + return; + } // Decide whether to retract & lift if (dist_start > 2.0) retract_lift_move(s); diff --git a/Marlin/src/gcode/calibrate/G33.cpp b/Marlin/src/gcode/calibrate/G33.cpp index 395da649d3..76bf250346 100644 --- a/Marlin/src/gcode/calibrate/G33.cpp +++ b/Marlin/src/gcode/calibrate/G33.cpp @@ -598,7 +598,7 @@ void GcodeSuite::G33() { LOOP_NUM_AXES(axis) delta_tower_angle_trim[axis] -= a_sum / 3.0f; } - // adjust delta_height and endstops by the max amount + // Adjust delta_height and endstops by the max amount const float z_temp = _MAX(delta_endstop_adj.a, delta_endstop_adj.b, delta_endstop_adj.c); delta_height -= z_temp; LOOP_NUM_AXES(axis) delta_endstop_adj[axis] -= z_temp; @@ -606,7 +606,7 @@ void GcodeSuite::G33() { recalc_delta_settings(); NOMORE(zero_std_dev_min, zero_std_dev); - // print report + // Print report if (verbose_level == 3 || verbose_level == 0) { print_calibration_results(z_at_pt, _tower_results, _opposite_results); diff --git a/Marlin/src/gcode/feature/powerloss/M413.cpp b/Marlin/src/gcode/feature/powerloss/M413.cpp index 7f0e2e2b9a..68cdc01668 100644 --- a/Marlin/src/gcode/feature/powerloss/M413.cpp +++ b/Marlin/src/gcode/feature/powerloss/M413.cpp @@ -41,10 +41,10 @@ */ void GcodeSuite::M413() { + if (!parser.seen_any()) return M413_report(); + if (parser.seen('S')) recovery.enable(parser.value_bool()); - else - M413_report(); #if HAS_PLR_BED_THRESHOLD if (parser.seenval('B')) diff --git a/Marlin/src/gcode/motion/G0_G1.cpp b/Marlin/src/gcode/motion/G0_G1.cpp index c6c1833806..b489b659ae 100644 --- a/Marlin/src/gcode/motion/G0_G1.cpp +++ b/Marlin/src/gcode/motion/G0_G1.cpp @@ -86,9 +86,10 @@ void GcodeSuite::G0_G1(TERN_(HAS_FAST_MOVES, const bool fast_move/*=false*/)) { const float echange = destination.e - current_position.e; // Is this a retract or recover move? if (WITHIN(ABS(echange), MIN_AUTORETRACT, MAX_AUTORETRACT) && fwretract.retracted[active_extruder] == (echange > 0.0)) { - current_position.e = destination.e; // Hide a G1-based retract/recover from calculations - sync_plan_position_e(); // AND from the planner - return fwretract.retract(echange < 0.0); // Firmware-based retract/recover (double-retract ignored) + current_position.e = destination.e; // Hide a G1-based retract/recover from calculations + sync_plan_position_e(); // AND from the planner + fwretract.retract(echange < 0.0); // Firmware-based retract/recover (double-retract ignored) + return; } } } diff --git a/Marlin/src/gcode/probe/M951.cpp b/Marlin/src/gcode/probe/M951.cpp index db0278e431..15d3d47af0 100644 --- a/Marlin/src/gcode/probe/M951.cpp +++ b/Marlin/src/gcode/probe/M951.cpp @@ -80,7 +80,7 @@ void GcodeSuite::M951() { if (parser.seenval('H')) mpe_settings.fast_feedrate = MMM_TO_MMS(parser.value_linear_units()); if (parser.seenval('D')) mpe_settings.travel_distance = parser.value_linear_units(); if (parser.seenval('C')) mpe_settings.compensation_factor = parser.value_float(); - if (!parser.seen("CDHIJLR")) mpe_settings_report(); + if (!parser.seen_any()) mpe_settings_report(); } #endif // MAGNETIC_PARKING_EXTRUDER diff --git a/Marlin/src/gcode/temp/M106_M107.cpp b/Marlin/src/gcode/temp/M106_M107.cpp index afa2ebfc56..ddfc8514c0 100644 --- a/Marlin/src/gcode/temp/M106_M107.cpp +++ b/Marlin/src/gcode/temp/M106_M107.cpp @@ -65,7 +65,10 @@ void GcodeSuite::M106() { #if ENABLED(EXTRA_FAN_SPEED) const uint16_t t = parser.intval('T'); - if (t > 0) return thermalManager.set_temp_fan_speed(pfan, t); + if (t > 0) { + thermalManager.set_temp_fan_speed(pfan, t); + return; + } #endif const uint16_t dspeed = parser.seen_test('A') ? thermalManager.fan_speed[active_extruder] : 255; diff --git a/Marlin/src/inc/Changes.h b/Marlin/src/inc/Changes.h index 839804d920..cbfdcfc47f 100644 --- a/Marlin/src/inc/Changes.h +++ b/Marlin/src/inc/Changes.h @@ -765,15 +765,15 @@ #endif // Consolidate TMC26X, validate migration (#24373) -#define _ISMAX_1(A) defined(A##_MAX_CURRENT) -#define _ISSNS_1(A) defined(A##_SENSE_RESISTOR) -#if DO(ISMAX,||,ALL_AXIS_NAMES) +#define _ISMAX(A) defined(A##_MAX_CURRENT) || +#define _ISSNS(A) defined(A##_SENSE_RESISTOR) || +#if MAP(_ISMAX, ALL_AXIS_NAMES) 0 #error "*_MAX_CURRENT is now set with *_CURRENT." -#elif DO(ISSNS,||,ALL_AXIS_NAMES) +#elif MAP(_ISSNS, ALL_AXIS_NAMES) 0 #error "*_SENSE_RESISTOR (in Milli-Ohms) is now set with *_RSENSE (in Ohms), so you must divide values by 1000." #endif -#undef _ISMAX_1 -#undef _ISSNS_1 +#undef _ISMAX +#undef _ISSNS // L64xx stepper drivers have been removed #define _L6470 0x6470 diff --git a/Marlin/src/inc/Conditionals-2-LCD.h b/Marlin/src/inc/Conditionals-2-LCD.h index 362ca7a714..8f92948d56 100644 --- a/Marlin/src/inc/Conditionals-2-LCD.h +++ b/Marlin/src/inc/Conditionals-2-LCD.h @@ -663,11 +663,6 @@ #define BOOT_MARLIN_LOGO_SMALL #endif -// Flow and feedrate editing -#if HAS_EXTRUDERS && ANY(HAS_MARLINUI_MENU, DWIN_CREALITY_LCD, DWIN_LCD_PROUI, MALYAN_LCD, TOUCH_SCREEN) - #define HAS_FLOW_EDIT 1 -#endif - /** * TFT Displays * diff --git a/Marlin/src/lcd/e3v2/proui/dwin.cpp b/Marlin/src/lcd/e3v2/proui/dwin.cpp index 08782553ba..9d857f1e3a 100644 --- a/Marlin/src/lcd/e3v2/proui/dwin.cpp +++ b/Marlin/src/lcd/e3v2/proui/dwin.cpp @@ -2382,6 +2382,7 @@ void setMoveZ() { hmiValue.axis = Z_AXIS; setPFloatOnClick(Z_MIN_POS, Z_MAX_POS, #endif void setSpeed() { setPIntOnClick(SPEED_EDIT_MIN, SPEED_EDIT_MAX); } +void setFlow() { setPIntOnClick(FLOW_EDIT_MIN, FLOW_EDIT_MAX, []{ planner.refresh_e_factor(0); }); } #if HAS_HOTEND void applyHotendTemp() { thermalManager.setTargetHotend(menuData.value, 0); } @@ -2426,8 +2427,6 @@ void setSpeed() { setPIntOnClick(SPEED_EDIT_MIN, SPEED_EDIT_MAX); } #endif // ADVANCED_PAUSE_FEATURE -void setFlow() { setPIntOnClick(FLOW_EDIT_MIN, FLOW_EDIT_MAX, []{ planner.refresh_e_factor(0); }); } - // Bed Tramming #if ENABLED(LCD_BED_TRAMMING) @@ -2596,23 +2595,25 @@ void setFlow() { setPIntOnClick(FLOW_EDIT_MIN, FLOW_EDIT_MAX, []{ planner.refres #if ENABLED(MESH_BED_LEVELING) + #define MESH_Z_FDIGITS 2 + void manualMeshStart() { LCD_MESSAGE(MSG_UBL_BUILD_MESH_MENU); gcode.process_subcommands_now(F("G28XYO\nG28Z\nM211S0\nG29S1")); #ifdef MANUAL_PROBE_START_Z const uint8_t line = currentMenu->line(mMeshMoveZItem->pos); - DWINUI::drawSignedFloat(hmiData.colorText, hmiData.colorBackground, 3, 2, VALX - 2 * DWINUI::fontWidth(DWIN_FONT_MENU), MBASE(line), MANUAL_PROBE_START_Z); + DWINUI::drawSignedFloat(hmiData.colorText, hmiData.colorBackground, 3, MESH_Z_FDIGITS, VALX - 2 * DWINUI::fontWidth(DWIN_FONT_MENU), MBASE(line), MANUAL_PROBE_START_Z); #endif } void liveMeshMoveZ() { - *menuData.floatPtr = menuData.value / POW(10, 2); + *menuData.floatPtr = menuData.value / POW(10, MESH_Z_FDIGITS); if (!planner.is_full()) { planner.synchronize(); planner.buffer_line(current_position, manual_feedrate_mm_s[Z_AXIS]); } } - void setMMeshMoveZ() { setPFloatOnClick(-1, 1, 2, planner.synchronize, liveMeshMoveZ); } + void setMMeshMoveZ() { setPFloatOnClick(-1, 1, MESH_Z_FDIGITS, planner.synchronize, liveMeshMoveZ); } void manualMeshContinue() { gcode.process_subcommands_now(F("G29S2")); @@ -2686,8 +2687,9 @@ void applyMaxAccel() { planner.set_max_acceleration(hmiValue.axis, menuData.valu #endif #if ENABLED(LIN_ADVANCE) - void applyLA_K() { planner.set_advance_k(menuData.value / MINUNITMULT); } - void setLA_K() { setPFloatOnClick(0, 10, 3, applyLA_K); } + #define LA_FDIGITS 3 + void applyLA_K() { planner.set_advance_k(menuData.value / POW(10, LA_FDIGITS)); } + void setLA_K() { setPFloatOnClick(0, 10, LA_FDIGITS, applyLA_K); } #endif #if HAS_X_AXIS @@ -3515,6 +3517,7 @@ void drawTuneMenu() { if (SET_MENU_R(tuneMenu, selrect({73, 2, 28, 12}), MSG_TUNE, items)) { BACK_ITEM(gotoPrintProcess); EDIT_ITEM(ICON_Speed, MSG_SPEED, onDrawSpeedItem, setSpeed, &feedrate_percentage); + EDIT_ITEM(ICON_Flow, MSG_FLOW, onDrawPIntMenu, setFlow, &planner.flow_percentage[0]); #if HAS_HOTEND hotendTargetItem = EDIT_ITEM(ICON_HotendTemp, MSG_UBL_SET_TEMP_HOTEND, onDrawHotendTemp, setHotendTemp, &thermalManager.temp_hotend[0].target); #endif @@ -3529,7 +3532,6 @@ void drawTuneMenu() { #elif ALL(HAS_ZOFFSET_ITEM, MESH_BED_LEVELING, BABYSTEPPING) EDIT_ITEM(ICON_Zoffset, MSG_HOME_OFFSET_Z, onDrawPFloat2Menu, setZOffset, &BABY_Z_VAR); #endif - EDIT_ITEM(ICON_Flow, MSG_FLOW, onDrawPIntMenu, setFlow, &planner.flow_percentage[0]); #if ENABLED(ADVANCED_PAUSE_FEATURE) MENU_ITEM(ICON_FilMan, MSG_FILAMENTCHANGE, onDrawMenuItem, changeFilament); #endif @@ -3546,8 +3548,8 @@ void drawTuneMenu() { EDIT_ITEM(ICON_JDmm, MSG_JUNCTION_DEVIATION, onDrawPFloat3Menu, setJDmm, &planner.junction_deviation_mm); #endif #if ENABLED(PROUI_ITEM_ADVK) - float editable_decimal = planner.get_advance_k(); - EDIT_ITEM(ICON_MaxAccelerated, MSG_ADVANCE_K, onDrawPFloat3Menu, setLA_K, &editable_decimal); + float editable_k = planner.get_advance_k(); + EDIT_ITEM(ICON_MaxAccelerated, MSG_ADVANCE_K, onDrawPFloat3Menu, setLA_K, &editable_k); #endif #if HAS_LOCKSCREEN MENU_ITEM(ICON_Lock, MSG_LOCKSCREEN, onDrawMenuItem, dwinLockScreen); @@ -3685,8 +3687,8 @@ void drawMotionMenu() { MENU_ITEM(ICON_Homing, MSG_HOMING_FEEDRATE, onDrawSubMenu, drawHomingFRMenu); #endif #if ENABLED(LIN_ADVANCE) - float editable_decimal = planner.get_advance_k(); - EDIT_ITEM(ICON_MaxAccelerated, MSG_ADVANCE_K, onDrawPFloat3Menu, setLA_K, &editable_decimal); + float editable_k = planner.get_advance_k(); + EDIT_ITEM(ICON_MaxAccelerated, MSG_ADVANCE_K, onDrawPFloat3Menu, setLA_K, &editable_k); #endif #if ENABLED(SHAPING_MENU) MENU_ITEM(ICON_InputShaping, MSG_INPUT_SHAPING, onDrawSubMenu, drawInputShaping_menu); @@ -3694,8 +3696,8 @@ void drawMotionMenu() { #if ENABLED(ADAPTIVE_STEP_SMOOTHING_TOGGLE) EDIT_ITEM(ICON_UBLActive, MSG_STEP_SMOOTHING, onDrawChkbMenu, setAdaptiveStepSmoothing, &stepper.adaptive_step_smoothing_enabled); #endif + EDIT_ITEM(ICON_Speed, MSG_SPEED, onDrawSpeedItem, setSpeed, &feedrate_percentage); EDIT_ITEM(ICON_Flow, MSG_FLOW, onDrawPIntMenu, setFlow, &planner.flow_percentage[0]); - EDIT_ITEM(ICON_Speed, MSG_SPEED, onDrawPIntMenu, setSpeed, &feedrate_percentage); } updateMenu(motionMenu); } @@ -4028,9 +4030,10 @@ void drawMaxAccelMenu() { void setSensorResponse() { setPFloatOnClick(0, 1, 4); } void setAmbientXfer() { setPFloatOnClick(0, 1, 4); } #if ENABLED(MPC_INCLUDE_FAN) - void onDrawFanAdj(MenuItem* menuitem, int8_t line) { onDrawFloatMenu(menuitem, line, 4, thermalManager.temp_hotend[0].fanCoefficient()); } - void applyFanAdj() { thermalManager.temp_hotend[0].applyFanAdjustment(menuData.value / POW(10, 4)); } - void setFanAdj() { setFloatOnClick(0, 1, 4, thermalManager.temp_hotend[0].fanCoefficient(), applyFanAdj); } + #define MPC_FAN_FDIGITS 4 + void onDrawFanAdj(MenuItem* menuitem, int8_t line) { onDrawFloatMenu(menuitem, line, MPC_FAN_FDIGITS, thermalManager.temp_hotend[0].fanCoefficient()); } + void applyFanAdj() { thermalManager.temp_hotend[0].applyFanAdjustment(menuData.value / POW(10, MPC_FAN_FDIGITS)); } + void setFanAdj() { setFloatOnClick(0, 1, MPC_FAN_FDIGITS, thermalManager.temp_hotend[0].fanCoefficient(), applyFanAdj); } #endif #endif @@ -4074,27 +4077,28 @@ void drawMaxAccelMenu() { #endif #if ENABLED(PID_EDIT_MENU) - void setKp() { setPFloatOnClick(0, 1000, 2); } + #define PID_FDIGITS 2 + void setKp() { setPFloatOnClick(0, 1000, PID_FDIGITS); } void applyPIDi() { - *menuData.floatPtr = scalePID_i(menuData.value / POW(10, 2)); + *menuData.floatPtr = scalePID_i(menuData.value / POW(10, PID_FDIGITS)); TERN_(PIDTEMP, thermalManager.updatePID()); } void applyPIDd() { - *menuData.floatPtr = scalePID_d(menuData.value / POW(10, 2)); + *menuData.floatPtr = scalePID_d(menuData.value / POW(10, PID_FDIGITS)); TERN_(PIDTEMP, thermalManager.updatePID()); } void setKi() { menuData.floatPtr = (float*)static_cast(currentMenu->selectedItem())->value; const float value = unscalePID_i(*menuData.floatPtr); - setFloatOnClick(0, 1000, 2, value, applyPIDi); + setFloatOnClick(0, 1000, PID_FDIGITS, value, applyPIDi); } void setKd() { menuData.floatPtr = (float*)static_cast(currentMenu->selectedItem())->value; const float value = unscalePID_d(*menuData.floatPtr); - setFloatOnClick(0, 1000, 2, value, applyPIDd); + setFloatOnClick(0, 1000, PID_FDIGITS, value, applyPIDd); } - void onDrawPIDi(MenuItem* menuitem, int8_t line) { onDrawFloatMenu(menuitem, line, 2, unscalePID_i(*(float*)static_cast(menuitem)->value)); } - void onDrawPIDd(MenuItem* menuitem, int8_t line) { onDrawFloatMenu(menuitem, line, 2, unscalePID_d(*(float*)static_cast(menuitem)->value)); } + void onDrawPIDi(MenuItem* menuitem, int8_t line) { onDrawFloatMenu(menuitem, line, PID_FDIGITS, unscalePID_i(*(float*)static_cast(menuitem)->value)); } + void onDrawPIDd(MenuItem* menuitem, int8_t line) { onDrawFloatMenu(menuitem, line, PID_FDIGITS, unscalePID_d(*(float*)static_cast(menuitem)->value)); } #endif // PID_EDIT_MENU #endif // HAS_PID_HEATING diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index 5e1c08f863..8678c82130 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -1505,10 +1505,12 @@ void Planner::check_axes_activity() { #if HAS_LEVELING - constexpr xy_pos_t level_fulcrum = { - TERN(Z_SAFE_HOMING, Z_SAFE_HOMING_X_POINT, X_HOME_POS), - TERN(Z_SAFE_HOMING, Z_SAFE_HOMING_Y_POINT, Y_HOME_POS) - }; + #if ABL_PLANAR + constexpr xy_pos_t level_fulcrum = { + TERN(Z_SAFE_HOMING, Z_SAFE_HOMING_X_POINT, X_HOME_POS), + TERN(Z_SAFE_HOMING, Z_SAFE_HOMING_Y_POINT, Y_HOME_POS) + }; + #endif /** * rx, ry, rz - Cartesian positions in mm diff --git a/Marlin/src/module/planner.h b/Marlin/src/module/planner.h index c71a73c5be..bda5720919 100644 --- a/Marlin/src/module/planner.h +++ b/Marlin/src/module/planner.h @@ -249,7 +249,7 @@ typedef struct PlannerBlock { uint32_t cruise_time; // Cruise time in STEP timer counts int32_t e_step_ratio_q30; // Ratio of e steps to block steps. #if ENABLED(INPUT_SHAPING_E_SYNC) - uint32_t xy_length_inv_q30; // inverse of block->steps.x + block.steps.y + uint32_t xy_length_inv_q30; // Inverse of block->steps.x + block.steps.y #endif #endif #if ANY(S_CURVE_ACCELERATION, SMOOTH_LIN_ADVANCE) @@ -370,7 +370,6 @@ typedef struct PlannerSettings { }; #undef _EASU #undef _DASU - #undef _DLIM #endif feedRate_t max_feedrate_mm_s[DISTINCT_AXES]; // (mm/s) M203 XYZE - Max speeds diff --git a/ini/hc32.ini b/ini/hc32.ini index 8a55e3b495..19baeda210 100644 --- a/ini/hc32.ini +++ b/ini/hc32.ini @@ -27,8 +27,8 @@ # Base Environment for all HC32F460 variants # [HC32F460_base] -platform = https://github.com/shadow578/platform-hc32f46x/archive/1.1.0.zip -platform_packages = framework-hc32f46x-ddl@https://github.com/shadow578/framework-hc32f46x-ddl/archive/2.2.2.zip +platform = https://github.com/shadow578/platform-hc32f46x/archive/1.1.1.zip +platform_packages = framework-hc32f46x-ddl@https://github.com/shadow578/framework-hc32f46x-ddl/archive/2.2.3.zip framework-arduino-hc32f46x@https://github.com/shadow578/framework-arduino-hc32f46x/archive/1.2.0.zip board = generic_hc32f460 build_src_filter = ${common.default_src_filter} + + From fde0eaf1e7e9a42d22f7dfb4d48f905e07949384 Mon Sep 17 00:00:00 2001 From: narno2202 <130909513+narno2202@users.noreply.github.com> Date: Tue, 27 May 2025 00:36:14 +0200 Subject: [PATCH 348/787] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20Remove=20FT=20Moti?= =?UTF-8?q?on=20extraneous=20code=20(#27881)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/module/stepper.cpp | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp index a6931c8d0d..ad7995bfc7 100644 --- a/Marlin/src/module/stepper.cpp +++ b/Marlin/src/module/stepper.cpp @@ -1541,7 +1541,7 @@ void Stepper::isr() { uint8_t max_loops = 10; #if ENABLED(FT_MOTION) - static uint32_t ftMotion_nextAuxISR = 0U; // Storage for the next ISR of the auxilliary tasks. + static uint32_t ftMotion_nextAuxISR = 0U; // Storage for the next ISR of the auxiliary tasks. const bool using_ftMotion = ftMotion.cfg.active; #else constexpr bool using_ftMotion = false; @@ -1556,21 +1556,18 @@ void Stepper::isr() { #if ENABLED(FT_MOTION) if (using_ftMotion) { - if (!nextMainISR) { // Main ISR is ready to fire during this iteration? - nextMainISR = FTM_MIN_TICKS; // Set to minimum interval (a limit on the top speed) - ftMotion_stepper(); // Run FTM Stepping - // Define 2.5 msec task for auxilliary functions. - if (!ftMotion_nextAuxISR) { - TERN_(BABYSTEPPING, if (babystep.has_steps()) babystepping_isr()); - ftMotion_nextAuxISR = (STEPPER_TIMER_RATE) / 400; - } + ftMotion_stepper(); // Run FTM Stepping + + // Define 2.5 msec task for auxiliary functions. + if (!ftMotion_nextAuxISR) { + TERN_(BABYSTEPPING, if (babystep.has_steps()) babystepping_isr()); + ftMotion_nextAuxISR = (STEPPER_TIMER_RATE) / 400; } - // Enable ISRs to reduce latency for higher priority ISRs, or all ISRs if no prioritization. + // Enable ISRs to reduce latency for higher priority ISRs hal.isr_on(); - - interval = _MIN(nextMainISR, ftMotion_nextAuxISR); - nextMainISR -= interval; + + interval = FTM_MIN_TICKS; ftMotion_nextAuxISR -= interval; } From e9ae5208cbf1948b92e08ee463a1ecfba53be722 Mon Sep 17 00:00:00 2001 From: Vovodroid Date: Tue, 27 May 2025 03:16:45 +0300 Subject: [PATCH 349/787] =?UTF-8?q?=E2=9C=A8=20EVENT=5FGCODE=5FAFTER=5FMPC?= =?UTF-8?q?=5FTUNE=20(#27865)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Scott Lahteine --- Marlin/Configuration.h | 1 + Marlin/src/module/temperature.cpp | 4 ++++ buildroot/tests/STM32F103RE_creality | 3 ++- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 859f0bbd33..08216d17b8 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -767,6 +767,7 @@ #define MPC_TUNING_POS { X_CENTER, Y_CENTER, 1.0f } // (mm) M306 Autotuning position, ideally bed center at first layer height. #define MPC_TUNING_END_Z 10.0f // (mm) M306 Autotuning final Z position. + //#define EVENT_GCODE_AFTER_MPC_TUNE "M84" // G-code to execute after MPC tune finished and Z raised. #endif //=========================================================================== diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index 30690345a5..5c760a7689 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -1104,6 +1104,10 @@ void Temperature::factory_reset() { do_z_clearance(MPC_TUNING_END_Z, false); + #ifdef EVENT_GCODE_AFTER_MPC_TUNE + gcode.process_subcommands_now(F(EVENT_GCODE_AFTER_MPC_TUNE)); + #endif + TERN_(TEMP_TUNING_MAINTAIN_FAN, adaptive_fan_slowing = true); } diff --git a/buildroot/tests/STM32F103RE_creality b/buildroot/tests/STM32F103RE_creality index 5681688929..0855a71ee4 100755 --- a/buildroot/tests/STM32F103RE_creality +++ b/buildroot/tests/STM32F103RE_creality @@ -20,7 +20,8 @@ exec_test $1 $2 "Ender-3 V2 - JyersUI (ABL Bilinear/Manual)" "$3" use_example_configs "Creality/Ender-3 V2/CrealityV422/CrealityUI" opt_disable DWIN_CREALITY_LCD PIDTEMP -opt_enable DWIN_MARLINUI_LANDSCAPE LCD_ENDSTOP_TEST AUTO_BED_LEVELING_UBL BLTOUCH Z_SAFE_HOMING MPCTEMP MPC_AUTOTUNE \ +opt_enable DWIN_MARLINUI_LANDSCAPE LCD_ENDSTOP_TEST AUTO_BED_LEVELING_UBL BLTOUCH Z_SAFE_HOMING \ + MPCTEMP MPC_AUTOTUNE EVENT_GCODE_AFTER_MPC_TUNE \ MARLIN_BRICKOUT MARLIN_INVADERS MARLIN_SNAKE GAMES_EASTER_EGG exec_test $1 $2 "Ender-3 V2 - MarlinUI (Games, UBL+BLTOUCH, MPCTEMP, LCD_ENDSTOP_TEST)" "$3" From 3f3c8257f7fc133471c1a86e6adc463bc9539f2c Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Tue, 27 May 2025 00:35:13 +0000 Subject: [PATCH 350/787] [cron] Bump distribution date (2025-05-27) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index b46b688339..34ac9adaa3 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-05-26" +//#define STRING_DISTRIBUTION_DATE "2025-05-27" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 06c29974a7..8d0c6361af 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-05-26" + #define STRING_DISTRIBUTION_DATE "2025-05-27" #endif /** From ebecd7649286fe12a111218dfc2a1185a48cc9aa Mon Sep 17 00:00:00 2001 From: Keith Bennett <13375512+thisiskeithb@users.noreply.github.com> Date: Mon, 26 May 2025 20:51:41 -0700 Subject: [PATCH 351/787] =?UTF-8?q?=F0=9F=94=A7=20Update=20BIQU=20BX=20SPI?= =?UTF-8?q?=20driver=20conditionals=20(#27886)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/Configuration_adv.h | 2 +- .../pins/stm32h7/pins_BTT_SKR_SE_BX_common.h | 21 +++++++++++-------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index fee4c452ab..7939b5cc9b 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -3470,7 +3470,7 @@ * * It is recommended to set HOMING_BUMP_MM to { 0, 0, 0 }. * - * SPI_ENDSTOPS *** TMC2130/TMC5160 Only *** + * SPI_ENDSTOPS *** TMC2130, TMC2240, and TMC5160 Only *** * Poll the driver through SPI to determine load when homing. * Removes the need for a wire from DIAG1 to an endstop pin. * diff --git a/Marlin/src/pins/stm32h7/pins_BTT_SKR_SE_BX_common.h b/Marlin/src/pins/stm32h7/pins_BTT_SKR_SE_BX_common.h index 529e610624..736f79e664 100644 --- a/Marlin/src/pins/stm32h7/pins_BTT_SKR_SE_BX_common.h +++ b/Marlin/src/pins/stm32h7/pins_BTT_SKR_SE_BX_common.h @@ -124,16 +124,19 @@ #endif // -// SPI pins for TMC2130 stepper drivers +// SPI pins for TMC2130, TMC2160, TMC2240, TMC2660, TMC5130, or TMC5160 stepper drivers // -#ifndef TMC_SPI_MOSI - #define TMC_SPI_MOSI PC6 -#endif -#ifndef TMC_SPI_MISO - #define TMC_SPI_MISO PG3 -#endif -#ifndef TMC_SPI_SCK - #define TMC_SPI_SCK PC7 +#if HAS_TMC_SPI + #define TMC_USE_SW_SPI + #ifndef TMC_SPI_MOSI + #define TMC_SPI_MOSI PC6 + #endif + #ifndef TMC_SPI_MISO + #define TMC_SPI_MISO PG3 + #endif + #ifndef TMC_SPI_SCK + #define TMC_SPI_SCK PC7 + #endif #endif #if HAS_TMC_UART From 3572fd75b596ed99e43093d99ce360828a187a4d Mon Sep 17 00:00:00 2001 From: vehystrix Date: Tue, 27 May 2025 06:46:46 +0200 Subject: [PATCH 352/787] =?UTF-8?q?=F0=9F=90=9B=20Fix=20M201=20with=20XY?= =?UTF-8?q?=5FFREQUENCY=5FLIMIT=20(#27859)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Scott Lahteine --- Marlin/src/gcode/config/M200-M205.cpp | 29 +++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/Marlin/src/gcode/config/M200-M205.cpp b/Marlin/src/gcode/config/M200-M205.cpp index a55813aeae..7ad7de8617 100644 --- a/Marlin/src/gcode/config/M200-M205.cpp +++ b/Marlin/src/gcode/config/M200-M205.cpp @@ -124,8 +124,13 @@ * S : Speed factor percentage. */ void GcodeSuite::M201() { - if (!parser.seen("T" STR_AXES_LOGICAL TERN_(XY_FREQUENCY_LIMIT, "FS"))) + if (!parser.seen("T" STR_AXES_LOGICAL + #ifdef XY_FREQUENCY_LIMIT + "FS" + #endif + )) { return M201_report(); + } const int8_t target_extruder = get_target_extruder_from_command(); if (target_extruder < 0) return; @@ -147,7 +152,11 @@ void GcodeSuite::M201_report(const bool forReplay/*=true*/) { TERN_(MARLIN_SMALL_BUILD, return); report_heading_etc(forReplay, F(STR_MAX_ACCELERATION)); + + bool eol = false; + #if NUM_AXES + eol = true; SERIAL_ECHOPGM_P( LIST_N(DOUBLE(NUM_AXES), PSTR(" M201 X"), LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[X_AXIS]), @@ -164,13 +173,18 @@ void GcodeSuite::M201_report(const bool forReplay/*=true*/) { #endif #if HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS) + eol = true; SERIAL_ECHOPGM_P(SP_E_STR, VOLUMETRIC_UNIT(planner.settings.max_acceleration_mm_per_s2[E_AXIS])); #endif - #if NUM_AXES || (HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS)) - SERIAL_EOL(); + #ifdef XY_FREQUENCY_LIMIT + eol = true; + SERIAL_ECHOPGM_P(PSTR(" F"), planner.xy_freq_limit_hz); + SERIAL_ECHOPGM_P(PSTR(" S"), (planner.xy_freq_min_speed_factor * 100)); #endif + if (eol) SERIAL_EOL(); + #if ENABLED(DISTINCT_E_FACTORS) for (uint8_t i = 0; i < E_STEPPERS; ++i) { report_echo_start(forReplay); @@ -205,7 +219,11 @@ void GcodeSuite::M203_report(const bool forReplay/*=true*/) { TERN_(MARLIN_SMALL_BUILD, return); report_heading_etc(forReplay, F(STR_MAX_FEEDRATES)); + + bool eol = false; + #if NUM_AXES + eol = true; SERIAL_ECHOPGM_P( LIST_N(DOUBLE(NUM_AXES), PSTR(" M203 X"), LINEAR_UNIT(planner.settings.max_feedrate_mm_s[X_AXIS]), @@ -222,12 +240,11 @@ void GcodeSuite::M203_report(const bool forReplay/*=true*/) { #endif #if HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS) + eol = true; SERIAL_ECHOPGM_P(SP_E_STR, VOLUMETRIC_UNIT(planner.settings.max_feedrate_mm_s[E_AXIS])); #endif - #if NUM_AXES || (HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS)) - SERIAL_EOL(); - #endif + if (eol) SERIAL_EOL(); #if ENABLED(DISTINCT_E_FACTORS) for (uint8_t i = 0; i < E_STEPPERS; ++i) { From 3494482cb0a192024929fc14deee3cc7f329c386 Mon Sep 17 00:00:00 2001 From: Andrew <18502096+classicrocker883@users.noreply.github.com> Date: Tue, 27 May 2025 02:05:01 -0400 Subject: [PATCH 353/787] =?UTF-8?q?=F0=9F=8E=A8=20Misc.=20cleanup,=20tweak?= =?UTF-8?q?=20unused=20LED=5FGraduallyControl=20(#27422)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Scott Lahteine --- Marlin/src/lcd/e3v2/common/encoder.cpp | 17 +++++++++-------- Marlin/src/module/settings.cpp | 2 +- Marlin/src/module/stepper.cpp | 4 ++-- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/Marlin/src/lcd/e3v2/common/encoder.cpp b/Marlin/src/lcd/e3v2/common/encoder.cpp index 889d1c61f3..2ae16f8bb1 100644 --- a/Marlin/src/lcd/e3v2/common/encoder.cpp +++ b/Marlin/src/lcd/e3v2/common/encoder.cpp @@ -137,9 +137,8 @@ EncoderState encoderReceiveAnalyze() { // LED write data void LED_WriteData() { - uint8_t tempCounter_LED, tempCounter_Bit; - for (tempCounter_LED = 0; tempCounter_LED < LED_NUM; tempCounter_LED++) { - for (tempCounter_Bit = 0; tempCounter_Bit < 24; tempCounter_Bit++) { + for (uint8_t tempCounter_LED = 0; tempCounter_LED < LED_NUM; tempCounter_LED++) { + for (uint8_t tempCounter_Bit = 0; tempCounter_Bit < 24; tempCounter_Bit++) { if (LED_DataArray[tempCounter_LED] & (0x800000 >> tempCounter_Bit)) { LED_DATA_HIGH; DELAY_NS(300); @@ -190,20 +189,22 @@ EncoderState encoderReceiveAnalyze() { } } - struct { bool g, r, b; } led_flag = { false, false, false }; + struct { bool g, r, b; } led_flag; for (uint8_t i = 0; i < LED_NUM; i++) { + led_flag = { false, false, false }; while (1) { const uint8_t g = uint8_t(LED_DataArray[i] >> 16), r = uint8_t(LED_DataArray[i] >> 8), b = uint8_t(LED_DataArray[i]); if (g == led_data[i].g) led_flag.g = true; - else LED_DataArray[i] += (g > led_data[i].g) ? -0x010000 : 0x010000; + else LED_DataArray[i] += (g > led_data[i].g) ? -_BV32(16) : _BV32(16); if (r == led_data[i].r) led_flag.r = true; - else LED_DataArray[i] += (r > led_data[i].r) ? -0x000100 : 0x000100; + else LED_DataArray[i] += (r > led_data[i].r) ? -_BV32(8) : _BV32(8); if (b == led_data[i].b) led_flag.b = true; - else LED_DataArray[i] += (b > led_data[i].b) ? -0x000001 : 0x000001; + else LED_DataArray[i] += (b > led_data[i].b) ? -_BV32(0) : _BV32(0); + LED_WriteData(); - if (led_flag.r && led_flag.g && led_flag.b) break; + if (led_flag.g && led_flag.r && led_flag.b) break; delay(change_Interval); } } diff --git a/Marlin/src/module/settings.cpp b/Marlin/src/module/settings.cpp index 59cb7244e9..2161be5abc 100644 --- a/Marlin/src/module/settings.cpp +++ b/Marlin/src/module/settings.cpp @@ -655,7 +655,7 @@ typedef struct SettingsDataStruct { // Fixed-Time Motion // #if ENABLED(FT_MOTION) - ft_config_t ftMotion_cfg; // M493 + ft_config_t ftMotion_cfg; // M493 #endif // diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp index ad7995bfc7..e5255246e1 100644 --- a/Marlin/src/module/stepper.cpp +++ b/Marlin/src/module/stepper.cpp @@ -1557,7 +1557,7 @@ void Stepper::isr() { if (using_ftMotion) { ftMotion_stepper(); // Run FTM Stepping - + // Define 2.5 msec task for auxiliary functions. if (!ftMotion_nextAuxISR) { TERN_(BABYSTEPPING, if (babystep.has_steps()) babystepping_isr()); @@ -1566,7 +1566,7 @@ void Stepper::isr() { // Enable ISRs to reduce latency for higher priority ISRs hal.isr_on(); - + interval = FTM_MIN_TICKS; ftMotion_nextAuxISR -= interval; } From 843f79589cd3f305998f217af55914e9cacb11f6 Mon Sep 17 00:00:00 2001 From: Keith Bennett <13375512+thisiskeithb@users.noreply.github.com> Date: Tue, 27 May 2025 10:58:49 -0700 Subject: [PATCH 354/787] =?UTF-8?q?=F0=9F=94=A7=20Update=20BTT002=20SPI=20?= =?UTF-8?q?driver=20conditionals=20(#27887)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Counterpart to #27886 --- .../src/pins/stm32f4/pins_BTT_BTT002_V1_0.h | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/Marlin/src/pins/stm32f4/pins_BTT_BTT002_V1_0.h b/Marlin/src/pins/stm32f4/pins_BTT_BTT002_V1_0.h index bcbdaedcf2..0e059106b8 100644 --- a/Marlin/src/pins/stm32f4/pins_BTT_BTT002_V1_0.h +++ b/Marlin/src/pins/stm32f4/pins_BTT_BTT002_V1_0.h @@ -108,16 +108,19 @@ #endif // -// SPI pins for TMC2130 stepper drivers +// SPI pins for TMC2130, TMC2160, TMC2240, TMC2660, TMC5130, or TMC5160 stepper drivers // -#ifndef TMC_SPI_MOSI - #define TMC_SPI_MOSI PB15 -#endif -#ifndef TMC_SPI_MISO - #define TMC_SPI_MISO PB14 -#endif -#ifndef TMC_SPI_SCK - #define TMC_SPI_SCK PB13 +#if HAS_TMC_SPI + #define TMC_USE_SW_SPI + #ifndef TMC_SPI_MOSI + #define TMC_SPI_MOSI PB15 + #endif + #ifndef TMC_SPI_MISO + #define TMC_SPI_MISO PB14 + #endif + #ifndef TMC_SPI_SCK + #define TMC_SPI_SCK PB13 + #endif #endif #if HAS_TMC_UART From 88d368ad9ded208c7a8f10459aa2c560eed407db Mon Sep 17 00:00:00 2001 From: ellensp <530024+ellensp@users.noreply.github.com> Date: Wed, 28 May 2025 06:01:01 +1200 Subject: [PATCH 355/787] =?UTF-8?q?=F0=9F=A9=B9=20Misc=20temp=20sensor=20f?= =?UTF-8?q?ixups=20(#27884)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Scott Lahteine --- Marlin/src/HAL/GD32_MFL/temp_soc.h | 2 +- Marlin/src/HAL/STM32/temp_soc.h | 2 +- Marlin/src/module/temperature.cpp | 90 ++++++++++++++++-------------- 3 files changed, 51 insertions(+), 43 deletions(-) diff --git a/Marlin/src/HAL/GD32_MFL/temp_soc.h b/Marlin/src/HAL/GD32_MFL/temp_soc.h index eeb144c422..5f1be64e43 100644 --- a/Marlin/src/HAL/GD32_MFL/temp_soc.h +++ b/Marlin/src/HAL/GD32_MFL/temp_soc.h @@ -26,4 +26,4 @@ #define TS_TYPICAL_SLOPE 4.5 // TODO: Implement voltage scaling (calibrated Vrefint) and ADC resolution scaling (when applicable) -#define TEMP_SOC_SENSOR(RAW) ((TS_TYPICAL_V - (RAW) / float(OVERSAMPLENR) / float(HAL_ADC_RANGE) * (float(ADC_VREF_MV) / 1000)) / ((TS_TYPICAL_SLOPE) / 1000) + TS_TYPICAL_TEMP) +#define TEMP_SOC_SENSOR(RAW) ((TS_TYPICAL_V - (RAW) / float(OVERSAMPLENR) / float(HAL_ADC_RANGE) * (float(ADC_VREF_MV) / 1000.0f)) / ((TS_TYPICAL_SLOPE) / 1000.0f) + TS_TYPICAL_TEMP) diff --git a/Marlin/src/HAL/STM32/temp_soc.h b/Marlin/src/HAL/STM32/temp_soc.h index 05fad695c3..cc165dd5e4 100644 --- a/Marlin/src/HAL/STM32/temp_soc.h +++ b/Marlin/src/HAL/STM32/temp_soc.h @@ -341,6 +341,6 @@ #elif defined(TS_TYPICAL_V) && defined(TS_TYPICAL_SLOPE) && defined(TS_TYPICAL_TEMP) - #define TEMP_SOC_SENSOR(RAW) ((TS_TYPICAL_V - (RAW) / float(OVERSAMPLENR) / float(HAL_ADC_RANGE) * (float(ADC_VREF_MV) / 1000.0f)) / ((TS_TYPICAL_SLOPE) / 1000) + TS_TYPICAL_TEMP) + #define TEMP_SOC_SENSOR(RAW) ((TS_TYPICAL_V - (RAW) / float(OVERSAMPLENR) / float(HAL_ADC_RANGE) * (float(ADC_VREF_MV) / 1000.0f)) / ((TS_TYPICAL_SLOPE) / 1000.0f) + TS_TYPICAL_TEMP) #endif diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index 5c760a7689..c1684a9fe1 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -2460,11 +2460,6 @@ void Temperature::task() { UNUSED(ms); } -// For a 5V input the AD595 returns a value scaled with 10mV per °C. (Minimum input voltage is 5V.) -#define TEMP_AD595(RAW) ((RAW) * (ADC_VREF_MV / 10) / float(HAL_ADC_RANGE) / (OVERSAMPLENR) * (TEMP_SENSOR_AD595_GAIN) + TEMP_SENSOR_AD595_OFFSET) -// For a 5V input the AD8495 returns a value scaled with 5mV per °C. (Minimum input voltage is 2.7V.) -#define TEMP_AD8495(RAW) ((RAW) * (ADC_VREF_MV / 5) / float(HAL_ADC_RANGE) / (OVERSAMPLENR) * (TEMP_SENSOR_AD8495_GAIN) + TEMP_SENSOR_AD8495_OFFSET) - /** * Bisect search for the range of the 'raw' value, then interpolate * proportionally between the under and over values. @@ -2604,6 +2599,22 @@ void Temperature::task() { } #endif +#if ANY_THERMISTOR_IS(-1) + // For a 5V input the AD595 returns a value scaled with 10mV per °C. (Minimum input voltage is 5V.) + static constexpr celsius_float_t temp_ad595(const raw_adc_t raw) { + return raw * (float(ADC_VREF_MV) / 10.0f) / float(HAL_ADC_RANGE) / (OVERSAMPLENR) + * (TEMP_SENSOR_AD595_GAIN) + (TEMP_SENSOR_AD595_OFFSET); + } +#endif + +#if ANY_THERMISTOR_IS(-4) + // For a 5V input the AD8495 returns a value scaled with 5mV per °C. (Minimum input voltage is 2.7V.) + static constexpr celsius_float_t temp_ad8495(const raw_adc_t raw) { + return raw * (float(ADC_VREF_MV) / 5.0f) / float(HAL_ADC_RANGE) / (OVERSAMPLENR) + * (TEMP_SENSOR_AD8495_GAIN) + (TEMP_SENSOR_AD8495_OFFSET); + } +#endif + #if HAS_HOTEND // Derived from RepRap FiveD extruder::getTemperature() // For hot end temperature measurement. @@ -2630,9 +2641,9 @@ void Temperature::task() { return (int16_t)raw * 0.25f; #endif #elif TEMP_SENSOR_0_IS_AD595 - return TEMP_AD595(raw); + return temp_ad595(raw); #elif TEMP_SENSOR_0_IS_AD8495 - return TEMP_AD8495(raw); + return temp_ad8495(raw); #else break; #endif @@ -2649,9 +2660,9 @@ void Temperature::task() { return (int16_t)raw * 0.25f; #endif #elif TEMP_SENSOR_1_IS_AD595 - return TEMP_AD595(raw); + return temp_ad595(raw); #elif TEMP_SENSOR_1_IS_AD8495 - return TEMP_AD8495(raw); + return temp_ad8495(raw); #else break; #endif @@ -2668,9 +2679,9 @@ void Temperature::task() { return (int16_t)raw * 0.25f; #endif #elif TEMP_SENSOR_2_IS_AD595 - return TEMP_AD595(raw); + return temp_ad595(raw); #elif TEMP_SENSOR_2_IS_AD8495 - return TEMP_AD8495(raw); + return temp_ad8495(raw); #else break; #endif @@ -2678,9 +2689,9 @@ void Temperature::task() { #if TEMP_SENSOR_3_IS_CUSTOM return user_thermistor_to_deg_c(CTI_HOTEND_3, raw); #elif TEMP_SENSOR_3_IS_AD595 - return TEMP_AD595(raw); + return temp_ad595(raw); #elif TEMP_SENSOR_3_IS_AD8495 - return TEMP_AD8495(raw); + return temp_ad8495(raw); #else break; #endif @@ -2688,9 +2699,9 @@ void Temperature::task() { #if TEMP_SENSOR_4_IS_CUSTOM return user_thermistor_to_deg_c(CTI_HOTEND_4, raw); #elif TEMP_SENSOR_4_IS_AD595 - return TEMP_AD595(raw); + return temp_ad595(raw); #elif TEMP_SENSOR_4_IS_AD8495 - return TEMP_AD8495(raw); + return temp_ad8495(raw); #else break; #endif @@ -2698,9 +2709,9 @@ void Temperature::task() { #if TEMP_SENSOR_5_IS_CUSTOM return user_thermistor_to_deg_c(CTI_HOTEND_5, raw); #elif TEMP_SENSOR_5_IS_AD595 - return TEMP_AD595(raw); + return temp_ad595(raw); #elif TEMP_SENSOR_5_IS_AD8495 - return TEMP_AD8495(raw); + return temp_ad8495(raw); #else break; #endif @@ -2708,9 +2719,9 @@ void Temperature::task() { #if TEMP_SENSOR_6_IS_CUSTOM return user_thermistor_to_deg_c(CTI_HOTEND_6, raw); #elif TEMP_SENSOR_6_IS_AD595 - return TEMP_AD595(raw); + return temp_ad595(raw); #elif TEMP_SENSOR_6_IS_AD8495 - return TEMP_AD8495(raw); + return temp_ad8495(raw); #else break; #endif @@ -2718,9 +2729,9 @@ void Temperature::task() { #if TEMP_SENSOR_7_IS_CUSTOM return user_thermistor_to_deg_c(CTI_HOTEND_7, raw); #elif TEMP_SENSOR_7_IS_AD595 - return TEMP_AD595(raw); + return temp_ad595(raw); #elif TEMP_SENSOR_7_IS_AD8495 - return TEMP_AD8495(raw); + return temp_ad8495(raw); #else break; #endif @@ -2754,9 +2765,9 @@ void Temperature::task() { #elif TEMP_SENSOR_BED_IS_THERMISTOR SCAN_THERMISTOR_TABLE(TEMPTABLE_BED, TEMPTABLE_BED_LEN); #elif TEMP_SENSOR_BED_IS_AD595 - return TEMP_AD595(raw); + return temp_ad595(raw); #elif TEMP_SENSOR_BED_IS_AD8495 - return TEMP_AD8495(raw); + return temp_ad8495(raw); #else UNUSED(raw); return 0; @@ -2772,9 +2783,9 @@ void Temperature::task() { #elif TEMP_SENSOR_CHAMBER_IS_THERMISTOR SCAN_THERMISTOR_TABLE(TEMPTABLE_CHAMBER, TEMPTABLE_CHAMBER_LEN); #elif TEMP_SENSOR_CHAMBER_IS_AD595 - return TEMP_AD595(raw); + return temp_ad595(raw); #elif TEMP_SENSOR_CHAMBER_IS_AD8495 - return TEMP_AD8495(raw); + return temp_ad8495(raw); #else UNUSED(raw); return 0; @@ -2790,9 +2801,9 @@ void Temperature::task() { #elif TEMP_SENSOR_COOLER_IS_THERMISTOR SCAN_THERMISTOR_TABLE(TEMPTABLE_COOLER, TEMPTABLE_COOLER_LEN); #elif TEMP_SENSOR_COOLER_IS_AD595 - return TEMP_AD595(raw); + return temp_ad595(raw); #elif TEMP_SENSOR_COOLER_IS_AD8495 - return TEMP_AD8495(raw); + return temp_ad8495(raw); #else UNUSED(raw); return 0; @@ -2808,9 +2819,9 @@ void Temperature::task() { #elif TEMP_SENSOR_PROBE_IS_THERMISTOR SCAN_THERMISTOR_TABLE(TEMPTABLE_PROBE, TEMPTABLE_PROBE_LEN); #elif TEMP_SENSOR_PROBE_IS_AD595 - return TEMP_AD595(raw); + return temp_ad595(raw); #elif TEMP_SENSOR_PROBE_IS_AD8495 - return TEMP_AD8495(raw); + return temp_ad8495(raw); #else UNUSED(raw); return 0; @@ -2826,9 +2837,9 @@ void Temperature::task() { #elif TEMP_SENSOR_BOARD_IS_THERMISTOR SCAN_THERMISTOR_TABLE(TEMPTABLE_BOARD, TEMPTABLE_BOARD_LEN); #elif TEMP_SENSOR_BOARD_IS_AD595 - return TEMP_AD595(raw); + return temp_ad595(raw); #elif TEMP_SENSOR_BOARD_IS_AD8495 - return TEMP_AD8495(raw); + return temp_ad8495(raw); #else UNUSED(raw); return 0; @@ -2839,14 +2850,11 @@ void Temperature::task() { #if HAS_TEMP_SOC // For SoC temperature measurement. celsius_float_t Temperature::analog_to_celsius_soc(const raw_adc_t raw) { - return ( - #ifdef TEMP_SOC_SENSOR - TEMP_SOC_SENSOR(raw) - #else - 0 - #error "TEMP_SENSOR_SOC requires the TEMP_SOC_SENSOR(RAW) macro to be defined for your board." - #endif - ); + #ifndef TEMP_SOC_SENSOR + #error "TEMP_SENSOR_SOC requires the TEMP_SOC_SENSOR(RAW) macro to be defined for your board." + #define TEMP_SOC_SENSOR(...) 0 + #endif + return TEMP_SOC_SENSOR(raw); } #endif @@ -2864,9 +2872,9 @@ void Temperature::task() { #elif TEMP_SENSOR_REDUNDANT_IS_THERMISTOR SCAN_THERMISTOR_TABLE(TEMPTABLE_REDUNDANT, TEMPTABLE_REDUNDANT_LEN); #elif TEMP_SENSOR_REDUNDANT_IS_AD595 - return TEMP_AD595(raw); + return temp_ad595(raw); #elif TEMP_SENSOR_REDUNDANT_IS_AD8495 - return TEMP_AD8495(raw); + return temp_ad8495(raw); #else UNUSED(raw); return 0; From d0e8edad3c5f836dd7f7c200e74bf660c587aee0 Mon Sep 17 00:00:00 2001 From: David Buezas Date: Tue, 27 May 2025 20:15:38 +0200 Subject: [PATCH 356/787] =?UTF-8?q?=F0=9F=90=9B=20More=20robust=20Smooth?= =?UTF-8?q?=20Linear=20Advance=20(#27862)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Scott Lahteine --- Marlin/src/module/stepper.cpp | 55 +++++++++++++++++------------------ 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp index e5255246e1..edfed3b8e2 100644 --- a/Marlin/src/module/stepper.cpp +++ b/Marlin/src/module/stepper.cpp @@ -2921,8 +2921,13 @@ hal_timer_t Stepper::block_phase_isr() { if (++index == IS_COMPENSATION_BUFFER_SIZE) index = 0; } FORCE_INLINE xy_long_t past_item(const uint16_t n) { - const int16_t i = int16_t(index) - n; - return buffer[i >= 0 ? i : i + IS_COMPENSATION_BUFFER_SIZE]; + int16_t i = int16_t(index) - n; + if (i < 0) i += IS_COMPENSATION_BUFFER_SIZE; + // The following only happens when IS Freq is set below the minimum + // configured at build time ...in which case IS will also misbehave! + // Using setters whenever possible prevents values being set too low. + if (TERN0(MARLIN_DEV_MODE, i < 0)) return {0, 0}; + return buffer[i]; } } DelayBuffer; @@ -2995,44 +3000,38 @@ hal_timer_t Stepper::block_phase_isr() { ? MULT_Q(30, curr_step_rate, current_block->e_step_ratio_q30) : 0; - int32_t total_step_rate = la_step_rate + planned_step_rate; - #if ENABLED(INPUT_SHAPING_E_SYNC) - xy_long_t pre_shaping_rate = xy_long_t({0, 0}), - first_pulse_rate = xy_long_t({0, 0}); - int32_t unshaped_rate_e = total_step_rate; - if (current_block) { - if (current_block->xy_length_inv_q30 > 0) { - unshaped_rate_e = 0; + int32_t unshaped_rate_e = la_step_rate + planned_step_rate; - pre_shaping_rate = xy_long_t({ - TERN0(INPUT_SHAPING_X, MULT_Q(30, total_step_rate * current_block->steps.x, current_block->xy_length_inv_q30)), - TERN0(INPUT_SHAPING_Y, MULT_Q(30, total_step_rate * current_block->steps.y, current_block->xy_length_inv_q30)) - }); + xy_long_t pre_shaping_rate{0}, first_pulse_rate{0}; + if (current_block && current_block->xy_length_inv_q30 > 0) { + pre_shaping_rate = xy_long_t({ + MULT_Q(30, unshaped_rate_e * current_block->steps.x, current_block->xy_length_inv_q30), + MULT_Q(30, unshaped_rate_e * current_block->steps.y, current_block->xy_length_inv_q30) + }); + unshaped_rate_e = 0; - first_pulse_rate = xy_long_t({ - TERN0(INPUT_SHAPING_X, (pre_shaping_rate.x * Stepper::shaping_x.factor1) >> 7), - TERN0(INPUT_SHAPING_Y, (pre_shaping_rate.y * Stepper::shaping_y.factor1) >> 7) - }); - } + first_pulse_rate = xy_long_t({ + TERN_(INPUT_SHAPING_X, shaping_x.enabled ? (pre_shaping_rate.x * shaping_x.factor1) >> 7 :) pre_shaping_rate.x, + TERN_(INPUT_SHAPING_Y, shaping_y.enabled ? (pre_shaping_rate.y * shaping_y.factor1) >> 7 :) pre_shaping_rate.y + }); } - const xy_long_t second_pulse_rate = { - TERN0(INPUT_SHAPING_X, (smooth_lin_adv_lookback(ShapingQueue::get_delay_x()).x * Stepper::shaping_x.factor2)) >> 7, - TERN0(INPUT_SHAPING_Y, (smooth_lin_adv_lookback(ShapingQueue::get_delay_y()).y * Stepper::shaping_y.factor2)) >> 7 - }; + const xy_long_t second_pulse_rate = xy_long_t({ + TERN0(INPUT_SHAPING_X, shaping_x.enabled ? (smooth_lin_adv_lookback(ShapingQueue::get_delay_x()).x * shaping_x.factor2) >> 7 : 0), + TERN0(INPUT_SHAPING_Y, shaping_y.enabled ? (smooth_lin_adv_lookback(ShapingQueue::get_delay_y()).y * shaping_y.factor2) >> 7 : 0) + }); delayBuffer.add(pre_shaping_rate); - const int32_t x = TERN0(INPUT_SHAPING_X, first_pulse_rate.x + second_pulse_rate.x), - y = TERN0(INPUT_SHAPING_Y, first_pulse_rate.y + second_pulse_rate.y); + set_la_interval(unshaped_rate_e + first_pulse_rate.x + second_pulse_rate.x + first_pulse_rate.y + second_pulse_rate.y); - total_step_rate = unshaped_rate_e + x + y; + #else // !INPUT_SHAPING_E_SYNC - #endif // INPUT_SHAPING_E_SYNC + set_la_interval(la_step_rate + planned_step_rate); - set_la_interval(total_step_rate); + #endif curr_timer_tick += SMOOTH_LIN_ADV_INTERVAL; return SMOOTH_LIN_ADV_INTERVAL; From c20c6b61f1a9222f0550356eeadb7007e5c78f5a Mon Sep 17 00:00:00 2001 From: staff1010 <132726146+staff1010@users.noreply.github.com> Date: Wed, 28 May 2025 03:49:19 +0800 Subject: [PATCH 357/787] =?UTF-8?q?=F0=9F=9A=B8=20Improve=20MKS=20UI=20wit?= =?UTF-8?q?h=20LVGL=20v6.1.2=20(#27889)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/lcd/extui/mks_ui/draw_ui.cpp | 21 +- Marlin/src/lcd/extui/mks_ui/pic_manager.cpp | 133 +- Marlin/src/lcd/extui/mks_ui/pic_manager.h | 15 +- .../extui/mks_ui/tft_lvgl_configuration.cpp | 27 +- .../lcd/extui/mks_ui/tft_lvgl_configuration.h | 2 +- Marlin/src/lcd/extui/mks_ui/uthash.h | 1137 +++++++++++++++++ ini/features.ini | 2 +- 7 files changed, 1277 insertions(+), 60 deletions(-) create mode 100644 Marlin/src/lcd/extui/mks_ui/uthash.h diff --git a/Marlin/src/lcd/extui/mks_ui/draw_ui.cpp b/Marlin/src/lcd/extui/mks_ui/draw_ui.cpp index 4278092472..875f2d8e72 100644 --- a/Marlin/src/lcd/extui/mks_ui/draw_ui.cpp +++ b/Marlin/src/lcd/extui/mks_ui/draw_ui.cpp @@ -579,7 +579,7 @@ char *creat_title_text() { update_spi_flash(); } card.closefile(); - #endif + #endif // HAS_MEDIA } void gcode_preview(char *path, int xpos_pixel, int ypos_pixel) { @@ -662,27 +662,27 @@ char *creat_title_text() { } void draw_default_preview(int xpos_pixel, int ypos_pixel, uint8_t sel) { - int index; + static constexpr uint16_t draw_col_count = 40; // Number of rows displayed each time, determines the size of bmp_public_buf + static constexpr int draw_count = 200 / draw_col_count; // Total number of times to be displayed + static constexpr uint32_t pixel_count = (DEFAULT_VIEW_MAX_SIZE) / draw_count; // Number of pixels read per time (uint8_t) int y_off = 0; - W25QXX.init(SPI_QUARTER_SPEED); - for (index = 0; index < 10; index++) { // 200*200 + for (int index = 0; index < draw_count; index++) { // 200*200 #if HAS_BAK_VIEW_IN_FLASH if (sel == 1) { - flash_view_Read(bmp_public_buf, 8000); // 20k + flash_view_Read(bmp_public_buf, pixel_count); // 16k } else { - default_view_Read(bmp_public_buf, DEFAULT_VIEW_MAX_SIZE / 10); // 8k + default_view_Read(bmp_public_buf, pixel_count); // 16k } #else - default_view_Read(bmp_public_buf, DEFAULT_VIEW_MAX_SIZE / 10); // 8k + default_view_Read(bmp_public_buf, pixel_count); // 8k #endif - SPI_TFT.setWindow(xpos_pixel, y_off * 20 + ypos_pixel, 200, 20); // 200*200 - SPI_TFT.tftio.writeSequence((uint16_t*)(bmp_public_buf), DEFAULT_VIEW_MAX_SIZE / 20); + SPI_TFT.setWindow(xpos_pixel, y_off * draw_col_count + ypos_pixel, 200, draw_col_count); // 200 * draw_col_count + SPI_TFT.tftio.writeSequence((uint16_t*)(bmp_public_buf), uint16_t(pixel_count / 2)); y_off++; } - W25QXX.init(SPI_QUARTER_SPEED); } void disp_pre_gcode(int xpos_pixel, int ypos_pixel) { @@ -700,6 +700,7 @@ char *creat_title_text() { } #endif } + #endif // HAS_GCODE_PREVIEW void print_time_run() { diff --git a/Marlin/src/lcd/extui/mks_ui/pic_manager.cpp b/Marlin/src/lcd/extui/mks_ui/pic_manager.cpp index 04ea827236..5db110ec1b 100644 --- a/Marlin/src/lcd/extui/mks_ui/pic_manager.cpp +++ b/Marlin/src/lcd/extui/mks_ui/pic_manager.cpp @@ -35,6 +35,10 @@ #include +#if ENABLED(USE_HASH_TABLE) + #include "uthash.h" +#endif + extern uint16_t DeviceCode; #if HAS_MEDIA @@ -92,7 +96,7 @@ static FSTR_P const assets[] = { F("bmp_file.bin"), // Move motor screen - // TODO: 6 equal icons, just in diffenct rotation... it may be optimized too + // TODO: 6 equal icons, just in different rotation... it may be optimized too F("bmp_xAdd.bin"), F("bmp_xDec.bin"), F("bmp_yAdd.bin"), @@ -223,42 +227,98 @@ static FSTR_P const assets[] = { static FSTR_P const fonts[] = { F("FontUNIGBK.bin") }; #endif -uint8_t currentFlashPage = 0; +#if HAS_SPI_FLASH_COMPRESSION + uint8_t currentFlashPage = 0; +#endif -uint32_t lv_get_pic_addr(uint8_t *Pname) { - uint8_t Pic_cnt; - uint8_t i, j; - PIC_MSG PIC; - uint32_t tmp_cnt = 0; - uint32_t addr = 0; +#if ENABLED(USE_HASH_TABLE) - currentFlashPage = 0; + typedef struct { + char name[PIC_NAME_MAX_LEN - PIC_NAME_OFFSET]; /* key */ + uint32_t addr; + UT_hash_handle hh; /* makes this structure hashable */ + } PicHashEntry; - #if ENABLED(MARLIN_DEV_MODE) - SERIAL_ECHOLNPGM("Getting picture SPI Flash Address: ", (const char*)Pname); - #endif + PicHashEntry* pic_hash = NULL; - W25QXX.init(SPI_QUARTER_SPEED); + // Initialize the image address hash table + void init_img_map() { + uint8_t Pic_cnt; + W25QXX.SPI_FLASH_BufferRead(&Pic_cnt, PIC_COUNTER_ADDR, 1); + if (Pic_cnt == 0xFF) Pic_cnt = 0; - W25QXX.SPI_FLASH_BufferRead(&Pic_cnt, PIC_COUNTER_ADDR, 1); - if (Pic_cnt == 0xFF) Pic_cnt = 0; - for (i = 0; i < Pic_cnt; i++) { - j = 0; - do { - W25QXX.SPI_FLASH_BufferRead(&PIC.name[j], PIC_NAME_ADDR + tmp_cnt, 1); - tmp_cnt++; - } while (PIC.name[j++] != '\0'); + uint32_t tmp_cnt = 0; + for (uint8_t i = 0; i < Pic_cnt; i++) { + char name[PIC_NAME_MAX_LEN - PIC_NAME_OFFSET]; + uint8_t j = 0; + do { + W25QXX.SPI_FLASH_BufferRead((uint8_t*)&name[j], PIC_NAME_ADDR + tmp_cnt, 1); + tmp_cnt++; + } while (name[j++] != '\0'); - if ((strcasecmp((char*)Pname, (char*)PIC.name)) == 0) { + uint32_t addr; if (DeviceCode == 0x9488 || DeviceCode == 0x5761) addr = PIC_DATA_ADDR_TFT35 + i * PER_PIC_MAX_SPACE_TFT35; else addr = PIC_DATA_ADDR_TFT32 + i * PER_PIC_MAX_SPACE_TFT32; - return addr; + + // Add to hash table, don't save "bmp_" + PicHashEntry* entry = (PicHashEntry*)malloc(sizeof(*entry)); + strncpy(entry->name, (name + PIC_NAME_OFFSET), sizeof(name)); + entry->addr = addr; + HASH_ADD_STR(pic_hash, name, entry); } + #if ENABLED(MARLIN_DEV_MODE) + SERIAL_ECHOLNPGM("Image Hash Table Count: ", HASH_COUNT(pic_hash), ", Size(Bytes): ", HASH_OVERHEAD(hh, pic_hash)); + #endif } - return addr; -} + + uint32_t lv_get_pic_addr(uint8_t *Pname) { + #if ENABLED(MARLIN_DEV_MODE) + SERIAL_ECHOLNPGM("Getting picture SPI Flash Address: ", (const char*)Pname); + #endif + + PicHashEntry* entry; + HASH_FIND_STR(pic_hash, (char*)(Pname + PIC_NAME_OFFSET), entry); + return entry ? entry->addr : 0; + } + +#else // !USE_HASH_TABLE + + uint32_t lv_get_pic_addr(uint8_t *Pname) { + uint8_t Pic_cnt; + uint8_t i, j; + PIC_MSG PIC; + uint32_t tmp_cnt = 0; + uint32_t addr = 0; + + #if ENABLED(MARLIN_DEV_MODE) + SERIAL_ECHOLNPGM("Getting picture SPI Flash Address: ", (const char*)Pname); + #endif + + W25QXX.init(SPI_QUARTER_SPEED); + + W25QXX.SPI_FLASH_BufferRead(&Pic_cnt, PIC_COUNTER_ADDR, 1); + if (Pic_cnt == 0xFF) Pic_cnt = 0; + for (i = 0; i < Pic_cnt; i++) { + j = 0; + do { + W25QXX.SPI_FLASH_BufferRead(&PIC.name[j], PIC_NAME_ADDR + tmp_cnt, 1); + tmp_cnt++; + } while (PIC.name[j++] != '\0'); + + if ((strcasecmp((char*)Pname, (char*)PIC.name)) == 0) { + if (DeviceCode == 0x9488 || DeviceCode == 0x5761) + addr = PIC_DATA_ADDR_TFT35 + i * PER_PIC_MAX_SPACE_TFT35; + else + addr = PIC_DATA_ADDR_TFT32 + i * PER_PIC_MAX_SPACE_TFT32; + break; + } + } + return addr; + } + +#endif // !USE_HASH_TABLE const char *assetsPath = "assets"; const char *bakPath = "_assets"; @@ -309,8 +369,8 @@ uint8_t picLogoWrite(uint8_t *LogoName, uint8_t *Logo_Wbuff, uint32_t LogoWriteS uint32_t TitleLogoWrite_Addroffset = 0; uint8_t picTitleLogoWrite(uint8_t *TitleLogoName, uint8_t *TitleLogo_Wbuff, uint32_t TitleLogoWriteSize) { - if (TitleLogoWriteSize <= 0) - return 0; + if (TitleLogoWriteSize <= 0) return 0; + if ((DeviceCode == 0x9488) || (DeviceCode == 0x5761)) W25QXX.SPI_FLASH_BufferWrite(TitleLogo_Wbuff, PIC_ICON_LOGO_ADDR_TFT35 + TitleLogoWrite_Addroffset, TitleLogoWriteSize); else @@ -341,9 +401,7 @@ uint32_t picInfoWrite(uint8_t *P_name, uint32_t P_size) { union union32 size_tmp; W25QXX.SPI_FLASH_BufferRead(&pic_counter, PIC_COUNTER_ADDR, 1); - - if (pic_counter == 0xFF) - pic_counter = 0; + if (pic_counter == 0xFF) pic_counter = 0; if ((DeviceCode == 0x9488) || (DeviceCode == 0x5761)) picSaveAddr = PIC_DATA_ADDR_TFT35 + pic_counter * PER_PIC_MAX_SPACE_TFT35; @@ -416,6 +474,7 @@ uint32_t picInfoWrite(uint8_t *P_name, uint32_t P_size) { } hal.watchdog_refresh(); + disp_string(100, 165, FTOP(F(" ")), 0xFFFF, 0x0000); // clean string disp_assets_update_progress(fn); W25QXX.init(SPI_QUARTER_SPEED); @@ -449,16 +508,18 @@ uint32_t picInfoWrite(uint8_t *P_name, uint32_t P_size) { } else if (assetType == ASSET_TYPE_ICON) { Pic_Write_Addr = picInfoWrite((uint8_t*)fn, pfileSize); - SPIFlash.beginWrite(Pic_Write_Addr); #if HAS_SPI_FLASH_COMPRESSION + SPIFlash.beginWrite(Pic_Write_Addr); do { hal.watchdog_refresh(); pbr = file.read(public_buf, SPI_FLASH_PageSize); TERN_(MARLIN_DEV_MODE, totalSizes += pbr); SPIFlash.writeData(public_buf, SPI_FLASH_PageSize); } while (pbr >= SPI_FLASH_PageSize); + SPIFlash.endWrite(); #else do { + hal.watchdog_refresh(); pbr = file.read(public_buf, BMP_WRITE_BUF_LEN); W25QXX.SPI_FLASH_BufferWrite(public_buf, Pic_Write_Addr, pbr); Pic_Write_Addr += pbr; @@ -468,7 +529,6 @@ uint32_t picInfoWrite(uint8_t *P_name, uint32_t P_size) { SERIAL_ECHOLNPGM("Space used: ", fn, " - ", (SPIFlash.getCurrentPage() + 1) * SPI_FLASH_PageSize / 1024, "KB"); totalCompressed += (SPIFlash.getCurrentPage() + 1) * SPI_FLASH_PageSize; #endif - SPIFlash.endWrite(); } else if (assetType == ASSET_TYPE_FONT) { Pic_Write_Addr = UNIGBK_FLASH_ADDR; @@ -557,8 +617,7 @@ void picRead(uint8_t *Pname, uint8_t *P_Rbuff) { PIC_MSG PIC; W25QXX.SPI_FLASH_BufferRead(&Pic_cnt, PIC_COUNTER_ADDR, 1); - if (Pic_cnt == 0xFF) - Pic_cnt = 0; + if (Pic_cnt == 0xFF) Pic_cnt = 0; for (i = 0; i < Pic_cnt; i++) { j = 0; @@ -578,12 +637,12 @@ void picRead(uint8_t *Pname, uint8_t *P_Rbuff) { void lv_pic_test(uint8_t *P_Rbuff, uint32_t addr, uint32_t size) { #if HAS_SPI_FLASH_COMPRESSION - if (currentFlashPage == 0) + if (currentFlashPage == 0) { + currentFlashPage = 1; SPIFlash.beginRead(addr); + } SPIFlash.readData(P_Rbuff, size); - currentFlashPage++; #else - W25QXX.init(SPI_QUARTER_SPEED); W25QXX.SPI_FLASH_BufferRead((uint8_t *)P_Rbuff, addr, size); #endif } diff --git a/Marlin/src/lcd/extui/mks_ui/pic_manager.h b/Marlin/src/lcd/extui/mks_ui/pic_manager.h index 1483b96461..30003a16d6 100644 --- a/Marlin/src/lcd/extui/mks_ui/pic_manager.h +++ b/Marlin/src/lcd/extui/mks_ui/pic_manager.h @@ -29,6 +29,9 @@ #include #include +#include "SPIFlashStorage.h" + +#define USE_HASH_TABLE #ifndef HAS_SPI_FLASH_FONT #define HAS_SPI_FLASH_FONT 1 // Disabled until fix the font load code @@ -53,7 +56,8 @@ #endif #define PIC_MAX_CN 100 // Maximum number of pictures -#define PIC_NAME_MAX_LEN 50 // Picture name maximum length +#define PIC_NAME_MAX_LEN 30 // Picture name maximum length +#define PIC_NAME_OFFSET 4 // Same picture filename section #define LOGO_MAX_SIZE_TFT35 (300 * 1024) #define LOGO_MAX_SIZE_TFT32 (150 * 1024) @@ -61,7 +65,11 @@ #define DEFAULT_VIEW_MAX_SIZE (200 * 200 * 2) #define FLASH_VIEW_MAX_SIZE (200 * 200 * 2) -#define PER_PIC_MAX_SPACE_TFT35 (9 * 1024) +#if HAS_SPI_FLASH_COMPRESSION + #define PER_PIC_MAX_SPACE_TFT35 ( 9 * 1024) +#else + #define PER_PIC_MAX_SPACE_TFT35 (32 * 1024) +#endif #define PER_PIC_MAX_SPACE_TFT32 (16 * 1024) #define PER_FONT_MAX_SPACE (16 * 1024) @@ -154,6 +162,9 @@ typedef struct pic_msg PIC_MSG; #define PIC_SIZE_xM 6 #define FONT_SIZE_xM 2 +#if ENABLED(USE_HASH_TABLE) + void init_img_map(); +#endif void picRead(uint8_t *Pname, uint8_t *P_Rbuff); void picLogoRead(uint8_t *LogoName, uint8_t *Logo_Rbuff, uint32_t LogoReadsize); void lv_pic_test(uint8_t *P_Rbuff, uint32_t addr, uint32_t size); diff --git a/Marlin/src/lcd/extui/mks_ui/tft_lvgl_configuration.cpp b/Marlin/src/lcd/extui/mks_ui/tft_lvgl_configuration.cpp index 903afad884..0ea29dda0c 100644 --- a/Marlin/src/lcd/extui/mks_ui/tft_lvgl_configuration.cpp +++ b/Marlin/src/lcd/extui/mks_ui/tft_lvgl_configuration.cpp @@ -85,7 +85,7 @@ lv_group_t* g; uint16_t DeviceCode = 0x9488; extern uint8_t sel_id; -uint8_t bmp_public_buf[14 * 1024]; +uint8_t bmp_public_buf[16 * 1024]; uint8_t public_buf[513]; extern bool flash_preview_begin, default_preview_flg, gcode_preview_over; @@ -149,9 +149,14 @@ void tft_lvgl_init() { touch.init(); + #if ENABLED(USE_HASH_TABLE) + init_img_map(); // Initialize the image address hash table + hal.watchdog_refresh(); // Hash table init takes time + #endif + lv_init(); - lv_disp_buf_init(&disp_buf, bmp_public_buf, nullptr, LV_HOR_RES_MAX * 14); // Initialize the display buffer + lv_disp_buf_init(&disp_buf, bmp_public_buf, nullptr, LV_HOR_RES_MAX * 17); // Initialize the display buffer lv_disp_drv_t disp_drv; // Descriptor of a display driver lv_disp_drv_init(&disp_drv); // Basic initialization @@ -268,8 +273,6 @@ void my_disp_flush(lv_disp_drv_t * disp, const lv_area_t * area, lv_color_t * co SPI_TFT.tftio.writeSequence((uint16_t*)color_p, width * height); lv_disp_flush_ready(disp_drv_p); // Indicate you are ready with the flushing #endif - - W25QXX.init(SPI_QUARTER_SPEED); } #if ENABLED(USE_SPI_DMA_TC) @@ -327,20 +330,26 @@ bool my_mousewheel_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data) { return false; // No more data to read so return false } -extern uint8_t currentFlashPage; +#if HAS_SPI_FLASH_COMPRESSION + extern uint8_t currentFlashPage; +#endif // spi_flash uint32_t pic_read_base_addr = 0, pic_read_addr_offset = 0; lv_fs_res_t spi_flash_open_cb (lv_fs_drv_t * drv, void * file_p, const char * path, lv_fs_mode_t mode) { static char last_path_name[30]; + #if HAS_SPI_FLASH_COMPRESSION + currentFlashPage = 0; + #endif if (strcasecmp(last_path_name, path) != 0) { pic_read_base_addr = lv_get_pic_addr((uint8_t *)path); + // clean lvgl image cache + char cache_path_name[30 + 3] = {0}; + strcat(cache_path_name, "F:/"); + strcat(cache_path_name, (const char *)last_path_name); + lv_img_cache_invalidate_src(cache_path_name); strcpy(last_path_name, path); } - else { - W25QXX.init(SPI_QUARTER_SPEED); - currentFlashPage = 0; - } pic_read_addr_offset = pic_read_base_addr; return LV_FS_RES_OK; } diff --git a/Marlin/src/lcd/extui/mks_ui/tft_lvgl_configuration.h b/Marlin/src/lcd/extui/mks_ui/tft_lvgl_configuration.h index 43e82bd34d..606fdb50e0 100644 --- a/Marlin/src/lcd/extui/mks_ui/tft_lvgl_configuration.h +++ b/Marlin/src/lcd/extui/mks_ui/tft_lvgl_configuration.h @@ -32,7 +32,7 @@ #include -extern uint8_t bmp_public_buf[14 * 1024]; +extern uint8_t bmp_public_buf[16 * 1024]; extern uint8_t public_buf[513]; void tft_lvgl_init(); diff --git a/Marlin/src/lcd/extui/mks_ui/uthash.h b/Marlin/src/lcd/extui/mks_ui/uthash.h new file mode 100644 index 0000000000..06c2eebdb8 --- /dev/null +++ b/Marlin/src/lcd/extui/mks_ui/uthash.h @@ -0,0 +1,1137 @@ +/* +Copyright (c) 2003-2025, Troy D. Hanson https://troydhanson.github.io/uthash/ +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef UTHASH_H +#define UTHASH_H + +#define UTHASH_VERSION 2.3.0 + +#include /* memcmp, memset, strlen */ +#include /* ptrdiff_t */ +#include /* exit */ + +#if defined(HASH_NO_STDINT) && HASH_NO_STDINT +/* The user doesn't have , and must figure out their own way + to provide definitions for uint8_t and uint32_t. */ +#else +#include /* uint8_t, uint32_t */ +#endif + +/* These macros use decltype or the earlier __typeof GNU extension. + As decltype is only available in newer compilers (VS2010 or gcc 4.3+ + when compiling c++ source) this code uses whatever method is needed + or, for VS2008 where neither is available, uses casting workarounds. */ +#if !defined(DECLTYPE) && !defined(NO_DECLTYPE) +#if defined(_MSC_VER) /* MS compiler */ +#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ +#define DECLTYPE(x) (decltype(x)) +#else /* VS2008 or older (or VS2010 in C mode) */ +#define NO_DECLTYPE +#endif +#elif defined(__MCST__) /* Elbrus C Compiler */ +#define DECLTYPE(x) (__typeof(x)) +#elif defined(__BORLANDC__) || defined(__ICCARM__) || defined(__LCC__) || defined(__WATCOMC__) +#define NO_DECLTYPE +#else /* GNU, Sun and other compilers */ +#define DECLTYPE(x) (__typeof(x)) +#endif +#endif + +#ifdef NO_DECLTYPE +#define DECLTYPE(x) +#define DECLTYPE_ASSIGN(dst,src) \ +do { \ + char **_da_dst = (char**)(&(dst)); \ + *_da_dst = (char*)(src); \ +} while (0) +#else +#define DECLTYPE_ASSIGN(dst,src) \ +do { \ + (dst) = DECLTYPE(dst)(src); \ +} while (0) +#endif + +#ifndef uthash_malloc +#define uthash_malloc(sz) malloc(sz) /* malloc fcn */ +#endif +#ifndef uthash_free +#define uthash_free(ptr,sz) free(ptr) /* free fcn */ +#endif +#ifndef uthash_bzero +#define uthash_bzero(a,n) memset(a,'\0',n) +#endif +#ifndef uthash_strlen +#define uthash_strlen(s) strlen(s) +#endif + +#ifndef HASH_FUNCTION +#define HASH_FUNCTION(keyptr,keylen,hashv) HASH_JEN(keyptr, keylen, hashv) +#endif + +#ifndef HASH_KEYCMP +#define HASH_KEYCMP(a,b,n) memcmp(a,b,n) +#endif + +#ifndef uthash_noexpand_fyi +#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */ +#endif +#ifndef uthash_expand_fyi +#define uthash_expand_fyi(tbl) /* can be defined to log expands */ +#endif + +#ifndef HASH_NONFATAL_OOM +#define HASH_NONFATAL_OOM 0 +#endif + +#if HASH_NONFATAL_OOM +/* malloc failures can be recovered from */ + +#ifndef uthash_nonfatal_oom +#define uthash_nonfatal_oom(obj) do {} while (0) /* non-fatal OOM error */ +#endif + +#define HASH_RECORD_OOM(oomed) do { (oomed) = 1; } while (0) +#define IF_HASH_NONFATAL_OOM(x) x + +#else +/* malloc failures result in lost memory, hash tables are unusable */ + +#ifndef uthash_fatal +#define uthash_fatal(msg) exit(-1) /* fatal OOM error */ +#endif + +#define HASH_RECORD_OOM(oomed) uthash_fatal("out of memory") +#define IF_HASH_NONFATAL_OOM(x) + +#endif + +/* initial number of buckets */ +#define HASH_INITIAL_NUM_BUCKETS 32U /* initial number of buckets */ +#define HASH_INITIAL_NUM_BUCKETS_LOG2 5U /* lg2 of initial number of buckets */ +#define HASH_BKT_CAPACITY_THRESH 10U /* expand when bucket count reaches */ + +/* calculate the element whose hash handle address is hhp */ +#define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho))) +/* calculate the hash handle from element address elp */ +#define HH_FROM_ELMT(tbl,elp) ((UT_hash_handle*)(void*)(((char*)(elp)) + ((tbl)->hho))) + +#define HASH_ROLLBACK_BKT(hh, head, itemptrhh) \ +do { \ + struct UT_hash_handle *_hd_hh_item = (itemptrhh); \ + unsigned _hd_bkt; \ + HASH_TO_BKT(_hd_hh_item->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ + (head)->hh.tbl->buckets[_hd_bkt].count++; \ + _hd_hh_item->hh_next = NULL; \ + _hd_hh_item->hh_prev = NULL; \ +} while (0) + +#define HASH_VALUE(keyptr,keylen,hashv) \ +do { \ + HASH_FUNCTION(keyptr, keylen, hashv); \ +} while (0) + +#define HASH_FIND_BYHASHVALUE(hh,head,keyptr,keylen,hashval,out) \ +do { \ + (out) = NULL; \ + if (head) { \ + unsigned _hf_bkt; \ + HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _hf_bkt); \ + if (HASH_BLOOM_TEST((head)->hh.tbl, hashval)) { \ + HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], keyptr, keylen, hashval, out); \ + } \ + } \ +} while (0) + +#define HASH_FIND(hh,head,keyptr,keylen,out) \ +do { \ + (out) = NULL; \ + if (head) { \ + unsigned _hf_hashv; \ + HASH_VALUE(keyptr, keylen, _hf_hashv); \ + HASH_FIND_BYHASHVALUE(hh, head, keyptr, keylen, _hf_hashv, out); \ + } \ +} while (0) + +#ifdef HASH_BLOOM +#define HASH_BLOOM_BITLEN (1UL << HASH_BLOOM) +#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8UL) + (((HASH_BLOOM_BITLEN%8UL)!=0UL) ? 1UL : 0UL) +#define HASH_BLOOM_MAKE(tbl,oomed) \ +do { \ + (tbl)->bloom_nbits = HASH_BLOOM; \ + (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \ + if (!(tbl)->bloom_bv) { \ + HASH_RECORD_OOM(oomed); \ + } else { \ + uthash_bzero((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ + (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \ + } \ +} while (0) + +#define HASH_BLOOM_FREE(tbl) \ +do { \ + uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ +} while (0) + +#define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8U] |= (1U << ((idx)%8U))) +#define HASH_BLOOM_BITTEST(bv,idx) ((bv[(idx)/8U] & (1U << ((idx)%8U))) != 0) + +#define HASH_BLOOM_ADD(tbl,hashv) \ + HASH_BLOOM_BITSET((tbl)->bloom_bv, ((hashv) & (uint32_t)((1UL << (tbl)->bloom_nbits) - 1U))) + +#define HASH_BLOOM_TEST(tbl,hashv) \ + HASH_BLOOM_BITTEST((tbl)->bloom_bv, ((hashv) & (uint32_t)((1UL << (tbl)->bloom_nbits) - 1U))) + +#else +#define HASH_BLOOM_MAKE(tbl,oomed) +#define HASH_BLOOM_FREE(tbl) +#define HASH_BLOOM_ADD(tbl,hashv) +#define HASH_BLOOM_TEST(tbl,hashv) 1 +#define HASH_BLOOM_BYTELEN 0U +#endif + +#define HASH_MAKE_TABLE(hh,head,oomed) \ +do { \ + (head)->hh.tbl = (UT_hash_table*)uthash_malloc(sizeof(UT_hash_table)); \ + if (!(head)->hh.tbl) { \ + HASH_RECORD_OOM(oomed); \ + } else { \ + uthash_bzero((head)->hh.tbl, sizeof(UT_hash_table)); \ + (head)->hh.tbl->tail = &((head)->hh); \ + (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \ + (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \ + (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \ + (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \ + HASH_INITIAL_NUM_BUCKETS * sizeof(struct UT_hash_bucket)); \ + (head)->hh.tbl->signature = HASH_SIGNATURE; \ + if (!(head)->hh.tbl->buckets) { \ + HASH_RECORD_OOM(oomed); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + } else { \ + uthash_bzero((head)->hh.tbl->buckets, \ + HASH_INITIAL_NUM_BUCKETS * sizeof(struct UT_hash_bucket)); \ + HASH_BLOOM_MAKE((head)->hh.tbl, oomed); \ + IF_HASH_NONFATAL_OOM( \ + if (oomed) { \ + uthash_free((head)->hh.tbl->buckets, \ + HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + } \ + ) \ + } \ + } \ +} while (0) + +#define HASH_REPLACE_BYHASHVALUE_INORDER(hh,head,fieldname,keylen_in,hashval,add,replaced,cmpfcn) \ +do { \ + (replaced) = NULL; \ + HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, replaced); \ + if (replaced) { \ + HASH_DELETE(hh, head, replaced); \ + } \ + HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, &((add)->fieldname), keylen_in, hashval, add, cmpfcn); \ +} while (0) + +#define HASH_REPLACE_BYHASHVALUE(hh,head,fieldname,keylen_in,hashval,add,replaced) \ +do { \ + (replaced) = NULL; \ + HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, replaced); \ + if (replaced) { \ + HASH_DELETE(hh, head, replaced); \ + } \ + HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, add); \ +} while (0) + +#define HASH_REPLACE(hh,head,fieldname,keylen_in,add,replaced) \ +do { \ + unsigned _hr_hashv; \ + HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv); \ + HASH_REPLACE_BYHASHVALUE(hh, head, fieldname, keylen_in, _hr_hashv, add, replaced); \ +} while (0) + +#define HASH_REPLACE_INORDER(hh,head,fieldname,keylen_in,add,replaced,cmpfcn) \ +do { \ + unsigned _hr_hashv; \ + HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv); \ + HASH_REPLACE_BYHASHVALUE_INORDER(hh, head, fieldname, keylen_in, _hr_hashv, add, replaced, cmpfcn); \ +} while (0) + +#define HASH_APPEND_LIST(hh, head, add) \ +do { \ + (add)->hh.next = NULL; \ + (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \ + (head)->hh.tbl->tail->next = (add); \ + (head)->hh.tbl->tail = &((add)->hh); \ +} while (0) + +#define HASH_AKBI_INNER_LOOP(hh,head,add,cmpfcn) \ +do { \ + do { \ + if (cmpfcn(DECLTYPE(head)(_hs_iter), add) > 0) { \ + break; \ + } \ + } while ((_hs_iter = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->next)); \ +} while (0) + +#ifdef NO_DECLTYPE +#undef HASH_AKBI_INNER_LOOP +#define HASH_AKBI_INNER_LOOP(hh,head,add,cmpfcn) \ +do { \ + char *_hs_saved_head = (char*)(head); \ + do { \ + DECLTYPE_ASSIGN(head, _hs_iter); \ + if (cmpfcn(head, add) > 0) { \ + DECLTYPE_ASSIGN(head, _hs_saved_head); \ + break; \ + } \ + DECLTYPE_ASSIGN(head, _hs_saved_head); \ + } while ((_hs_iter = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->next)); \ +} while (0) +#endif + +#if HASH_NONFATAL_OOM + +#define HASH_ADD_TO_TABLE(hh,head,keyptr,keylen_in,hashval,add,oomed) \ +do { \ + if (!(oomed)) { \ + unsigned _ha_bkt; \ + (head)->hh.tbl->num_items++; \ + HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt); \ + HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], hh, &(add)->hh, oomed); \ + if (oomed) { \ + HASH_ROLLBACK_BKT(hh, head, &(add)->hh); \ + HASH_DELETE_HH(hh, head, &(add)->hh); \ + (add)->hh.tbl = NULL; \ + uthash_nonfatal_oom(add); \ + } else { \ + HASH_BLOOM_ADD((head)->hh.tbl, hashval); \ + HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \ + } \ + } else { \ + (add)->hh.tbl = NULL; \ + uthash_nonfatal_oom(add); \ + } \ +} while (0) + +#else + +#define HASH_ADD_TO_TABLE(hh,head,keyptr,keylen_in,hashval,add,oomed) \ +do { \ + unsigned _ha_bkt; \ + (head)->hh.tbl->num_items++; \ + HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt); \ + HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], hh, &(add)->hh, oomed); \ + HASH_BLOOM_ADD((head)->hh.tbl, hashval); \ + HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \ +} while (0) + +#endif + + +#define HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh,head,keyptr,keylen_in,hashval,add,cmpfcn) \ +do { \ + IF_HASH_NONFATAL_OOM( int _ha_oomed = 0; ) \ + (add)->hh.hashv = (hashval); \ + (add)->hh.key = (char*) (keyptr); \ + (add)->hh.keylen = (unsigned) (keylen_in); \ + if (!(head)) { \ + (add)->hh.next = NULL; \ + (add)->hh.prev = NULL; \ + HASH_MAKE_TABLE(hh, add, _ha_oomed); \ + IF_HASH_NONFATAL_OOM( if (!_ha_oomed) { ) \ + (head) = (add); \ + IF_HASH_NONFATAL_OOM( } ) \ + } else { \ + void *_hs_iter = (head); \ + (add)->hh.tbl = (head)->hh.tbl; \ + HASH_AKBI_INNER_LOOP(hh, head, add, cmpfcn); \ + if (_hs_iter) { \ + (add)->hh.next = _hs_iter; \ + if (((add)->hh.prev = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->prev)) { \ + HH_FROM_ELMT((head)->hh.tbl, (add)->hh.prev)->next = (add); \ + } else { \ + (head) = (add); \ + } \ + HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->prev = (add); \ + } else { \ + HASH_APPEND_LIST(hh, head, add); \ + } \ + } \ + HASH_ADD_TO_TABLE(hh, head, keyptr, keylen_in, hashval, add, _ha_oomed); \ + HASH_FSCK(hh, head, "HASH_ADD_KEYPTR_BYHASHVALUE_INORDER"); \ +} while (0) + +#define HASH_ADD_KEYPTR_INORDER(hh,head,keyptr,keylen_in,add,cmpfcn) \ +do { \ + unsigned _hs_hashv; \ + HASH_VALUE(keyptr, keylen_in, _hs_hashv); \ + HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, keyptr, keylen_in, _hs_hashv, add, cmpfcn); \ +} while (0) + +#define HASH_ADD_BYHASHVALUE_INORDER(hh,head,fieldname,keylen_in,hashval,add,cmpfcn) \ + HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, &((add)->fieldname), keylen_in, hashval, add, cmpfcn) + +#define HASH_ADD_INORDER(hh,head,fieldname,keylen_in,add,cmpfcn) \ + HASH_ADD_KEYPTR_INORDER(hh, head, &((add)->fieldname), keylen_in, add, cmpfcn) + +#define HASH_ADD_KEYPTR_BYHASHVALUE(hh,head,keyptr,keylen_in,hashval,add) \ +do { \ + IF_HASH_NONFATAL_OOM( int _ha_oomed = 0; ) \ + (add)->hh.hashv = (hashval); \ + (add)->hh.key = (const void*) (keyptr); \ + (add)->hh.keylen = (unsigned) (keylen_in); \ + if (!(head)) { \ + (add)->hh.next = NULL; \ + (add)->hh.prev = NULL; \ + HASH_MAKE_TABLE(hh, add, _ha_oomed); \ + IF_HASH_NONFATAL_OOM( if (!_ha_oomed) { ) \ + (head) = (add); \ + IF_HASH_NONFATAL_OOM( } ) \ + } else { \ + (add)->hh.tbl = (head)->hh.tbl; \ + HASH_APPEND_LIST(hh, head, add); \ + } \ + HASH_ADD_TO_TABLE(hh, head, keyptr, keylen_in, hashval, add, _ha_oomed); \ + HASH_FSCK(hh, head, "HASH_ADD_KEYPTR_BYHASHVALUE"); \ +} while (0) + +#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \ +do { \ + unsigned _ha_hashv; \ + HASH_VALUE(keyptr, keylen_in, _ha_hashv); \ + HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, keyptr, keylen_in, _ha_hashv, add); \ +} while (0) + +#define HASH_ADD_BYHASHVALUE(hh,head,fieldname,keylen_in,hashval,add) \ + HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, add) + +#define HASH_ADD(hh,head,fieldname,keylen_in,add) \ + HASH_ADD_KEYPTR(hh, head, &((add)->fieldname), keylen_in, add) + +#define HASH_TO_BKT(hashv,num_bkts,bkt) \ +do { \ + bkt = ((hashv) & ((num_bkts) - 1U)); \ +} while (0) + +/* delete "delptr" from the hash table. + * "the usual" patch-up process for the app-order doubly-linked-list. + * The use of _hd_hh_del below deserves special explanation. + * These used to be expressed using (delptr) but that led to a bug + * if someone used the same symbol for the head and deletee, like + * HASH_DELETE(hh,users,users); + * We want that to work, but by changing the head (users) below + * we were forfeiting our ability to further refer to the deletee (users) + * in the patch-up process. Solution: use scratch space to + * copy the deletee pointer, then the latter references are via that + * scratch pointer rather than through the repointed (users) symbol. + */ +#define HASH_DELETE(hh,head,delptr) \ + HASH_DELETE_HH(hh, head, &(delptr)->hh) + +#define HASH_DELETE_HH(hh,head,delptrhh) \ +do { \ + const struct UT_hash_handle *_hd_hh_del = (delptrhh); \ + if ((_hd_hh_del->prev == NULL) && (_hd_hh_del->next == NULL)) { \ + HASH_BLOOM_FREE((head)->hh.tbl); \ + uthash_free((head)->hh.tbl->buckets, \ + (head)->hh.tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + (head) = NULL; \ + } else { \ + unsigned _hd_bkt; \ + if (_hd_hh_del == (head)->hh.tbl->tail) { \ + (head)->hh.tbl->tail = HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->prev); \ + } \ + if (_hd_hh_del->prev != NULL) { \ + HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->prev)->next = _hd_hh_del->next; \ + } else { \ + DECLTYPE_ASSIGN(head, _hd_hh_del->next); \ + } \ + if (_hd_hh_del->next != NULL) { \ + HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->next)->prev = _hd_hh_del->prev; \ + } \ + HASH_TO_BKT(_hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ + HASH_DEL_IN_BKT((head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \ + (head)->hh.tbl->num_items--; \ + } \ + HASH_FSCK(hh, head, "HASH_DELETE_HH"); \ +} while (0) + +/* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */ +#define HASH_FIND_STR(head,findstr,out) \ +do { \ + unsigned _uthash_hfstr_keylen = (unsigned)uthash_strlen(findstr); \ + HASH_FIND(hh, head, findstr, _uthash_hfstr_keylen, out); \ +} while (0) +#define HASH_ADD_STR(head,strfield,add) \ +do { \ + unsigned _uthash_hastr_keylen = (unsigned)uthash_strlen((add)->strfield); \ + HASH_ADD(hh, head, strfield[0], _uthash_hastr_keylen, add); \ +} while (0) +#define HASH_REPLACE_STR(head,strfield,add,replaced) \ +do { \ + unsigned _uthash_hrstr_keylen = (unsigned)uthash_strlen((add)->strfield); \ + HASH_REPLACE(hh, head, strfield[0], _uthash_hrstr_keylen, add, replaced); \ +} while (0) +#define HASH_FIND_INT(head,findint,out) \ + HASH_FIND(hh,head,findint,sizeof(int),out) +#define HASH_ADD_INT(head,intfield,add) \ + HASH_ADD(hh,head,intfield,sizeof(int),add) +#define HASH_REPLACE_INT(head,intfield,add,replaced) \ + HASH_REPLACE(hh,head,intfield,sizeof(int),add,replaced) +#define HASH_FIND_PTR(head,findptr,out) \ + HASH_FIND(hh,head,findptr,sizeof(void *),out) +#define HASH_ADD_PTR(head,ptrfield,add) \ + HASH_ADD(hh,head,ptrfield,sizeof(void *),add) +#define HASH_REPLACE_PTR(head,ptrfield,add,replaced) \ + HASH_REPLACE(hh,head,ptrfield,sizeof(void *),add,replaced) +#define HASH_DEL(head,delptr) \ + HASH_DELETE(hh,head,delptr) + +/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined. + * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined. + */ +#ifdef HASH_DEBUG +#include /* fprintf, stderr */ +#define HASH_OOPS(...) do { fprintf(stderr, __VA_ARGS__); exit(-1); } while (0) +#define HASH_FSCK(hh,head,where) \ +do { \ + struct UT_hash_handle *_thh; \ + if (head) { \ + unsigned _bkt_i; \ + unsigned _count = 0; \ + char *_prev; \ + for (_bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; ++_bkt_i) { \ + unsigned _bkt_count = 0; \ + _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \ + _prev = NULL; \ + while (_thh) { \ + if (_prev != (char*)(_thh->hh_prev)) { \ + HASH_OOPS("%s: invalid hh_prev %p, actual %p\n", \ + (where), (void*)_thh->hh_prev, (void*)_prev); \ + } \ + _bkt_count++; \ + _prev = (char*)(_thh); \ + _thh = _thh->hh_next; \ + } \ + _count += _bkt_count; \ + if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \ + HASH_OOPS("%s: invalid bucket count %u, actual %u\n", \ + (where), (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \ + } \ + } \ + if (_count != (head)->hh.tbl->num_items) { \ + HASH_OOPS("%s: invalid hh item count %u, actual %u\n", \ + (where), (head)->hh.tbl->num_items, _count); \ + } \ + _count = 0; \ + _prev = NULL; \ + _thh = &(head)->hh; \ + while (_thh) { \ + _count++; \ + if (_prev != (char*)_thh->prev) { \ + HASH_OOPS("%s: invalid prev %p, actual %p\n", \ + (where), (void*)_thh->prev, (void*)_prev); \ + } \ + _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \ + _thh = (_thh->next ? HH_FROM_ELMT((head)->hh.tbl, _thh->next) : NULL); \ + } \ + if (_count != (head)->hh.tbl->num_items) { \ + HASH_OOPS("%s: invalid app item count %u, actual %u\n", \ + (where), (head)->hh.tbl->num_items, _count); \ + } \ + } \ +} while (0) +#else +#define HASH_FSCK(hh,head,where) +#endif + +/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to + * the descriptor to which this macro is defined for tuning the hash function. + * The app can #include to get the prototype for write(2). */ +#ifdef HASH_EMIT_KEYS +#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \ +do { \ + unsigned _klen = fieldlen; \ + write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \ + write(HASH_EMIT_KEYS, keyptr, (unsigned long)fieldlen); \ +} while (0) +#else +#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) +#endif + +/* The Bernstein hash function, used in Perl prior to v5.6. Note (x<<5+x)=x*33. */ +#define HASH_BER(key,keylen,hashv) \ +do { \ + unsigned _hb_keylen = (unsigned)keylen; \ + const unsigned char *_hb_key = (const unsigned char*)(key); \ + (hashv) = 0; \ + while (_hb_keylen-- != 0U) { \ + (hashv) = (((hashv) << 5) + (hashv)) + *_hb_key++; \ + } \ +} while (0) + + +/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at + * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx + * (archive link: https://archive.is/Ivcan ) + */ +#define HASH_SAX(key,keylen,hashv) \ +do { \ + unsigned _sx_i; \ + const unsigned char *_hs_key = (const unsigned char*)(key); \ + hashv = 0; \ + for (_sx_i=0; _sx_i < keylen; _sx_i++) { \ + hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \ + } \ +} while (0) +/* FNV-1a variation */ +#define HASH_FNV(key,keylen,hashv) \ +do { \ + unsigned _fn_i; \ + const unsigned char *_hf_key = (const unsigned char*)(key); \ + (hashv) = 2166136261U; \ + for (_fn_i=0; _fn_i < keylen; _fn_i++) { \ + hashv = hashv ^ _hf_key[_fn_i]; \ + hashv = hashv * 16777619U; \ + } \ +} while (0) + +#define HASH_OAT(key,keylen,hashv) \ +do { \ + unsigned _ho_i; \ + const unsigned char *_ho_key=(const unsigned char*)(key); \ + hashv = 0; \ + for(_ho_i=0; _ho_i < keylen; _ho_i++) { \ + hashv += _ho_key[_ho_i]; \ + hashv += (hashv << 10); \ + hashv ^= (hashv >> 6); \ + } \ + hashv += (hashv << 3); \ + hashv ^= (hashv >> 11); \ + hashv += (hashv << 15); \ +} while (0) + +#define HASH_JEN_MIX(a,b,c) \ +do { \ + a -= b; a -= c; a ^= ( c >> 13 ); \ + b -= c; b -= a; b ^= ( a << 8 ); \ + c -= a; c -= b; c ^= ( b >> 13 ); \ + a -= b; a -= c; a ^= ( c >> 12 ); \ + b -= c; b -= a; b ^= ( a << 16 ); \ + c -= a; c -= b; c ^= ( b >> 5 ); \ + a -= b; a -= c; a ^= ( c >> 3 ); \ + b -= c; b -= a; b ^= ( a << 10 ); \ + c -= a; c -= b; c ^= ( b >> 15 ); \ +} while (0) + +#define HASH_JEN(key,keylen,hashv) \ +do { \ + unsigned _hj_i,_hj_j,_hj_k; \ + unsigned const char *_hj_key=(unsigned const char*)(key); \ + hashv = 0xfeedbeefu; \ + _hj_i = _hj_j = 0x9e3779b9u; \ + _hj_k = (unsigned)(keylen); \ + while (_hj_k >= 12U) { \ + _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \ + + ( (unsigned)_hj_key[2] << 16 ) \ + + ( (unsigned)_hj_key[3] << 24 ) ); \ + _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \ + + ( (unsigned)_hj_key[6] << 16 ) \ + + ( (unsigned)_hj_key[7] << 24 ) ); \ + hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \ + + ( (unsigned)_hj_key[10] << 16 ) \ + + ( (unsigned)_hj_key[11] << 24 ) ); \ + \ + HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ + \ + _hj_key += 12; \ + _hj_k -= 12U; \ + } \ + hashv += (unsigned)(keylen); \ + switch ( _hj_k ) { \ + case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); /* FALLTHROUGH */ \ + case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); /* FALLTHROUGH */ \ + case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); /* FALLTHROUGH */ \ + case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); /* FALLTHROUGH */ \ + case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); /* FALLTHROUGH */ \ + case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); /* FALLTHROUGH */ \ + case 5: _hj_j += _hj_key[4]; /* FALLTHROUGH */ \ + case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); /* FALLTHROUGH */ \ + case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); /* FALLTHROUGH */ \ + case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); /* FALLTHROUGH */ \ + case 1: _hj_i += _hj_key[0]; /* FALLTHROUGH */ \ + default: ; \ + } \ + HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ +} while (0) + +/* The Paul Hsieh hash function */ +#undef get16bits +#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ + || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) +#define get16bits(d) (*((const uint16_t *) (d))) +#endif + +#if !defined (get16bits) +#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \ + +(uint32_t)(((const uint8_t *)(d))[0]) ) +#endif +#define HASH_SFH(key,keylen,hashv) \ +do { \ + unsigned const char *_sfh_key=(unsigned const char*)(key); \ + uint32_t _sfh_tmp, _sfh_len = (uint32_t)keylen; \ + \ + unsigned _sfh_rem = _sfh_len & 3U; \ + _sfh_len >>= 2; \ + hashv = 0xcafebabeu; \ + \ + /* Main loop */ \ + for (;_sfh_len > 0U; _sfh_len--) { \ + hashv += get16bits (_sfh_key); \ + _sfh_tmp = ((uint32_t)(get16bits (_sfh_key+2)) << 11) ^ hashv; \ + hashv = (hashv << 16) ^ _sfh_tmp; \ + _sfh_key += 2U*sizeof (uint16_t); \ + hashv += hashv >> 11; \ + } \ + \ + /* Handle end cases */ \ + switch (_sfh_rem) { \ + case 3: hashv += get16bits (_sfh_key); \ + hashv ^= hashv << 16; \ + hashv ^= (uint32_t)(_sfh_key[sizeof (uint16_t)]) << 18; \ + hashv += hashv >> 11; \ + break; \ + case 2: hashv += get16bits (_sfh_key); \ + hashv ^= hashv << 11; \ + hashv += hashv >> 17; \ + break; \ + case 1: hashv += *_sfh_key; \ + hashv ^= hashv << 10; \ + hashv += hashv >> 1; \ + break; \ + default: ; \ + } \ + \ + /* Force "avalanching" of final 127 bits */ \ + hashv ^= hashv << 3; \ + hashv += hashv >> 5; \ + hashv ^= hashv << 4; \ + hashv += hashv >> 17; \ + hashv ^= hashv << 25; \ + hashv += hashv >> 6; \ +} while (0) + +/* iterate over items in a known bucket to find desired item */ +#define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,hashval,out) \ +do { \ + if ((head).hh_head != NULL) { \ + DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (head).hh_head)); \ + } else { \ + (out) = NULL; \ + } \ + while ((out) != NULL) { \ + if ((out)->hh.hashv == (hashval) && (out)->hh.keylen == (keylen_in)) { \ + if (HASH_KEYCMP((out)->hh.key, keyptr, keylen_in) == 0) { \ + break; \ + } \ + } \ + if ((out)->hh.hh_next != NULL) { \ + DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (out)->hh.hh_next)); \ + } else { \ + (out) = NULL; \ + } \ + } \ +} while (0) + +/* add an item to a bucket */ +#define HASH_ADD_TO_BKT(head,hh,addhh,oomed) \ +do { \ + UT_hash_bucket *_ha_head = &(head); \ + _ha_head->count++; \ + (addhh)->hh_next = _ha_head->hh_head; \ + (addhh)->hh_prev = NULL; \ + if (_ha_head->hh_head != NULL) { \ + _ha_head->hh_head->hh_prev = (addhh); \ + } \ + _ha_head->hh_head = (addhh); \ + if ((_ha_head->count >= ((_ha_head->expand_mult + 1U) * HASH_BKT_CAPACITY_THRESH)) \ + && !(addhh)->tbl->noexpand) { \ + HASH_EXPAND_BUCKETS(addhh,(addhh)->tbl, oomed); \ + IF_HASH_NONFATAL_OOM( \ + if (oomed) { \ + HASH_DEL_IN_BKT(head,addhh); \ + } \ + ) \ + } \ +} while (0) + +/* remove an item from a given bucket */ +#define HASH_DEL_IN_BKT(head,delhh) \ +do { \ + UT_hash_bucket *_hd_head = &(head); \ + _hd_head->count--; \ + if (_hd_head->hh_head == (delhh)) { \ + _hd_head->hh_head = (delhh)->hh_next; \ + } \ + if ((delhh)->hh_prev) { \ + (delhh)->hh_prev->hh_next = (delhh)->hh_next; \ + } \ + if ((delhh)->hh_next) { \ + (delhh)->hh_next->hh_prev = (delhh)->hh_prev; \ + } \ +} while (0) + +/* Bucket expansion has the effect of doubling the number of buckets + * and redistributing the items into the new buckets. Ideally the + * items will distribute more or less evenly into the new buckets + * (the extent to which this is true is a measure of the quality of + * the hash function as it applies to the key domain). + * + * With the items distributed into more buckets, the chain length + * (item count) in each bucket is reduced. Thus by expanding buckets + * the hash keeps a bound on the chain length. This bounded chain + * length is the essence of how a hash provides constant time lookup. + * + * The calculation of tbl->ideal_chain_maxlen below deserves some + * explanation. First, keep in mind that we're calculating the ideal + * maximum chain length based on the *new* (doubled) bucket count. + * In fractions this is just n/b (n=number of items,b=new num buckets). + * Since the ideal chain length is an integer, we want to calculate + * ceil(n/b). We don't depend on floating point arithmetic in this + * hash, so to calculate ceil(n/b) with integers we could write + * + * ceil(n/b) = (n/b) + ((n%b)?1:0) + * + * and in fact a previous version of this hash did just that. + * But now we have improved things a bit by recognizing that b is + * always a power of two. We keep its base 2 log handy (call it lb), + * so now we can write this with a bit shift and logical AND: + * + * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0) + * + */ +#define HASH_EXPAND_BUCKETS(hh,tbl,oomed) \ +do { \ + unsigned _he_bkt; \ + unsigned _he_bkt_i; \ + struct UT_hash_handle *_he_thh, *_he_hh_nxt; \ + UT_hash_bucket *_he_new_buckets, *_he_newbkt; \ + _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \ + sizeof(struct UT_hash_bucket) * (tbl)->num_buckets * 2U); \ + if (!_he_new_buckets) { \ + HASH_RECORD_OOM(oomed); \ + } else { \ + uthash_bzero(_he_new_buckets, \ + sizeof(struct UT_hash_bucket) * (tbl)->num_buckets * 2U); \ + (tbl)->ideal_chain_maxlen = \ + ((tbl)->num_items >> ((tbl)->log2_num_buckets+1U)) + \ + ((((tbl)->num_items & (((tbl)->num_buckets*2U)-1U)) != 0U) ? 1U : 0U); \ + (tbl)->nonideal_items = 0; \ + for (_he_bkt_i = 0; _he_bkt_i < (tbl)->num_buckets; _he_bkt_i++) { \ + _he_thh = (tbl)->buckets[ _he_bkt_i ].hh_head; \ + while (_he_thh != NULL) { \ + _he_hh_nxt = _he_thh->hh_next; \ + HASH_TO_BKT(_he_thh->hashv, (tbl)->num_buckets * 2U, _he_bkt); \ + _he_newbkt = &(_he_new_buckets[_he_bkt]); \ + if (++(_he_newbkt->count) > (tbl)->ideal_chain_maxlen) { \ + (tbl)->nonideal_items++; \ + if (_he_newbkt->count > _he_newbkt->expand_mult * (tbl)->ideal_chain_maxlen) { \ + _he_newbkt->expand_mult++; \ + } \ + } \ + _he_thh->hh_prev = NULL; \ + _he_thh->hh_next = _he_newbkt->hh_head; \ + if (_he_newbkt->hh_head != NULL) { \ + _he_newbkt->hh_head->hh_prev = _he_thh; \ + } \ + _he_newbkt->hh_head = _he_thh; \ + _he_thh = _he_hh_nxt; \ + } \ + } \ + uthash_free((tbl)->buckets, (tbl)->num_buckets * sizeof(struct UT_hash_bucket)); \ + (tbl)->num_buckets *= 2U; \ + (tbl)->log2_num_buckets++; \ + (tbl)->buckets = _he_new_buckets; \ + (tbl)->ineff_expands = ((tbl)->nonideal_items > ((tbl)->num_items >> 1)) ? \ + ((tbl)->ineff_expands+1U) : 0U; \ + if ((tbl)->ineff_expands > 1U) { \ + (tbl)->noexpand = 1; \ + uthash_noexpand_fyi(tbl); \ + } \ + uthash_expand_fyi(tbl); \ + } \ +} while (0) + + +/* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */ +/* Note that HASH_SORT assumes the hash handle name to be hh. + * HASH_SRT was added to allow the hash handle name to be passed in. */ +#define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn) +#define HASH_SRT(hh,head,cmpfcn) \ +do { \ + unsigned _hs_i; \ + unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \ + struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \ + if (head != NULL) { \ + _hs_insize = 1; \ + _hs_looping = 1; \ + _hs_list = &((head)->hh); \ + while (_hs_looping != 0U) { \ + _hs_p = _hs_list; \ + _hs_list = NULL; \ + _hs_tail = NULL; \ + _hs_nmerges = 0; \ + while (_hs_p != NULL) { \ + _hs_nmerges++; \ + _hs_q = _hs_p; \ + _hs_psize = 0; \ + for (_hs_i = 0; _hs_i < _hs_insize; ++_hs_i) { \ + _hs_psize++; \ + _hs_q = ((_hs_q->next != NULL) ? \ + HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \ + if (_hs_q == NULL) { \ + break; \ + } \ + } \ + _hs_qsize = _hs_insize; \ + while ((_hs_psize != 0U) || ((_hs_qsize != 0U) && (_hs_q != NULL))) { \ + if (_hs_psize == 0U) { \ + _hs_e = _hs_q; \ + _hs_q = ((_hs_q->next != NULL) ? \ + HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \ + _hs_qsize--; \ + } else if ((_hs_qsize == 0U) || (_hs_q == NULL)) { \ + _hs_e = _hs_p; \ + if (_hs_p != NULL) { \ + _hs_p = ((_hs_p->next != NULL) ? \ + HH_FROM_ELMT((head)->hh.tbl, _hs_p->next) : NULL); \ + } \ + _hs_psize--; \ + } else if ((cmpfcn( \ + DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl, _hs_p)), \ + DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl, _hs_q)) \ + )) <= 0) { \ + _hs_e = _hs_p; \ + if (_hs_p != NULL) { \ + _hs_p = ((_hs_p->next != NULL) ? \ + HH_FROM_ELMT((head)->hh.tbl, _hs_p->next) : NULL); \ + } \ + _hs_psize--; \ + } else { \ + _hs_e = _hs_q; \ + _hs_q = ((_hs_q->next != NULL) ? \ + HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \ + _hs_qsize--; \ + } \ + if ( _hs_tail != NULL ) { \ + _hs_tail->next = ((_hs_e != NULL) ? \ + ELMT_FROM_HH((head)->hh.tbl, _hs_e) : NULL); \ + } else { \ + _hs_list = _hs_e; \ + } \ + if (_hs_e != NULL) { \ + _hs_e->prev = ((_hs_tail != NULL) ? \ + ELMT_FROM_HH((head)->hh.tbl, _hs_tail) : NULL); \ + } \ + _hs_tail = _hs_e; \ + } \ + _hs_p = _hs_q; \ + } \ + if (_hs_tail != NULL) { \ + _hs_tail->next = NULL; \ + } \ + if (_hs_nmerges <= 1U) { \ + _hs_looping = 0; \ + (head)->hh.tbl->tail = _hs_tail; \ + DECLTYPE_ASSIGN(head, ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \ + } \ + _hs_insize *= 2U; \ + } \ + HASH_FSCK(hh, head, "HASH_SRT"); \ + } \ +} while (0) + +/* This function selects items from one hash into another hash. + * The end result is that the selected items have dual presence + * in both hashes. There is no copy of the items made; rather + * they are added into the new hash through a secondary hash + * hash handle that must be present in the structure. */ +#define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \ +do { \ + unsigned _src_bkt, _dst_bkt; \ + void *_last_elt = NULL, *_elt; \ + UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \ + ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \ + if ((src) != NULL) { \ + for (_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \ + for (_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \ + _src_hh != NULL; \ + _src_hh = _src_hh->hh_next) { \ + _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \ + if (cond(_elt)) { \ + IF_HASH_NONFATAL_OOM( int _hs_oomed = 0; ) \ + _dst_hh = (UT_hash_handle*)(void*)(((char*)_elt) + _dst_hho); \ + _dst_hh->key = _src_hh->key; \ + _dst_hh->keylen = _src_hh->keylen; \ + _dst_hh->hashv = _src_hh->hashv; \ + _dst_hh->prev = _last_elt; \ + _dst_hh->next = NULL; \ + if (_last_elt_hh != NULL) { \ + _last_elt_hh->next = _elt; \ + } \ + if ((dst) == NULL) { \ + DECLTYPE_ASSIGN(dst, _elt); \ + HASH_MAKE_TABLE(hh_dst, dst, _hs_oomed); \ + IF_HASH_NONFATAL_OOM( \ + if (_hs_oomed) { \ + uthash_nonfatal_oom(_elt); \ + (dst) = NULL; \ + continue; \ + } \ + ) \ + } else { \ + _dst_hh->tbl = (dst)->hh_dst.tbl; \ + } \ + HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \ + HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt], hh_dst, _dst_hh, _hs_oomed); \ + (dst)->hh_dst.tbl->num_items++; \ + IF_HASH_NONFATAL_OOM( \ + if (_hs_oomed) { \ + HASH_ROLLBACK_BKT(hh_dst, dst, _dst_hh); \ + HASH_DELETE_HH(hh_dst, dst, _dst_hh); \ + _dst_hh->tbl = NULL; \ + uthash_nonfatal_oom(_elt); \ + continue; \ + } \ + ) \ + HASH_BLOOM_ADD(_dst_hh->tbl, _dst_hh->hashv); \ + _last_elt = _elt; \ + _last_elt_hh = _dst_hh; \ + } \ + } \ + } \ + } \ + HASH_FSCK(hh_dst, dst, "HASH_SELECT"); \ +} while (0) + +#define HASH_CLEAR(hh,head) \ +do { \ + if ((head) != NULL) { \ + HASH_BLOOM_FREE((head)->hh.tbl); \ + uthash_free((head)->hh.tbl->buckets, \ + (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + (head) = NULL; \ + } \ +} while (0) + +#define HASH_OVERHEAD(hh,head) \ + (((head) != NULL) ? ( \ + (size_t)(((head)->hh.tbl->num_items * sizeof(UT_hash_handle)) + \ + ((head)->hh.tbl->num_buckets * sizeof(UT_hash_bucket)) + \ + sizeof(UT_hash_table) + \ + (HASH_BLOOM_BYTELEN))) : 0U) + +#ifdef NO_DECLTYPE +#define HASH_ITER(hh,head,el,tmp) \ +for(((el)=(head)), ((*(char**)(&(tmp)))=(char*)((head!=NULL)?(head)->hh.next:NULL)); \ + (el) != NULL; ((el)=(tmp)), ((*(char**)(&(tmp)))=(char*)((tmp!=NULL)?(tmp)->hh.next:NULL))) +#else +#define HASH_ITER(hh,head,el,tmp) \ +for(((el)=(head)), ((tmp)=DECLTYPE(el)((head!=NULL)?(head)->hh.next:NULL)); \ + (el) != NULL; ((el)=(tmp)), ((tmp)=DECLTYPE(el)((tmp!=NULL)?(tmp)->hh.next:NULL))) +#endif + +/* obtain a count of items in the hash */ +#define HASH_COUNT(head) HASH_CNT(hh,head) +#define HASH_CNT(hh,head) ((head != NULL)?((head)->hh.tbl->num_items):0U) + +typedef struct UT_hash_bucket { + struct UT_hash_handle *hh_head; + unsigned count; + + /* expand_mult is normally set to 0. In this situation, the max chain length + * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If + * the bucket's chain exceeds this length, bucket expansion is triggered). + * However, setting expand_mult to a non-zero value delays bucket expansion + * (that would be triggered by additions to this particular bucket) + * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH. + * (The multiplier is simply expand_mult+1). The whole idea of this + * multiplier is to reduce bucket expansions, since they are expensive, in + * situations where we know that a particular bucket tends to be overused. + * It is better to let its chain length grow to a longer yet-still-bounded + * value, than to do an O(n) bucket expansion too often. + */ + unsigned expand_mult; + +} UT_hash_bucket; + +/* random signature used only to find hash tables in external analysis */ +#define HASH_SIGNATURE 0xa0111fe1u +#define HASH_BLOOM_SIGNATURE 0xb12220f2u + +typedef struct UT_hash_table { + UT_hash_bucket *buckets; + unsigned num_buckets, log2_num_buckets; + unsigned num_items; + struct UT_hash_handle *tail; /* tail hh in app order, for fast append */ + ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */ + + /* in an ideal situation (all buckets used equally), no bucket would have + * more than ceil(#items/#buckets) items. that's the ideal chain length. */ + unsigned ideal_chain_maxlen; + + /* nonideal_items is the number of items in the hash whose chain position + * exceeds the ideal chain maxlen. these items pay the penalty for an uneven + * hash distribution; reaching them in a chain traversal takes >ideal steps */ + unsigned nonideal_items; + + /* ineffective expands occur when a bucket doubling was performed, but + * afterward, more than half the items in the hash had nonideal chain + * positions. If this happens on two consecutive expansions we inhibit any + * further expansion, as it's not helping; this happens when the hash + * function isn't a good fit for the key domain. When expansion is inhibited + * the hash will still work, albeit no longer in constant time. */ + unsigned ineff_expands, noexpand; + + uint32_t signature; /* used only to find hash tables in external analysis */ +#ifdef HASH_BLOOM + uint32_t bloom_sig; /* used only to test bloom exists in external analysis */ + uint8_t *bloom_bv; + uint8_t bloom_nbits; +#endif + +} UT_hash_table; + +typedef struct UT_hash_handle { + struct UT_hash_table *tbl; + void *prev; /* prev element in app order */ + void *next; /* next element in app order */ + struct UT_hash_handle *hh_prev; /* previous hh in bucket order */ + struct UT_hash_handle *hh_next; /* next hh in bucket order */ + const void *key; /* ptr to enclosing struct's key */ + unsigned keylen; /* enclosing struct's key len */ + unsigned hashv; /* result of hash-fcn(key) */ +} UT_hash_handle; + +#endif /* UTHASH_H */ diff --git a/ini/features.ini b/ini/features.ini index 833fe76510..da1865ea05 100644 --- a/ini/features.ini +++ b/ini/features.ini @@ -13,7 +13,7 @@ [features] YHCB2004 = LiquidCrystal_AIP31068=https://github.com/ellensp/LiquidCrystal_AIP31068/archive/3fc43b7.zip, red-scorp/SoftSPIB@^1.1.1 -HAS_TFT_LVGL_UI = lvgl=https://github.com/makerbase-mks/LVGL-6.1.1-MKS/archive/a3ebe98bc6.zip +HAS_TFT_LVGL_UI = lvgl=https://github.com/staff1010/LVGL-6.1.1-MKS/archive/v6.1.2.zip build_src_filter=+ extra_scripts=download_mks_assets.py MARLIN_TEST_BUILD = build_src_filter=+ From 5b59424447a370473aaaa0a4f08988fc0b803ca9 Mon Sep 17 00:00:00 2001 From: Giuliano <3684609+GMagician@users.noreply.github.com> Date: Tue, 27 May 2025 22:15:55 +0200 Subject: [PATCH 358/787] =?UTF-8?q?=F0=9F=8C=90=20Fix=20Italian=20typo,=20?= =?UTF-8?q?etc.=20(#27890)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Followup to #27877 Co-authored-by: Scott Lahteine --- Marlin/src/lcd/language/language_en.h | 3 +-- Marlin/src/lcd/language/language_it.h | 5 ++--- Marlin/src/lcd/language/language_tr.h | 1 - 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/Marlin/src/lcd/language/language_en.h b/Marlin/src/lcd/language/language_en.h index a74d28b82a..90948d7865 100644 --- a/Marlin/src/lcd/language/language_en.h +++ b/Marlin/src/lcd/language/language_en.h @@ -364,7 +364,7 @@ namespace LanguageNarrow_en { LSTR MSG_MOVE_N_MM = _UxGT("Move $mm"); LSTR MSG_MOVE_N_IN = _UxGT("Move $in"); LSTR MSG_MOVE_N_DEG = _UxGT("Move $") LCD_STR_DEGREE; - LSTR MSG_LIVE_MOVE = _UxGT("Live Move"); + LSTR MSG_LIVE_MOVE = _UxGT("Live Movement"); LSTR MSG_SPEED = _UxGT("Speed"); LSTR MSG_MESH_Z_OFFSET = _UxGT("Bed Z"); LSTR MSG_NOZZLE = _UxGT("Nozzle"); @@ -1124,7 +1124,6 @@ namespace LanguageNarrow_en { namespace LanguageWide_en { using namespace LanguageNarrow_en; #if LCD_WIDTH >= 20 || HAS_DWIN_E3V2 - LSTR MSG_LIVE_MOVE = _UxGT("Live Movement"); LSTR MSG_HOST_START_PRINT = _UxGT("Start Host Print"); LSTR MSG_PRINTING_OBJECT = _UxGT("Printing Object"); LSTR MSG_CANCEL_OBJECT = _UxGT("Cancel Object"); diff --git a/Marlin/src/lcd/language/language_it.h b/Marlin/src/lcd/language/language_it.h index dbf093c042..c0d717d0cc 100644 --- a/Marlin/src/lcd/language/language_it.h +++ b/Marlin/src/lcd/language/language_it.h @@ -341,7 +341,7 @@ namespace LanguageNarrow_it { LSTR MSG_MOVE_N_MM = _UxGT("Muovi di $mm"); LSTR MSG_MOVE_N_IN = _UxGT("Muovi di $in"); LSTR MSG_MOVE_N_DEG = _UxGT("Muovi di $") LCD_STR_DEGREE; - LSTR MSG_LIVE_MOVE = _UxGT("Modalità live"); + LSTR MSG_LIVE_MOVE = _UxGT("Movimento live"); LSTR MSG_SPEED = _UxGT("Velocità"); LSTR MSG_MESH_Z_OFFSET = _UxGT("Piatto Z"); LSTR MSG_NOZZLE = _UxGT("Ugello"); @@ -606,7 +606,7 @@ namespace LanguageNarrow_it { LSTR MSG_ATTACH_SD = _UxGT("Collega scheda SD"); LSTR MSG_ATTACH_USB = _UxGT("Collega unità USB"); LSTR MSG_RELEASE_MEDIA = _UxGT("Rilascia ") MEDIA_TYPE_IT; - LSTR MSG_RELEASE_SD = _UxGT("Rilascia sceda SD"); + LSTR MSG_RELEASE_SD = _UxGT("Rilascia scheda SD"); LSTR MSG_RELEASE_USB = _UxGT("Rilascia unità USB"); LSTR MSG_CHANGE_MEDIA = _UxGT("Selez.") MEDIA_TYPE_IT; LSTR MSG_CHANGE_SD = _UxGT("Selez. scheda SD"); @@ -1007,7 +1007,6 @@ namespace LanguageNarrow_it { namespace LanguageWide_it { using namespace LanguageNarrow_it; #if LCD_WIDTH >= 20 || HAS_DWIN_E3V2 - LSTR MSG_LIVE_MOVE = _UxGT("Movimento live"); LSTR MSG_HOST_START_PRINT = _UxGT("Avvio stampa host"); LSTR MSG_PRINTING_OBJECT = _UxGT("Stampa oggetto"); LSTR MSG_CANCEL_OBJECT = _UxGT("Cancella oggetto"); diff --git a/Marlin/src/lcd/language/language_tr.h b/Marlin/src/lcd/language/language_tr.h index 9e4f261271..77cb7bf9b8 100644 --- a/Marlin/src/lcd/language/language_tr.h +++ b/Marlin/src/lcd/language/language_tr.h @@ -891,7 +891,6 @@ namespace LanguageNarrow_tr { namespace LanguageWide_tr { using namespace LanguageNarrow_tr; #if LCD_WIDTH >= 20 || HAS_DWIN_E3V2 - LSTR MSG_LIVE_MOVE = _UxGT("Canlı Hareket"); LSTR MSG_HOST_START_PRINT = _UxGT("Host Baskıyı başlat"); LSTR MSG_PRINTING_OBJECT = _UxGT("Yazdırma Nesnesi"); LSTR MSG_CANCEL_OBJECT = _UxGT("Nesneyi İptal Et"); From 38eee768391280583bdc710630bce32a04a9be89 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Wed, 28 May 2025 00:32:03 +0000 Subject: [PATCH 359/787] [cron] Bump distribution date (2025-05-28) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 34ac9adaa3..ec6539e4fa 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-05-27" +//#define STRING_DISTRIBUTION_DATE "2025-05-28" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 8d0c6361af..745e8e40a0 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-05-27" + #define STRING_DISTRIBUTION_DATE "2025-05-28" #endif /** From fa25737a9f874999c0bb22862ad6ceeb3a1688ad Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Wed, 28 May 2025 14:08:07 -0500 Subject: [PATCH 360/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20TMC?= =?UTF-8?q?Stepper=20=3D>=200.8.3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ini/features.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ini/features.ini b/ini/features.ini index da1865ea05..011163b5d9 100644 --- a/ini/features.ini +++ b/ini/features.ini @@ -20,7 +20,7 @@ MARLIN_TEST_BUILD = build_src_filter=+ POSTMORTEM_DEBUGGING = build_src_filter=+ + build_flags=-funwind-tables MKS_WIFI_MODULE = QRCode=https://github.com/makerbase-mks/QRCode/archive/261c5a696a.zip -HAS_TRINAMIC_CONFIG = TMCStepper=https://github.com/MarlinFirmware/TMCStepper/archive/v0.8.2.zip +HAS_TRINAMIC_CONFIG = TMCStepper=https://github.com/MarlinFirmware/TMCStepper/archive/v0.8.3.zip build_src_filter=+ + + + + HAS_STEPPER_CONTROL = build_src_filter=+ HAS_T(RINAMIC_CONFIG|MC_SPI) = build_src_filter=+ From a270cc36e69e162de1e698306b730ef0a5f3c911 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Thu, 29 May 2025 00:31:57 +0000 Subject: [PATCH 361/787] [cron] Bump distribution date (2025-05-29) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index ec6539e4fa..76d1da5dda 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-05-28" +//#define STRING_DISTRIBUTION_DATE "2025-05-29" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 745e8e40a0..154547cb93 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-05-28" + #define STRING_DISTRIBUTION_DATE "2025-05-29" #endif /** From 8f19e2d7d4450000ca9aaf8b4fb2822ebe86df2d Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Thu, 29 May 2025 13:24:40 -0500 Subject: [PATCH 362/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20TMC?= =?UTF-8?q?Stepper=20=3D>=200.8.4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ini/features.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ini/features.ini b/ini/features.ini index 011163b5d9..6b1e684561 100644 --- a/ini/features.ini +++ b/ini/features.ini @@ -20,7 +20,7 @@ MARLIN_TEST_BUILD = build_src_filter=+ POSTMORTEM_DEBUGGING = build_src_filter=+ + build_flags=-funwind-tables MKS_WIFI_MODULE = QRCode=https://github.com/makerbase-mks/QRCode/archive/261c5a696a.zip -HAS_TRINAMIC_CONFIG = TMCStepper=https://github.com/MarlinFirmware/TMCStepper/archive/v0.8.3.zip +HAS_TRINAMIC_CONFIG = TMCStepper=https://github.com/MarlinFirmware/TMCStepper/archive/v0.8.4.zip build_src_filter=+ + + + + HAS_STEPPER_CONTROL = build_src_filter=+ HAS_T(RINAMIC_CONFIG|MC_SPI) = build_src_filter=+ From e8f2430dacbf9533f916f000f57a5dbedbb6662f Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Fri, 30 May 2025 00:32:05 +0000 Subject: [PATCH 363/787] [cron] Bump distribution date (2025-05-30) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 76d1da5dda..f7598786c8 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-05-29" +//#define STRING_DISTRIBUTION_DATE "2025-05-30" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 154547cb93..5f6f7fdbf0 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-05-29" + #define STRING_DISTRIBUTION_DATE "2025-05-30" #endif /** From a6bfdf351f241955519af675f5af9dd9dd9f3a52 Mon Sep 17 00:00:00 2001 From: Vovodroid Date: Sat, 31 May 2025 06:53:21 +0300 Subject: [PATCH 364/787] =?UTF-8?q?=E2=9C=A8=20NONLINEAR=5FEXTRUSION=5FDEF?= =?UTF-8?q?AULT=5FON=20(#27819)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Scott Lahteine --- Marlin/Configuration_adv.h | 3 ++ Marlin/src/gcode/feature/nonlinear/M592.cpp | 20 ++++++--- Marlin/src/lcd/language/language_en.h | 1 + Marlin/src/lcd/menu/menu_advanced.cpp | 4 ++ Marlin/src/lcd/menu/menu_tune.cpp | 7 +++ Marlin/src/module/planner.cpp | 4 +- Marlin/src/module/settings.cpp | 8 ++-- Marlin/src/module/stepper.cpp | 41 +++++++----------- Marlin/src/module/stepper.h | 48 ++++++++++++++------- buildroot/tests/STM32F103RC_btt | 2 +- 10 files changed, 83 insertions(+), 55 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 7939b5cc9b..f7ab7abd94 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -2384,6 +2384,9 @@ * For better results also enable ADAPTIVE_STEP_SMOOTHING. */ //#define NONLINEAR_EXTRUSION +#if ENABLED(NONLINEAR_EXTRUSION) + //#define NONLINEAR_EXTRUSION_DEFAULT_ON // Enable if NLE should be ON by default +#endif // @section leveling diff --git a/Marlin/src/gcode/feature/nonlinear/M592.cpp b/Marlin/src/gcode/feature/nonlinear/M592.cpp index 78c15443f8..b084e326f7 100644 --- a/Marlin/src/gcode/feature/nonlinear/M592.cpp +++ b/Marlin/src/gcode/feature/nonlinear/M592.cpp @@ -30,11 +30,13 @@ void GcodeSuite::M592_report(const bool forReplay/*=true*/) { TERN_(MARLIN_SMALL_BUILD, return); report_heading_etc(forReplay, F(STR_NONLINEAR_EXTRUSION)); - SERIAL_ECHOLNPGM(" M592 A", stepper.ne.A, " B", stepper.ne.B, " C", stepper.ne.C); + const nonlinear_settings_t &sns = stepper.ne.settings; + SERIAL_ECHOLNPGM(" M592 S", sns.enabled, " A", sns.coeff.A, " B", sns.coeff.B, " C", sns.coeff.C); } /** * M592: Get or set nonlinear extrusion parameters + * S Enable / Disable Nonlinear Extrusion * A Quadratic coefficient (default 0.0) * B Linear coefficient (default 0.0) * C Constant coefficient (default 1.0) @@ -46,14 +48,18 @@ void GcodeSuite::M592_report(const bool forReplay/*=true*/) { void GcodeSuite::M592() { if (!parser.seen_any()) return M592_report(); - if (parser.seenval('A')) stepper.ne.A = parser.value_float(); - if (parser.seenval('B')) stepper.ne.B = parser.value_float(); - if (parser.seenval('C')) stepper.ne.C = parser.value_float(); + nonlinear_t &ne = stepper.ne; + nonlinear_settings_t &sns = ne.settings; + + if (parser.seen('S')) sns.enabled = parser.value_bool(); + if (parser.seenval('A')) sns.coeff.A = parser.value_float(); + if (parser.seenval('B')) sns.coeff.B = parser.value_float(); + if (parser.seenval('C')) sns.coeff.C = parser.value_float(); #if ENABLED(SMOOTH_LIN_ADVANCE) - stepper.ne_q30.A = _BV32(30) * (stepper.ne.A * planner.mm_per_step[E_AXIS_N(0)] * planner.mm_per_step[E_AXIS_N(0)]); - stepper.ne_q30.B = _BV32(30) * (stepper.ne.B * planner.mm_per_step[E_AXIS_N(0)]); - stepper.ne_q30.C = _BV32(30) * stepper.ne.C; + ne.q30.A = _BV32(30) * (sns.coeff.A * planner.mm_per_step[E_AXIS_N(0)] * planner.mm_per_step[E_AXIS_N(0)]); + ne.q30.B = _BV32(30) * (sns.coeff.B * planner.mm_per_step[E_AXIS_N(0)]); + ne.q30.C = _BV32(30) * sns.coeff.C; #endif } diff --git a/Marlin/src/lcd/language/language_en.h b/Marlin/src/lcd/language/language_en.h index 90948d7865..be309f53d8 100644 --- a/Marlin/src/lcd/language/language_en.h +++ b/Marlin/src/lcd/language/language_en.h @@ -509,6 +509,7 @@ namespace LanguageNarrow_en { LSTR MSG_ADVANCE_TAU = _UxGT("Advance Tau"); LSTR MSG_ADVANCE_K_E = _UxGT("Advance K *"); LSTR MSG_ADVANCE_TAU_E = _UxGT("Advance Tau *"); + LSTR MSG_NLE_ON = _UxGT("NLE enabled"); LSTR MSG_CONTRAST = _UxGT("LCD Contrast"); LSTR MSG_BRIGHTNESS = _UxGT("LCD Brightness"); LSTR MSG_SCREEN_TIMEOUT = _UxGT("LCD Timeout (m)"); diff --git a/Marlin/src/lcd/menu/menu_advanced.cpp b/Marlin/src/lcd/menu/menu_advanced.cpp index b15a21fc7b..65d7a88f0d 100644 --- a/Marlin/src/lcd/menu/menu_advanced.cpp +++ b/Marlin/src/lcd/menu/menu_advanced.cpp @@ -138,6 +138,10 @@ void menu_backlash(); #endif #endif // LIN_ADVANCE + #if ENABLED(NONLINEAR_EXTRUSION) + EDIT_ITEM(bool, MSG_NLE_ON, &stepper.ne.settings.enabled); + #endif + #if DISABLED(NO_VOLUMETRICS) EDIT_ITEM(bool, MSG_VOLUMETRIC_ENABLED, &parser.volumetric_enabled, planner.calculate_volumetric_multipliers); diff --git a/Marlin/src/lcd/menu/menu_tune.cpp b/Marlin/src/lcd/menu/menu_tune.cpp index 7f4696a3f1..18d52bb640 100644 --- a/Marlin/src/lcd/menu/menu_tune.cpp +++ b/Marlin/src/lcd/menu/menu_tune.cpp @@ -237,6 +237,13 @@ void menu_tune() { #endif #endif + // + // Nonlinear Extrusion state + // + #if ENABLED(NONLINEAR_EXTRUSION) + EDIT_ITEM(bool, MSG_NLE_ON, &stepper.ne.settings.enabled); + #endif + // // Babystep X: // Babystep Y: diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index 8678c82130..2e2b5798b7 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -3255,8 +3255,8 @@ void Planner::refresh_positioning() { #if ENABLED(EDITABLE_STEPS_PER_UNIT) LOOP_DISTINCT_AXES(i) mm_per_step[i] = 1.0f / settings.axis_steps_per_mm[i]; #if ALL(NONLINEAR_EXTRUSION, SMOOTH_LIN_ADVANCE) - stepper.ne_q30.A = _BV32(30) * (stepper.ne.A * mm_per_step[E_AXIS_N(0)] * mm_per_step[E_AXIS_N(0)]); - stepper.ne_q30.B = _BV32(30) * (stepper.ne.B * mm_per_step[E_AXIS_N(0)]); + stepper.ne.q30.A = _BV32(30) * (stepper.ne.settings.coeff.A * mm_per_step[E_AXIS_N(0)] * mm_per_step[E_AXIS_N(0)]); + stepper.ne.q30.B = _BV32(30) * (stepper.ne.settings.coeff.B * mm_per_step[E_AXIS_N(0)]); #endif #endif set_position_mm(current_position); diff --git a/Marlin/src/module/settings.cpp b/Marlin/src/module/settings.cpp index 2161be5abc..0d197b2d12 100644 --- a/Marlin/src/module/settings.cpp +++ b/Marlin/src/module/settings.cpp @@ -685,7 +685,7 @@ typedef struct SettingsDataStruct { // Nonlinear Extrusion // #if ENABLED(NONLINEAR_EXTRUSION) - ne_coeff_t stepper_ne; // M592 A B C + nonlinear_settings_t stepper_ne_settings; // M592 S A B C #endif // @@ -1798,7 +1798,7 @@ void MarlinSettings::postprocess() { // Nonlinear Extrusion // #if ENABLED(NONLINEAR_EXTRUSION) - EEPROM_WRITE(stepper.ne); + EEPROM_WRITE(stepper.ne.settings); #endif // @@ -2933,7 +2933,7 @@ void MarlinSettings::postprocess() { // Nonlinear Extrusion // #if ENABLED(NONLINEAR_EXTRUSION) - EEPROM_READ(stepper.ne); + EEPROM_READ(stepper.ne.settings); #endif // @@ -3747,7 +3747,7 @@ void MarlinSettings::reset() { // // Nonlinear Extrusion // - TERN_(NONLINEAR_EXTRUSION, stepper.ne.reset()); + TERN_(NONLINEAR_EXTRUSION, stepper.ne.settings.reset()); // // Input Shaping diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp index edfed3b8e2..fd3d3bd800 100644 --- a/Marlin/src/module/stepper.cpp +++ b/Marlin/src/module/stepper.cpp @@ -256,17 +256,7 @@ uint32_t Stepper::advance_divisor = 0, #endif #if ENABLED(NONLINEAR_EXTRUSION) - ne_coeff_t Stepper::ne; - #if NONLINEAR_EXTRUSION_Q24 - ne_q24_t Stepper::ne_q24; - #else - ne_q30_t Stepper::ne_q30; - #endif - // private: - #if NONLINEAR_EXTRUSION_Q24 - int32_t Stepper::ne_edividend; - uint32_t Stepper::ne_scale_q24; - #endif + nonlinear_t Stepper::ne; // Initialized by settings.load #endif #if HAS_ZV_SHAPING @@ -2247,11 +2237,11 @@ hal_timer_t Stepper::calc_timer_interval(uint32_t step_rate) { #if NONLINEAR_EXTRUSION_Q24 void Stepper::calc_nonlinear_e(const uint32_t step_rate) { - const uint32_t velocity_q24 = ne_scale_q24 * step_rate; // Scale step_rate first so all intermediate values stay in range of 8.24 fixed point math - int32_t vd_q24 = (((((int64_t)ne_q24.A * velocity_q24) >> 24) * velocity_q24) >> 24) + (((int64_t)ne_q24.B * velocity_q24) >> 24); + const uint32_t velocity_q24 = ne.scale_q24 * step_rate; // Scale step_rate first so all intermediate values stay in range of 8.24 fixed point math + int32_t vd_q24 = ((((int64_t(ne.q24.A) * velocity_q24) >> 24) * velocity_q24) >> 24) + ((int64_t(ne.q24.B) * velocity_q24) >> 24); NOLESS(vd_q24, 0); - advance_dividend.e = (uint64_t(ne_q24.C + vd_q24) * ne_edividend) >> 24; + advance_dividend.e = (uint64_t(ne.q24.C + vd_q24) * ne.edividend) >> 24; } #endif @@ -2834,18 +2824,19 @@ hal_timer_t Stepper::block_phase_isr() { acc_step_rate = current_block->initial_rate; #endif + // Calculate Nonlinear Extrusion fixed-point quotients #if NONLINEAR_EXTRUSION_Q24 - ne_edividend = advance_dividend.e; - const float scale = (float(ne_edividend) / advance_divisor) * planner.mm_per_step[E_AXIS_N(current_block->extruder)]; - ne_scale_q24 = _BV32(24) * scale; - if (current_block->direction_bits.e && ANY_AXIS_MOVES(current_block)) { - ne_q24.A = _BV32(24) * ne.A; - ne_q24.B = _BV32(24) * ne.B; - ne_q24.C = _BV32(24) * ne.C; + ne.edividend = advance_dividend.e; + const float scale = (float(ne.edividend) / advance_divisor) * planner.mm_per_step[E_AXIS_N(current_block->extruder)]; + ne.scale_q24 = _BV32(24) * scale; + if (ne.settings.enabled && current_block->direction_bits.e && ANY_AXIS_MOVES(current_block)) { + ne.q24.A = _BV32(24) * ne.settings.coeff.A; + ne.q24.B = _BV32(24) * ne.settings.coeff.B; + ne.q24.C = _BV32(24) * ne.settings.coeff.C; } else { - ne_q24.A = ne_q24.B = 0; - ne_q24.C = _BV32(24); + ne.q24.A = ne.q24.B = 0; + ne.q24.C = _BV32(24); } #endif @@ -2891,9 +2882,9 @@ hal_timer_t Stepper::block_phase_isr() { #if ENABLED(NONLINEAR_EXTRUSION) if (forward_e && ANY_AXIS_MOVES(current_block)) { // Maximum polynomial value is just above 1, like 1.05..1.2, less than 2 anyway, so we can use 30 bits for fractional part - int32_t vd_q30 = ne_q30.A*step_rate*step_rate + ne_q30.B*step_rate; + int32_t vd_q30 = ne.q30.A * sq(step_rate) + ne.q30.B * step_rate; NOLESS(vd_q30, 0); - step_rate = (int64_t(step_rate) * (ne_q30.C + vd_q30)) >> 30; + step_rate = (int64_t(step_rate) * (ne.q30.C + vd_q30)) >> 30; } #endif diff --git a/Marlin/src/module/stepper.h b/Marlin/src/module/stepper.h index 73fd28fe85..90cbedc9fc 100644 --- a/Marlin/src/module/stepper.h +++ b/Marlin/src/module/stepper.h @@ -283,15 +283,41 @@ constexpr ena_mask_t enable_overlap[] = { #endif // HAS_ZV_SHAPING +// +// NonLinear Extrusion data +// #if ENABLED(NONLINEAR_EXTRUSION) - typedef struct { float A, B, C; void reset() { A = B = 0.0f; C = 1.0f; } } ne_coeff_t; + #if DISABLED(SMOOTH_LIN_ADVANCE) #define NONLINEAR_EXTRUSION_Q24 1 - typedef struct { int32_t A, B, C; } ne_q24_t; - #else - typedef struct { int32_t A, B, C; } ne_q30_t; #endif -#endif + + typedef struct { + bool enabled; + struct { + float A, B, C; + void reset() { A = B = 0.0f; C = 1.0f; } + } coeff; + void reset() { + enabled = ENABLED(NONLINEAR_EXTRUSION_DEFAULT_ON); + coeff.reset(); + } + } nonlinear_settings_t; + + typedef struct { + nonlinear_settings_t settings; + union { + struct { int32_t A, B, C; } q24; + struct { int32_t A, B, C; } q30; + }; + #if NONLINEAR_EXTRUSION_Q24 + protected: + int32_t edividend; + uint32_t scale_q24; + #endif + } nonlinear_t; + +#endif // NONLINEAR_EXTRUSION // // Stepper class definition @@ -347,12 +373,7 @@ class Stepper { #endif #if ENABLED(NONLINEAR_EXTRUSION) - static ne_coeff_t ne; - #if NONLINEAR_EXTRUSION_Q24 - static ne_q24_t ne_q24; - #else - static ne_q30_t ne_q30; - #endif + static nonlinear_t ne; #endif #if ENABLED(ADAPTIVE_STEP_SMOOTHING_TOGGLE) @@ -477,11 +498,6 @@ class Stepper { #endif #endif - #if NONLINEAR_EXTRUSION_Q24 - static int32_t ne_edividend; - static uint32_t ne_scale_q24; - #endif - #if ENABLED(BABYSTEPPING) static constexpr hal_timer_t BABYSTEP_NEVER = HAL_TIMER_TYPE_MAX; static hal_timer_t nextBabystepISR; diff --git a/buildroot/tests/STM32F103RC_btt b/buildroot/tests/STM32F103RC_btt index 2b05d42922..97339d7750 100755 --- a/buildroot/tests/STM32F103RC_btt +++ b/buildroot/tests/STM32F103RC_btt @@ -15,5 +15,5 @@ opt_set MOTHERBOARD BOARD_BTT_SKR_MINI_E3_V1_0 SERIAL_PORT 1 SERIAL_PORT_2 -1 \ X_CURRENT_HOME X_CURRENT/2 Y_CURRENT_HOME Y_CURRENT/2 Z_CURRENT_HOME Y_CURRENT/2 opt_enable CR10_STOCKDISPLAY PINS_DEBUGGING Z_IDLE_HEIGHT EDITABLE_HOMING_CURRENT \ FT_MOTION FT_MOTION_MENU BIQU_MICROPROBE_V1 PROBE_ENABLE_DISABLE Z_SAFE_HOMING AUTO_BED_LEVELING_BILINEAR \ - ADAPTIVE_STEP_SMOOTHING NONLINEAR_EXTRUSION + ADAPTIVE_STEP_SMOOTHING LIN_ADVANCE SMOOTH_LIN_ADVANCE NONLINEAR_EXTRUSION INPUT_SHAPING_X INPUT_SHAPING_Y exec_test $1 $2 "BigTreeTech SKR Mini E3 1.0 - TMC2209 HW Serial, FT_MOTION" "$3" From a2452a577b38d081a79e005532b4a710213289e0 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Sat, 31 May 2025 06:08:46 +0000 Subject: [PATCH 365/787] [cron] Bump distribution date (2025-05-31) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index f7598786c8..ca7a67dba7 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-05-30" +//#define STRING_DISTRIBUTION_DATE "2025-05-31" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 5f6f7fdbf0..f6c6927508 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-05-30" + #define STRING_DISTRIBUTION_DATE "2025-05-31" #endif /** From c377237fd8a9f982d3bb54ceab98f1ec23c70925 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sat, 31 May 2025 16:05:13 -0500 Subject: [PATCH 366/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Twe?= =?UTF-8?q?ak=20G90=20/=20G91=20declaration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/gcode/gcode.cpp | 4 ++-- Marlin/src/gcode/gcode.h | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp index 242972c24b..1fa5c55c22 100644 --- a/Marlin/src/gcode/gcode.cpp +++ b/Marlin/src/gcode/gcode.cpp @@ -458,8 +458,8 @@ void GcodeSuite::process_parsed_command(bool no_ok/*=false*/) { case 80: G80(); break; // G80: Reset the current motion mode #endif - case 90: set_relative_mode(false); break; // G90: Absolute Mode - case 91: set_relative_mode(true); break; // G91: Relative Mode + case 90: G90(); break; // G90: Absolute Mode + case 91: G91(); break; // G91: Relative Mode case 92: G92(); break; // G92: Set current axis position(s) diff --git a/Marlin/src/gcode/gcode.h b/Marlin/src/gcode/gcode.h index ee0ccb9a0f..61782d7d3d 100644 --- a/Marlin/src/gcode/gcode.h +++ b/Marlin/src/gcode/gcode.h @@ -632,6 +632,9 @@ private: static void G80(); #endif + static void G90() { set_relative_mode(false); } + static void G91() { set_relative_mode(true); } + static void G92(); #if ENABLED(CALIBRATION_GCODE) From b59251c388e249ec02d0a91db653dfd04e5a59f4 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sat, 31 May 2025 16:06:12 -0500 Subject: [PATCH 367/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Mac?= =?UTF-8?q?ros=20for=20larger=20sets?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/core/macros.h | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/Marlin/src/core/macros.h b/Marlin/src/core/macros.h index bef89040b3..fd6296707f 100644 --- a/Marlin/src/core/macros.h +++ b/Marlin/src/core/macros.h @@ -307,6 +307,12 @@ #define GANG_N_1(N,K) _GANG_N(N,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K) // Expansion of some list items +#define LIST_32(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,AA,BB,CC,DD,EE,FF,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,AA,BB,CC,DD,EE,FF +#define LIST_31(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,AA,BB,CC,DD,EE,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,AA,BB,CC,DD,EE +#define LIST_30(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,AA,BB,CC,DD,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,AA,BB,CC,DD +#define LIST_29(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,AA,BB,CC,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,AA,BB,CC +#define LIST_28(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,AA,BB,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,TU,V,W,X,Y,Z,AA,BB +#define LIST_27(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,AA,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,AA #define LIST_26(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z #define LIST_25(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y #define LIST_24(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X @@ -572,6 +578,17 @@ #define INC_18 19 #define INC_19 20 #define INC_20 21 +#define INC_21 22 +#define INC_22 23 +#define INC_23 24 +#define INC_24 25 +#define INC_25 26 +#define INC_26 27 +#define INC_27 28 +#define INC_28 29 +#define INC_29 30 +#define INC_30 31 +#define INC_31 32 #define INCREMENT_(n) INC_##n #define INCREMENT(n) INCREMENT_(n) @@ -607,6 +624,23 @@ #define DEC_13 12 #define DEC_14 13 #define DEC_15 14 +#define DEC_16 15 +#define DEC_17 16 +#define DEC_18 17 +#define DEC_19 18 +#define DEC_20 19 +#define DEC_21 20 +#define DEC_22 21 +#define DEC_23 22 +#define DEC_24 23 +#define DEC_25 24 +#define DEC_26 25 +#define DEC_27 26 +#define DEC_28 27 +#define DEC_29 28 +#define DEC_30 29 +#define DEC_31 30 +#define DEC_32 31 #define DECREMENT_(n) DEC_##n #define DECREMENT(n) DECREMENT_(n) From 9dbce712fccaf3792ef9503afd3a4e301419b357 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sat, 31 May 2025 16:08:47 -0500 Subject: [PATCH 368/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20TMC?= =?UTF-8?q?Stepper=20=3D>=200.8.5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ini/features.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ini/features.ini b/ini/features.ini index 6b1e684561..80663abf5b 100644 --- a/ini/features.ini +++ b/ini/features.ini @@ -20,7 +20,7 @@ MARLIN_TEST_BUILD = build_src_filter=+ POSTMORTEM_DEBUGGING = build_src_filter=+ + build_flags=-funwind-tables MKS_WIFI_MODULE = QRCode=https://github.com/makerbase-mks/QRCode/archive/261c5a696a.zip -HAS_TRINAMIC_CONFIG = TMCStepper=https://github.com/MarlinFirmware/TMCStepper/archive/v0.8.4.zip +HAS_TRINAMIC_CONFIG = TMCStepper=https://github.com/MarlinFirmware/TMCStepper/archive/v0.8.5.zip build_src_filter=+ + + + + HAS_STEPPER_CONTROL = build_src_filter=+ HAS_T(RINAMIC_CONFIG|MC_SPI) = build_src_filter=+ From 3ddf728333c4e5dd7d24f4842c00f48dd3980b61 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sat, 31 May 2025 16:54:57 -0500 Subject: [PATCH 369/787] =?UTF-8?q?=F0=9F=A9=B9=20Fix=20some=20missed=20ON?= =?UTF-8?q?BOARD=5FSDIO?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/HAL/RP2040/HAL.cpp | 2 +- Marlin/src/pins/stm32f4/pins_XTLW_CLIMBER_8TH.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/src/HAL/RP2040/HAL.cpp b/Marlin/src/HAL/RP2040/HAL.cpp index 8c35d45542..f0d9e4eec6 100644 --- a/Marlin/src/HAL/RP2040/HAL.cpp +++ b/Marlin/src/HAL/RP2040/HAL.cpp @@ -59,7 +59,7 @@ void MarlinHAL::init() { constexpr int cpuFreq = F_CPU; UNUSED(cpuFreq); - #if HAS_MEDIA && DISABLED(SDIO_SUPPORT) && PIN_EXISTS(SD_SS) + #if HAS_MEDIA && DISABLED(ONBOARD_SDIO) && PIN_EXISTS(SD_SS) OUT_WRITE(SD_SS_PIN, HIGH); // Try to set SD_SS_PIN inactive before any other SPI users start up #endif diff --git a/Marlin/src/pins/stm32f4/pins_XTLW_CLIMBER_8TH.h b/Marlin/src/pins/stm32f4/pins_XTLW_CLIMBER_8TH.h index 053fb19525..0b41764ec4 100644 --- a/Marlin/src/pins/stm32f4/pins_XTLW_CLIMBER_8TH.h +++ b/Marlin/src/pins/stm32f4/pins_XTLW_CLIMBER_8TH.h @@ -168,7 +168,7 @@ // Must use soft SPI because Marlin's default hardware SPI is tied to LCD's EXP2 // #if SD_CONNECTION_IS(ONBOARD) - #define SDIO_SUPPORT // Use SDIO for onboard SD + #define ONBOARD_SDIO // Use SDIO for onboard SD #define SDIO_D0_PIN PC8 #define SDIO_D1_PIN PC9 #define SDIO_D2_PIN PC10 From 7c30124f80edb0887faa49c0f904e3c68ef52a07 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sat, 31 May 2025 17:00:27 -0500 Subject: [PATCH 370/787] =?UTF-8?q?=F0=9F=93=8C=20Versions=20for=20adafrui?= =?UTF-8?q?t=20"SdFat",=20"Adafruit=20SPIFlash"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ini/samd51.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ini/samd51.ini b/ini/samd51.ini index cf1f9ed8c0..c2a83a0413 100644 --- a/ini/samd51.ini +++ b/ini/samd51.ini @@ -23,5 +23,5 @@ lib_deps = ${common.lib_deps} Adafruit TinyUSB Library extra_scripts = ${common.extra_scripts} pre:buildroot/share/PlatformIO/scripts/SAMD51_grandcentral_m4.py -custom_marlin.HAS_MEDIA = SdFat - Adafruit Fork, Adafruit SPIFlash +custom_marlin.HAS_MEDIA = adafruit/SdFat@~2.3.50, adafruit/Adafruit SPIFlash@~5.1.1 debug_tool = jlink From 823014868c1a9974f0f1881193a8f042577310f5 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Sun, 1 Jun 2025 01:15:51 +0000 Subject: [PATCH 371/787] [cron] Bump distribution date (2025-06-01) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index ca7a67dba7..cd9a44f5ab 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-05-31" +//#define STRING_DISTRIBUTION_DATE "2025-06-01" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index f6c6927508..33c044ebd5 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-05-31" + #define STRING_DISTRIBUTION_DATE "2025-06-01" #endif /** From cc05123a803bfbd483632443a98b236f5722d600 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sun, 1 Jun 2025 16:09:48 -0500 Subject: [PATCH 372/787] =?UTF-8?q?=F0=9F=A9=B9=20Fix=20EXP3=5F03=5FPIN=20?= =?UTF-8?q?for=20CREALITY=5FV24S1=5F301F4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #27904 Co-Authored-By: Nexrem --- Marlin/src/pins/stm32f4/pins_CREALITY_V24S1_301F4.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Marlin/src/pins/stm32f4/pins_CREALITY_V24S1_301F4.h b/Marlin/src/pins/stm32f4/pins_CREALITY_V24S1_301F4.h index fa524464e3..40ea8ae9bc 100644 --- a/Marlin/src/pins/stm32f4/pins_CREALITY_V24S1_301F4.h +++ b/Marlin/src/pins/stm32f4/pins_CREALITY_V24S1_301F4.h @@ -37,4 +37,6 @@ #define EEPROM_EXCL_ZONE 916,926 // Ender-3S1 STM32F401 Bootloader EEPROM exclusion zone +#define EXP3_03_PIN PA2 + #include "../stm32f1/pins_CREALITY_V24S1_301.h" From 8c6e9526b050006d7ea9cac786a8010d6d2aa31f Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Mon, 2 Jun 2025 00:34:11 +0000 Subject: [PATCH 373/787] [cron] Bump distribution date (2025-06-02) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index cd9a44f5ab..178fa18b69 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-06-01" +//#define STRING_DISTRIBUTION_DATE "2025-06-02" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 33c044ebd5..a90e2d857a 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-06-01" + #define STRING_DISTRIBUTION_DATE "2025-06-02" #endif /** From 9f6cafbae3a38d1432f8ed68fa27501012e57230 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sun, 1 Jun 2025 20:47:35 -0500 Subject: [PATCH 374/787] =?UTF-8?q?=F0=9F=A9=B9=20Fix=20Nozzle=20Cleaning?= =?UTF-8?q?=20wait=20for=20pre-set=20temp?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #27882 --- Marlin/src/libs/nozzle.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/src/libs/nozzle.cpp b/Marlin/src/libs/nozzle.cpp index 3b982718a2..ad77e1e0ae 100644 --- a/Marlin/src/libs/nozzle.cpp +++ b/Marlin/src/libs/nozzle.cpp @@ -189,12 +189,12 @@ Nozzle nozzle; #if ENABLED(NOZZLE_CLEAN_HEATUP) SERIAL_ECHOLNPGM("Nozzle too Cold - Heating"); thermalManager.setTargetHotend(NOZZLE_CLEAN_MIN_TEMP, arrPos); - thermalManager.wait_for_hotend(arrPos); #else SERIAL_ECHOLNPGM("Nozzle too cold - Skipping wipe"); return; #endif } + thermalManager.wait_for_hotend(arrPos); #endif #if HAS_SOFTWARE_ENDSTOPS From 6ea4a16212cc94b1665d057af8c504731d97f21e Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Mon, 2 Jun 2025 16:47:50 -0500 Subject: [PATCH 375/787] =?UTF-8?q?=F0=9F=8C=90=20Automated=20README=20tra?= =?UTF-8?q?nslations?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README-PT-BR.md | 81 ------------------------------------------------- README.md | 65 +++++++++++++++++++++++++++++++++------ 2 files changed, 56 insertions(+), 90 deletions(-) delete mode 100644 README-PT-BR.md diff --git a/README-PT-BR.md b/README-PT-BR.md deleted file mode 100644 index 3c730967ae..0000000000 --- a/README-PT-BR.md +++ /dev/null @@ -1,81 +0,0 @@ - -

Logo do MarlinFirmware

- -

Firmware de Impressora 3D Marlin

- -

- Licença GPL-V3.0 - Contribuidores - Data do Último Lançamento - Status do CI - Patrocínios no GitHub -
- Siga marlinfw.org no Bluesky - Siga MarlinFirmware no Mastodon -

- -Documentação adicional pode ser encontrada na [Página Inicial do Marlin](//marlinfw.org/). -Por favor, teste este firmware e nos avise se encontrar algum problema. Voluntários estão prontos para ajudar! - -## Branch de Correções do Marlin 2.1 - -__Não é para uso em produção. Use com cautela!__ - -O Marlin 2.1 continua oferecendo suporte a placas ARM 32 bits e AVR 8 bits, além de adicionar suporte para até 9 eixos coordenados e até 8 extrusoras. - -Este branch é para correções da versão mais recente 2.1.x. Periodicamente, ele servirá de base para o próximo lançamento menor da linha 2.1.x. - -Versões anteriores do Marlin podem ser baixadas na [página de lançamentos](//github.com/MarlinFirmware/Marlin/releases). - -## Configurações de Exemplo - -Antes de compilar o Marlin para sua máquina, você precisará de uma configuração específica para o seu hardware. Ao solicitar, seu fornecedor deve fornecer o código-fonte completo e as configurações da sua máquina. No entanto, se quiser instalar uma versão mais recente do Marlin, você precisará de arquivos de configuração atualizados. Felizmente, a comunidade do Marlin já contribuiu com dezenas de configurações testadas para ajudar no início. Visite o repositório [MarlinFirmware/Configurations](//github.com/MarlinFirmware/Configurations) para encontrar a configuração mais próxima da sua impressora. - -## Compilando o Marlin 2.1 - -Para compilar e enviar o Marlin você pode usar uma destas ferramentas: - -- O [Visual Studio Code](//code.visualstudio.com/download) com a extensão [Auto Build Marlin](//marlinfw.org/docs/basics/auto_build_marlin.html). -- A [IDE do Arduino](//www.arduino.cc/en/main/software): Veja [Compilando Marlin com Arduino](//marlinfw.org/docs/basics/install_arduino.html). -- Também é possível usar VSCode com devcontainer: Veja [Instalando Marlin (VSCode devcontainer)](http://marlinfw.org/docs/basics/install_devcontainer_vscode.html). - -O Marlin é otimizado para ser compilado com a extensão **PlatformIO IDE** no **Visual Studio Code**. Ainda é possível compilar com a **IDE do Arduino**, e temos planos para melhorar essa experiência, mas por enquanto o PlatformIO é a melhor escolha. - -## Placas AVR 8 Bits - -Pretendemos continuar oferecendo suporte às placas AVR 8 bits indefinidamente, mantendo uma base de código única que possa ser aplicada a todas as máquinas. Queremos que hobbystas, experimentadores e donos de máquinas antigas também se beneficiem das inovações da comunidade tanto quanto os donos de equipamentos mais modernos. Além disso, essas máquinas baseadas em AVR costumam ser ideais para testes e feedbacks! - -## Camada de Abstração de Hardware (HAL) - -O Marlin inclui uma camada de abstração de hardware para portar o firmware para uma grande variedade de chips. Essa camada trata das diferenças entre chips de forma modular, permitindo que as funcionalidades do Marlin sejam aproveitadas ao máximo. - -## Licença - -Marlin é publicado sob a licença GPL, então você pode usar, redistribuir e modificar o código-fonte, desde que o código derivado também seja publicado sob a mesma licença. Consulte o arquivo [LICENSE](https://github.com/MarlinFirmware/Marlin/blob/bugfix-2.1.x/LICENSE) para mais detalhes. - -## Ajude o Marlin! - -Você pode ajudar o projeto Marlin contribuindo com código, traduções, testes ou apoiando financeiramente no [GitHub Sponsors](https://github.com/sponsors/thinkyhead). - -...Marlin para diferentes plataformas de hardware. O HAL define as interfaces entre o núcleo do Marlin e o hardware da plataforma. O Marlin suporta atualmente as seguintes arquiteturas: - -- AVR -- SAM (Arduino Due) -- SAMD (Arduino Zero, etc.) -- STM32F1, STM32F4, STM32F7, STM32H7 -- LPC176x (Smoothieboard, ReARM, Archim, MKS Sbase, etc.) -- Teensy 3.5 e 3.6 (ARM Cortex-M4) -- ESP32 (experimental) - -## Comunicação Serial - -- **Baudrates suportados:** 250000, 115200, 57600, 38400, 19200, 9600 -- O baudrate padrão é 250000 para maior velocidade e estabilidade - -## Atualizações e Contribuições - -Aceitamos correções de bugs, melhorias de desempenho e novas funcionalidades. Veja as instruções de contribuição na [Wiki do Marlin](https://github.com/MarlinFirmware/Marlin/wiki/Contributing). - -## Licença - -Marlin é um software livre licenciado sob a [GNU General Public License v3.0](https://www.gnu.org/licenses/gpl-3.0.html). Você pode redistribuí-lo e/ou modificá-lo sob os termos da GPL. Para mais detalhes, veja o arquivo [LICENSE](LICENSE). diff --git a/README.md b/README.md index 69979f4884..cc5fa60db7 100644 --- a/README.md +++ b/README.md @@ -4,21 +4,68 @@

GPL-V3.0 License - Contributors - Last Release Date - CI Status - GitHub Sponsors + Contributors + Last Release Date + CI Status + GitHub Sponsors
- Follow marlinfw.org on Bluesky - Follow MarlinFirmware on Mastodon + Follow marlinfw.org on Bluesky + Follow MarlinFirmware on Mastodon

+### 🌍 Translations + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AragonésБългарскиCatalàČeštinaDanskDeutschΕλληνικά
EnglishEspañolEuskaraSuomiFrançaisGalegoHrvatski
MagyarItalianoにほんご한국어NederlandsPolskiPortuguês
Português (Brasil)RomânăРусскийSlovenčinaSvenskaTürkçeУкраїнська
Tiếng Việt简体中文繁體中文
+ Additional documentation can be found at the [Marlin Home Page](//marlinfw.org/). Please test this firmware and let us know if it misbehaves in any way. Volunteers are standing by! --- -This README is available in other languages -> **Versão em português:** [README-PT-BR.md](README-PT-BR.md) ## Marlin 2.1 Bugfix Branch @@ -140,7 +187,7 @@ Name|Role|Link|Donate ## Star History - + From 098e0961dcf01e9b7adf4f87e6ea92ab573ca95e Mon Sep 17 00:00:00 2001 From: David Buezas Date: Tue, 3 Jun 2025 00:34:02 +0200 Subject: [PATCH 376/787] =?UTF-8?q?=F0=9F=A9=B9=20TMC2240=20diag0=20push-p?= =?UTF-8?q?ull=20active=20HIGH=20(#27907)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/module/stepper/trinamic.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Marlin/src/module/stepper/trinamic.cpp b/Marlin/src/module/stepper/trinamic.cpp index 0f4a8aa89c..240adc9f4c 100644 --- a/Marlin/src/module/stepper/trinamic.cpp +++ b/Marlin/src/module/stepper/trinamic.cpp @@ -822,6 +822,8 @@ enum StealthIndex : uint8_t { st.PWMCONF(pwmconf.sr); TERN(HYBRID_THRESHOLD, st.set_pwm_thrs(hyb_thrs), UNUSED(hyb_thrs)); + + st.diag0_pushpull(true); st.GSTAT(); // Clear GSTAT } #endif // TMC2240 From 7df503de9388f2453515edd58fb5f74d01975b0a Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Mon, 2 Jun 2025 18:23:07 -0500 Subject: [PATCH 377/787] =?UTF-8?q?=F0=9F=A9=B9=20Fix=20FLY=20D5=20/=20D7?= =?UTF-8?q?=20serial=20for=20TMC2208?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See MarlinFirmware/TMCStepper#5 --- ini/stm32f0.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ini/stm32f0.ini b/ini/stm32f0.ini index a684b98871..e3762ebac2 100644 --- a/ini/stm32f0.ini +++ b/ini/stm32f0.ini @@ -62,7 +62,7 @@ platform_packages = framework-arduinoststm32@4.20500.230714 framework-cmsis@2.50700.210515 toolchain-gccarmnoneeabi@1.100301.220327 build_flags = ${stm32_variant.build_flags} - -DTIMER_SERIAL=TIM2 + -DTIMER_SERIAL=TIM2 -DTMC2208_BAUDRATE=9600 upload_protocol = stlink # @@ -77,5 +77,5 @@ platform_packages = framework-arduinoststm32@4.20500.230714 framework-cmsis@2.50700.210515 toolchain-gccarmnoneeabi@1.100301.220327 build_flags = ${stm32_variant.build_flags} - -DTIMER_SERIAL=TIM2 + -DTIMER_SERIAL=TIM2 -DTMC2208_BAUDRATE=9600 upload_protocol = dfu From 3bb9364c44131ae3680df4a35199cb67c117153b Mon Sep 17 00:00:00 2001 From: David Buezas Date: Tue, 3 Jun 2025 01:59:01 +0200 Subject: [PATCH 378/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Add?= =?UTF-8?q?=20TMC2240=20temperature=20reading=20(#27903)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/feature/tmc_util.cpp | 19 ++++++++++++++++++- ini/features.ini | 2 +- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/Marlin/src/feature/tmc_util.cpp b/Marlin/src/feature/tmc_util.cpp index d280b55854..6f53e1943c 100644 --- a/Marlin/src/feature/tmc_util.cpp +++ b/Marlin/src/feature/tmc_util.cpp @@ -526,7 +526,12 @@ TMC_HSTRT, TMC_SGT, TMC_MSCNT, - TMC_INTERPOLATE + TMC_INTERPOLATE, + TMC_VAIN, + TMC_VSUPPLY, + TMC_TEMP, + TMC_OVERTEMP, + TMC_OVERVOLT_THD }; enum TMC_drv_status_enum : char { TMC_DRV_CODES, @@ -701,6 +706,11 @@ case TMC_PWM_GRAD_AUTO: SERIAL_ECHO(st.pwm_grad_auto()); break; case TMC_STEALTHCHOP: print_true_or_false(st.stealth()); break; case TMC_INTERPOLATE: print_true_or_false(st.intpol()); break; + case TMC_VAIN: SERIAL_ECHO(st.get_ain_voltage()); break; + case TMC_VSUPPLY: SERIAL_ECHO(st.get_vsupply_voltage()); break; + case TMC_TEMP: SERIAL_ECHO(st.get_chip_temperature()); break; + case TMC_OVERTEMP: SERIAL_ECHO(st.get_overtemp_prewarn_celsius()); break; + case TMC_OVERVOLT_THD: SERIAL_ECHO(st.get_overvoltage_threshold_voltage()); break; default: break; } } @@ -978,6 +988,13 @@ DRV_REPORT("s2vsb\t", TMC_S2VSB); #endif DRV_REPORT("Driver registers:\n",TMC_DRV_STATUS_HEX); + #if HAS_DRIVER(TMC2240) + TMC_REPORT("Analog in (v)", TMC_VAIN); + TMC_REPORT("Supply (v)", TMC_VSUPPLY); + TMC_REPORT("Temp (°C)", TMC_TEMP); + TMC_REPORT("OT pre warn (°C)", TMC_OVERTEMP); + TMC_REPORT("OV theshold (v)", TMC_OVERVOLT_THD); + #endif SERIAL_EOL(); } diff --git a/ini/features.ini b/ini/features.ini index 80663abf5b..69ec43f030 100644 --- a/ini/features.ini +++ b/ini/features.ini @@ -20,7 +20,7 @@ MARLIN_TEST_BUILD = build_src_filter=+ POSTMORTEM_DEBUGGING = build_src_filter=+ + build_flags=-funwind-tables MKS_WIFI_MODULE = QRCode=https://github.com/makerbase-mks/QRCode/archive/261c5a696a.zip -HAS_TRINAMIC_CONFIG = TMCStepper=https://github.com/MarlinFirmware/TMCStepper/archive/v0.8.5.zip +HAS_TRINAMIC_CONFIG = TMCStepper=https://github.com/MarlinFirmware/TMCStepper/archive/v0.8.6.zip build_src_filter=+ + + + + HAS_STEPPER_CONTROL = build_src_filter=+ HAS_T(RINAMIC_CONFIG|MC_SPI) = build_src_filter=+ From f1bb46f5b8b86506ae38b29c6d323f194085f9f6 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Tue, 3 Jun 2025 00:32:58 +0000 Subject: [PATCH 379/787] [cron] Bump distribution date (2025-06-03) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 178fa18b69..b0c1c5acad 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-06-02" +//#define STRING_DISTRIBUTION_DATE "2025-06-03" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index a90e2d857a..98f11b7f3e 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-06-02" + #define STRING_DISTRIBUTION_DATE "2025-06-03" #endif /** From 951b8be3a111f7d84b6d949f37d7c45c0bd69916 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 3 Jun 2025 18:47:44 -0500 Subject: [PATCH 380/787] =?UTF-8?q?=F0=9F=A9=B9=20Update=20Creality=20CR4N?= =?UTF-8?q?S?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Followup to #27003 --- Marlin/src/pins/stm32f1/pins_CREALITY_CR4NS.h | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/Marlin/src/pins/stm32f1/pins_CREALITY_CR4NS.h b/Marlin/src/pins/stm32f1/pins_CREALITY_CR4NS.h index 7d19aec51d..ce019e0039 100644 --- a/Marlin/src/pins/stm32f1/pins_CREALITY_CR4NS.h +++ b/Marlin/src/pins/stm32f1/pins_CREALITY_CR4NS.h @@ -62,6 +62,8 @@ // // Limit Switches // +#define X_DIAG_PIN PB10 +#define Y_DIAG_PIN PB11 #ifndef Z_STOP_PIN #define Z_STOP_PIN PC14 #endif @@ -79,23 +81,19 @@ #define HEATER_BED_PIN PB2 // HOT BED #define FAN1_PIN PC1 // extruder fan -// -// Steppers -// + #if HAS_TMC_UART - - // Reduce baud rate to improve software serial reliability - #define TMC_BAUD_RATE 19200 - // Software serial #define X_SERIAL_TX_PIN PB12 - #define X_DIAG_PIN PB10 - #define Y_SERIAL_TX_PIN PB13 - #define Y_DIAG_PIN PB11 - #define Z_SERIAL_TX_PIN PB14 -#endif // HAS_TMC_UART + #define E0_SERIAL_TX_PIN PB15 + + // Reduce baud rate to improve software serial reliability + #ifndef TMC_BAUD_RATE + #define TMC_BAUD_RATE 19200 + #endif +#endif // // SD Card From 27621290b820f67df2755587601ff7d84ddc326f Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Wed, 4 Jun 2025 00:33:43 +0000 Subject: [PATCH 381/787] [cron] Bump distribution date (2025-06-04) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index b0c1c5acad..9ad04135eb 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-06-03" +//#define STRING_DISTRIBUTION_DATE "2025-06-04" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 98f11b7f3e..f3c366113f 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-06-03" + #define STRING_DISTRIBUTION_DATE "2025-06-04" #endif /** From fca60335e145ec6a1cbb154ef22a754e610faa86 Mon Sep 17 00:00:00 2001 From: Andrew <18502096+classicrocker883@users.noreply.github.com> Date: Tue, 3 Jun 2025 20:54:22 -0400 Subject: [PATCH 382/787] =?UTF-8?q?=F0=9F=A9=B9=20Fix=20Nonlinear=20Extrus?= =?UTF-8?q?ion=20build=20(#27906)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #27902 --- Marlin/src/core/boards.h | 4 ++-- Marlin/src/module/stepper.h | 5 ++--- buildroot/tests/STM32F103RE_creality | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Marlin/src/core/boards.h b/Marlin/src/core/boards.h index 32ee85daab..adc03b657c 100644 --- a/Marlin/src/core/boards.h +++ b/Marlin/src/core/boards.h @@ -275,7 +275,7 @@ #define BOARD_MKS_SGEN_L_V2 2509 // MKS SGEN_L V2 #define BOARD_BTT_SKR_E3_TURBO 2510 // BigTreeTech SKR E3 Turbo #define BOARD_FLY_CDY 2511 // FLYmaker FLY CDY -#define BOARD_XTLW_CLIMBER_8TH_LPC 2512 // XTLW_CLIMBER_8TH_LPC +#define BOARD_XTLW_CLIMBER_8TH_LPC 2512 // XTLW Climber 8 // // SAM3X8E ARM Cortex-M3 @@ -283,7 +283,7 @@ #define BOARD_DUE3DOM 3000 // DUE3DOM for Arduino DUE #define BOARD_DUE3DOM_MINI 3001 // DUE3DOM MINI for Arduino DUE -#define BOARD_RADDS 3002 // RADDS +#define BOARD_RADDS 3002 // RADDS v1.5/v1.6 #define BOARD_RAMPS_FD_V1 3003 // RAMPS-FD v1 #define BOARD_RAMPS_FD_V2 3004 // RAMPS-FD v2 #define BOARD_RAMPS_SMART_EFB 3005 // RAMPS-SMART (Power outputs: Hotend, Fan, Bed) diff --git a/Marlin/src/module/stepper.h b/Marlin/src/module/stepper.h index 90cbedc9fc..3083ad2973 100644 --- a/Marlin/src/module/stepper.h +++ b/Marlin/src/module/stepper.h @@ -311,9 +311,8 @@ constexpr ena_mask_t enable_overlap[] = { struct { int32_t A, B, C; } q30; }; #if NONLINEAR_EXTRUSION_Q24 - protected: - int32_t edividend; - uint32_t scale_q24; + int32_t edividend; + uint32_t scale_q24; #endif } nonlinear_t; diff --git a/buildroot/tests/STM32F103RE_creality b/buildroot/tests/STM32F103RE_creality index 0855a71ee4..45821598e0 100755 --- a/buildroot/tests/STM32F103RE_creality +++ b/buildroot/tests/STM32F103RE_creality @@ -32,7 +32,7 @@ opt_enable DWIN_LCD_PROUI INDIVIDUAL_AXIS_HOMING_SUBMENU PID_AUTOTUNE_MENU PID_E SOUND_MENU_ITEM PRINTCOUNTER NOZZLE_PARK_FEATURE ADVANCED_PAUSE_FEATURE FILAMENT_RUNOUT_SENSOR \ BLTOUCH Z_SAFE_HOMING AUTO_BED_LEVELING_UBL MESH_EDIT_MENU LCD_BED_TRAMMING LIN_ADVANCE \ LIMITED_MAX_FR_EDITING LIMITED_MAX_ACCEL_EDITING LIMITED_JERK_EDITING BAUD_RATE_GCODE \ - CASE_LIGHT_ENABLE CASE_LIGHT_MENU CASE_LIGHT_NO_BRIGHTNESS + CASE_LIGHT_ENABLE CASE_LIGHT_MENU CASE_LIGHT_NO_BRIGHTNESS NONLINEAR_EXTRUSION opt_set PREHEAT_3_LABEL '"CUSTOM"' PREHEAT_3_TEMP_HOTEND 240 PREHEAT_3_TEMP_BED 60 PREHEAT_3_FAN_SPEED 128 BOOTSCREEN_TIMEOUT 1100 CASE_LIGHT_PIN 4 exec_test $1 $2 "Ender-3 S1 - ProUI (PIDTEMP)" "$3" From 127bc9489119dfc2204f8e3505cc9810914a1af0 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Thu, 5 Jun 2025 00:32:27 +0000 Subject: [PATCH 383/787] [cron] Bump distribution date (2025-06-05) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 9ad04135eb..3f7e62e416 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-06-04" +//#define STRING_DISTRIBUTION_DATE "2025-06-05" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index f3c366113f..c0455cbc51 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-06-04" + #define STRING_DISTRIBUTION_DATE "2025-06-05" #endif /** From 5a5354107bfb70e8bcd76b0ab4744f6bfc6c75b8 Mon Sep 17 00:00:00 2001 From: RainMotorsports <100002265+RainMotorsports@users.noreply.github.com> Date: Sun, 8 Jun 2025 23:18:35 -0400 Subject: [PATCH 384/787] =?UTF-8?q?=E2=9C=A8=20E3D=20BigBox=20Rumba=20boar?= =?UTF-8?q?d=20(#27897)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/Makefile | 3 +- Marlin/src/core/boards.h | 1 + Marlin/src/pins/pins.h | 2 ++ Marlin/src/pins/ramps/pins_RUMBA_E3D.h | 33 +++++++++++++++++++ Marlin/src/pins/stm32f1/pins_CREALITY_CR4NS.h | 1 - 5 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 Marlin/src/pins/ramps/pins_RUMBA_E3D.h diff --git a/Marlin/Makefile b/Marlin/Makefile index 9acab53673..fb1786b6b0 100644 --- a/Marlin/Makefile +++ b/Marlin/Makefile @@ -338,7 +338,8 @@ else ifeq ($(HARDWARE_MOTHERBOARD),1164) else ifeq ($(HARDWARE_MOTHERBOARD),1165) # XTLW MFF V2.0 else ifeq ($(HARDWARE_MOTHERBOARD),1166) - +# E3D Rumba BigBox +else ifeq ($(HARDWARE_MOTHERBOARD),1167) # # RAMBo and derivatives diff --git a/Marlin/src/core/boards.h b/Marlin/src/core/boards.h index adc03b657c..ab7ad6fe47 100644 --- a/Marlin/src/core/boards.h +++ b/Marlin/src/core/boards.h @@ -131,6 +131,7 @@ #define BOARD_KODAMA_BARDO 1164 // Kodama Bardo V1.x (as found in the Kodama Trinus) #define BOARD_XTLW_MFF_V1 1165 // XTLW MFF V1.0 #define BOARD_XTLW_MFF_V2 1166 // XTLW MFF V2.0 +#define BOARD_RUMBA_E3D 1167 // E3D Rumba BigBox // // RAMBo and derivatives diff --git a/Marlin/src/pins/pins.h b/Marlin/src/pins/pins.h index 4a05b72a23..d5822f444b 100644 --- a/Marlin/src/pins/pins.h +++ b/Marlin/src/pins/pins.h @@ -223,6 +223,8 @@ #include "ramps/pins_XTLW_MFF_V1.h" // ATmega2560 env:mega2560 #elif MB(XTLW_MFF_V2) #include "ramps/pins_XTLW_MFF_V2.h" // ATmega2560 env:mega2560 +#elif MB(RUMBA_E3D) + #include "ramps/pins_RUMBA_E3D.h" // ATmega2560 env:mega2560 // // RAMBo and derivatives diff --git a/Marlin/src/pins/ramps/pins_RUMBA_E3D.h b/Marlin/src/pins/ramps/pins_RUMBA_E3D.h new file mode 100644 index 0000000000..2f268eacac --- /dev/null +++ b/Marlin/src/pins/ramps/pins_RUMBA_E3D.h @@ -0,0 +1,33 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +// ATmega2560 + +#define BOARD_INFO_NAME "E3D Rumba" +#define DEFAULT_MACHINE_NAME "E3D BigBox" + +// E3D uses PT100 connected to EXP3 +#define TEMP_0_PIN 10 // Analog Input +#define TEMP_1_PIN 9 // Analog Input + +#include "pins_RUMBA.h" diff --git a/Marlin/src/pins/stm32f1/pins_CREALITY_CR4NS.h b/Marlin/src/pins/stm32f1/pins_CREALITY_CR4NS.h index ce019e0039..5a4f5bfaa5 100644 --- a/Marlin/src/pins/stm32f1/pins_CREALITY_CR4NS.h +++ b/Marlin/src/pins/stm32f1/pins_CREALITY_CR4NS.h @@ -81,7 +81,6 @@ #define HEATER_BED_PIN PB2 // HOT BED #define FAN1_PIN PC1 // extruder fan - #if HAS_TMC_UART // Software serial #define X_SERIAL_TX_PIN PB12 From 781d9c470e756c2bcdff18bb84e76de071f1511a Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Mon, 9 Jun 2025 06:10:43 +0000 Subject: [PATCH 385/787] [cron] Bump distribution date (2025-06-09) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 3f7e62e416..9f5daa27a0 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-06-05" +//#define STRING_DISTRIBUTION_DATE "2025-06-09" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index c0455cbc51..16911f23ce 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-06-05" + #define STRING_DISTRIBUTION_DATE "2025-06-09" #endif /** From fbee2a2ff7ae02d7c87ff991b615afe6ad59641f Mon Sep 17 00:00:00 2001 From: David Buezas Date: Mon, 9 Jun 2025 20:26:57 +0200 Subject: [PATCH 386/787] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20SMOOTH=5FLIN=5FADV?= =?UTF-8?q?ANCE=20+=20S=5FCURVE=5FACCELERATION=20(#27827)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/inc/SanityCheck.h | 2 -- Marlin/src/module/planner.h | 2 +- Marlin/src/module/stepper.cpp | 59 +++++++++++++++++++++++++---------- Marlin/src/module/stepper.h | 7 +++++ 4 files changed, 50 insertions(+), 20 deletions(-) diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index 98498f4355..f3f4a97dff 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -866,8 +866,6 @@ static_assert(COUNT(arm) == LOGICAL_AXES, "AXIS_RELATIVE_MODES must contain " _L #if ENABLED(SMOOTH_LIN_ADVANCE) #ifndef CPU_32_BIT #error "SMOOTH_LIN_ADVANCE requires a 32-bit CPU." - #elif ENABLED(S_CURVE_ACCELERATION) - #error "SMOOTH_LIN_ADVANCE is not compatible with S_CURVE_ACCELERATION." #elif ENABLED(INPUT_SHAPING_E_SYNC) && NONE(INPUT_SHAPING_X, INPUT_SHAPING_Y) #error "INPUT_SHAPING_E_SYNC requires INPUT_SHAPING_X or INPUT_SHAPING_Y." #endif diff --git a/Marlin/src/module/planner.h b/Marlin/src/module/planner.h index bda5720919..eb8f2ed17f 100644 --- a/Marlin/src/module/planner.h +++ b/Marlin/src/module/planner.h @@ -45,7 +45,7 @@ #if ENABLED(SMOOTH_LIN_ADVANCE) #define SMOOTH_LIN_ADV_EXP_ORDER 5 // Closest to Gaussian smoothing between 3 and 7 - #define SMOOTH_LIN_ADV_INTERVAL (STEPPER_TIMER_RATE / SMOOTH_LIN_ADV_HZ) // Hz + #define SMOOTH_LIN_ADV_INTERVAL (STEPPER_TIMER_RATE / (SMOOTH_LIN_ADV_HZ)) // Hz #endif #include "motion.h" diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp index fd3d3bd800..945600e4fb 100644 --- a/Marlin/src/module/stepper.cpp +++ b/Marlin/src/module/stepper.cpp @@ -1401,7 +1401,7 @@ void Stepper::apply_directions() { return (r2 | (uint16_t(r3) << 8)) | (uint32_t(r4) << 16); } - #else + #else // !__AVR__ // For all the other 32bit CPUs FORCE_INLINE void Stepper::_calc_bezier_curve_coeffs(const int32_t v0, const int32_t v1, const uint32_t av) { @@ -1478,7 +1478,9 @@ void Stepper::apply_directions() { #endif } - #endif + + #endif // !__AVR__ + #endif // S_CURVE_ACCELERATION /** @@ -2697,7 +2699,7 @@ hal_timer_t Stepper::block_phase_isr() { oversampling_factor = 0; // Decide if axis smoothing is possible - if (stepper.adaptive_step_smoothing_enabled) { + if (adaptive_step_smoothing_enabled) { uint32_t max_rate = current_block->nominal_rate; // Get the step event rate while (max_rate < min_step_isr_frequency) { // As long as more ISRs are possible... max_rate <<= 1; // Try to double the rate @@ -2902,7 +2904,7 @@ hal_timer_t Stepper::block_phase_isr() { #if ENABLED(INPUT_SHAPING_E_SYNC) - constexpr uint16_t IS_COMPENSATION_BUFFER_SIZE = uint16_t(float(SMOOTH_LIN_ADV_HZ) / float(SHAPING_MIN_FREQ) / 2.0f + 0.5f); + constexpr uint16_t IS_COMPENSATION_BUFFER_SIZE = uint16_t(float(SMOOTH_LIN_ADV_HZ) / (2.0f * (SHAPING_MIN_FREQ)) + 0.5f); typedef struct { xy_long_t buffer[IS_COMPENSATION_BUFFER_SIZE]; @@ -2924,21 +2926,39 @@ hal_timer_t Stepper::block_phase_isr() { DelayBuffer delayBuffer; - xy_long_t smooth_lin_adv_lookback(const shaping_time_t stepper_ticks) { - constexpr uint32_t ADV_TICKS_PER_STEPPER_TICKS_Q30 = (uint64_t(SMOOTH_LIN_ADV_HZ) * _BV32(30)) / STEPPER_TIMER_RATE; - const uint16_t delay_steps = MULT_Q(30, stepper_ticks, ADV_TICKS_PER_STEPPER_TICKS_Q30); + xy_long_t Stepper::smooth_lin_adv_lookback(const shaping_time_t stepper_ticks) { + constexpr uint32_t adv_ticks_per_stepper_ticks_Q30 = (uint64_t(SMOOTH_LIN_ADV_HZ) * _BV32(30)) / (STEPPER_TIMER_RATE); + const uint16_t delay_steps = MULT_Q(30, stepper_ticks, adv_ticks_per_stepper_ticks_Q30); return delayBuffer.past_item(delay_steps); } #endif // INPUT_SHAPING_E_SYNC - int32_t smooth_lin_adv_lookahead(uint32_t stepper_ticks) { + #if ENABLED(S_CURVE_ACCELERATION) + int32_t Stepper::calc_bezier_curve(const int32_t v0, const int32_t v1, const uint32_t av, const uint32_t curr_step) { + int32_t A = bezier_A, B = bezier_B, C = bezier_C; + uint32_t F = bezier_F, AV = bezier_AV; + + _calc_bezier_curve_coeffs(v0, v1, av); + uint32_t rate = _eval_bezier_curve(curr_step); + + bezier_A = A; bezier_B = B; bezier_C = C; bezier_F = F; bezier_AV = AV; + return rate; + } + #endif + + int32_t Stepper::smooth_lin_adv_lookahead(uint32_t stepper_ticks) { for (uint8_t i = 0; block_t *block = planner.get_future_block(i); i++) { if (block->is_sync()) continue; if (stepper_ticks <= block->acceleration_time) { if (!block->use_advance_lead) return 0; - uint32_t rate = STEP_MULTIPLY(stepper_ticks, block->acceleration_rate) + block->initial_rate; - NOMORE(rate, block->nominal_rate); + uint32_t rate; + #if ENABLED(S_CURVE_ACCELERATION) + rate = calc_bezier_curve(block->initial_rate, block->cruise_rate, block->acceleration_time_inverse, stepper_ticks); + #else + rate = STEP_MULTIPLY(stepper_ticks, block->acceleration_rate) + block->initial_rate; + NOMORE(rate, block->nominal_rate); + #endif return MULT_Q(30, rate, block->e_step_ratio_q30); } stepper_ticks -= block->acceleration_time; @@ -2951,13 +2971,18 @@ hal_timer_t Stepper::block_phase_isr() { if (stepper_ticks <= block->deceleration_time) { if (!block->use_advance_lead) return 0; - uint32_t rate = STEP_MULTIPLY(stepper_ticks, block->acceleration_rate); - if (rate < block->cruise_rate) { - rate = block->cruise_rate - rate; - NOLESS(rate, block->final_rate); - } - else - rate = block->final_rate; + uint32_t rate; + #if ENABLED(S_CURVE_ACCELERATION) + rate = calc_bezier_curve(block->cruise_rate, block->final_rate, block->deceleration_time_inverse, stepper_ticks); + #else + rate = STEP_MULTIPLY(stepper_ticks, block->acceleration_rate); + if (rate < block->cruise_rate) { + rate = block->cruise_rate - rate; + NOLESS(rate, block->final_rate); + } + else + rate = block->final_rate; + #endif return MULT_Q(30, rate, block->e_step_ratio_q30); } stepper_ticks -= block->deceleration_time; diff --git a/Marlin/src/module/stepper.h b/Marlin/src/module/stepper.h index 3083ad2973..330ff9f6b6 100644 --- a/Marlin/src/module/stepper.h +++ b/Marlin/src/module/stepper.h @@ -555,8 +555,15 @@ class Stepper { // The Linear advance ISR phase static void advance_isr(); #if ENABLED(SMOOTH_LIN_ADVANCE) + #if ENABLED(INPUT_SHAPING_E_SYNC) + static xy_long_t smooth_lin_adv_lookback(const shaping_time_t stepper_ticks); + #endif + static int32_t smooth_lin_adv_lookahead(uint32_t stepper_ticks); static void set_la_interval(int32_t step_rate); static hal_timer_t smooth_lin_adv_isr(); + #if ENABLED(S_CURVE_ACCELERATION) + static int32_t calc_bezier_curve(const int32_t v0, const int32_t v1, const uint32_t av, const uint32_t curr_step); + #endif #endif #endif From 348099dabba1640049b995976b5ba6e74b731136 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Mon, 9 Jun 2025 13:33:07 -0500 Subject: [PATCH 387/787] =?UTF-8?q?=F0=9F=8E=A8=20MKS=20UI=20name=20adjust?= =?UTF-8?q?ments?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/lcd/extui/mks_ui/draw_about.cpp | 2 +- .../lcd/extui/mks_ui/draw_baby_stepping.cpp | 18 +++++++-------- .../lcd/extui/mks_ui/draw_change_speed.cpp | 12 +++++----- .../src/lcd/extui/mks_ui/draw_extrusion.cpp | 12 +++++----- Marlin/src/lcd/extui/mks_ui/draw_fan.cpp | 12 +++++----- .../lcd/extui/mks_ui/draw_filament_change.cpp | 8 +++---- Marlin/src/lcd/extui/mks_ui/draw_home.cpp | 14 ++++++------ Marlin/src/lcd/extui/mks_ui/draw_language.cpp | 16 +++++++------- .../src/lcd/extui/mks_ui/draw_manuaLevel.cpp | 12 +++++----- .../lcd/extui/mks_ui/draw_media_select.cpp | 6 ++--- Marlin/src/lcd/extui/mks_ui/draw_more.cpp | 16 +++++++------- .../src/lcd/extui/mks_ui/draw_move_motor.cpp | 18 +++++++-------- .../src/lcd/extui/mks_ui/draw_operation.cpp | 18 +++++++-------- Marlin/src/lcd/extui/mks_ui/draw_preHeat.cpp | 12 +++++----- .../src/lcd/extui/mks_ui/draw_print_file.cpp | 22 +++++++++---------- Marlin/src/lcd/extui/mks_ui/draw_set.cpp | 16 +++++++------- Marlin/src/lcd/extui/mks_ui/draw_tool.cpp | 16 +++++++------- .../extui/mks_ui/draw_touch_calibration.cpp | 2 +- Marlin/src/lcd/extui/mks_ui/draw_ui.cpp | 4 ++-- Marlin/src/lcd/extui/mks_ui/draw_ui.h | 14 ++++++------ Marlin/src/lcd/extui/mks_ui/draw_wifi.cpp | 6 ++--- .../src/lcd/extui/mks_ui/draw_wifi_list.cpp | 4 ++-- .../lcd/extui/mks_ui/draw_z_offset_wizard.cpp | 12 +++++----- 23 files changed, 136 insertions(+), 136 deletions(-) diff --git a/Marlin/src/lcd/extui/mks_ui/draw_about.cpp b/Marlin/src/lcd/extui/mks_ui/draw_about.cpp index e254523e12..7be129ebda 100644 --- a/Marlin/src/lcd/extui/mks_ui/draw_about.cpp +++ b/Marlin/src/lcd/extui/mks_ui/draw_about.cpp @@ -46,7 +46,7 @@ static void event_handler(lv_obj_t *obj, lv_event_t event) { void lv_draw_about() { scr = lv_screen_create(ABOUT_UI); - lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_A_RETURN); + lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_SIZE_X * 3 + INTERVAL_W * 4, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_A_RETURN); board = lv_label_create(scr, BOARD_INFO_NAME); lv_obj_align(board, nullptr, LV_ALIGN_CENTER, 0, -80); diff --git a/Marlin/src/lcd/extui/mks_ui/draw_baby_stepping.cpp b/Marlin/src/lcd/extui/mks_ui/draw_baby_stepping.cpp index 1a6767dcc1..b55d79c2a1 100644 --- a/Marlin/src/lcd/extui/mks_ui/draw_baby_stepping.cpp +++ b/Marlin/src/lcd/extui/mks_ui/draw_baby_stepping.cpp @@ -114,24 +114,24 @@ static void event_handler(lv_obj_t *obj, lv_event_t event) { void lv_draw_baby_stepping() { scr = lv_screen_create(BABYSTEP_UI); - lv_big_button_create(scr, "F:/bmp_xAdd.bin", move_menu.x_add, INTERVAL_V, titleHeight, event_handler, ID_BABYSTEP_X_P); - lv_big_button_create(scr, "F:/bmp_xDec.bin", move_menu.x_dec, INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_BABYSTEP_X_N); - lv_big_button_create(scr, "F:/bmp_yAdd.bin", move_menu.y_add, BTN_X_PIXEL + INTERVAL_V * 2, titleHeight, event_handler, ID_BABYSTEP_Y_P); - lv_big_button_create(scr, "F:/bmp_yDec.bin", move_menu.y_dec, BTN_X_PIXEL + INTERVAL_V * 2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_BABYSTEP_Y_N); - lv_big_button_create(scr, "F:/bmp_zAdd.bin", move_menu.z_add, BTN_X_PIXEL * 2 + INTERVAL_V * 3, titleHeight, event_handler, ID_BABYSTEP_Z_P); - lv_big_button_create(scr, "F:/bmp_zDec.bin", move_menu.z_dec, BTN_X_PIXEL * 2 + INTERVAL_V * 3, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_BABYSTEP_Z_N); - buttonV = lv_imgbtn_create(scr, nullptr, BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_BABYSTEP_DIST); + lv_big_button_create(scr, "F:/bmp_xAdd.bin", move_menu.x_add, INTERVAL_W, titleHeight, event_handler, ID_BABYSTEP_X_P); + lv_big_button_create(scr, "F:/bmp_xDec.bin", move_menu.x_dec, INTERVAL_W, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_BABYSTEP_X_N); + lv_big_button_create(scr, "F:/bmp_yAdd.bin", move_menu.y_add, BTN_SIZE_X + INTERVAL_W * 2, titleHeight, event_handler, ID_BABYSTEP_Y_P); + lv_big_button_create(scr, "F:/bmp_yDec.bin", move_menu.y_dec, BTN_SIZE_X + INTERVAL_W * 2, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_BABYSTEP_Y_N); + lv_big_button_create(scr, "F:/bmp_zAdd.bin", move_menu.z_add, BTN_SIZE_X * 2 + INTERVAL_W * 3, titleHeight, event_handler, ID_BABYSTEP_Z_P); + lv_big_button_create(scr, "F:/bmp_zDec.bin", move_menu.z_dec, BTN_SIZE_X * 2 + INTERVAL_W * 3, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_BABYSTEP_Z_N); + buttonV = lv_imgbtn_create(scr, nullptr, BTN_SIZE_X * 3 + INTERVAL_W * 4, titleHeight, event_handler, ID_BABYSTEP_DIST); labelV = lv_label_create_empty(buttonV); #if HAS_ROTARY_ENCODER if (gCfgItems.encoder_enable) lv_group_add_obj(g, buttonV); #endif - lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_BABYSTEP_RETURN); + lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_SIZE_X * 3 + INTERVAL_W * 4, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_BABYSTEP_RETURN); disp_baby_step_dist(); - zOffsetText = lv_label_create(scr, 290, TITLE_YPOS, nullptr); + zOffsetText = lv_label_create(scr, 290, TITLE_POS_Y, nullptr); disp_z_offset_value(); } diff --git a/Marlin/src/lcd/extui/mks_ui/draw_change_speed.cpp b/Marlin/src/lcd/extui/mks_ui/draw_change_speed.cpp index e5d0f4244f..da0ce3c811 100644 --- a/Marlin/src/lcd/extui/mks_ui/draw_change_speed.cpp +++ b/Marlin/src/lcd/extui/mks_ui/draw_change_speed.cpp @@ -93,11 +93,11 @@ static void event_handler(lv_obj_t *obj, lv_event_t event) { void lv_draw_change_speed() { scr = lv_screen_create(CHANGE_SPEED_UI); // Create an Image button - lv_big_button_create(scr, "F:/bmp_Add.bin", speed_menu.add, INTERVAL_V, titleHeight, event_handler, ID_C_ADD); - lv_big_button_create(scr, "F:/bmp_Dec.bin", speed_menu.dec, BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_C_DEC); - buttonMov = lv_imgbtn_create(scr, nullptr, INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_C_MOVE); - buttonExt = lv_imgbtn_create(scr, nullptr, BTN_X_PIXEL + INTERVAL_V * 2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_C_EXT); - buttonStep = lv_imgbtn_create(scr, nullptr, BTN_X_PIXEL * 2 + INTERVAL_V * 3, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_C_STEP); + lv_big_button_create(scr, "F:/bmp_Add.bin", speed_menu.add, INTERVAL_W, titleHeight, event_handler, ID_C_ADD); + lv_big_button_create(scr, "F:/bmp_Dec.bin", speed_menu.dec, BTN_SIZE_X * 3 + INTERVAL_W * 4, titleHeight, event_handler, ID_C_DEC); + buttonMov = lv_imgbtn_create(scr, nullptr, INTERVAL_W, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_C_MOVE); + buttonExt = lv_imgbtn_create(scr, nullptr, BTN_SIZE_X + INTERVAL_W * 2, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_C_EXT); + buttonStep = lv_imgbtn_create(scr, nullptr, BTN_SIZE_X * 2 + INTERVAL_W * 3, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_C_STEP); #if HAS_ROTARY_ENCODER if (gCfgItems.encoder_enable) { lv_group_add_obj(g, buttonMov); @@ -105,7 +105,7 @@ void lv_draw_change_speed() { lv_group_add_obj(g, buttonStep); } #endif - lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_C_RETURN); + lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_SIZE_X * 3 + INTERVAL_W * 4, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_C_RETURN); // Create labels on the image buttons labelMov = lv_label_create_empty(buttonMov); diff --git a/Marlin/src/lcd/extui/mks_ui/draw_extrusion.cpp b/Marlin/src/lcd/extui/mks_ui/draw_extrusion.cpp index 0cacf90f36..85d08ef197 100644 --- a/Marlin/src/lcd/extui/mks_ui/draw_extrusion.cpp +++ b/Marlin/src/lcd/extui/mks_ui/draw_extrusion.cpp @@ -114,13 +114,13 @@ static void event_handler(lv_obj_t *obj, lv_event_t event) { void lv_draw_extrusion() { scr = lv_screen_create(EXTRUSION_UI); // Create image buttons - lv_obj_t *buttonAdd = lv_big_button_create(scr, "F:/bmp_in.bin", extrude_menu.in, INTERVAL_V, titleHeight, event_handler, ID_E_ADD); + lv_obj_t *buttonAdd = lv_big_button_create(scr, "F:/bmp_in.bin", extrude_menu.in, INTERVAL_W, titleHeight, event_handler, ID_E_ADD); lv_obj_clear_protect(buttonAdd, LV_PROTECT_FOLLOW); - lv_big_button_create(scr, "F:/bmp_out.bin", extrude_menu.out, BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_E_DEC); + lv_big_button_create(scr, "F:/bmp_out.bin", extrude_menu.out, BTN_SIZE_X * 3 + INTERVAL_W * 4, titleHeight, event_handler, ID_E_DEC); - buttonType = lv_imgbtn_create(scr, nullptr, INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_E_TYPE); - buttonStep = lv_imgbtn_create(scr, nullptr, BTN_X_PIXEL + INTERVAL_V * 2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_E_STEP); - buttonSpeed = lv_imgbtn_create(scr, nullptr, BTN_X_PIXEL * 2 + INTERVAL_V * 3, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_E_SPEED); + buttonType = lv_imgbtn_create(scr, nullptr, INTERVAL_W, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_E_TYPE); + buttonStep = lv_imgbtn_create(scr, nullptr, BTN_SIZE_X + INTERVAL_W * 2, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_E_STEP); + buttonSpeed = lv_imgbtn_create(scr, nullptr, BTN_SIZE_X * 2 + INTERVAL_W * 3, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_E_SPEED); #if HAS_ROTARY_ENCODER if (gCfgItems.encoder_enable) { @@ -130,7 +130,7 @@ void lv_draw_extrusion() { } #endif - lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_E_RETURN); + lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_SIZE_X * 3 + INTERVAL_W * 4, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_E_RETURN); // Create labels on the image buttons labelType = lv_label_create_empty(buttonType); diff --git a/Marlin/src/lcd/extui/mks_ui/draw_fan.cpp b/Marlin/src/lcd/extui/mks_ui/draw_fan.cpp index 12b47d9e94..ea7469980b 100644 --- a/Marlin/src/lcd/extui/mks_ui/draw_fan.cpp +++ b/Marlin/src/lcd/extui/mks_ui/draw_fan.cpp @@ -66,13 +66,13 @@ void lv_draw_fan() { scr = lv_screen_create(FAN_UI); // Create an Image button - buttonAdd = lv_big_button_create(scr, "F:/bmp_Add.bin", fan_menu.add, INTERVAL_V, titleHeight, event_handler, ID_F_ADD); + buttonAdd = lv_big_button_create(scr, "F:/bmp_Add.bin", fan_menu.add, INTERVAL_W, titleHeight, event_handler, ID_F_ADD); lv_obj_clear_protect(buttonAdd, LV_PROTECT_FOLLOW); - lv_big_button_create(scr, "F:/bmp_Dec.bin", fan_menu.dec, BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_F_DEC); - lv_big_button_create(scr, "F:/bmp_speed255.bin", fan_menu.full, INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_F_HIGH); - lv_big_button_create(scr, "F:/bmp_speed127.bin", fan_menu.half, BTN_X_PIXEL + INTERVAL_V * 2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_F_MID); - lv_big_button_create(scr, "F:/bmp_speed0.bin", fan_menu.off, BTN_X_PIXEL * 2 + INTERVAL_V * 3, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_F_OFF); - lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_F_RETURN); + lv_big_button_create(scr, "F:/bmp_Dec.bin", fan_menu.dec, BTN_SIZE_X * 3 + INTERVAL_W * 4, titleHeight, event_handler, ID_F_DEC); + lv_big_button_create(scr, "F:/bmp_speed255.bin", fan_menu.full, INTERVAL_W, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_F_HIGH); + lv_big_button_create(scr, "F:/bmp_speed127.bin", fan_menu.half, BTN_SIZE_X + INTERVAL_W * 2, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_F_MID); + lv_big_button_create(scr, "F:/bmp_speed0.bin", fan_menu.off, BTN_SIZE_X * 2 + INTERVAL_W * 3, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_F_OFF); + lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_SIZE_X * 3 + INTERVAL_W * 4, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_F_RETURN); fanText = lv_label_create_empty(scr); lv_obj_set_style(fanText, &tft_style_label_rel); diff --git a/Marlin/src/lcd/extui/mks_ui/draw_filament_change.cpp b/Marlin/src/lcd/extui/mks_ui/draw_filament_change.cpp index bd9c3ccbe7..26ed471a3a 100644 --- a/Marlin/src/lcd/extui/mks_ui/draw_filament_change.cpp +++ b/Marlin/src/lcd/extui/mks_ui/draw_filament_change.cpp @@ -109,17 +109,17 @@ static void event_handler(lv_obj_t *obj, lv_event_t event) { void lv_draw_filament_change() { scr = lv_screen_create(FILAMENTCHANGE_UI); // Create an Image button - lv_obj_t *buttonIn = lv_big_button_create(scr, "F:/bmp_in.bin", filament_menu.in, INTERVAL_V, titleHeight, event_handler, ID_FILAMNT_IN); + lv_obj_t *buttonIn = lv_big_button_create(scr, "F:/bmp_in.bin", filament_menu.in, INTERVAL_W, titleHeight, event_handler, ID_FILAMNT_IN); lv_obj_clear_protect(buttonIn, LV_PROTECT_FOLLOW); - lv_big_button_create(scr, "F:/bmp_out.bin", filament_menu.out, BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_FILAMNT_OUT); + lv_big_button_create(scr, "F:/bmp_out.bin", filament_menu.out, BTN_SIZE_X * 3 + INTERVAL_W * 4, titleHeight, event_handler, ID_FILAMNT_OUT); - buttonType = lv_imgbtn_create(scr, nullptr, INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_FILAMNT_TYPE); + buttonType = lv_imgbtn_create(scr, nullptr, INTERVAL_W, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_FILAMNT_TYPE); #if HAS_ROTARY_ENCODER if (gCfgItems.encoder_enable) lv_group_add_obj(g, buttonType); #endif - lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_FILAMNT_RETURN); + lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_SIZE_X * 3 + INTERVAL_W * 4, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_FILAMNT_RETURN); // Create labels on the image buttons labelType = lv_label_create_empty(buttonType); diff --git a/Marlin/src/lcd/extui/mks_ui/draw_home.cpp b/Marlin/src/lcd/extui/mks_ui/draw_home.cpp index a819fffacd..101afe6bd3 100644 --- a/Marlin/src/lcd/extui/mks_ui/draw_home.cpp +++ b/Marlin/src/lcd/extui/mks_ui/draw_home.cpp @@ -74,13 +74,13 @@ static void event_handler(lv_obj_t *obj, lv_event_t event) { void lv_draw_home() { scr = lv_screen_create(ZERO_UI); - lv_big_button_create(scr, "F:/bmp_zeroAll.bin", home_menu.home_all, INTERVAL_V, titleHeight, event_handler, ID_H_ALL); - lv_big_button_create(scr, "F:/bmp_zeroX.bin", home_menu.home_x, BTN_X_PIXEL + INTERVAL_V * 2, titleHeight, event_handler, ID_H_X); - lv_big_button_create(scr, "F:/bmp_zeroY.bin", home_menu.home_y, BTN_X_PIXEL * 2 + INTERVAL_V * 3, titleHeight, event_handler, ID_H_Y); - lv_big_button_create(scr, "F:/bmp_zeroZ.bin", home_menu.home_z, BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_H_Z); - lv_big_button_create(scr, "F:/bmp_function1.bin", set_menu.motoroff, INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_H_OFF_ALL); - lv_big_button_create(scr, "F:/bmp_function1.bin", set_menu.motoroffXY, BTN_X_PIXEL + INTERVAL_V * 2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_H_OFF_XY); - lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_H_RETURN); + lv_big_button_create(scr, "F:/bmp_zeroAll.bin", home_menu.home_all, INTERVAL_W, titleHeight, event_handler, ID_H_ALL); + lv_big_button_create(scr, "F:/bmp_zeroX.bin", home_menu.home_x, BTN_SIZE_X + INTERVAL_W * 2, titleHeight, event_handler, ID_H_X); + lv_big_button_create(scr, "F:/bmp_zeroY.bin", home_menu.home_y, BTN_SIZE_X * 2 + INTERVAL_W * 3, titleHeight, event_handler, ID_H_Y); + lv_big_button_create(scr, "F:/bmp_zeroZ.bin", home_menu.home_z, BTN_SIZE_X * 3 + INTERVAL_W * 4, titleHeight, event_handler, ID_H_Z); + lv_big_button_create(scr, "F:/bmp_function1.bin", set_menu.motoroff, INTERVAL_W, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_H_OFF_ALL); + lv_big_button_create(scr, "F:/bmp_function1.bin", set_menu.motoroffXY, BTN_SIZE_X + INTERVAL_W * 2, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_H_OFF_XY); + lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_SIZE_X * 3 + INTERVAL_W * 4, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_H_RETURN); } void lv_clear_home() { diff --git a/Marlin/src/lcd/extui/mks_ui/draw_language.cpp b/Marlin/src/lcd/extui/mks_ui/draw_language.cpp index 3ef8c6a0ee..d3eba04783 100644 --- a/Marlin/src/lcd/extui/mks_ui/draw_language.cpp +++ b/Marlin/src/lcd/extui/mks_ui/draw_language.cpp @@ -187,15 +187,15 @@ static void disp_language(uint8_t language, uint8_t state) { void lv_draw_language() { scr = lv_screen_create(LANGUAGE_UI); // Create image buttons - buttonCN = lv_big_button_create(scr, "F:/bmp_simplified_cn.bin", language_menu.chinese_s, INTERVAL_V, titleHeight, event_handler, ID_CN); + buttonCN = lv_big_button_create(scr, "F:/bmp_simplified_cn.bin", language_menu.chinese_s, INTERVAL_W, titleHeight, event_handler, ID_CN); lv_obj_clear_protect(buttonCN, LV_PROTECT_FOLLOW); - buttonT_CN = lv_big_button_create(scr, "F:/bmp_traditional_cn.bin", language_menu.chinese_t, BTN_X_PIXEL + INTERVAL_V * 2, titleHeight, event_handler, ID_T_CN); - buttonEN = lv_big_button_create(scr, "F:/bmp_english.bin", language_menu.english, BTN_X_PIXEL * 2 + INTERVAL_V * 3, titleHeight, event_handler, ID_EN); - buttonRU = lv_big_button_create(scr, "F:/bmp_russian.bin", language_menu.russian, BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_RU); - buttonES = lv_big_button_create(scr, "F:/bmp_spanish.bin", language_menu.spanish, INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_ES); - buttonFR = lv_big_button_create(scr, "F:/bmp_french.bin", language_menu.french, BTN_X_PIXEL + INTERVAL_V * 2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_FR); - buttonIT = lv_big_button_create(scr, "F:/bmp_italy.bin", language_menu.italy, BTN_X_PIXEL * 2 + INTERVAL_V * 3, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_IT); - lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_L_RETURN); + buttonT_CN = lv_big_button_create(scr, "F:/bmp_traditional_cn.bin", language_menu.chinese_t, BTN_SIZE_X + INTERVAL_W * 2, titleHeight, event_handler, ID_T_CN); + buttonEN = lv_big_button_create(scr, "F:/bmp_english.bin", language_menu.english, BTN_SIZE_X * 2 + INTERVAL_W * 3, titleHeight, event_handler, ID_EN); + buttonRU = lv_big_button_create(scr, "F:/bmp_russian.bin", language_menu.russian, BTN_SIZE_X * 3 + INTERVAL_W * 4, titleHeight, event_handler, ID_RU); + buttonES = lv_big_button_create(scr, "F:/bmp_spanish.bin", language_menu.spanish, INTERVAL_W, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_ES); + buttonFR = lv_big_button_create(scr, "F:/bmp_french.bin", language_menu.french, BTN_SIZE_X + INTERVAL_W * 2, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_FR); + buttonIT = lv_big_button_create(scr, "F:/bmp_italy.bin", language_menu.italy, BTN_SIZE_X * 2 + INTERVAL_W * 3, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_IT); + lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_SIZE_X * 3 + INTERVAL_W * 4, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_L_RETURN); disp_language(gCfgItems.language, SELECTED); } diff --git a/Marlin/src/lcd/extui/mks_ui/draw_manuaLevel.cpp b/Marlin/src/lcd/extui/mks_ui/draw_manuaLevel.cpp index 60724aa4f3..dd28381904 100644 --- a/Marlin/src/lcd/extui/mks_ui/draw_manuaLevel.cpp +++ b/Marlin/src/lcd/extui/mks_ui/draw_manuaLevel.cpp @@ -69,13 +69,13 @@ static void event_handler(lv_obj_t *obj, lv_event_t event) { void lv_draw_manualLevel() { scr = lv_screen_create(LEVELING_UI); // Create an Image button - lv_obj_t *buttonPoint1 = lv_big_button_create(scr, "F:/bmp_leveling1.bin", leveling_menu.position1, INTERVAL_V, titleHeight, event_handler, ID_M_POINT1); + lv_obj_t *buttonPoint1 = lv_big_button_create(scr, "F:/bmp_leveling1.bin", leveling_menu.position1, INTERVAL_W, titleHeight, event_handler, ID_M_POINT1); lv_obj_clear_protect(buttonPoint1, LV_PROTECT_FOLLOW); - lv_big_button_create(scr, "F:/bmp_leveling2.bin", leveling_menu.position2, BTN_X_PIXEL + INTERVAL_V * 2, titleHeight, event_handler, ID_M_POINT2); - lv_big_button_create(scr, "F:/bmp_leveling3.bin", leveling_menu.position3, BTN_X_PIXEL * 2 + INTERVAL_V * 3, titleHeight, event_handler, ID_M_POINT3); - lv_big_button_create(scr, "F:/bmp_leveling4.bin", leveling_menu.position4, BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_M_POINT4); - lv_big_button_create(scr, "F:/bmp_leveling5.bin", leveling_menu.position5, INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_M_POINT5); - lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_MANUAL_RETURN); + lv_big_button_create(scr, "F:/bmp_leveling2.bin", leveling_menu.position2, BTN_SIZE_X + INTERVAL_W * 2, titleHeight, event_handler, ID_M_POINT2); + lv_big_button_create(scr, "F:/bmp_leveling3.bin", leveling_menu.position3, BTN_SIZE_X * 2 + INTERVAL_W * 3, titleHeight, event_handler, ID_M_POINT3); + lv_big_button_create(scr, "F:/bmp_leveling4.bin", leveling_menu.position4, BTN_SIZE_X * 3 + INTERVAL_W * 4, titleHeight, event_handler, ID_M_POINT4); + lv_big_button_create(scr, "F:/bmp_leveling5.bin", leveling_menu.position5, INTERVAL_W, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_M_POINT5); + lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_SIZE_X * 3 + INTERVAL_W * 4, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_MANUAL_RETURN); } void lv_clear_manualLevel() { diff --git a/Marlin/src/lcd/extui/mks_ui/draw_media_select.cpp b/Marlin/src/lcd/extui/mks_ui/draw_media_select.cpp index a327f2f33e..2b96ab6e12 100644 --- a/Marlin/src/lcd/extui/mks_ui/draw_media_select.cpp +++ b/Marlin/src/lcd/extui/mks_ui/draw_media_select.cpp @@ -58,9 +58,9 @@ static void event_handler(lv_obj_t *obj, lv_event_t event) { void lv_draw_media_select() { scr = lv_screen_create(MEDIA_SELECT_UI); - lv_big_button_create(scr, "F:/bmp_sd.bin", media_select_menu.sd_disk, INTERVAL_V, titleHeight, event_handler, ID_T_SD_DISK); - lv_big_button_create(scr, "F:/bmp_usb_disk.bin", media_select_menu.usb_disk, BTN_X_PIXEL + INTERVAL_V * 2, titleHeight, event_handler, ID_T_USB_DISK); - lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_T_RETURN); + lv_big_button_create(scr, "F:/bmp_sd.bin", media_select_menu.sd_disk, INTERVAL_W, titleHeight, event_handler, ID_T_SD_DISK); + lv_big_button_create(scr, "F:/bmp_usb_disk.bin", media_select_menu.usb_disk, BTN_SIZE_X + INTERVAL_W * 2, titleHeight, event_handler, ID_T_USB_DISK); + lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_SIZE_X * 3 + INTERVAL_W * 4, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_T_RETURN); } void lv_clear_media_select() { diff --git a/Marlin/src/lcd/extui/mks_ui/draw_more.cpp b/Marlin/src/lcd/extui/mks_ui/draw_more.cpp index a9c1dc1ec6..864a3e1d96 100644 --- a/Marlin/src/lcd/extui/mks_ui/draw_more.cpp +++ b/Marlin/src/lcd/extui/mks_ui/draw_more.cpp @@ -91,47 +91,47 @@ void lv_draw_more() { const bool enc_ena = TERN0(HAS_ROTARY_ENCODER, gCfgItems.encoder_enable); - lv_obj_t *buttonGCode = lv_imgbtn_create(scr, "F:/bmp_machine_para.bin", INTERVAL_V, titleHeight, event_handler, ID_GCODE); + lv_obj_t *buttonGCode = lv_imgbtn_create(scr, "F:/bmp_machine_para.bin", INTERVAL_W, titleHeight, event_handler, ID_GCODE); if (enc_ena) lv_group_add_obj(g, buttonGCode); lv_obj_t *labelGCode = lv_label_create_empty(buttonGCode); #if HAS_USER_ITEM(1) - lv_obj_t *buttonCustom1 = lv_imgbtn_create(scr, "F:/bmp_custom1.bin", BTN_X_PIXEL + INTERVAL_V * 2, titleHeight, event_handler, ID_CUSTOM_1); + lv_obj_t *buttonCustom1 = lv_imgbtn_create(scr, "F:/bmp_custom1.bin", BTN_SIZE_X + INTERVAL_W * 2, titleHeight, event_handler, ID_CUSTOM_1); if (enc_ena) lv_group_add_obj(g, buttonCustom1); lv_obj_t *labelCustom1 = lv_label_create_empty(buttonCustom1); #endif #if HAS_USER_ITEM(2) - lv_obj_t *buttonCustom2 = lv_imgbtn_create(scr, "F:/bmp_custom2.bin", BTN_X_PIXEL * 2 + INTERVAL_V * 3, titleHeight, event_handler, ID_CUSTOM_2); + lv_obj_t *buttonCustom2 = lv_imgbtn_create(scr, "F:/bmp_custom2.bin", BTN_SIZE_X * 2 + INTERVAL_W * 3, titleHeight, event_handler, ID_CUSTOM_2); if (enc_ena) lv_group_add_obj(g, buttonCustom2); lv_obj_t *labelCustom2 = lv_label_create_empty(buttonCustom2); #endif #if HAS_USER_ITEM(3) - lv_obj_t *buttonCustom3 = lv_imgbtn_create(scr, "F:/bmp_custom3.bin", BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_CUSTOM_3); + lv_obj_t *buttonCustom3 = lv_imgbtn_create(scr, "F:/bmp_custom3.bin", BTN_SIZE_X * 3 + INTERVAL_W * 4, titleHeight, event_handler, ID_CUSTOM_3); if (enc_ena) lv_group_add_obj(g, buttonCustom3); lv_obj_t *labelCustom3 = lv_label_create_empty(buttonCustom3); #endif #if HAS_USER_ITEM(4) - lv_obj_t *buttonCustom4 = lv_imgbtn_create(scr, "F:/bmp_custom4.bin", INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_CUSTOM_4); + lv_obj_t *buttonCustom4 = lv_imgbtn_create(scr, "F:/bmp_custom4.bin", INTERVAL_W, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_CUSTOM_4); if (enc_ena) lv_group_add_obj(g, buttonCustom4); lv_obj_t *labelCustom4 = lv_label_create_empty(buttonCustom4); #endif #if HAS_USER_ITEM(5) - lv_obj_t *buttonCustom5 = lv_imgbtn_create(scr, "F:/bmp_custom5.bin", BTN_X_PIXEL + INTERVAL_V * 2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_CUSTOM_5); + lv_obj_t *buttonCustom5 = lv_imgbtn_create(scr, "F:/bmp_custom5.bin", BTN_SIZE_X + INTERVAL_W * 2, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_CUSTOM_5); if (enc_ena) lv_group_add_obj(g, buttonCustom5); lv_obj_t *labelCustom5 = lv_label_create_empty(buttonCustom5); #endif #if HAS_USER_ITEM(6) - lv_obj_t *buttonCustom6 = lv_imgbtn_create(scr, "F:/bmp_custom6.bin", BTN_X_PIXEL * 2 + INTERVAL_V * 3, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_CUSTOM_6); + lv_obj_t *buttonCustom6 = lv_imgbtn_create(scr, "F:/bmp_custom6.bin", BTN_SIZE_X * 2 + INTERVAL_W * 3, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_CUSTOM_6); if (enc_ena) lv_group_add_obj(g, buttonCustom6); lv_obj_t *labelCustom6 = lv_label_create_empty(buttonCustom6); #endif - lv_obj_t *buttonBack = lv_imgbtn_create(scr, "F:/bmp_return.bin", BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_M_RETURN); + lv_obj_t *buttonBack = lv_imgbtn_create(scr, "F:/bmp_return.bin", BTN_SIZE_X * 3 + INTERVAL_W * 4, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_M_RETURN); if (enc_ena) lv_group_add_obj(g, buttonBack); lv_obj_t *label_Back = lv_label_create_empty(buttonBack); diff --git a/Marlin/src/lcd/extui/mks_ui/draw_move_motor.cpp b/Marlin/src/lcd/extui/mks_ui/draw_move_motor.cpp index aa9fbdcd95..84959c15a1 100644 --- a/Marlin/src/lcd/extui/mks_ui/draw_move_motor.cpp +++ b/Marlin/src/lcd/extui/mks_ui/draw_move_motor.cpp @@ -99,27 +99,27 @@ void refresh_pos(lv_task_t *) { void lv_draw_move_motor() { scr = lv_screen_create(MOVE_MOTOR_UI); - lv_obj_t *buttonXI = lv_big_button_create(scr, "F:/bmp_xAdd.bin", move_menu.x_add, INTERVAL_V, titleHeight, event_handler, ID_M_X_P); + lv_obj_t *buttonXI = lv_big_button_create(scr, "F:/bmp_xAdd.bin", move_menu.x_add, INTERVAL_W, titleHeight, event_handler, ID_M_X_P); lv_obj_clear_protect(buttonXI, LV_PROTECT_FOLLOW); - lv_big_button_create(scr, "F:/bmp_xDec.bin", move_menu.x_dec, INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_M_X_N); - lv_big_button_create(scr, "F:/bmp_yAdd.bin", move_menu.y_add, BTN_X_PIXEL + INTERVAL_V * 2, titleHeight, event_handler, ID_M_Y_P); - lv_big_button_create(scr, "F:/bmp_yDec.bin", move_menu.y_dec, BTN_X_PIXEL + INTERVAL_V * 2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_M_Y_N); - lv_big_button_create(scr, "F:/bmp_zAdd.bin", move_menu.z_add, BTN_X_PIXEL * 2 + INTERVAL_V * 3, titleHeight, event_handler, ID_M_Z_P); - lv_big_button_create(scr, "F:/bmp_zDec.bin", move_menu.z_dec, BTN_X_PIXEL * 2 + INTERVAL_V * 3, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_M_Z_N); + lv_big_button_create(scr, "F:/bmp_xDec.bin", move_menu.x_dec, INTERVAL_W, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_M_X_N); + lv_big_button_create(scr, "F:/bmp_yAdd.bin", move_menu.y_add, BTN_SIZE_X + INTERVAL_W * 2, titleHeight, event_handler, ID_M_Y_P); + lv_big_button_create(scr, "F:/bmp_yDec.bin", move_menu.y_dec, BTN_SIZE_X + INTERVAL_W * 2, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_M_Y_N); + lv_big_button_create(scr, "F:/bmp_zAdd.bin", move_menu.z_add, BTN_SIZE_X * 2 + INTERVAL_W * 3, titleHeight, event_handler, ID_M_Z_P); + lv_big_button_create(scr, "F:/bmp_zDec.bin", move_menu.z_dec, BTN_SIZE_X * 2 + INTERVAL_W * 3, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_M_Z_N); // button with image and label changed dynamically by disp_move_dist - buttonV = lv_imgbtn_create(scr, nullptr, BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_M_STEP); + buttonV = lv_imgbtn_create(scr, nullptr, BTN_SIZE_X * 3 + INTERVAL_W * 4, titleHeight, event_handler, ID_M_STEP); labelV = lv_label_create_empty(buttonV); #if HAS_ROTARY_ENCODER if (gCfgItems.encoder_enable) lv_group_add_obj(g, buttonV); #endif - lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_M_RETURN); + lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_SIZE_X * 3 + INTERVAL_W * 4, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_M_RETURN); // We need to patch the title to leave some space on the right for displaying the status lv_obj_t * title = lv_obj_get_child_back(scr, nullptr); if (title != nullptr) lv_obj_set_width(title, TFT_WIDTH - 101); - labelP = lv_label_create(scr, TFT_WIDTH - 100, TITLE_YPOS, "Z:0.0mm"); + labelP = lv_label_create(scr, TFT_WIDTH - 100, TITLE_POS_Y, "Z:0.0mm"); if (labelP != nullptr) updatePosTask = lv_task_create(refresh_pos, 300, LV_TASK_PRIO_LOWEST, 0); diff --git a/Marlin/src/lcd/extui/mks_ui/draw_operation.cpp b/Marlin/src/lcd/extui/mks_ui/draw_operation.cpp index bf39a52fe9..14b655e09c 100644 --- a/Marlin/src/lcd/extui/mks_ui/draw_operation.cpp +++ b/Marlin/src/lcd/extui/mks_ui/draw_operation.cpp @@ -126,10 +126,10 @@ void lv_draw_operation() { scr = lv_screen_create(OPERATE_UI); // Create image buttons - lv_obj_t *buttonPreHeat = lv_imgbtn_create(scr, "F:/bmp_temp.bin", INTERVAL_V, titleHeight, event_handler, ID_O_PRE_HEAT); - lv_obj_t *buttonFilament = lv_imgbtn_create(scr, "F:/bmp_filamentchange.bin", BTN_X_PIXEL + INTERVAL_V * 2, titleHeight, event_handler, ID_O_FILAMENT); - lv_obj_t *buttonFan = lv_imgbtn_create(scr, "F:/bmp_fan.bin", BTN_X_PIXEL * 2 + INTERVAL_V * 3, titleHeight, event_handler, ID_O_FAN); - buttonPowerOff = lv_imgbtn_create(scr, gCfgItems.finish_power_off ? "F:/bmp_auto_off.bin" : "F:/bmp_manual_off.bin", BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_O_POWER_OFF); + lv_obj_t *buttonPreHeat = lv_imgbtn_create(scr, "F:/bmp_temp.bin", INTERVAL_W, titleHeight, event_handler, ID_O_PRE_HEAT); + lv_obj_t *buttonFilament = lv_imgbtn_create(scr, "F:/bmp_filamentchange.bin", BTN_SIZE_X + INTERVAL_W * 2, titleHeight, event_handler, ID_O_FILAMENT); + lv_obj_t *buttonFan = lv_imgbtn_create(scr, "F:/bmp_fan.bin", BTN_SIZE_X * 2 + INTERVAL_W * 3, titleHeight, event_handler, ID_O_FAN); + buttonPowerOff = lv_imgbtn_create(scr, gCfgItems.finish_power_off ? "F:/bmp_auto_off.bin" : "F:/bmp_manual_off.bin", BTN_SIZE_X * 3 + INTERVAL_W * 4, titleHeight, event_handler, ID_O_POWER_OFF); #if HAS_ROTARY_ENCODER if (gCfgItems.encoder_enable) { @@ -141,8 +141,8 @@ void lv_draw_operation() { #endif if (uiCfg.print_state != WORKING) { - buttonExtrusion = lv_imgbtn_create(scr, "F:/bmp_extrude_opr.bin", INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_O_EXTRUCT); - buttonMove = lv_imgbtn_create(scr, "F:/bmp_move_opr.bin", BTN_X_PIXEL + INTERVAL_V * 2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_O_MOV); + buttonExtrusion = lv_imgbtn_create(scr, "F:/bmp_extrude_opr.bin", INTERVAL_W, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_O_EXTRUCT); + buttonMove = lv_imgbtn_create(scr, "F:/bmp_move_opr.bin", BTN_SIZE_X + INTERVAL_W * 2, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_O_MOV); #if HAS_ROTARY_ENCODER if (gCfgItems.encoder_enable) { lv_group_add_obj(g, buttonExtrusion); @@ -151,8 +151,8 @@ void lv_draw_operation() { #endif } else { - buttonSpeed = lv_imgbtn_create(scr, "F:/bmp_speed.bin", INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_O_SPEED); - buttonBabyStep = lv_imgbtn_create(scr, "F:/bmp_mov.bin", BTN_X_PIXEL + INTERVAL_V * 2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_O_BABY_STEP); + buttonSpeed = lv_imgbtn_create(scr, "F:/bmp_speed.bin", INTERVAL_W, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_O_SPEED); + buttonBabyStep = lv_imgbtn_create(scr, "F:/bmp_mov.bin", BTN_SIZE_X + INTERVAL_W * 2, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_O_BABY_STEP); #if HAS_ROTARY_ENCODER if (gCfgItems.encoder_enable) { lv_group_add_obj(g, buttonSpeed); @@ -161,7 +161,7 @@ void lv_draw_operation() { #endif } - buttonBack = lv_imgbtn_create(scr, "F:/bmp_return.bin", BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_O_RETURN); + buttonBack = lv_imgbtn_create(scr, "F:/bmp_return.bin", BTN_SIZE_X * 3 + INTERVAL_W * 4, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_O_RETURN); #if HAS_ROTARY_ENCODER if (gCfgItems.encoder_enable) lv_group_add_obj(g, buttonBack); diff --git a/Marlin/src/lcd/extui/mks_ui/draw_preHeat.cpp b/Marlin/src/lcd/extui/mks_ui/draw_preHeat.cpp index fe289d8cad..a024f050be 100644 --- a/Marlin/src/lcd/extui/mks_ui/draw_preHeat.cpp +++ b/Marlin/src/lcd/extui/mks_ui/draw_preHeat.cpp @@ -182,8 +182,8 @@ static void event_handler(lv_obj_t *obj, lv_event_t event) { void disp_add_dec() { // Create image buttons - buttonAdd = lv_big_button_create(scr, "F:/bmp_Add.bin", preheat_menu.add, INTERVAL_V, titleHeight, event_handler, ID_P_ADD); - buttonDec = lv_big_button_create(scr, "F:/bmp_Dec.bin", preheat_menu.dec, BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_P_DEC); + buttonAdd = lv_big_button_create(scr, "F:/bmp_Add.bin", preheat_menu.add, INTERVAL_W, titleHeight, event_handler, ID_P_ADD); + buttonDec = lv_big_button_create(scr, "F:/bmp_Dec.bin", preheat_menu.dec, BTN_SIZE_X * 3 + INTERVAL_W * 4, titleHeight, event_handler, ID_P_DEC); } void lv_draw_preHeat() { @@ -192,8 +192,8 @@ void lv_draw_preHeat() { // Create image buttons disp_add_dec(); - buttonType = lv_imgbtn_create(scr, nullptr, INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_P_TYPE); - buttonStep = lv_imgbtn_create(scr, nullptr, BTN_X_PIXEL + INTERVAL_V * 2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_P_STEP); + buttonType = lv_imgbtn_create(scr, nullptr, INTERVAL_W, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_P_TYPE); + buttonStep = lv_imgbtn_create(scr, nullptr, BTN_SIZE_X + INTERVAL_W * 2, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_P_STEP); if (uiCfg.curTempType == 0) disp_ext_heart(); if (uiCfg.curTempType == 1) disp_ext_heart(); @@ -205,8 +205,8 @@ void lv_draw_preHeat() { } #endif - lv_big_button_create(scr, "F:/bmp_speed0.bin", preheat_menu.off, BTN_X_PIXEL * 2 + INTERVAL_V * 3, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_P_OFF); - lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_P_RETURN); + lv_big_button_create(scr, "F:/bmp_speed0.bin", preheat_menu.off, BTN_SIZE_X * 2 + INTERVAL_W * 3, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_P_OFF); + lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_SIZE_X * 3 + INTERVAL_W * 4, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_P_RETURN); // Create labels on the image buttons labelType = lv_label_create_empty(buttonType); diff --git a/Marlin/src/lcd/extui/mks_ui/draw_print_file.cpp b/Marlin/src/lcd/extui/mks_ui/draw_print_file.cpp index 69300ee9c9..4fbd76fccf 100644 --- a/Marlin/src/lcd/extui/mks_ui/draw_print_file.cpp +++ b/Marlin/src/lcd/extui/mks_ui/draw_print_file.cpp @@ -241,9 +241,9 @@ void disp_gcode_icon(uint8_t file_num) { scr = lv_screen_create(PRINT_FILE_UI, ""); // Create image buttons - buttonPageUp = lv_imgbtn_create(scr, "F:/bmp_pageUp.bin", OTHER_BTN_XPIEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_P_UP); - buttonPageDown = lv_imgbtn_create(scr, "F:/bmp_pageDown.bin", OTHER_BTN_XPIEL * 3 + INTERVAL_V * 4, titleHeight + OTHER_BTN_YPIEL + INTERVAL_H, event_handler, ID_P_DOWN); - buttonBack = lv_imgbtn_create(scr, "F:/bmp_back.bin", OTHER_BTN_XPIEL * 3 + INTERVAL_V * 4, titleHeight + OTHER_BTN_YPIEL * 2 + INTERVAL_H * 2, event_handler, ID_P_RETURN); + buttonPageUp = lv_imgbtn_create(scr, "F:/bmp_pageUp.bin", OTHER_BTN_SIZE_X * 3 + INTERVAL_W * 4, titleHeight, event_handler, ID_P_UP); + buttonPageDown = lv_imgbtn_create(scr, "F:/bmp_pageDown.bin", OTHER_BTN_SIZE_X * 3 + INTERVAL_W * 4, titleHeight + OTHER_BTN_SIZE_Y + INTERVAL_H, event_handler, ID_P_DOWN); + buttonBack = lv_imgbtn_create(scr, "F:/bmp_back.bin", OTHER_BTN_SIZE_X * 3 + INTERVAL_W * 4, titleHeight + OTHER_BTN_SIZE_Y * 2 + INTERVAL_H * 2, event_handler, ID_P_RETURN); // Create labels on the image buttons for (i = 0; i < FILE_BTN_CNT; i++) { @@ -273,9 +273,9 @@ void disp_gcode_icon(uint8_t file_num) { lv_obj_set_event_cb_mks(buttonGcode[i], event_handler, (i + 1), "", 0); lv_imgbtn_set_src_both(buttonGcode[i], "F:/bmp_dir.bin"); if (i < 3) - lv_obj_set_pos(buttonGcode[i], BTN_X_PIXEL * i + INTERVAL_V * (i + 1), titleHeight); + lv_obj_set_pos(buttonGcode[i], BTN_SIZE_X * i + INTERVAL_W * (i + 1), titleHeight); else - lv_obj_set_pos(buttonGcode[i], BTN_X_PIXEL * (i - 3) + INTERVAL_V * ((i - 3) + 1), BTN_Y_PIXEL + INTERVAL_H + titleHeight); + lv_obj_set_pos(buttonGcode[i], BTN_SIZE_X * (i - 3) + INTERVAL_W * ((i - 3) + 1), BTN_SIZE_Y + INTERVAL_H + titleHeight); labelPageUp[i] = lv_label_create(buttonGcode[i], public_buf_m); lv_obj_align(labelPageUp[i], buttonGcode[i], LV_ALIGN_IN_BOTTOM_MID, 0, -5); @@ -292,7 +292,7 @@ void disp_gcode_icon(uint8_t file_num) { lv_obj_set_event_cb_mks(buttonGcode[i], event_handler, (i + 1), test_public_buf_l, 0); lv_imgbtn_set_src_both(buttonGcode[i], buttonGcode[i]->mks_pic_name); if (i < 3) { - lv_obj_set_pos(buttonGcode[i], BTN_X_PIXEL * i + INTERVAL_V * (i + 1) + FILE_PRE_PIC_X_OFFSET, titleHeight + FILE_PRE_PIC_Y_OFFSET); + lv_obj_set_pos(buttonGcode[i], BTN_SIZE_X * i + INTERVAL_W * (i + 1) + FILE_PRE_PIC_X_OFFSET, titleHeight + FILE_PRE_PIC_Y_OFFSET); buttonText[i] = lv_btn_create(scr, nullptr); //lv_obj_set_event_cb(buttonText[i], event_handler); @@ -300,11 +300,11 @@ void disp_gcode_icon(uint8_t file_num) { lv_obj_clear_protect(buttonText[i], LV_PROTECT_FOLLOW); lv_btn_set_layout(buttonText[i], LV_LAYOUT_OFF); //lv_obj_set_event_cb_mks(buttonText[i], event_handler,(i+10),"", 0); - lv_obj_set_pos(buttonText[i], BTN_X_PIXEL * i + INTERVAL_V * (i + 1) + FILE_PRE_PIC_X_OFFSET, titleHeight + FILE_PRE_PIC_Y_OFFSET + 100); + lv_obj_set_pos(buttonText[i], BTN_SIZE_X * i + INTERVAL_W * (i + 1) + FILE_PRE_PIC_X_OFFSET, titleHeight + FILE_PRE_PIC_Y_OFFSET + 100); lv_obj_set_size(buttonText[i], 100, 40); } else { - lv_obj_set_pos(buttonGcode[i], BTN_X_PIXEL * (i - 3) + INTERVAL_V * ((i - 3) + 1) + FILE_PRE_PIC_X_OFFSET, BTN_Y_PIXEL + INTERVAL_H + titleHeight + FILE_PRE_PIC_Y_OFFSET); + lv_obj_set_pos(buttonGcode[i], BTN_SIZE_X * (i - 3) + INTERVAL_W * ((i - 3) + 1) + FILE_PRE_PIC_X_OFFSET, BTN_SIZE_Y + INTERVAL_H + titleHeight + FILE_PRE_PIC_Y_OFFSET); buttonText[i] = lv_btn_create(scr, nullptr); //lv_obj_set_event_cb(buttonText[i], event_handler); @@ -312,7 +312,7 @@ void disp_gcode_icon(uint8_t file_num) { lv_obj_clear_protect(buttonText[i], LV_PROTECT_FOLLOW); lv_btn_set_layout(buttonText[i], LV_LAYOUT_OFF); //lv_obj_set_event_cb_mks(buttonText[i], event_handler,(i+10),"", 0); - lv_obj_set_pos(buttonText[i], BTN_X_PIXEL * (i - 3) + INTERVAL_V * ((i - 3) + 1) + FILE_PRE_PIC_X_OFFSET, BTN_Y_PIXEL + INTERVAL_H + titleHeight + FILE_PRE_PIC_Y_OFFSET + 100); + lv_obj_set_pos(buttonText[i], BTN_SIZE_X * (i - 3) + INTERVAL_W * ((i - 3) + 1) + FILE_PRE_PIC_X_OFFSET, BTN_SIZE_Y + INTERVAL_H + titleHeight + FILE_PRE_PIC_Y_OFFSET + 100); lv_obj_set_size(buttonText[i], 100, 40); } labelPageUp[i] = lv_label_create(buttonText[i], public_buf_m); @@ -322,9 +322,9 @@ void disp_gcode_icon(uint8_t file_num) { lv_obj_set_event_cb_mks(buttonGcode[i], event_handler, (i + 1), "", 0); lv_imgbtn_set_src_both(buttonGcode[i], "F:/bmp_file.bin"); if (i < 3) - lv_obj_set_pos(buttonGcode[i], BTN_X_PIXEL * i + INTERVAL_V * (i + 1), titleHeight); + lv_obj_set_pos(buttonGcode[i], BTN_SIZE_X * i + INTERVAL_W * (i + 1), titleHeight); else - lv_obj_set_pos(buttonGcode[i], BTN_X_PIXEL * (i - 3) + INTERVAL_V * ((i - 3) + 1), BTN_Y_PIXEL + INTERVAL_H + titleHeight); + lv_obj_set_pos(buttonGcode[i], BTN_SIZE_X * (i - 3) + INTERVAL_W * ((i - 3) + 1), BTN_SIZE_Y + INTERVAL_H + titleHeight); labelPageUp[i] = lv_label_create(buttonGcode[i], public_buf_m); lv_obj_align(labelPageUp[i], buttonGcode[i], LV_ALIGN_IN_BOTTOM_MID, 0, -5); diff --git a/Marlin/src/lcd/extui/mks_ui/draw_set.cpp b/Marlin/src/lcd/extui/mks_ui/draw_set.cpp index aadf0d98f0..f991b615f6 100644 --- a/Marlin/src/lcd/extui/mks_ui/draw_set.cpp +++ b/Marlin/src/lcd/extui/mks_ui/draw_set.cpp @@ -112,18 +112,18 @@ static void event_handler(lv_obj_t *obj, lv_event_t event) { void lv_draw_set() { scr = lv_screen_create(SET_UI); - lv_big_button_create(scr, "F:/bmp_eeprom_settings.bin", set_menu.eepromSet, INTERVAL_V, titleHeight, event_handler, ID_S_EEPROM_SET); - lv_big_button_create(scr, "F:/bmp_fan.bin", set_menu.fan, BTN_X_PIXEL + INTERVAL_V * 2, titleHeight, event_handler, ID_S_FAN); - lv_big_button_create(scr, "F:/bmp_about.bin", set_menu.about, BTN_X_PIXEL * 2 + INTERVAL_V * 3, titleHeight, event_handler, ID_S_ABOUT); - lv_big_button_create(scr, ENABLED(HAS_SUICIDE) ? "F:/bmp_manual_off.bin" : "F:/bmp_function1.bin", set_menu.TERN(HAS_SUICIDE, shutdown, motoroff), BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_S_MOTOR_OFF); - lv_big_button_create(scr, "F:/bmp_machine_para.bin", set_menu.machine_para, INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_S_MACHINE_PARA); + lv_big_button_create(scr, "F:/bmp_eeprom_settings.bin", set_menu.eepromSet, INTERVAL_W, titleHeight, event_handler, ID_S_EEPROM_SET); + lv_big_button_create(scr, "F:/bmp_fan.bin", set_menu.fan, BTN_SIZE_X + INTERVAL_W * 2, titleHeight, event_handler, ID_S_FAN); + lv_big_button_create(scr, "F:/bmp_about.bin", set_menu.about, BTN_SIZE_X * 2 + INTERVAL_W * 3, titleHeight, event_handler, ID_S_ABOUT); + lv_big_button_create(scr, ENABLED(HAS_SUICIDE) ? "F:/bmp_manual_off.bin" : "F:/bmp_function1.bin", set_menu.TERN(HAS_SUICIDE, shutdown, motoroff), BTN_SIZE_X * 3 + INTERVAL_W * 4, titleHeight, event_handler, ID_S_MOTOR_OFF); + lv_big_button_create(scr, "F:/bmp_machine_para.bin", set_menu.machine_para, INTERVAL_W, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_S_MACHINE_PARA); #if HAS_LANG_SELECT_SCREEN - lv_big_button_create(scr, "F:/bmp_language.bin", set_menu.language, BTN_X_PIXEL + INTERVAL_V * 2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_S_LANGUAGE); + lv_big_button_create(scr, "F:/bmp_language.bin", set_menu.language, BTN_SIZE_X + INTERVAL_W * 2, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_S_LANGUAGE); #endif #if ENABLED(MKS_WIFI_MODULE) - lv_big_button_create(scr, "F:/bmp_wifi.bin", set_menu.wifi, BTN_X_PIXEL * 2 + INTERVAL_V * 3, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_S_WIFI); + lv_big_button_create(scr, "F:/bmp_wifi.bin", set_menu.wifi, BTN_SIZE_X * 2 + INTERVAL_W * 3, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_S_WIFI); #endif - lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_S_RETURN); + lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_SIZE_X * 3 + INTERVAL_W * 4, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_S_RETURN); } void lv_clear_set() { diff --git a/Marlin/src/lcd/extui/mks_ui/draw_tool.cpp b/Marlin/src/lcd/extui/mks_ui/draw_tool.cpp index 66b30342b2..34df931764 100644 --- a/Marlin/src/lcd/extui/mks_ui/draw_tool.cpp +++ b/Marlin/src/lcd/extui/mks_ui/draw_tool.cpp @@ -84,14 +84,14 @@ static void event_handler(lv_obj_t *obj, lv_event_t event) { void lv_draw_tool() { scr = lv_screen_create(TOOL_UI); - lv_big_button_create(scr, "F:/bmp_preHeat.bin", tool_menu.preheat, INTERVAL_V, titleHeight, event_handler, ID_T_PRE_HEAT); - lv_big_button_create(scr, "F:/bmp_extruct.bin", tool_menu.extrude, BTN_X_PIXEL + INTERVAL_V * 2, titleHeight, event_handler, ID_T_EXTRUCT); - lv_big_button_create(scr, "F:/bmp_mov.bin", tool_menu.move, BTN_X_PIXEL * 2 + INTERVAL_V * 3, titleHeight, event_handler, ID_T_MOV); - lv_big_button_create(scr, "F:/bmp_zero.bin", tool_menu.home, BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_T_HOME); - lv_big_button_create(scr, "F:/bmp_leveling.bin", tool_menu.TERN(AUTO_BED_LEVELING_BILINEAR, autoleveling, leveling), INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_T_LEVELING); - lv_big_button_create(scr, "F:/bmp_filamentchange.bin", tool_menu.filament, BTN_X_PIXEL + INTERVAL_V * 2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_T_FILAMENT); - lv_big_button_create(scr, "F:/bmp_more.bin", tool_menu.more, BTN_X_PIXEL * 2 + INTERVAL_V * 3, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_T_MORE); - lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_T_RETURN); + lv_big_button_create(scr, "F:/bmp_preHeat.bin", tool_menu.preheat, INTERVAL_W, titleHeight, event_handler, ID_T_PRE_HEAT); + lv_big_button_create(scr, "F:/bmp_extruct.bin", tool_menu.extrude, BTN_SIZE_X + INTERVAL_W * 2, titleHeight, event_handler, ID_T_EXTRUCT); + lv_big_button_create(scr, "F:/bmp_mov.bin", tool_menu.move, BTN_SIZE_X * 2 + INTERVAL_W * 3, titleHeight, event_handler, ID_T_MOV); + lv_big_button_create(scr, "F:/bmp_zero.bin", tool_menu.home, BTN_SIZE_X * 3 + INTERVAL_W * 4, titleHeight, event_handler, ID_T_HOME); + lv_big_button_create(scr, "F:/bmp_leveling.bin", tool_menu.TERN(AUTO_BED_LEVELING_BILINEAR, autoleveling, leveling), INTERVAL_W, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_T_LEVELING); + lv_big_button_create(scr, "F:/bmp_filamentchange.bin", tool_menu.filament, BTN_SIZE_X + INTERVAL_W * 2, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_T_FILAMENT); + lv_big_button_create(scr, "F:/bmp_more.bin", tool_menu.more, BTN_SIZE_X * 2 + INTERVAL_W * 3, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_T_MORE); + lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_SIZE_X * 3 + INTERVAL_W * 4, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_T_RETURN); } void lv_clear_tool() { diff --git a/Marlin/src/lcd/extui/mks_ui/draw_touch_calibration.cpp b/Marlin/src/lcd/extui/mks_ui/draw_touch_calibration.cpp index 0fd2aa0ee9..a24d66a60d 100644 --- a/Marlin/src/lcd/extui/mks_ui/draw_touch_calibration.cpp +++ b/Marlin/src/lcd/extui/mks_ui/draw_touch_calibration.cpp @@ -86,7 +86,7 @@ void lv_update_touch_calibration_screen() { // end calibration str = stage == CALIBRATION_SUCCESS ? GET_TEXT(MSG_CALIBRATION_COMPLETED) : GET_TEXT(MSG_CALIBRATION_FAILED); touch_calibration.calibration_end(); - lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_TC_RETURN); + lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_SIZE_X * 3 + INTERVAL_H * 4, BTN_SIZE_Y + INTERVAL_W + titleHeight, event_handler, ID_TC_RETURN); } // draw current message diff --git a/Marlin/src/lcd/extui/mks_ui/draw_ui.cpp b/Marlin/src/lcd/extui/mks_ui/draw_ui.cpp index 875f2d8e72..2779db5b02 100644 --- a/Marlin/src/lcd/extui/mks_ui/draw_ui.cpp +++ b/Marlin/src/lcd/extui/mks_ui/draw_ui.cpp @@ -1144,9 +1144,9 @@ lv_obj_t* lv_screen_create(DISP_STATE newScreenType, const char *title) { // title lv_obj_t *titleLabel = nullptr; if (!title) - titleLabel = lv_label_create(scr, TITLE_XPOS, TITLE_YPOS, creat_title_text()); + titleLabel = lv_label_create(scr, TITLE_POS_X, TITLE_POS_Y, creat_title_text()); else if (title[0] != '\0') - titleLabel = lv_label_create(scr, TITLE_XPOS, TITLE_YPOS, title); + titleLabel = lv_label_create(scr, TITLE_POS_X, TITLE_POS_Y, title); if (titleLabel) lv_obj_set_style(titleLabel, &tft_style_label_rel); diff --git a/Marlin/src/lcd/extui/mks_ui/draw_ui.h b/Marlin/src/lcd/extui/mks_ui/draw_ui.h index 33a0764d2c..316e5edca3 100644 --- a/Marlin/src/lcd/extui/mks_ui/draw_ui.h +++ b/Marlin/src/lcd/extui/mks_ui/draw_ui.h @@ -113,21 +113,21 @@ #define titleHeight 36 // TFT_screen.title_high #define INTERVAL_H 2 // TFT_screen.gap_h // 2 - #define INTERVAL_V 2 // TFT_screen.gap_v // 2 - #define BTN_X_PIXEL 117 // TFT_screen.btn_x_pixel - #define BTN_Y_PIXEL 140 // TFT_screen.btn_y_pixel + #define INTERVAL_W 2 // TFT_screen.gap_v // 2 + #define BTN_SIZE_X 117 // TFT_screen.btn_x_pixel + #define BTN_SIZE_Y 140 // TFT_screen.btn_y_pixel #define SIMPLE_FIRST_PAGE_GRAP 30 #define BUTTON_TEXT_Y_OFFSET -20 - #define TITLE_XPOS 3 // TFT_screen.title_xpos - #define TITLE_YPOS 5 // TFT_screen.title_ypos + #define TITLE_POS_X 3 // TFT_screen.title_xpos + #define TITLE_POS_Y 5 // TFT_screen.title_ypos #define FILE_BTN_CNT 6 - #define OTHER_BTN_XPIEL 117 - #define OTHER_BTN_YPIEL 92 + #define OTHER_BTN_SIZE_X 117 + #define OTHER_BTN_SIZE_Y 92 #define FILE_PRE_PIC_X_OFFSET 8 #define FILE_PRE_PIC_Y_OFFSET 0 diff --git a/Marlin/src/lcd/extui/mks_ui/draw_wifi.cpp b/Marlin/src/lcd/extui/mks_ui/draw_wifi.cpp index c12449f316..f2285c450a 100644 --- a/Marlin/src/lcd/extui/mks_ui/draw_wifi.cpp +++ b/Marlin/src/lcd/extui/mks_ui/draw_wifi.cpp @@ -71,9 +71,9 @@ void lv_draw_wifi() { if (gCfgItems.wifi_mode_sel == STA_MODEL) { if (gCfgItems.cloud_enable) - buttonCloud = lv_imgbtn_create(scr, "F:/bmp_cloud.bin", BTN_X_PIXEL + INTERVAL_V * 2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_W_CLOUD); + buttonCloud = lv_imgbtn_create(scr, "F:/bmp_cloud.bin", BTN_SIZE_X + INTERVAL_W * 2, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_W_CLOUD); - buttonReconnect = lv_imgbtn_create(scr, "F:/bmp_wifi.bin", BTN_X_PIXEL * 2 + INTERVAL_V * 3, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_W_RECONNECT); + buttonReconnect = lv_imgbtn_create(scr, "F:/bmp_wifi.bin", BTN_SIZE_X * 2 + INTERVAL_W * 3, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_W_RECONNECT); #if HAS_ROTARY_ENCODER if (gCfgItems.cloud_enable) lv_group_add_obj(g, buttonCloud); @@ -85,7 +85,7 @@ void lv_draw_wifi() { } // Create an Image button - lv_obj_t *buttonBack = lv_imgbtn_create(scr, "F:/bmp_return.bin", BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_W_RETURN); + lv_obj_t *buttonBack = lv_imgbtn_create(scr, "F:/bmp_return.bin", BTN_SIZE_X * 3 + INTERVAL_W * 4, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_W_RETURN); if (enc_ena) lv_group_add_obj(g, buttonBack); lv_obj_t *label_Back = lv_label_create_empty(buttonBack); diff --git a/Marlin/src/lcd/extui/mks_ui/draw_wifi_list.cpp b/Marlin/src/lcd/extui/mks_ui/draw_wifi_list.cpp index 6283b1dc58..56010c3583 100644 --- a/Marlin/src/lcd/extui/mks_ui/draw_wifi_list.cpp +++ b/Marlin/src/lcd/extui/mks_ui/draw_wifi_list.cpp @@ -92,8 +92,8 @@ static void event_handler(lv_obj_t *obj, lv_event_t event) { void lv_draw_wifi_list() { scr = lv_screen_create(WIFI_LIST_UI); - lv_obj_t *buttonDown = lv_imgbtn_create(scr, "F:/bmp_pageDown.bin", OTHER_BTN_XPIEL * 3 + INTERVAL_V * 4, titleHeight + OTHER_BTN_YPIEL + INTERVAL_H, event_handler, ID_WL_DOWN); - lv_obj_t *buttonBack = lv_imgbtn_create(scr, "F:/bmp_back.bin", OTHER_BTN_XPIEL * 3 + INTERVAL_V * 4, titleHeight + (OTHER_BTN_YPIEL + INTERVAL_H) * 2, event_handler, ID_WL_RETURN); + lv_obj_t *buttonDown = lv_imgbtn_create(scr, "F:/bmp_pageDown.bin", OTHER_BTN_SIZE_X * 3 + INTERVAL_W * 4, titleHeight + OTHER_BTN_SIZE_Y + INTERVAL_H, event_handler, ID_WL_DOWN); + lv_obj_t *buttonBack = lv_imgbtn_create(scr, "F:/bmp_back.bin", OTHER_BTN_SIZE_X * 3 + INTERVAL_W * 4, titleHeight + (OTHER_BTN_SIZE_Y + INTERVAL_H) * 2, event_handler, ID_WL_RETURN); for (uint8_t i = 0; i < NUMBER_OF_PAGE; i++) { buttonWifiN[i] = lv_label_btn_create(scr, 0, NAME_BTN_Y * i + 10 + titleHeight, NAME_BTN_X, NAME_BTN_Y, event_handler, i + 1); diff --git a/Marlin/src/lcd/extui/mks_ui/draw_z_offset_wizard.cpp b/Marlin/src/lcd/extui/mks_ui/draw_z_offset_wizard.cpp index cdd151322b..2ad9816e01 100644 --- a/Marlin/src/lcd/extui/mks_ui/draw_z_offset_wizard.cpp +++ b/Marlin/src/lcd/extui/mks_ui/draw_z_offset_wizard.cpp @@ -159,21 +159,21 @@ void lv_draw_z_offset_wizard() { scr = lv_screen_create(Z_OFFSET_WIZARD_UI, machine_menu.LevelingZoffsetTitle); - lv_obj_t *buttonXI = lv_big_button_create(scr, "F:/bmp_zAdd.bin", move_menu.z_add, INTERVAL_V, titleHeight, event_handler, ID_M_Z_P); + lv_obj_t *buttonXI = lv_big_button_create(scr, "F:/bmp_zAdd.bin", move_menu.z_add, INTERVAL_W, titleHeight, event_handler, ID_M_Z_P); lv_obj_clear_protect(buttonXI, LV_PROTECT_FOLLOW); - lv_big_button_create(scr, "F:/bmp_zDec.bin", move_menu.z_dec, INTERVAL_V * 3, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_M_Z_N); + lv_big_button_create(scr, "F:/bmp_zDec.bin", move_menu.z_dec, INTERVAL_W * 3, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_M_Z_N); // button with image and label changed dynamically by disp_move_dist - buttonV = lv_imgbtn_create(scr, nullptr, BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_M_STEP); + buttonV = lv_imgbtn_create(scr, nullptr, BTN_SIZE_X * 3 + INTERVAL_W * 4, titleHeight, event_handler, ID_M_STEP); labelV = lv_label_create_empty(buttonV); #if HAS_ROTARY_ENCODER if (gCfgItems.encoder_enable) lv_group_add_obj(g, buttonV); #endif // save and back - lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_save, BTN_X_PIXEL * 2 + INTERVAL_V * 3, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_M_SAVE); + lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_save, BTN_SIZE_X * 2 + INTERVAL_W * 3, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_M_SAVE); // cancel and back - lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_M_RETURN); + lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_SIZE_X * 3 + INTERVAL_W * 4, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_M_RETURN); // We need to patch the title to leave some space on the right for displaying the status lv_obj_t * z_offset_ref_title = lv_obj_get_child_back(scr, nullptr); @@ -183,7 +183,7 @@ void lv_draw_z_offset_wizard() { // We need to patch the Z Offset to leave some space in the middle for displaying the status lv_obj_t * title= lv_obj_get_child_back(scr, nullptr); if (title != nullptr) lv_obj_set_width(title, TFT_WIDTH - 101); - labelP = lv_label_create(scr, TFT_WIDTH - 100, TITLE_YPOS, "Z:0.0mm"); + labelP = lv_label_create(scr, TFT_WIDTH - 100, TITLE_POS_Y, "Z:0.0mm"); if (labelP != nullptr) updatePosTask = lv_task_create(refresh_wizard_pos, 300, LV_TASK_PRIO_LOWEST, 0); From c09638f821747ff86e3db402aff8f62c7dd8abbc Mon Sep 17 00:00:00 2001 From: staff1010 <132726146+staff1010@users.noreply.github.com> Date: Tue, 10 Jun 2025 02:37:38 +0800 Subject: [PATCH 388/787] =?UTF-8?q?=F0=9F=9A=B8=20Improve=20XPT2046=20touc?= =?UTF-8?q?h,=20MKS=20UI=20calibration=20(#27892)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/HAL/STM32/tft/xpt2046.h | 6 +++++- Marlin/src/gcode/lcd/M995.cpp | 2 ++ Marlin/src/lcd/extui/mks_ui/draw_touch_calibration.cpp | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Marlin/src/HAL/STM32/tft/xpt2046.h b/Marlin/src/HAL/STM32/tft/xpt2046.h index 685c9441ae..f3d3e53291 100644 --- a/Marlin/src/HAL/STM32/tft/xpt2046.h +++ b/Marlin/src/HAL/STM32/tft/xpt2046.h @@ -49,7 +49,11 @@ #define TOUCH_INT_PIN -1 #endif -#define XPT2046_DFR_MODE 0x00 +#if PIN_EXISTS(TOUCH_INT) + #define XPT2046_DFR_MODE 0x00 +#else + #define XPT2046_DFR_MODE 0x01 +#endif #define XPT2046_SER_MODE 0x04 #define XPT2046_CONTROL 0x80 diff --git a/Marlin/src/gcode/lcd/M995.cpp b/Marlin/src/gcode/lcd/M995.cpp index d5f825c0c8..2b698a5c58 100644 --- a/Marlin/src/gcode/lcd/M995.cpp +++ b/Marlin/src/gcode/lcd/M995.cpp @@ -28,6 +28,7 @@ #if HAS_TFT_LVGL_UI #include "../../lcd/extui/mks_ui/draw_touch_calibration.h" + #include "../../lcd/extui/mks_ui/draw_ui.h" #else #include "../../lcd/menu/menu.h" #endif @@ -38,6 +39,7 @@ void GcodeSuite::M995() { #if HAS_TFT_LVGL_UI + clear_cur_ui(); lv_draw_touch_calibration_screen(); #else ui.goto_screen(touch_screen_calibration); diff --git a/Marlin/src/lcd/extui/mks_ui/draw_touch_calibration.cpp b/Marlin/src/lcd/extui/mks_ui/draw_touch_calibration.cpp index a24d66a60d..25c50a2436 100644 --- a/Marlin/src/lcd/extui/mks_ui/draw_touch_calibration.cpp +++ b/Marlin/src/lcd/extui/mks_ui/draw_touch_calibration.cpp @@ -86,7 +86,7 @@ void lv_update_touch_calibration_screen() { // end calibration str = stage == CALIBRATION_SUCCESS ? GET_TEXT(MSG_CALIBRATION_COMPLETED) : GET_TEXT(MSG_CALIBRATION_FAILED); touch_calibration.calibration_end(); - lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_SIZE_X * 3 + INTERVAL_H * 4, BTN_SIZE_Y + INTERVAL_W + titleHeight, event_handler, ID_TC_RETURN); + lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, 180, BTN_SIZE_Y + INTERVAL_H + titleHeight, event_handler, ID_TC_RETURN); } // draw current message From fbce32740205da4b8cafef56cadd9ddb81b37306 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sun, 8 Jun 2025 16:37:39 -0500 Subject: [PATCH 389/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20TMC?= =?UTF-8?q?Stepper=20=3D>=200.8.7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ini/features.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ini/features.ini b/ini/features.ini index 69ec43f030..d2e0f9d92e 100644 --- a/ini/features.ini +++ b/ini/features.ini @@ -20,7 +20,7 @@ MARLIN_TEST_BUILD = build_src_filter=+ POSTMORTEM_DEBUGGING = build_src_filter=+ + build_flags=-funwind-tables MKS_WIFI_MODULE = QRCode=https://github.com/makerbase-mks/QRCode/archive/261c5a696a.zip -HAS_TRINAMIC_CONFIG = TMCStepper=https://github.com/MarlinFirmware/TMCStepper/archive/v0.8.6.zip +HAS_TRINAMIC_CONFIG = TMCStepper=https://github.com/MarlinFirmware/TMCStepper/archive/v0.8.7.zip build_src_filter=+ + + + + HAS_STEPPER_CONTROL = build_src_filter=+ HAS_T(RINAMIC_CONFIG|MC_SPI) = build_src_filter=+ From c2d586cf5f48750f8541f9f063f513e2796b3805 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Tue, 10 Jun 2025 00:32:33 +0000 Subject: [PATCH 390/787] [cron] Bump distribution date (2025-06-10) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 9f5daa27a0..ac647da94a 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-06-09" +//#define STRING_DISTRIBUTION_DATE "2025-06-10" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 16911f23ce..749e1a9543 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-06-09" + #define STRING_DISTRIBUTION_DATE "2025-06-10" #endif /** From 68dc89cf75b72cefeee19728236bae592bd295e7 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 10 Jun 2025 15:29:22 -0500 Subject: [PATCH 391/787] =?UTF-8?q?=F0=9F=8E=A8=20Align=20Bed=20PID?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/Configuration.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 08216d17b8..239a91facf 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -805,8 +805,8 @@ // 120V 250W silicone heater into 4mm borosilicate (MendelMax 1.5+) // from FOPDT model - kp=.39 Tp=405 Tdead=66, Tc set to 79.2, aggressive factor of .15 (vs .1, 1, 10) - #define DEFAULT_bedKp 10.00 - #define DEFAULT_bedKi .023 + #define DEFAULT_bedKp 10.00 + #define DEFAULT_bedKi 0.023 #define DEFAULT_bedKd 305.4 // FIND YOUR OWN: "M303 E-1 C8 S90" to run autotune on the bed at 90 degreesC for 8 cycles. From 1bb1603886339853e4a3d41857ead45f9cea331a Mon Sep 17 00:00:00 2001 From: narno2202 <130909513+narno2202@users.noreply.github.com> Date: Tue, 10 Jun 2025 22:31:02 +0200 Subject: [PATCH 392/787] =?UTF-8?q?=F0=9F=8E=A8=20FT=20Motion=20cleanup=20?= =?UTF-8?q?(#27910)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/module/ft_motion.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/Marlin/src/module/ft_motion.cpp b/Marlin/src/module/ft_motion.cpp index cb31525572..5ccc364c1d 100644 --- a/Marlin/src/module/ft_motion.cpp +++ b/Marlin/src/module/ft_motion.cpp @@ -441,13 +441,7 @@ void FTMotion::runoutBlock() { const int32_t n_diff = n_to_settle_shaper - n_to_fill_batch, n_to_fill_batch_after_settling = n_diff > 0 ? (FTM_BATCH_SIZE) - (n_diff % (FTM_BATCH_SIZE)) : -n_diff; - const int32_t n_to_settle_and_fill_batch = n_to_settle_shaper + n_to_fill_batch_after_settling; - - const int32_t N_needed_to_propagate_to_stepper = PROP_BATCHES; - - const int32_t n_to_use = N_needed_to_propagate_to_stepper * (FTM_BATCH_SIZE) + n_to_settle_and_fill_batch; - - max_intervals = n_to_use; + max_intervals = PROP_BATCHES * (FTM_BATCH_SIZE) + n_to_settle_shaper + n_to_fill_batch_after_settling; blockProcRdy = true; } From 950f492ce703ff5d545833020b208020755cd194 Mon Sep 17 00:00:00 2001 From: Andrew <18502096+classicrocker883@users.noreply.github.com> Date: Tue, 10 Jun 2025 16:34:54 -0400 Subject: [PATCH 393/787] =?UTF-8?q?=F0=9F=A9=B9=20Fix=20ProUI=20edit=20Lin?= =?UTF-8?q?.Adv.K=20(#27895)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/lcd/e3v2/proui/dwin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/src/lcd/e3v2/proui/dwin.cpp b/Marlin/src/lcd/e3v2/proui/dwin.cpp index 9d857f1e3a..cf99a13529 100644 --- a/Marlin/src/lcd/e3v2/proui/dwin.cpp +++ b/Marlin/src/lcd/e3v2/proui/dwin.cpp @@ -2689,7 +2689,7 @@ void applyMaxAccel() { planner.set_max_acceleration(hmiValue.axis, menuData.valu #if ENABLED(LIN_ADVANCE) #define LA_FDIGITS 3 void applyLA_K() { planner.set_advance_k(menuData.value / POW(10, LA_FDIGITS)); } - void setLA_K() { setPFloatOnClick(0, 10, LA_FDIGITS, applyLA_K); } + void setLA_K() { setFloatOnClick(0, 10, LA_FDIGITS, planner.extruder_advance_K[0], applyLA_K); } #endif #if HAS_X_AXIS From cf7f5bcdee96582bbb1feac0b4edd78ed09a50b1 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Wed, 11 Jun 2025 00:32:31 +0000 Subject: [PATCH 394/787] [cron] Bump distribution date (2025-06-11) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index ac647da94a..5d9ae871e5 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-06-10" +//#define STRING_DISTRIBUTION_DATE "2025-06-11" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 749e1a9543..ae5ce93f40 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-06-10" + #define STRING_DISTRIBUTION_DATE "2025-06-11" #endif /** From 9ad9323aac3c39a7243d293cc0bab66de84f2681 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Fri, 13 Jun 2025 18:10:34 -0500 Subject: [PATCH 395/787] =?UTF-8?q?=F0=9F=8E=A8=20Minor=20ternary=20style?= =?UTF-8?q?=20tweak?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/module/planner.cpp | 8 ++++---- Marlin/src/module/settings.cpp | 4 +++- Marlin/src/module/temperature.cpp | 4 ++-- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index 2e2b5798b7..156ab142f9 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -1609,7 +1609,7 @@ void Planner::quick_stop() { // Restart the block delay for the first movement - As the queue was // forced to empty, there's no risk the ISR will touch this. - delay_before_delivering = TERN_(FT_MOTION, ftMotion.cfg.active ? BLOCK_DELAY_NONE :) BLOCK_DELAY_FOR_1ST_MOVE; + delay_before_delivering = TERN0(FT_MOTION, ftMotion.cfg.active) ? BLOCK_DELAY_NONE : BLOCK_DELAY_FOR_1ST_MOVE; TERN_(HAS_WIRED_LCD, clear_block_buffer_runtime()); // Clear the accumulated runtime @@ -1770,7 +1770,7 @@ bool Planner::_buffer_steps(const xyze_long_t &target // As there are no queued movements, the Stepper ISR will not touch this // variable, so there is no risk setting this here (but it MUST be done // before the following line!!) - delay_before_delivering = TERN_(FT_MOTION, ftMotion.cfg.active ? BLOCK_DELAY_NONE :) BLOCK_DELAY_FOR_1ST_MOVE; + delay_before_delivering = TERN0(FT_MOTION, ftMotion.cfg.active) ? BLOCK_DELAY_NONE : BLOCK_DELAY_FOR_1ST_MOVE; } // Move buffer head @@ -2841,7 +2841,7 @@ void Planner::buffer_sync_block(const BlockFlagBit sync_flag/*=BLOCK_BIT_SYNC_PO // As there are no queued movements, the Stepper ISR will not touch this // variable, so there is no risk setting this here (but it MUST be done // before the following line!!) - delay_before_delivering = TERN_(FT_MOTION, ftMotion.cfg.active ? BLOCK_DELAY_NONE :) BLOCK_DELAY_FOR_1ST_MOVE; + delay_before_delivering = TERN0(FT_MOTION, ftMotion.cfg.active) ? BLOCK_DELAY_NONE : BLOCK_DELAY_FOR_1ST_MOVE; } block_buffer_head = next_buffer_head; @@ -3133,7 +3133,7 @@ bool Planner::buffer_line(const xyze_pos_t &cart, const_feedRate_t fr_mm_s // As there are no queued movements, the Stepper ISR will not touch this // variable, so there is no risk setting this here (but it MUST be done // before the following line!!) - delay_before_delivering = TERN_(FT_MOTION, ftMotion.cfg.active ? BLOCK_DELAY_NONE :) BLOCK_DELAY_FOR_1ST_MOVE; + delay_before_delivering = TERN0(FT_MOTION, ftMotion.cfg.active) ? BLOCK_DELAY_NONE : BLOCK_DELAY_FOR_1ST_MOVE; } // Move buffer head diff --git a/Marlin/src/module/settings.cpp b/Marlin/src/module/settings.cpp index 0d197b2d12..fde92376fb 100644 --- a/Marlin/src/module/settings.cpp +++ b/Marlin/src/module/settings.cpp @@ -3708,6 +3708,7 @@ void MarlinSettings::reset() { // Model predictive control // #if ENABLED(MPCTEMP) + constexpr float _mpc_heater_power[] = MPC_HEATER_POWER; constexpr float _mpc_block_heat_capacity[] = MPC_BLOCK_HEAT_CAPACITY; constexpr float _mpc_sensor_responsiveness[] = MPC_SENSOR_RESPONSIVENESS; @@ -3737,7 +3738,8 @@ void MarlinSettings::reset() { #endif mpc.filament_heat_capacity_permm = _filament_heat_capacity_permm[e]; } - #endif + + #endif // MPCTEMP // // Fixed-Time Motion diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index c1684a9fe1..04431ff299 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -1383,7 +1383,7 @@ void Temperature::factory_reset() { // If analytic tuning fails, fall back to differential tuning if (tuning_type == AUTO && (mpc.sensor_responsiveness <= 0 || mpc.block_heat_capacity <= 0)) - tuning_type = FORCE_DIFFERENTIAL; + tuning_type = FORCE_DIFFERENTIAL; if (tuning_type == FORCE_DIFFERENTIAL) { #if ENABLED(MPC_AUTOTUNE_DEBUG) @@ -1846,7 +1846,7 @@ void Temperature::mintemp_error(const heater_id_t heater_id OPTARG(ERR_INCLUDE_T float ambient_xfer_coeff = mpc.ambient_xfer_coeff_fan0; #if ENABLED(MPC_INCLUDE_FAN) const uint8_t fan_index = TERN(SINGLEFAN, 0, ee); - const float fan_fraction = TERN_(MPC_FAN_0_ACTIVE_HOTEND, !this_hotend ? 0.0f :) fan_speed[fan_index] * RECIPROCAL(255); + const float fan_fraction = TERN0(MPC_FAN_0_ACTIVE_HOTEND, !this_hotend) ? 0.0f : fan_speed[fan_index] * RECIPROCAL(255); ambient_xfer_coeff += fan_fraction * mpc.fan255_adjustment; #endif From 89416a583c413e3696734a21373397f75a4b4fea Mon Sep 17 00:00:00 2001 From: tombrazier <68918209+tombrazier@users.noreply.github.com> Date: Sat, 14 Jun 2025 01:10:03 +0100 Subject: [PATCH 396/787] =?UTF-8?q?=E2=9C=A8=20MPC=5FPTC=20(#27911)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/Configuration.h | 7 ++++++- Marlin/src/gcode/temp/M306.cpp | 30 +++++++++++++++++++++--------- Marlin/src/inc/SanityCheck.h | 1 + Marlin/src/module/settings.cpp | 12 ++++++++++++ Marlin/src/module/temperature.cpp | 5 +++-- Marlin/src/module/temperature.h | 4 ++++ 6 files changed, 47 insertions(+), 12 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 239a91facf..f6c48eae95 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -735,7 +735,12 @@ //#define MPC_AUTOTUNE_MENU // Add MPC auto-tuning to the "Advanced Settings" menu. (~350 bytes of flash) #define MPC_MAX 255 // (0..255) Current to nozzle while MPC is active. - #define MPC_HEATER_POWER { 40.0f } // (W) Heat cartridge powers. + #define MPC_HEATER_POWER { 40.0f } // (W) Nominal heat cartridge powers. + //#define MPC_PTC // Hotend power changes with temperature (e.g., PTC heat cartridges). + #if ENABLED(MPC_PTC) + #define MPC_HEATER_ALPHA { 0.0028f } // Temperature coefficient of resistance of the heat cartridges. + #define MPC_HEATER_REFTEMP { 20 } // (°C) Reference temperature for MPC_HEATER_POWER and MPC_HEATER_ALPHA. + #endif #define MPC_INCLUDE_FAN // Model the fan speed? diff --git a/Marlin/src/gcode/temp/M306.cpp b/Marlin/src/gcode/temp/M306.cpp index 12e175420d..e0c9d935e3 100644 --- a/Marlin/src/gcode/temp/M306.cpp +++ b/Marlin/src/gcode/temp/M306.cpp @@ -64,9 +64,13 @@ void GcodeSuite::M306() { case 2: tuning_type = Temperature::MPCTuningType::FORCE_ASYMPTOTIC; break; default: tuning_type = Temperature::MPCTuningType::AUTO; break; } - LCD_MESSAGE(MSG_MPC_AUTOTUNE); - thermalManager.MPC_autotune(e, tuning_type); - ui.reset_status(); + if (TERN0(MPC_PTC, tuning_type == Temperature::MPCTuningType::FORCE_ASYMPTOTIC)) + SERIAL_ECHOLNPGM("Aymptotic tuning not avaiable for PTC hotends"); + else { + LCD_MESSAGE(MSG_MPC_AUTOTUNE); + thermalManager.MPC_autotune(e, tuning_type); + ui.reset_status(); + } return; } #endif @@ -74,6 +78,10 @@ void GcodeSuite::M306() { if (parser.seen("ACFPRH")) { MPC_t &mpc = thermalManager.temp_hotend[e].mpc; if (parser.seenval('P')) mpc.heater_power = parser.value_float(); + #if ENABLED(MPC_PTC) + if (parser.seenval('L')) mpc.heater_alpha = parser.value_float(); + if (parser.seenval('Q')) mpc.heater_reftemp = parser.value_float(); + #endif if (parser.seenval('C')) mpc.block_heat_capacity = parser.value_float(); if (parser.seenval('R')) mpc.sensor_responsiveness = parser.value_float(); if (parser.seenval('A')) mpc.ambient_xfer_coeff_fan0 = parser.value_float(); @@ -94,16 +102,20 @@ void GcodeSuite::M306_report(const bool forReplay/*=true*/) { HOTEND_LOOP() { report_echo_start(forReplay); MPC_t &mpc = thermalManager.temp_hotend[e].mpc; - SERIAL_ECHOPGM(" M306 E", e, + SERIAL_ECHOLNPGM(" M306 E", e, " P", p_float_t(mpc.heater_power, 2), + #if ENABLED(MPC_PTC) + " L", p_float_t(mpc.heater_alpha, 4), + " Q", p_float_t(mpc.heater_reftemp, 2), + #endif " C", p_float_t(mpc.block_heat_capacity, 2), " R", p_float_t(mpc.sensor_responsiveness, 4), - " A", p_float_t(mpc.ambient_xfer_coeff_fan0, 4) + " A", p_float_t(mpc.ambient_xfer_coeff_fan0, 4), + #if ENABLED(MPC_INCLUDE_FAN) + " F", p_float_t(mpc.fanCoefficient(), 4), + #endif + " H", p_float_t(mpc.filament_heat_capacity_permm, 4) ); - #if ENABLED(MPC_INCLUDE_FAN) - SERIAL_ECHOPGM(" F", p_float_t(mpc.fanCoefficient(), 4)); - #endif - SERIAL_ECHOLNPGM(" H", p_float_t(mpc.filament_heat_capacity_permm, 4)); } } diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index f3f4a97dff..60b328ea67 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -1026,6 +1026,7 @@ static_assert(NUM_SERVOS <= NUM_SERVO_PLUGS, "NUM_SERVOS (or some servo index) i #undef MPC_AUTOTUNE #undef MPC_EDIT_MENU #undef MPC_AUTOTUNE_MENU + #undef MPC_PTC #endif #if ENABLED(MPC_INCLUDE_FAN) diff --git a/Marlin/src/module/settings.cpp b/Marlin/src/module/settings.cpp index fde92376fb..c8e5df92b3 100644 --- a/Marlin/src/module/settings.cpp +++ b/Marlin/src/module/settings.cpp @@ -3710,6 +3710,10 @@ void MarlinSettings::reset() { #if ENABLED(MPCTEMP) constexpr float _mpc_heater_power[] = MPC_HEATER_POWER; + #if ENABLED(MPC_PTC) + constexpr float _mpc_heater_alpha[] = MPC_HEATER_ALPHA; + constexpr float _mpc_heater_reftemp[] = MPC_HEATER_REFTEMP; + #endif constexpr float _mpc_block_heat_capacity[] = MPC_BLOCK_HEAT_CAPACITY; constexpr float _mpc_sensor_responsiveness[] = MPC_SENSOR_RESPONSIVENESS; constexpr float _mpc_ambient_xfer_coeff[] = MPC_AMBIENT_XFER_COEFF; @@ -3719,6 +3723,10 @@ void MarlinSettings::reset() { constexpr float _filament_heat_capacity_permm[] = FILAMENT_HEAT_CAPACITY_PERMM; static_assert(COUNT(_mpc_heater_power) == HOTENDS, "MPC_HEATER_POWER must have HOTENDS items."); + #if ENABLED(MPC_PTC) + static_assert(COUNT(_mpc_heater_alpha) == HOTENDS, "MPC_HEATER_ALPHA must have HOTENDS items."); + static_assert(COUNT(_mpc_heater_reftemp) == HOTENDS, "MPC_HEATER_REFTEMP must have HOTENDS items."); + #endif static_assert(COUNT(_mpc_block_heat_capacity) == HOTENDS, "MPC_BLOCK_HEAT_CAPACITY must have HOTENDS items."); static_assert(COUNT(_mpc_sensor_responsiveness) == HOTENDS, "MPC_SENSOR_RESPONSIVENESS must have HOTENDS items."); static_assert(COUNT(_mpc_ambient_xfer_coeff) == HOTENDS, "MPC_AMBIENT_XFER_COEFF must have HOTENDS items."); @@ -3730,6 +3738,10 @@ void MarlinSettings::reset() { HOTEND_LOOP() { MPC_t &mpc = thermalManager.temp_hotend[e].mpc; mpc.heater_power = _mpc_heater_power[e]; + #if ENABLED(MPC_PTC) + mpc.heater_alpha = _mpc_heater_alpha[e]; + mpc.heater_reftemp = _mpc_heater_reftemp[e]; + #endif mpc.block_heat_capacity = _mpc_block_heat_capacity[e]; mpc.sensor_responsiveness = _mpc_sensor_responsiveness[e]; mpc.ambient_xfer_coeff_fan0 = _mpc_ambient_xfer_coeff[e]; diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index 04431ff299..9c3dee6cdd 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -1864,7 +1864,8 @@ void Temperature::mintemp_error(const heater_id_t heater_id OPTARG(ERR_INCLUDE_T } // Update the modeled temperatures - float blocktempdelta = hotend.soft_pwm_amount * mpc.heater_power * (MPC_dT / 127) / mpc.block_heat_capacity; + const float _heater_power = DIV_TERN(MPC_PTC, mpc.heater_power, 1.0f + mpc.heater_alpha * (hotend.modeled_block_temp - mpc.heater_reftemp)); + float blocktempdelta = hotend.soft_pwm_amount * _heater_power * (MPC_dT / 127) / mpc.block_heat_capacity; blocktempdelta += (hotend.modeled_ambient_temp - hotend.modeled_block_temp) * ambient_xfer_coeff * MPC_dT / mpc.block_heat_capacity; hotend.modeled_block_temp += blocktempdelta; @@ -1888,7 +1889,7 @@ void Temperature::mintemp_error(const heater_id_t heater_id OPTARG(ERR_INCLUDE_T power -= (hotend.modeled_ambient_temp - hotend.modeled_block_temp) * ambient_xfer_coeff; } - float pid_output = power * 254.0f / mpc.heater_power + 1.0f; // Ensure correct quantization into a range of 0 to 127 + float pid_output = power * 254.0f / _heater_power + 1.0f; // Ensure correct quantization into a range of 0 to 127 LIMIT(pid_output, 0, MPC_MAX); /* <-- add a slash to enable diff --git a/Marlin/src/module/temperature.h b/Marlin/src/module/temperature.h index c96d9aba74..33b7bfb226 100644 --- a/Marlin/src/module/temperature.h +++ b/Marlin/src/module/temperature.h @@ -386,6 +386,10 @@ typedef struct { float p, i, d, c, f; } raw_pidcf_t; static bool e_paused; // Pause E filament permm tracking static int32_t e_position; // For E tracking float heater_power; // M306 P + #if ENABLED(MPC_PTC) + float heater_alpha; // M306 L + float heater_reftemp; // M306 Q + #endif float block_heat_capacity; // M306 C float sensor_responsiveness; // M306 R float ambient_xfer_coeff_fan0; // M306 A From 54a7ce999fc7cef38a1f7e6bce47cbccbca3373d Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Fri, 13 Jun 2025 19:28:20 -0500 Subject: [PATCH 397/787] =?UTF-8?q?=F0=9F=8E=A8=20Update=20MPC=20sanity=20?= =?UTF-8?q?checka?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Followup to #27911 --- Marlin/src/module/settings.cpp | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/Marlin/src/module/settings.cpp b/Marlin/src/module/settings.cpp index c8e5df92b3..8c3fae1393 100644 --- a/Marlin/src/module/settings.cpp +++ b/Marlin/src/module/settings.cpp @@ -3710,30 +3710,31 @@ void MarlinSettings::reset() { #if ENABLED(MPCTEMP) constexpr float _mpc_heater_power[] = MPC_HEATER_POWER; + static_assert(HOTENDS == COUNT(_mpc_heater_power), "MPC_HEATER_POWER requires values for all (" STRINGIFY(HOTENDS) ") hotends."); + #if ENABLED(MPC_PTC) constexpr float _mpc_heater_alpha[] = MPC_HEATER_ALPHA; constexpr float _mpc_heater_reftemp[] = MPC_HEATER_REFTEMP; + static_assert(HOTENDS == COUNT(_mpc_heater_alpha), "MPC_HEATER_ALPHA requires values for all (" STRINGIFY(HOTENDS) ") hotends."); + static_assert(HOTENDS == COUNT(_mpc_heater_reftemp), "MPC_HEATER_REFTEMP requires values for all (" STRINGIFY(HOTENDS) ") hotends."); #endif + constexpr float _mpc_block_heat_capacity[] = MPC_BLOCK_HEAT_CAPACITY; + static_assert(HOTENDS == COUNT(_mpc_block_heat_capacity), "MPC_BLOCK_HEAT_CAPACITY requires values for all (" STRINGIFY(HOTENDS) ") hotends."); + constexpr float _mpc_sensor_responsiveness[] = MPC_SENSOR_RESPONSIVENESS; + static_assert(HOTENDS == COUNT(_mpc_sensor_responsiveness), "MPC_SENSOR_RESPONSIVENESS requires values for all (" STRINGIFY(HOTENDS) ") hotends."); + constexpr float _mpc_ambient_xfer_coeff[] = MPC_AMBIENT_XFER_COEFF; + static_assert(HOTENDS == COUNT(_mpc_ambient_xfer_coeff), "MPC_AMBIENT_XFER_COEFF requires values for all (" STRINGIFY(HOTENDS) ") hotends."); + #if ENABLED(MPC_INCLUDE_FAN) constexpr float _mpc_ambient_xfer_coeff_fan255[] = MPC_AMBIENT_XFER_COEFF_FAN255; + static_assert(HOTENDS == COUNT(_mpc_ambient_xfer_coeff_fan255), "MPC_AMBIENT_XFER_COEFF_FAN255 requires values for all (" STRINGIFY(HOTENDS) ") hotends."); #endif - constexpr float _filament_heat_capacity_permm[] = FILAMENT_HEAT_CAPACITY_PERMM; - static_assert(COUNT(_mpc_heater_power) == HOTENDS, "MPC_HEATER_POWER must have HOTENDS items."); - #if ENABLED(MPC_PTC) - static_assert(COUNT(_mpc_heater_alpha) == HOTENDS, "MPC_HEATER_ALPHA must have HOTENDS items."); - static_assert(COUNT(_mpc_heater_reftemp) == HOTENDS, "MPC_HEATER_REFTEMP must have HOTENDS items."); - #endif - static_assert(COUNT(_mpc_block_heat_capacity) == HOTENDS, "MPC_BLOCK_HEAT_CAPACITY must have HOTENDS items."); - static_assert(COUNT(_mpc_sensor_responsiveness) == HOTENDS, "MPC_SENSOR_RESPONSIVENESS must have HOTENDS items."); - static_assert(COUNT(_mpc_ambient_xfer_coeff) == HOTENDS, "MPC_AMBIENT_XFER_COEFF must have HOTENDS items."); - #if ENABLED(MPC_INCLUDE_FAN) - static_assert(COUNT(_mpc_ambient_xfer_coeff_fan255) == HOTENDS, "MPC_AMBIENT_XFER_COEFF_FAN255 must have HOTENDS items."); - #endif - static_assert(COUNT(_filament_heat_capacity_permm) == HOTENDS, "FILAMENT_HEAT_CAPACITY_PERMM must have HOTENDS items."); + constexpr float _filament_heat_capacity_permm[] = FILAMENT_HEAT_CAPACITY_PERMM; + static_assert(HOTENDS == COUNT(_filament_heat_capacity_permm), "FILAMENT_HEAT_CAPACITY_PERMM requires values for all (" STRINGIFY(HOTENDS) ") hotends."); HOTEND_LOOP() { MPC_t &mpc = thermalManager.temp_hotend[e].mpc; From 7ac308fe4d87abbf1713a571e83829890d801c97 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Sat, 14 Jun 2025 00:31:29 +0000 Subject: [PATCH 398/787] [cron] Bump distribution date (2025-06-14) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 5d9ae871e5..90209ec147 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-06-11" +//#define STRING_DISTRIBUTION_DATE "2025-06-14" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index ae5ce93f40..607cd35bbe 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-06-11" + #define STRING_DISTRIBUTION_DATE "2025-06-14" #endif /** From 1e03f696f5069bb7807a7b3ccb50fb7e44ab224e Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Fri, 13 Jun 2025 22:13:09 -0500 Subject: [PATCH 399/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Som?= =?UTF-8?q?e=20TMC2240=20updates=20(#27901)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/Configuration.h | 4 +- Marlin/Configuration_adv.h | 18 ++-- Marlin/src/HAL/shared/progmem.h | 2 +- Marlin/src/core/drivers.h | 3 +- Marlin/src/feature/tmc_util.cpp | 140 ++++++++++++++----------- Marlin/src/module/stepper/trinamic.cpp | 119 ++++++++++++--------- docs/TMC2240_Datasheet.pdf | Bin 0 -> 1171521 bytes 7 files changed, 163 insertions(+), 123 deletions(-) create mode 100644 docs/TMC2240_Datasheet.pdf diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index f6c48eae95..5cb5682991 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -148,9 +148,9 @@ * Options: A4988, A5984, DRV8825, LV8729, TB6560, TB6600, TMC2100, * TMC2130, TMC2130_STANDALONE, TMC2160, TMC2160_STANDALONE, * TMC2208, TMC2208_STANDALONE, TMC2209, TMC2209_STANDALONE, - * TMC2240, TMC2240_STANDALONE, TMC2660, TMC2660_STANDALONE, + * TMC2240, TMC2660, TMC2660_STANDALONE, * TMC5130, TMC5130_STANDALONE, TMC5160, TMC5160_STANDALONE - * :['A4988', 'A5984', 'DRV8825', 'LV8729', 'TB6560', 'TB6600', 'TMC2100', 'TMC2130', 'TMC2130_STANDALONE', 'TMC2160', 'TMC2160_STANDALONE', 'TMC2208', 'TMC2208_STANDALONE', 'TMC2209', 'TMC2209_STANDALONE', 'TMC2240', 'TMC2240_STANDALONE', 'TMC2660', 'TMC2660_STANDALONE', 'TMC5130', 'TMC5130_STANDALONE', 'TMC5160', 'TMC5160_STANDALONE'] + * :['A4988', 'A5984', 'DRV8825', 'LV8729', 'TB6560', 'TB6600', 'TMC2100', 'TMC2130', 'TMC2130_STANDALONE', 'TMC2160', 'TMC2160_STANDALONE', 'TMC2208', 'TMC2208_STANDALONE', 'TMC2209', 'TMC2209_STANDALONE', 'TMC2240', 'TMC2660', 'TMC2660_STANDALONE', 'TMC5130', 'TMC5130_STANDALONE', 'TMC5160', 'TMC5160_STANDALONE'] */ #define X_DRIVER_TYPE A4988 #define Y_DRIVER_TYPE A4988 diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index f7ab7abd94..ebea2a2faf 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -1394,7 +1394,7 @@ * Multi-stepping sends steps in bursts to reduce MCU usage for high step-rates. * This allows higher feedrates than the MCU could otherwise support. */ -#define MULTISTEPPING_LIMIT 16 //: [1, 2, 4, 8, 16, 32, 64, 128] +#define MULTISTEPPING_LIMIT 16 // :[1, 2, 4, 8, 16, 32, 64, 128] /** * Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies @@ -3031,12 +3031,11 @@ #define INTERPOLATE true #if HAS_DRIVER(TMC2240) - #define TMC2240_CURRENT_RANGE 1 // RMS: { 0:'690mA', 1:'1410mA', 2:'2120mA', 3:'2110mA' } - // PEAK:{ 0:'1A', 1:'2A', 2:'3A', 3:'3A' } - // Determines max current. Lower is more internal current resolution. Higher runs cooler. - #define TMC2240_Rref 12000 // ('rref', 12000, minval=12000, maxval=60000) - #define TMC2240_SLOPE_CONTROL 0 // :{ 0:'100V/us', 1:'200V/us', 2:'400V/us', 3:'800V/us' } - // Lower is more silent. Higher runs cooler. + #define TMC2240_RREF 12000 // (Ω) 12000 .. 60000. (FLY TMC2240 = 12300) + // Max Current. Lower for more internal resolution. Raise to run cooler. + #define TMC2240_CURRENT_RANGE 1 // :{ 0:'RMS=690mA PEAK=1A', 1:'RMS=1410mA PEAK=2A', 2:'RMS=2120mA PEAK=3A', 3:'RMS=2110mA PEAK=3A' } + // Slope Control: Lower is more silent. Higher runs cooler. + #define TMC2240_SLOPE_CONTROL 0 // :{ 0:'100V/µs', 1:'200V/µs', 2:'400V/µs', 3:'800V/µs' } #endif #if AXIS_IS_TMC_CONFIG(X) @@ -3467,7 +3466,7 @@ * X/Y/Z_STALL_SENSITIVITY is the default stall threshold. * Use M914 X Y Z to set the stall threshold at runtime: * - * Sensitivity TMC2209/2240 Others + * Sensitivity TMC2209 Others * HIGHEST 255 -64 (Too sensitive => False positive) * LOWEST 0 63 (Too insensitive => No trigger) * @@ -3486,7 +3485,7 @@ //#define SENSORLESS_HOMING // StallGuard capable drivers only #if ANY(SENSORLESS_HOMING, SENSORLESS_PROBING) - // TMC2209/2240: 0...255. TMC2130: -64...63 + // TMC2209: 0...255. TMC2130: -64...63 #define X_STALL_SENSITIVITY 8 #define X2_STALL_SENSITIVITY X_STALL_SENSITIVITY #define Y_STALL_SENSITIVITY 8 @@ -3503,6 +3502,7 @@ //#define W_STALL_SENSITIVITY 8 //#define SPI_ENDSTOPS // TMC2130, TMC2240, and TMC5160 //#define IMPROVE_HOMING_RELIABILITY + //#define PREFER_STALLGUARD4 // TMC2240 #endif // @section tmc/config diff --git a/Marlin/src/HAL/shared/progmem.h b/Marlin/src/HAL/shared/progmem.h index 4cd7663df9..b3bd5c32fd 100644 --- a/Marlin/src/HAL/shared/progmem.h +++ b/Marlin/src/HAL/shared/progmem.h @@ -39,7 +39,7 @@ #endif #ifndef F class __FlashStringHelper; -#define F(str) (reinterpret_cast(PSTR(str))) +#define F(string_literal) (reinterpret_cast(PSTR(string_literal))) #endif #ifndef _SFR_BYTE #define _SFR_BYTE(n) (n) diff --git a/Marlin/src/core/drivers.h b/Marlin/src/core/drivers.h index 3a53360e26..80980380a5 100644 --- a/Marlin/src/core/drivers.h +++ b/Marlin/src/core/drivers.h @@ -42,7 +42,6 @@ #define _TMC2209 0x2209A #define _TMC2209_STANDALONE 0x2209B #define _TMC2240 0x2240A -#define _TMC2240_STANDALONE 0x2240B #define _TMC2660 0x2660A #define _TMC2660_STANDALONE 0x2660B #define _TMC5130 0x5130A @@ -108,7 +107,7 @@ #if ( HAS_DRIVER(TMC2100) \ || HAS_DRIVER(TMC2130_STANDALONE) || HAS_DRIVER(TMC2160_STANDALONE) \ || HAS_DRIVER(TMC2208_STANDALONE) || HAS_DRIVER(TMC2209_STANDALONE) \ - || HAS_DRIVER(TMC2240_STANDALONE) || HAS_DRIVER(TMC2660_STANDALONE) \ + || HAS_DRIVER(TMC2660_STANDALONE) \ || HAS_DRIVER(TMC5130_STANDALONE) || HAS_DRIVER(TMC5160_STANDALONE) ) #define HAS_TRINAMIC_STANDALONE 1 #endif diff --git a/Marlin/src/feature/tmc_util.cpp b/Marlin/src/feature/tmc_util.cpp index 6f53e1943c..84014e697b 100644 --- a/Marlin/src/feature/tmc_util.cpp +++ b/Marlin/src/feature/tmc_util.cpp @@ -83,9 +83,7 @@ #if HAS_TMCX1X0 - #if ENABLED(TMC_DEBUG) - static uint32_t get_pwm_scale(TMC2130Stepper &st) { return st.PWM_SCALE(); } - #endif + static uint32_t get_pwm_scale(TMC2130Stepper &st) { return st.PWM_SCALE(); } static TMC_driver_data get_driver_data(TMC2130Stepper &st) { constexpr uint8_t OT_bp = 25, OTPW_bp = 26; @@ -144,9 +142,7 @@ #if HAS_DRIVER(TMC2240) - #if ENABLED(TMC_DEBUG) - static uint32_t get_pwm_scale(TMC2240Stepper &st) { return st.PWM_SCALE(); } - #endif + static uint32_t get_pwm_scale(TMC2240Stepper &st) { return st.PWM_SCALE(); } static TMC_driver_data get_driver_data(TMC2240Stepper &st) { constexpr uint8_t OT_bp = 25, OTPW_bp = 26; @@ -205,9 +201,7 @@ #if HAS_TMC220x - #if ENABLED(TMC_DEBUG) - static uint32_t get_pwm_scale(TMC2208Stepper &st) { return st.pwm_scale_sum(); } - #endif + static uint32_t get_pwm_scale(TMC2208Stepper &st) { return st.pwm_scale_sum(); } static TMC_driver_data get_driver_data(TMC2208Stepper &st) { constexpr uint8_t OTPW_bp = 0, OT_bp = 1; @@ -242,9 +236,7 @@ #if HAS_DRIVER(TMC2660) - #if ENABLED(TMC_DEBUG) - static uint32_t get_pwm_scale(TMC2660Stepper) { return 0; } - #endif + static uint32_t get_pwm_scale(TMC2660Stepper) { return 0; } static TMC_driver_data get_driver_data(TMC2660Stepper &st) { constexpr uint8_t OT_bp = 1, OTPW_bp = 2; @@ -383,9 +375,9 @@ else if (st.otpw_count > 0) st.otpw_count = 0; } - #if ENABLED(TMC_DEBUG) - if (need_debug_reporting) report_polled_driver_data(st, data); - #endif + if (need_debug_reporting) { + TERN_(TMC_DEBUG, report_polled_driver_data(st, data)); + } return should_step_down; } @@ -518,7 +510,7 @@ TMC_TSTEP, TMC_TPWMTHRS, TMC_TPWMTHRS_MMS, - TMC_OTPW, + TMC_DEBUG_OTPW, TMC_OTPW_TRIGGERED, TMC_TOFF, TMC_TBL, @@ -575,7 +567,9 @@ TMC_GET_DRVCTRL, TMC_GET_DRVSTATUS, TMC_GET_SGCSCONF, - TMC_GET_SMARTEN + TMC_GET_SMARTEN, + TMC_GET_SG4_THRS, + TMC_GET_SG4_RESULT }; template @@ -603,6 +597,7 @@ static void print_true_or_false(const bool tf) { SERIAL_ECHO(TRUE_FALSE(tf)); } #if HAS_DRIVER(TMC2130) || HAS_DRIVER(TMC5130) + // Additional tmc_status fields for 2130/5130 and related drivers static void _tmc_status(TMC2130Stepper &st, const TMC_debug_enum i) { switch (i) { case TMC_PWM_SCALE: SERIAL_ECHO(st.PWM_SCALE()); break; @@ -614,6 +609,7 @@ } #endif #if HAS_TMCX1X0 + // Additional tmc_parse_drv_status fields for 2130 and related drivers static void _tmc_parse_drv_status(TMC2130Stepper &st, const TMC_drv_status_enum i) { switch (i) { case TMC_STALLGUARD: if (st.stallguard()) SERIAL_CHAR('*'); break; @@ -626,18 +622,17 @@ #endif #if HAS_DRIVER(TMC2160) || HAS_DRIVER(TMC5160) + // Additional tmc_status fields for 2160/5160 and related drivers static void _tmc_status(TMC2160Stepper &st, const TMC_debug_enum i) { switch (i) { case TMC_PWM_SCALE: SERIAL_ECHO(st.PWM_SCALE()); break; case TMC_SGT: SERIAL_ECHO(st.sgt()); break; case TMC_STEALTHCHOP: print_true_or_false(st.en_pwm_mode()); break; - case TMC_GLOBAL_SCALER: - { - const uint16_t value = st.GLOBAL_SCALER(); - SERIAL_ECHO(value ?: 256); - SERIAL_ECHOPGM("/256"); - } - break; + case TMC_GLOBAL_SCALER: { + const uint16_t value = st.GLOBAL_SCALER(); + SERIAL_ECHO(value ?: 256); + SERIAL_ECHOPGM("/256"); + } break; case TMC_INTERPOLATE: print_true_or_false(st.intpol()); break; default: break; } @@ -646,12 +641,16 @@ #if HAS_TMC220x + // Additional tmc_status fields for 2208/2224/2209 drivers static void _tmc_status(TMC2208Stepper &st, const TMC_debug_enum i) { switch (i) { + // PWM_SCALE case TMC_PWM_SCALE_SUM: SERIAL_ECHO(st.pwm_scale_sum()); break; case TMC_PWM_SCALE_AUTO: SERIAL_ECHO(st.pwm_scale_auto()); break; + // PWM_AUTO case TMC_PWM_OFS_AUTO: SERIAL_ECHO(st.pwm_ofs_auto()); break; case TMC_PWM_GRAD_AUTO: SERIAL_ECHO(st.pwm_grad_auto()); break; + // CHOPCONF case TMC_STEALTHCHOP: print_true_or_false(st.stealth()); break; case TMC_INTERPOLATE: print_true_or_false(st.intpol()); break; default: break; @@ -659,19 +658,20 @@ } #if HAS_DRIVER(TMC2209) + // Additional tmc_status fields for 2209 drivers template static void _tmc_status(TMCMarlin &st, const TMC_debug_enum i) { switch (i) { case TMC_SGT: SERIAL_ECHO(st.SGTHRS()); break; case TMC_UART_ADDR: SERIAL_ECHO(st.get_address()); break; default: - TMC2208Stepper *parent = &st; - _tmc_status(*parent, i); + _tmc_status(static_cast(st), i); break; } } #endif + // Additional tmc_parse_drv_status fields for 2208/2224/2209 drivers static void _tmc_parse_drv_status(TMC2208Stepper &st, const TMC_drv_status_enum i) { switch (i) { case TMC_T157: if (st.t157()) SERIAL_CHAR('*'); break; @@ -686,10 +686,13 @@ } #if HAS_DRIVER(TMC2209) + // Additional tmc_parse_drv_status fields for 2209 drivers static void _tmc_parse_drv_status(TMC2209Stepper &st, const TMC_drv_status_enum i) { switch (i) { case TMC_SG_RESULT: SERIAL_ECHO(st.SG_RESULT()); break; - default: _tmc_parse_drv_status(static_cast(st), i); break; + default: + _tmc_parse_drv_status(static_cast(st), i); + break; } } #endif @@ -697,13 +700,38 @@ #endif // HAS_TMC220x #if HAS_DRIVER(TMC2240) - static void _tmc_parse_drv_status(TMC2240Stepper, const TMC_drv_status_enum) { } + + // Additional tmc_parse_drv_status fields for 2240 drivers + static void _tmc_parse_drv_status(TMC2240Stepper &st, const TMC_drv_status_enum i) { + switch (i) { + case TMC_S2VSA: if (st.s2vsa()) SERIAL_CHAR('*'); break; + case TMC_S2VSB: if (st.s2vsb()) SERIAL_CHAR('*'); break; + case TMC_STEALTHCHOP: print_true_or_false(st.stealth()); break; + case TMC_FSACTIVE: if (st.fsactive()) SERIAL_CHAR('*'); break; + case TMC_DRV_CS_ACTUAL: if (st.CS_ACTUAL()) SERIAL_CHAR('*'); break; + case TMC_STALLGUARD: if (st.stallguard()) SERIAL_CHAR('*'); break; + //case TMC_OT: if (st.ot()) SERIAL_CHAR('*'); break; + case TMC_DEBUG_OTPW: print_true_or_false(st.otpw()); break; + //case TMC_S2GA: if (st.s2ga()) SERIAL_CHAR('*'); break; + //case TMC_S2GB: if (st.s2gb()) SERIAL_CHAR('*'); break; + //case TMC_OLA: if (st.ola()) SERIAL_CHAR('*'); break; + //case TMC_OLB: if (st.olb()) SERIAL_CHAR('*'); break; + case TMC_SG_RESULT: SERIAL_ECHO(st.SG_RESULT()); break; + case TMC_STST: if (!st.stst()) SERIAL_CHAR('*'); break; + default: break; // other... + } + } + + // Additional tmc_status fields for 2240 drivers static void _tmc_status(TMC2240Stepper &st, const TMC_debug_enum i) { switch (i) { + // PWM_SCALE case TMC_PWM_SCALE_SUM: SERIAL_ECHO(st.pwm_scale_sum()); break; case TMC_PWM_SCALE_AUTO: SERIAL_ECHO(st.pwm_scale_auto()); break; + // PWM_AUTO case TMC_PWM_OFS_AUTO: SERIAL_ECHO(st.pwm_ofs_auto()); break; case TMC_PWM_GRAD_AUTO: SERIAL_ECHO(st.pwm_grad_auto()); break; + // CHOPCONF case TMC_STEALTHCHOP: print_true_or_false(st.stealth()); break; case TMC_INTERPOLATE: print_true_or_false(st.intpol()); break; case TMC_VAIN: SERIAL_ECHO(st.get_ain_voltage()); break; @@ -714,7 +742,8 @@ default: break; } } - #endif + + #endif // TMC2240 #if HAS_DRIVER(TMC2660) static void _tmc_parse_drv_status(TMC2660Stepper, const TMC_drv_status_enum) { } @@ -750,14 +779,8 @@ case TMC_CURRENT: SERIAL_ECHO(st.getMilliamps()); break; case TMC_RMS_CURRENT: SERIAL_ECHO(st.rms_current()); break; case TMC_MAX_CURRENT: SERIAL_ECHO(p_float_t(st.rms_current() * 1.41, 0)); break; - case TMC_IRUN: - SERIAL_ECHO(st.irun()); - SERIAL_ECHOPGM("/31"); - break; - case TMC_IHOLD: - SERIAL_ECHO(st.ihold()); - SERIAL_ECHOPGM("/31"); - break; + case TMC_IRUN: SERIAL_ECHO(st.irun()); SERIAL_ECHOPGM("/31"); break; + case TMC_IHOLD: SERIAL_ECHO(st.ihold()); SERIAL_ECHOPGM("/31"); break; case TMC_CS_ACTUAL: print_cs_actual(st); break; case TMC_VSENSE: print_vsense(st); break; case TMC_MICROSTEPS: SERIAL_ECHO(st.microsteps()); break; @@ -769,7 +792,7 @@ if (tpwmthrs_val) SERIAL_ECHO(tpwmthrs_val); else SERIAL_CHAR('-'); } break; #endif - case TMC_OTPW: print_true_or_false(st.otpw()); break; + case TMC_DEBUG_OTPW: print_true_or_false(st.otpw()); break; #if ENABLED(MONITOR_DRIVER_STATUS) case TMC_OTPW_TRIGGERED: print_true_or_false(st.getOTPW()); break; #endif @@ -792,13 +815,10 @@ case TMC_CURRENT: SERIAL_ECHO(st.getMilliamps()); break; case TMC_RMS_CURRENT: SERIAL_ECHO(st.rms_current()); break; case TMC_MAX_CURRENT: SERIAL_ECHO(p_float_t(st.rms_current() * 1.41, 0)); break; - case TMC_IRUN: - SERIAL_ECHO(st.cs()); - SERIAL_ECHOPGM("/31"); - break; + case TMC_IRUN: SERIAL_ECHO(st.cs()); SERIAL_ECHOPGM("/31"); break; case TMC_VSENSE: SERIAL_ECHO(st.vsense() ? F("1=.165") : F("0=.310")); break; case TMC_MICROSTEPS: SERIAL_ECHO(st.microsteps()); break; - //case TMC_OTPW: print_true_or_false(st.otpw()); break; + //case TMC_DEBUG_OTPW: print_true_or_false(st.otpw()); break; //case TMC_OTPW_TRIGGERED: print_true_or_false(st.getOTPW()); break; case TMC_SGT: SERIAL_ECHO(st.sgt()); break; case TMC_TOFF: SERIAL_ECHO(st.toff()); break; @@ -808,30 +828,26 @@ default: _tmc_status(st, i); break; } } - #endif + #endif // TMC2660 template static void tmc_parse_drv_status(TMC &st, const TMC_drv_status_enum i) { SERIAL_CHAR('\t'); switch (i) { - case TMC_DRV_CODES: st.printLabel(); break; - case TMC_STST: if (!st.stst()) SERIAL_CHAR('*'); break; - case TMC_OLB: if (st.olb()) SERIAL_CHAR('*'); break; - case TMC_OLA: if (st.ola()) SERIAL_CHAR('*'); break; - case TMC_S2GB: if (st.s2gb()) SERIAL_CHAR('*'); break; - case TMC_S2GA: if (st.s2ga()) SERIAL_CHAR('*'); break; - case TMC_DRV_OTPW: if (st.otpw()) SERIAL_CHAR('*'); break; - case TMC_OT: if (st.ot()) SERIAL_CHAR('*'); break; + case TMC_DRV_CODES: st.printLabel(); break; + case TMC_STST: if (!st.stst()) SERIAL_CHAR('*'); break; + case TMC_OLB: if (st.olb()) SERIAL_CHAR('*'); break; + case TMC_OLA: if (st.ola()) SERIAL_CHAR('*'); break; + case TMC_S2GB: if (st.s2gb()) SERIAL_CHAR('*'); break; + case TMC_S2GA: if (st.s2ga()) SERIAL_CHAR('*'); break; + case TMC_DRV_OTPW: if (st.otpw()) SERIAL_CHAR('*'); break; + case TMC_OT: if (st.ot()) SERIAL_CHAR('*'); break; case TMC_DRV_STATUS_HEX: { const uint32_t drv_status = st.DRV_STATUS(); - SERIAL_CHAR('\t'); - st.printLabel(); - SERIAL_CHAR('\t'); - print_hex_long(drv_status, ':', true); + SERIAL_CHAR('\t'); st.printLabel(); SERIAL_CHAR('\t'); print_hex_long(drv_status, ':', true); if (drv_status == 0xFFFFFFFF || drv_status == 0) SERIAL_ECHOPGM("\t Bad response!"); SERIAL_EOL(); - break; - } + } break; default: _tmc_parse_drv_status(st, i); break; } } @@ -946,7 +962,7 @@ TMC_REPORT("tstep\t", TMC_TSTEP); TMC_REPORT("PWM thresh.", TMC_TPWMTHRS); TMC_REPORT("[mm/s]\t", TMC_TPWMTHRS_MMS); - TMC_REPORT("OT prewarn", TMC_OTPW); + TMC_REPORT("OT prewarn", TMC_DEBUG_OTPW); #if ENABLED(MONITOR_DRIVER_STATUS) TMC_REPORT("triggered\n OTP\t", TMC_OTPW_TRIGGERED); #endif @@ -964,6 +980,7 @@ TMC_REPORT(" -start\t", TMC_HSTRT); TMC_REPORT("Stallguard thrs", TMC_SGT); TMC_REPORT("uStep count", TMC_MSCNT); + DRV_REPORT("DRVSTATUS", TMC_DRV_CODES); #if HAS_TMCX1X0_OR_2240 || HAS_TMC220x DRV_REPORT("sg_result", TMC_SG_RESULT); @@ -984,10 +1001,12 @@ DRV_REPORT("150C\t", TMC_T150); DRV_REPORT("143C\t", TMC_T143); DRV_REPORT("120C\t", TMC_T120); + #endif + #if HAS_TMC220x || HAS_DRIVER(TMC2240) DRV_REPORT("s2vsa\t", TMC_S2VSA); DRV_REPORT("s2vsb\t", TMC_S2VSB); #endif - DRV_REPORT("Driver registers:\n",TMC_DRV_STATUS_HEX); + DRV_REPORT("Driver registers:\n", TMC_DRV_STATUS_HEX); #if HAS_DRIVER(TMC2240) TMC_REPORT("Analog in (v)", TMC_VAIN); TMC_REPORT("Supply (v)", TMC_VSUPPLY); @@ -1035,6 +1054,7 @@ } SERIAL_CHAR('\t'); } + #endif // HAS_TRINAMIC_CONFIG #if HAS_DRIVER(TMC2660) diff --git a/Marlin/src/module/stepper/trinamic.cpp b/Marlin/src/module/stepper/trinamic.cpp index 240adc9f4c..ea123c5392 100644 --- a/Marlin/src/module/stepper/trinamic.cpp +++ b/Marlin/src/module/stepper/trinamic.cpp @@ -32,9 +32,6 @@ #include "trinamic.h" #include "../stepper.h" -#include -#include - enum StealthIndex : uint8_t { LOGICAL_AXIS_LIST(STEALTH_AXIS_E, STEALTH_AXIS_X, STEALTH_AXIS_Y, STEALTH_AXIS_Z, STEALTH_AXIS_I, STEALTH_AXIS_J, STEALTH_AXIS_K, STEALTH_AXIS_U, STEALTH_AXIS_V, STEALTH_AXIS_W) }; @@ -242,12 +239,12 @@ enum StealthIndex : uint8_t { st.begin(); CHOPCONF_t chopconf{0}; - chopconf.tbl = 0b01; - chopconf.toff = chop_init.toff; + chopconf.tbl = 0b01; + chopconf.toff = chop_init.toff; chopconf.intpol = interpolate; - chopconf.hend = chop_init.hend + 3; - chopconf.hstrt = chop_init.hstrt - 1; - TERN_(EDGE_STEPPING, chopconf.dedge = true); + chopconf.hend = chop_init.hend + 3; + chopconf.hstrt = chop_init.hstrt - 1; + chopconf.dedge = ENABLED(EDGE_STEPPING); st.CHOPCONF(chopconf.sr); st.rms_current(mA, hold_multiplier); @@ -280,12 +277,12 @@ enum StealthIndex : uint8_t { st.begin(); CHOPCONF_t chopconf{0}; - chopconf.tbl = 0b01; - chopconf.toff = chop_init.toff; + chopconf.tbl = 0b01; + chopconf.toff = chop_init.toff; chopconf.intpol = interpolate; - chopconf.hend = chop_init.hend + 3; - chopconf.hstrt = chop_init.hstrt - 1; - TERN_(EDGE_STEPPING, chopconf.dedge = true); + chopconf.hend = chop_init.hend + 3; + chopconf.hstrt = chop_init.hstrt - 1; + chopconf.dedge = ENABLED(EDGE_STEPPING); st.CHOPCONF(chopconf.sr); st.rms_current(mA, hold_multiplier); @@ -705,12 +702,12 @@ enum StealthIndex : uint8_t { st.stored.stealthChop_enabled = stealth; TMC2208_n::CHOPCONF_t chopconf{0}; - chopconf.tbl = 0b01; // blank_time = 24 - chopconf.toff = chop_init.toff; + chopconf.tbl = 0b01; // blank_time = 24 + chopconf.toff = chop_init.toff; chopconf.intpol = interpolate; - chopconf.hend = chop_init.hend + 3; - chopconf.hstrt = chop_init.hstrt - 1; - TERN_(EDGE_STEPPING, chopconf.dedge = true); + chopconf.hend = chop_init.hend + 3; + chopconf.hstrt = chop_init.hstrt - 1; + chopconf.dedge = ENABLED(EDGE_STEPPING); st.CHOPCONF(chopconf.sr); st.rms_current(mA, hold_multiplier); @@ -750,12 +747,12 @@ enum StealthIndex : uint8_t { st.stored.stealthChop_enabled = stealth; TMC2208_n::CHOPCONF_t chopconf{0}; - chopconf.tbl = 0b01; // blank_time = 24 - chopconf.toff = chop_init.toff; + chopconf.tbl = 0b01; // blank_time = 24 + chopconf.toff = chop_init.toff; chopconf.intpol = interpolate; - chopconf.hend = chop_init.hend + 3; - chopconf.hstrt = chop_init.hstrt - 1; - TERN_(EDGE_STEPPING, chopconf.dedge = true); + chopconf.hend = chop_init.hend + 3; + chopconf.hstrt = chop_init.hstrt - 1; + chopconf.dedge = ENABLED(EDGE_STEPPING); st.CHOPCONF(chopconf.sr); st.rms_current(mA, hold_multiplier); @@ -788,44 +785,68 @@ enum StealthIndex : uint8_t { ) { st.begin(); - st.Rref = TMC2240_Rref; + st.Rref = TMC2240_RREF; // Minimum: 12000 ; FLY TMC2240: 12300 + + TMC2240_n::GCONF_t gconf{0}; + gconf.en_pwm_mode = !stealth; + st.GCONF(gconf.sr); + TMC2240_n::DRV_CONF_t drv_conf{0}; drv_conf.current_range = TMC2240_CURRENT_RANGE; drv_conf.slope_control = TMC2240_SLOPE_CONTROL; st.DRV_CONF(drv_conf.sr); - CHOPCONF_t chopconf{0}; - chopconf.tbl = 0b01; - chopconf.toff = chop_init.toff; - chopconf.intpol = interpolate; - chopconf.hend = chop_init.hend + 3; - chopconf.hstrt = chop_init.hstrt - 1; - TERN_(EDGE_STEPPING, chopconf.dedge = true); + // Adjust based on user experience + TMC2240_n::CHOPCONF_t chopconf{0}; + chopconf.toff = chop_init.toff; // 3 (3) + chopconf.intpol = interpolate; // true + chopconf.hend = chop_init.hend + 3; // 2 (-1) + chopconf.hstrt = chop_init.hstrt - 1; // 5 (6) + chopconf.TBL = 0b10; // 36 tCLK + chopconf.tpfd = 4; // 512 NCLK + chopconf.dedge = ENABLED(EDGE_STEPPING); st.CHOPCONF(chopconf.sr); st.rms_current(mA, hold_multiplier); st.microsteps(microsteps); - st.iholddelay(10); + st.iholddelay(6); + st.irundelay(4); + + // (from Makerbase) + //st.TPOWERDOWN(10); + st.TPOWERDOWN(128); // ~2s until driver lowers to hold current st.en_pwm_mode(stealth); st.stored.stealthChop_enabled = stealth; + // Adjust based on user experience TMC2240_n::PWMCONF_t pwmconf{0}; - pwmconf.pwm_lim = 12; - pwmconf.pwm_reg = 8; - pwmconf.pwm_autograd = true; - pwmconf.pwm_autoscale = true; - pwmconf.pwm_freq = 0b01; - pwmconf.pwm_grad = 14; - pwmconf.pwm_ofs = 36; + pwmconf.pwm_ofs = 29; + pwmconf.pwm_grad = 0; + pwmconf.pwm_freq = 0b00; // fPWM = 2/1024 fCLK | 16MHz clock -> 31.3kHz PWM + pwmconf.pwm_autograd = true; + pwmconf.pwm_autoscale = true; + pwmconf.freewheel = 0; + pwmconf.pwm_meas_sd_enable = false; + pwmconf.pwm_dis_reg_stst = false; + pwmconf.pwm_reg = 4; + pwmconf.pwm_lim = 12; st.PWMCONF(pwmconf.sr); TERN(HYBRID_THRESHOLD, st.set_pwm_thrs(hyb_thrs), UNUSED(hyb_thrs)); + // (from Makerbase) + //st.GCONF(0x00); + //st.IHOLD_IRUN(0x04071f03); + //st.GSTAT(0x07); + //st.GSTAT(0x00); + st.diag0_pushpull(true); + st.GSTAT(); // Clear GSTAT } + #endif // TMC2240 #if HAS_DRIVER(TMC2660) @@ -862,12 +883,12 @@ enum StealthIndex : uint8_t { st.begin(); CHOPCONF_t chopconf{0}; - chopconf.tbl = 0b01; - chopconf.toff = chop_init.toff; + chopconf.tbl = 0b01; + chopconf.toff = chop_init.toff; chopconf.intpol = interpolate; - chopconf.hend = chop_init.hend + 3; - chopconf.hstrt = chop_init.hstrt - 1; - TERN_(EDGE_STEPPING, chopconf.dedge = true); + chopconf.hend = chop_init.hend + 3; + chopconf.hstrt = chop_init.hstrt - 1; + chopconf.dedge = ENABLED(EDGE_STEPPING); st.CHOPCONF(chopconf.sr); st.rms_current(mA, hold_multiplier); @@ -900,12 +921,12 @@ enum StealthIndex : uint8_t { st.begin(); CHOPCONF_t chopconf{0}; - chopconf.tbl = 0b01; - chopconf.toff = chop_init.toff; + chopconf.tbl = 0b01; + chopconf.toff = chop_init.toff; chopconf.intpol = interpolate; - chopconf.hend = chop_init.hend + 3; - chopconf.hstrt = chop_init.hstrt - 1; - TERN_(EDGE_STEPPING, chopconf.dedge = true); + chopconf.hend = chop_init.hend + 3; + chopconf.hstrt = chop_init.hstrt - 1; + chopconf.dedge = ENABLED(EDGE_STEPPING); st.CHOPCONF(chopconf.sr); st.rms_current(mA, hold_multiplier); diff --git a/docs/TMC2240_Datasheet.pdf b/docs/TMC2240_Datasheet.pdf new file mode 100644 index 0000000000000000000000000000000000000000..89c9cf817e671daddfbe1d376cd0cd2a4ce99cd3 GIT binary patch literal 1171521 zcmZ_VV|X3yy8!y8NgCU>?WD17+qRv?wr$(C)ueG6+jhf~x9k1yz0W@T*wx*DDa{8vm zj`)n9pDRGp$vQh(ncIB+&A>ztxT5If;B4rmJBmB=hjd?zQAdPK|{&^N81Jgh3zmJtNwlQ@w!)N4R2LK}GR!+ta_;eyx`cB3| z#)h^=#*qKMo2-F_qLVcwoeVw$D=Q?Oh`EE~=aX4j=|62pCkJDFYe;w9xbaqwyT~hq=dWQ3f`cy-$2#CqHyn3A!G_M>A%)q&3Sw?{}(q1rQ3AOQv1LsD)Zw+sLq+w*bowMs|Vf^dWf8=D$bH^3dp~BP>j0tRqJGB z9Nv>RUS`T5w^tq04_<=wg}1aSNw?_UDO3r0|8l*!riCWJ$rDGOP@lSBOuq2ZzCm`M z-L3;mz%8w=>Lk@aMH#KVia!>>2i`VvPZow#+FbzpBg1mbTRSl1B!+%v1S%o>=2b@) zzfd8uIQUh=co_E%X}1|n{=uu2M}!#sXF>{k!#-pL%1J51(ht%+#%Hg#&cyY(b?2F# z*8}h^x^Il9^mE$88S`{e>ouz#moJY2Q8=rlYI^8wwh81Xzr4XP*}h>^N!PnAy7B4i zvO<+Hg%ny;1zRC7w}w#dvpm+d53>83zD^DM>zIOr2xhd6SNX&0K%d{HNwqtW8&dH* zC6QSxDhx#8GL^_ooWPoD``sA?2ohhRPjjo!S@mvk?0>|qSqQ=+c(d-u1h2K-#rl8n zL%!jkIb}mx&8DTsS;h}!X@2bk?%~(uW=L-TCJc2Ud)c#`VA`QkS^Bn0as4=o5Fq!h z5%r3U$l`mqR-7`5WjY^v#K*KK#w8Iu>+b>ekqxlz7(&~~T#%^h5>qq+9`H#hFd#ge zy<;s%GIXa%1<^MkPYO zLD)(8CyYTfmYEVr&(586&eYH~5uMGg$|^+@G0*vBNu9X$=mV*Sx`z&))_ir0zL#G_ zbXA55rr8UT%p!Z^`l9PyExcLRRi)lpm2IA6=(5ddr=dWi_&mCjRJ}10QExzMic}4O zv1+D1Sj6LO$QVg`+y`cI2;6i^6w**$^k_bZ7D4raTol8xI`6#nGaLLBY9jOb!)`fuv>#P%3gT;~_H zmgD~Bcz&&J>s58V9g9pKP#zfx>!RypMF%<8yn)T&W*^;f?ubaGam9@jdAE4kY&EJJ zK+9#G*Y_;5&gZywEAVqE0-Xgm*No$*JiS)m73 z#i=2liE~Z8-G}o z*=6_e8)o-t#yE(ePzbn#5HiIt@h*2QM7Zsi4W*=*s~2`x{?f8%`G(3GOyKl|nu1?E zHTO|g_+vDZ-)miiRA39vB8h$c%Vv!#V@%c-HQThVD00AJ6@+QJ(x$=v$gQPEi%w+K zGEd3lb}!Jj+T$}8^7B?D%Q;)v_(WTnQVpR@=UZllH6uV#t@Xh4oUpeNUZ26yE;T=hJBBZR^r~O#n@Y$O6?VruT|KCeMvsKp25!Dt z^S_Z>l*g^Swkf4KjHVvToDelMm%2LR6-5?2gau|sAZI)(2|9#r=O1`gEfd6R2{3OM z;R#`D-r3&}YR{fKdm*7-Ecrx^jqx86kWd2 zr=x*77=D$ZNF(&X5TjNHojL8Fq^t~~iX7$xMm$#bJ*<0uKL*A%$6$RzuwLDGrTXf3 zc<`m9gI$z}RTLzH#sKwCFcHF+50IYy;vZ+(6pKp0(8onvX>$g_US$j)a^2&}S5J@i zjbsy=Wr_$iFjt^FL(+L@(_t3Dz~q93)g*E^5wAK%YZGWLwX6lp7Wjm_W}6zw!bP$Mzj<75h zX<|JD!qS7|wQwPIn+t^CVk9fg$H3|w&|kstLr!1`PLrI3u}+#^`i)Q=G)39WAiVNe z&*&`6U%*6h(XW`*)1l6JgyCq9;%AYczati+xzm==gRTU zIid9`nf?tnb<1B7v&DQJqu5IyS~Nv#@H%Xub2*JaaHDBQRXTV2N3P7-dMV78FCCs6Coqc0xg!=T24nAIMcQi>>qE%!r@fXRqd-=gX)x+5M zUqu8?#&?4S96({gSK(vf%+zB-#=HGC#MVxkQ!RgB0R~Dn`lZS4l0i1WEPx5ZFOW%yp3Q>oGC< z7k%}-Qjghj-*tm05+BjAtN*h4SQFq9UU;Boh?l@mFa`scnMYMlu=ov>K?CX;hp*mV z-5o798%sKO?0vf`+jC~s9NkGsnt>SOy?>-D_st)^Y+40Y{-hlYi9!opjo2?7$oRZc zYI3%v+IrwY-%|PAX}82uipEljEP@!m-TVvNP+UhOK1Zn-SY}K9;l0k|uVtAH>#b(r zKROdeYf{KbKN<2hU4rDo)}U%1^nc6vR;;e&6U#DD3@)V{-1$^eYETI9IgsE~rkzk0d=VEFkb$2KAs3KI6q?K<% zHF1p?Gqu&t{7b2N)?Fy_V)`GxoQ~)`BLYu-FGUjTn29htitBe&=YGCxs@x+}^XCD7 zJd75ctU`K9|97y66?X^?-#DM?dyj2HmrLq{uQO=%y@Lxf{WW`9SYZ?^&7o2&<0W{g zS9XH#c6;_DoT zHk-5DfGFPr$29IlzS)w(l$n2Av(78US|h=>?pVv5Az^_BU)M#IYw*LHaj^F3WSjgx z)&zczR-S1%P`}d-{^?+~F_p6fL8-GMfPu&#IkE*0`|a9xq0MT@-e zQbo`^f^*?X#*e%@WAoPGpe+AgHJ?*eRBy%#MZ+Zllq*d5nTRy;zONV0=^R%Db-hWR zbGL&5b_=Fq?i$7+=i(`v$b%*OR4ASSZzbaBw_F+A_zNhQSn{GchNx{Ej6}y5%$2f* zt07LAa9L2d2ItZNpu?5e665E{d0giVmfk~~p@}TuHA?ZjB!z6~LJHJ`#!h>Y^m4y6 zgvQ|@D93zvX4meQdBG@{_RiB$=p#RfGarfG9iRtp0`-wCt?@4w9IQknKZ!O1;9R6y z*R;@})nVo=l}u*B@HjSS{-|)$?rjVrZ2EMSJ)x)?B23CwU5bOja7FU`cp;_viIhsx z;T{$LKpUb0q(svo_#m)Y_Vu33_va~arDX=ETG?-GkI{APNvW%}_vFRqfM40hJ`J^B z{YZ-G_hiv*88*kgmQVKbKhV0pMaVnmaHy1Tj$v<(40BptT)^AWw5!GUZ`SrfF9)gs&T8RLf+4Om-Z7~3+ zdn6g6YApsN8NH~%Af{R~u)wpM?w7#wgG9fp`02Veg7LQ)nLX;8*%pMbt!cJdSmiro zZoAq#m;n97RnecT4pB^fr9i2Nc+mldFLP=wx~)B=E9@ZR_Afxr_OLFl>(ke&;N3GO!YQK&gw4{5e;@e~>!CC<35TlH!LKVXF4!o;3Mpkr`CvpV zGK8$h4&yk{0+qu;yf+L)=UmM`b?7=bFW7lbk5^x!EVg3-ZFb*Bck3-}C|zvZPqH41 zjqYbQ-ysDw>PF5t>x3Z$ zxM*x*xe0R3$1T%m!|RC~OEfrNzsB$P(_E?rcps79@_9CqBTduP*5Z{-RJ4< zU>b2qSN^FdpV^#Gg+TP=v9xHQHEoFxe}(YYD6y*WjF z>$hbNp!ZiRch?#gj)7KKr+Mzjr$4JzG_5K&{fVJb7g;JMW2em;LQwjTqMoX0yB^kb z6cw{b5?AEtPK^c#jyrRsSK~df(fQx{qO9V13_uwL!H_#u;+ajY@z9I^NjUzS7yM7^ z5s+s5C-um}z{K=l8Oi^Vj|8Ma|7JfS=_JjK9Pu@o{>e<@GygrZ{5`V%J+l2h{>@wB zbNoGL_?sQYXZV{8#b@}NJ^jp$0zLx(3;=-vKrjFd1^~hUP#6IUBS2vUD2xDw5uh*v z6h?r;2v8US3L`)PWNPsNiCO%=DOUx2CV;{OP?!J;6F^}CC`;Q!wps)iJ4uHY|P&fbz2SDKfC>#KV1E6pK6hN{Zp97#U&;u9- zdVs?~4}cix0TKf}fMTErSPb+4jDa4YG0+2Eih=%L@4v$MU++JG{GUi>_}BYSEdM8% z{}avs3Fm*~nc?4nX81Rv8U77vhJRz4;oqQU_&2H<{tat}f8(0r-@s-7M7B00ouI9= z&1dSLk?ns}6&U}n#{avjzyw&Ce`*E)pQ^%t7Y%}DXi!;)bCvXkm+;FbSb#p(C~dmW z!&g{63yW_a4kTWkonyF*+WFbc`D=YyO1l>&0xh6wWoaaiMzGTZQK%#k`UAL%-k{sI z3S^Th3=7kl@d_8|Vo`5hAAHkIh19YSxh^F-0wZ^BC8BtsfP-&327eD`&PCd7<=}=2 zuhDk2v+pj0A`5ZsJ=K(~NNtDQ+K>J|B4 zhbN@N{9?!;4?4Pz!RILvptVUpRv$m?RSYoeO~Xnc!tv#cl?Zp=U&3bZ3*gw}!yb__ z2`HZ=51oLt1Km50Ms0D>)P{$%7S>fRJfY;cH5>c%jkTGyW^qzZL_}F7iAB>A zgAEAn9)j)1t9ncNjeZi#5kX-Dm?q(JOpj{9%u--=!h&_z{);Kk2Z|qR(vhP5ns0eg znNTYxcY|MF;g1ltbc7v)AEqUbb1iK{iHA+;umi{kl^7eKCnTBXsS}*zRx1k~nIV}( zqJp2a_@f{Gs9>U2MD-n7d^J!%J;} zwk*oxJ_@+YCi)~D`I>^cjh41t$@UQ zO0Sg#8rE+eYxh;0&Bd4^t$iX>dRprY4eVUkMl$GI#JQaBOCL^({6d$nX5&HUAMRPY z#BG>yvvGTlM^%b4@%`;G#kMor-z3Ay=lEQFZIR0THX@n7yl7DwT2b2)HI$)Z5Kg0= zK%0vef4r;ZILy+=Wv`oUgL}A3bP(WQj6J(F=J(nJ`7+E9onl4Ndx9nqIL@sJPjvW1 z-RIDGIzv5@H$^-Id`vj+N{Rn`A~g}*$3P)Aby9cshnzPn{M|eEp7iZ(k$lud8yfjC zm^x;b_>~uEz0E>M%kXv>Y}>hamE-$BzrW6Y&zaFFn~*UJnJq8~zV}}%~V56f^E@JwoKRU)ch^yC-&8$7evz!Zs@W=Kvj6j&Gt|uK$x{~K! znssF|F}F;;%JHxAbUgFQsHbi;SV$IQmgSzyeB3iq;t$n4zpuECCgQ516cPwVckbqi zt?(a7$RFWvRU}M%Hh22;IicRyqjpMs>;2ugRKd<%s=>3MOXa>-S8rhV_v}Q$CqfqV z8JsK{1#k<*Qj0YA0Vn@Hh%}r23QqXFn~+mPp-KT-LoujvQG?ssuy;FX8ED+I9>+nG z_2bTV0rH#0x3!bf1#|p zvU1uKSrr?-Tqsd8r-68d=}${GZfIJf3(#r27?VtENMHf9d%IlL++ldm`>Ottk%PfX zk7KNa85(=9(g@+q-?jXaWuo=GaAeO68Yl0ZY#a-LN>pWt=htrvIM<_N1dOL01RTzG4}c3g8t_yuO(^=DTQ5*!xUiXKPXPAnAKA6*kV zFJuYsbrba|D3v*icqrT|kO}G!KFU(LN_*eetu$lAtfRqc8{6Qz{m|c-JyRLnZaPsm zGDILa52D1s>$=5=nrt1VRMX@<`@z6)G&r`-K*Qw~$T((UL?AAOa5eU_`Zf5Bl1$$7 zaw~qOI_ww_v6-f}g+w#Q^>d>5|5SC?DxQg0`kLEzc9oF;!qgS6h$+tP-XMsH)W2{K zk2UqyF;FnvF4v_ftBo{z@b!%TC?K_v&5!qYlhZrO2gE>>JRHUN-7$RbOs}rQfmFtH z1dcZi%IR$sDrcZ^MUTu51A8wc+-OGkg3`dAKc@0_O;bka!BHZ9A>MTw#Kh#&WCMEJ z3+mXNFz<)#kM1km259^qpZo{1ZV|t$+#?HSevOwkl@CKnoU(4pGqWev;?rCwIiMSw8=|Oh)1`T|4p$g~rJ%guqH9J(X4cY&e zIBQ1D=Y{)1QYzOkk)R#nnm^1}_FG}@(c5|((+I@gsHuQVf)(=>cM4^@`+mq}ILZ(7 zIrULYh|Sold5M$8kW0~p0L|XJ6Ss`qCE3{l1oA54uuRf>%|+nVh$*B?Q~0MEJl{fZ zHJB?$R%AuwF`p8~^oCzD-4{e(H>{;5s;F~GZ`F_$afUmj1ZRFGpIK<4vP@PMrslAC zz3f{7B{qPU6;PW_ZWAO5nV01U1`Q|381Lf0<-fv|H- zV8CbYGk0{URVlsx^3Wrs$ZC_Mv=G~k)ct1b9W@fo&r zxW8f};;{!|z91JI=j8@2so&7lc1swJ`iuG`Sc38P?R*l^B$6AhVWbJlg4Eubl3Yr z-|*I<4o*?@Y8{W1kFLG1mS1xkTz=XmNR)$1A1;}Uda|wiI9yp1Pg3z;L?&=&PR3iw zWMTGR;U?KFn8m-D_x$`#Kweu+GaTHpus;PNE$?2YN}4ux&-{_ccW?6`!+p=1zLiCU z$U7P=f9hwSNOc%!>+P2vwJN5S{>^Rd>K97c{gvjo{)7z7dzlXx>;9}GJ6-GG4az^E8d({S z%<>Ojb76=`%Sau*{C0>w$*ZWa?5tjaac$2ElCJ&_D-|uYVP|)MmjX_WUHr~Uolrt^tX`TDNr z+BBvVw7|=9aYwHN>UdqZ&M3QDTH2+&+4Ke*yRuw=7y{L@5)=n#a8G>Fv&W_CdNZp+ z(qYEtF#>LS5f#sk1ESaB_xK|67O*P9yU@ptC}SR^xRY$M;{J(veYDiRzJ}bicwA1V zRe2$__&U2vZwb0Kr(Y&y#(8yg7I#x}FKz9pp|RDwce|N6DMmN@?jpg3LwJ-Q2;@6j{Sw3s+HWGBVaVrFpDA z-Y|56;(Ua6AFn`j1B@2?NujDuKMk5Izxo9`3fhb%q2jF^0znuambgKcOXJ{dPCmog zhI$zO8Y%6GoMmFK+58PPX&kb2R z*S{hG?V8S$w_3UKSalzOD-`CI8 z8eNr2A|%7I821K0EMy=ja{PwFLlrC9PBIhh;CS*mhm1r{{ND#v@Q&8Pn%nK6$^u2z zq_(}>&b8lOa)A{&BN&RO+p)fw@e_K9Y6GL#F)}+C7-y%W1vpqajb_llQjNNMUTmsF zx{3a1D)}P@Bs3DI8&JmPb&c73v?JK5>VM2ujov2ifCy6ZAQj>xZwu7DIzs40&9>GU zau|24nz1{+tl(w~Gxz3a1o_9a$j_Z$Ea!@0+3q^bmv*+ON^Y+p#)omD_|I2|dB;1D zmhmB}k-=sdTnShK{~YfOPPBj`xT)ag7oq_wY{ z-t05+H-ZTk`jcf2oIGceui>OT*q$~`89aMN>YoiV`1Xyg-XmwW3_pS}f5hgzuUo@Q z8IdpUDUS3j*00mh=M@n`z3FzZJyGxaP$dlrsUs<};6+C36ZV1cBn}7Flj0-ORKgC1 z2{YM^@}oLfSh#t9^ijhju!b*SlpXkR#PO<|76;4M$>!9z3LmC-gW^x zDl5RP1C9^D1qy)BEp*pDYOm}E0oQ57h*V$}oVJg(J1j#Yvqw>F3urX0DvY^qsk2wJTnRGKeKu%{a=oipXC-5@J8?#3=XK681LCnj}a0abe$rHRn+<#g+O!1sYX7JYUSX(Luoeu9cp9eK*Y(3n}x*(V~`=cZC3>V9V0$H}~kc zWN|G}r(r?1o0tVjQ0YI0g)W?Mx$ekE)!%ijOF0^9kWAh5#XgdH&sN&~>jks-QP9E{ z`?P(o3n&}VI$;?f-3}ZD+D3#<0r@OvAYJ zZd#Nh7{G={@Oq{)d_P5yARUL=ocNljthLLHLV77Ws6sxgoDrDBCO12T5>jrXaE$Te z?AQn_oU{e=oS8<@JcK`{bAw-JxN#d4CHLxXdl@cC%@-cF#3I@Xcrqnf@ek#Nf3a-IrQQA)6sN6 zNANP!wEa~49p;TKxeR-eOBUCEnE%9Bh_p_JTPF-^9R~l>J9zfz;5)^-(Qr?PvO;!8 zzL(VHfU;;dreqoayEc#AN^IFL%3z4>_*`Zd@y2)dr;XMgrww?rQ+&UGKh?&GG}^)4 zZRYZWi*U5%9p-mJz8iFu=-xf>609bJ@H?sV{6?@ab!eTmWQp20p8MkJ%J%t7MI%{W zI>Gv?S|ep&wx&H#wi4Cgaxnfpfxo@zmaZ#1^sFlwW$4Lgj_bDH z#5RPQ<)0nZ)zq%_%-?MMokaHrk!~A749fLG{%5EZj#lTooh7RL(-WPkW=1vim(CDh z0x76iL^U~jHpi0Go!n?SS-R^s>hrR5YGj(#M3&9l;d4tW;0Tf0FHumx;-gqeD&qSN zJs$3hRH2cd546VEYpm*C33xz?2kw_HCU!PA;D=)?x{nL8dh~|1w%Q)11LU8>I|ZCW z3ewk%b~VIDQw{G7FVRuuLYN*u1TJep1s)4mgN`kMr}`qNtMossv8+9wU-ovB0@U%l z1{M@>-x>`1{6PEax~NNzqWd_?1#ZyN#6C!2oayn%=En|W&pLqGoLgx#>gRPDsw2sV z!}e^IDrHgzTaoQ0lkq%~)4&JzgKvY5;LXBgcZfHcou(lJ`rp1c)*)~>xqVb84eeAT z>1w_HCWH|D^1;c&%FrnNUH!q;eKlPNZXHtCVA|lA`qh0a1By}Zo^U(^M0gpGHq9B_ z`;ekHHf zuQKf(Q_@AqvjBmim8^h^(}@w!Pu6E0j~aY=*=}pmxR0n0taWHbnsNZD z_vrFSD;M}3nEHC1Il2miBhZ9jD5!>%yKnQy`B=^aZ!^o|TGEr4<i;MG&r1I}9q^xmAJgC3 z$N#Ph{H=rhpH+c>rVE(lFR!ycoVPGm{BUiQr|oYUuVByE zS~@gubvS!o)2c%|Dwu{gDgq87yUdecU#iD451 ze=1HYJL5%c3E6a_{y3LciX$s9L<`B6aK@~T6wSe(OmkEdq3HSQVqU+f=Jk?&wz0XY z{QJsVXunm|><6dJj(BMzo0@ytjpuq&O1%22g@Qp=0m83uf$vPQyN+%=6^=*a;qYP z!>cacIM>p$dcEDg2wJPO+r4|XrMQ+N zHL+(WLZ@W_E0sgrAG7248Q^=rwN(rr@|0Vuy4E-b-M=b(ly6{xTorztFQq*%Q0q!U z#oOZ;RA*0MP%UqbFU^g`6~Mg6V3<4AkJpyDk&Iz_$N9cUw;&_C%f;j`x!$&m6~l)< zv9Wd9c(@mYLvE7(j&cl}K)&=HTSAF6sH%Y(^>O6bL>f|Bn85@V-qbc`t^_^Fsre!h z##!AKN2tN3Ljd)f*-obDwI?KzB=0R#q_Us5uEtGi`Idz0P9VHs`GcN2PHU@*Q9~9_ zcp$^&LlfHan1V#GGLTlX#R%)h-4q|E*y>boM|Ts4LNevCP{AMAz0jRL`~p= zH=X-r>~1yj^@IDQSKAtoBeyDZuw)X}v$tD`Rl&zDYKNU%P|vC9tFi{_$?5Hc zGop84OSx?&F>8DXf{R-z+-|*EtAo>>Q zcQE_$)(d8nNxQ4kB_jp9A`?!6q}B>`rXM{~19XG8VhRj4IW*mNAa1|ql6s0r5oLd< zC`DU%H(Caj#H*C-hD_nRA)v5I342zP566y?EooF7w{$Jlw}Fl3e;do|{;q9@bM7y= znbVJJ?quuL?3_P68!(}$TqPYNnJ3Cnbc|DF(*r(q(Pz)rI0`Q?hl#rozZJ&SSOx|~ z^5+0=Me^1S@oR1`#o}Xs7=)w^GKCw$D?__0?X+t6_v+G#qic877`^gXVo;{0bEmuS z$-$C9ol+WO>&#UwqQ2_A?c0Tge!mg#RW!tjjJN1QoIQC&w7pbzkodVt~Njnx!tM=W|YVOAi?lZZD98em}(dX6GOKg<-{ zHR$G=(0Dt~HNg}bkR&H%jrkTXc1Hx$DngW!2Yj?+*T`F;QZNslw1;0gwlD!3yJ#Il zlA$SMmN{4^VxeKFhtHwmdf;kUT{QN-0$(-=KZM<(E8^tuA;lub>-kg7(%9oWX?OjW zqr^ebN7030I$W$C0?5Gl#u=J&mSTBWnzFNMofqqQOk!2khzIxEI_KyVz)R zDaVimQP zFeC4mwuD>DzQrRk4Rvlabbq}gB}^$PA|r(NC&dn9rPh)Nh6C>s@M8xM0$Fvh;-MG_+4N`I;?Wz zZfa$w4jqAgyy+~&1xU2fP8|h{*F6eJ-lSS4yipVUP`gP6mbGQ7HzY27uUU#tIjd7S zYH18g$ojqO#NA!ZSxW+`J||3cj0%eijQ}20<*+Wt=uCAqmv=aj&ETS6JF=tU7xF2L+A`Ps~qPO zbC7XL%dQaHH)u1W0(?*sq4-&%x(p|Ux_}Y8TizV+y==y#D-4Npy}wLhhMdkg&ChV7 z2y9>;FGE(Y6wt?MXwKfKNG|ju(KcrC=}VLI+zNk?b=mYQ^(CkGLjb`lNXDl6e7T^L zlIVyNUN{hF383iK#%^eQR#aivI|enzE{xKy*)jjs!L~+sna|oc^9z%{S%+9x4v;#elC-?&tF?Ro|*Q6-NB~%;@hhwdj*`^;r zp18+TF{&5=$CL9if{Ji7k5hjXa!b1r-EGE zqd9Ls{+~O~f3}nVY%v*G*x3Gi=lSo&{~E3Rr>E?nxmpL~&)${49Xg-mvc^W{`U19Y z_?rK;@UVV1+OTmj{%vrvar(UNa{w36;{!>jVC-n?>|ppggZl}J*nSfK{AR>w0yOh{ zZf2Q2&;K^`e4ev>p8sv?`8;R+JpbF+^SQ01QAK0Pf9J^kn0?LS`>w6(Hz zP_)xG{Ckg(v5CI3m6L*~z^5cGC@7%s_&Ea%*oG@;1HK{ZVC!u6kEHnd90z?HN4tL( z#nAoJ`n)1!>|$pa>|7*+t zxBc#aZTSH$O#eSyen8LP=gRy$Ud;5*eg6y>GctU-|F#f5`nO92m0HU@QoNv;)?Evu zAh44^6a^lXG&YO)M){6p#yfa1c^0LRn%$u3TjOUPDnE5e3MR%aLYoWO3~l`RY6Z$S zWy8fn_nqU}M3ExDzJZVDsbmWZ6+6O z$=V#I=3i|fJYFx6s@VJA*x&JzkCTPSagi31sk_pQj}#3a#yn!{+2mHqQFt;1Y;yd~ zm9+zI*`yCHYW}Yf|GRvDL;QbqO)~xM2m9X({kJ#l|6J(*UdvxW$r(RNcz*uM6@f&U zbdT!cTKm)1WcmYzqc3>p__jKpvO+=%R3p^eC(+Nat`^y?E#}UH$x(q&p|fQxRR_&g zu}3l5=rCEgl&oTm%x74vIOo)=?3&K!d`F1R07r3Lbabj8bu=d2TXTH@SyR+2*CU`H z=Ip^T#iB83ua5U~Mi~cj6#Jr*NuYD_r9}cAQ9u>+PS=FA1T&@Kv4b{B3GsvsM9>h7 zlK!1&Fx}JLl$BH?yV@W1nN@-{H9MmGsKVr&CQROAn{gYvy|aIZaF04OYm~o0g(E!J z4hKy6Iq|6tos~4i!43^ce1PTnhqPS$po9I=^H?(!3g_(x2PqnaYlYb&TU5ulABBHd zGud7sefI8C#vVw-TW)QnzR72Y!63F(NumfA@$;y~;XoCNjRDhuywLEqKZ?qtwlWAy zaWH{e&}6^fdaGK09VqK9ycBAt!@8D8981zZlDybxsVR{XW(BhmNM2K5<5->8P^+yRc>f-#t7zlYE476Nl() zRj6QBiU84bQoNPawY`o;X!T2vck@TsQt2b@iZQQWIT+pvypX>u7NR;0TM!}VQ^|H+ z(tQVuxCL6W(Hut1RRuT)2v;q$X79&+rqY#P{hwxFOk&d$8*2~SGk1qfck6@1#rL># z=W@3Str*<*=f^j6T0RScEGvqHR1pg-Z?oM!bX&GISWXtm!C;p zEO^4f&M-wLMyhUlk|(=mgug$?um*sE?okHLfp7?m`00XhcrbcK6L>bdg10HaW|1rO-iY;lQ-)y%y4!o)z@wa#rXCLec=wiKLNEO)2sy;=-gk3Vw$U zN$17_ggA*T$mTaUPs>##2g9HBortflRBJj#vMKVzHtBB0OU~rJD-0%)Z0)+#^!Kyy^{GDG0YK*Rt0kE;QuMcl`ao;!SN0y^q zlCj%C?jUP;>VZ*(Mot%A9_rl%m0soS_mg%=I|lYE&+l2K)$`VW2(;X(dLIv1=J8A>3JEIt45LjbBeMqx(ibdo{jwqbN6!9jC9)KlVb~+aQe{^o}W?Pfq)^{ zs@H!ctx38}eqLayu<1zdo8y?#*0(=)b64;LDfLyNDfC-f(d1;%t1xW(7YBT?N!JoR z6t+hB*WP*Na|n}GetJ~l6~y6kfl`~?Ec>W%^~BY}TN8BP$+w?hnN&HTNxx(`*c0<5 zF3!(6>~|92qiSvY0ek-Ls? z_zF^a0MXY(oq3k~4xj2ftbBN@w*416g@CQTciP`re7;F5&Hb98f2zQ^ejRKT5Bx4q zRb--OGXH;=d&ekA*DY%_ZQHi3N>w_u(zb2ewr$(CZQFKMIyABl2d3b)HNk?FA?Y=dg7Je;2hUn(x|LLWla# zUpn`wPN{)9tWUTbsqGEB@Ut&LItItUZ>C3-KtbH)ig)N)ZmeSERVEJLfln`3(P8twx|QT-NDEQEuub?1nJa)VN2_Egcb9wdb1gA zmRcS{2eKF!1q z!7kx7Oe~p0(+i@&{WTvhK)@4ubijSIPvdK46&PJ9aX^0qm`$Pi@V!c@&d1|wvO6#k zctkWaX+NCuwQ{U1l+|iu%S@hK`(ENZr_dL^3gDrrHlPp;x2_UiiJn?gl=U%(21AFY zs^c2OP_9J)J{&%KGs(T+DK<7*-CiqZH8S%y?`}(I;EY7~^|z(-9phKp(x^?`D$Qhf zobUF>D(37qVzoHAV#Tpsg5;b%OH*OB_O%*A{DUZWeG83Mprvgl9(%xv?UKIMS2|sF zM7w3I;Vp!P!^e4sE)TnW0NVj_ftI^s2ao&HPjQ5%2H15wbl;p&Qws%zr%$RfUYF6~ zJ|Z(MlF`{>xgkH|#nxqCN?_r?Y+GomNM4|;;OA=We@>G(^MSAoH8*#0E(X;W0|R#{ zD7ddAuht-=*gy0q`{1R!l~gcM8T42y66Wp{oNhuM6FMo}vzV)^T%-~T;fvJ%u+gPz z04H{?p%i>tcgk!RqwjQQZu}lgyFVoLWI|1WgUnX8fxQ`0QdT6DYFpoQtG^Ogj%mmv zz%bSahAuPeEW6n!LJYG47V%+SglFagCo8tev$w4x%@Wn5^j;&JcYM4_Js@)Fe^QRw zv(R!`o`Yav2r%j%%_FjDXVGj=rJAxennFzY!T}3FDBG>Ss%O^a<|d)enTk0{xY0CH z!9FUt#$$(x$pok00W>*`*61#m&7h=@ak~@obuueo*Xb>;Hq`+zz8n~ zIt83{cSMQzG5;&St6vE1M*y%*BFZIoq`HWGbo?CNHs_z{iP`OPG&VoR;m_ zHL@+ly{Nx16wvdGsP@MP?b?(Qnf#mLl2jDps~p)3mdyP{sSMYW+&wTwMh5jNo$tus zvV=dd{~vsSnSqhiSQp}@_#4A z{XZ!!M5AoS6OxFwO=NHV@YFjt~MsF%l%ji-ucPU zL^i<^D*fWCYtvQv1&HOI+M!h`Sl-Zwy5zBvTZgt%Lhuv1cF6BYwy(V}%*d$vjUy2~ z;KOoMk2&-w0E9&|i^vOuw94Y^j}SQ4S!9nHsap3*k6<}3ir6C{ShR7L>4<$78M0B# z;;6v!C>^^C7^hM~f`*LC-g1S>;X6YI##DGK&#WpSfWT>>fRndviG()%oE*|7>&JIn zio=HUGgfN3iN`QS?E}yls^>$-YxCezPIjx#W1CevUV=AwhDQD>5*hJ+9lxSX`x$-WjYM^+V zgl*`^_`^LZV*GZLy1U zQC_I&9o5!WVaOF;))n_|Gc3nZ0WB+bY!1w}FC2lwx;-5VbVy4NWJ2wnX*B{|Gp~5Y zabY(#MsnHE$6;+(>dXgL=URp{;ev$L46T}))^AZK_>eEcBT#N7hz@H98J>STSOG|A zBYNF#CCQL5s~;;3xuXpqJ^8j=c9B}sVA}^Cw;;o}g69#Z1wB72+RZ3ek|Bm(BD!GF z9G4uLhu2ES+*$@caDhplrux^E%9#9&-UHk@gx_v*>iL$Wug{_ zfiGrh|8^kgG=B;$luz#&!qyplIVm5d060290ssvJja06P!*y{GC@EJY@1FKW zAfB)k=V(xf+mw|=M`=ilm> z;fq8GD7O{3=ijWt$=XN#(1;Rx#0MXw&OT4nDiH%H@gBtSaL|*ww!SDO!D8H>4@n(; z+5=!Qt5!1Lg?Ur@f>CLKj_+0JDWxGUwkwO5ihiTjm>`{ci%z=!W z#e>|Iy-myb=21A2Z^WqvgL5Loxu)|qt7%)`xGqRwP(}r5K-7cJ3^<1>}_eq1U`yjstH#-@ri%<7f<;by3WtkW>Al8v6VJ^LP|-W%U4@9Y88 zaDe=iKTV-RgAmPK8oT3!F+f8dWaJrt->-;+`4(g%)~xw+wM}h)%D(Or{br4>rZu~* z0$VSSF%B=0$0g$gyL(FqvN$ZQv5*ojKf#syeh#I4K}Bx;9= zA&+gOt>jdPS-gqAg2)aJ%1G)Vn`$@(E#EUhdSw3k=jk`=;LGMRT;yW`J`Gl}vK0R9 zoE4jrHYSC+l_BQ?tXQkO>v(lfpxjm@iAQpp=fWJ5$uT_q;R9BnyVB>*6?~mc;gkA7 z#i@nOpn8QMlOLiFCp$}b1I)y=B6?eF*W49_QeCY{f$`LPd0QAdSO(A?_T#rYm~v)@NoeP5fuV4Z02?oJLnUK2L@DTsqF|-{ggp4Who(AI@f>P zTs;m}oeL3HUd!E~=Wm%H7|EZAS}^5l=iFg-WjKG=nM)fw6t{=a>Z2ftghY3o)fDK- zm)n5&(Bzh{zK5Tp+w~&N2WsvPC%XAL`NnK>P3_AmUp4>BmLw_L-Ae7e_$JAN2~e|8 z%@o)f>p}aR?BS%@D5)O8ujhLjVV2it7`pvxjW#ZsIo}X}2ZMBE^3|f()THdSVm#>B ztz)$m(7MFBL#?kZ8wl~Zys|EHSGj5}S7j&}u+-2>W>Fqj6k_H|=E#9d!HxG!`q+_n9kEk!QgbYM5JGvUW zJZyjoJle`Q_$lE?-+r-_H0%n=EEe9N5OK8XK2QvAO$O&rv9zSx^$&rzdmo|xdl_v8 zrQC37kPXhJr~!F9wUIpY1zqd4y~K>L`0?`j(&qBKH!({rlXRSZj2?;>vPtkyr~&S7 zn)U`YMr{PowMDHK@YpWM@RX$;>1{?HK!6~TUN=enYpd?Enj#l@ovN%9H4w%*^Jzek z4FMZdy8xas^%DIuGf>4sNLE+nfE}LUo`>z_?p0*1-C^Lpm} zb3=}?s+xTc1l&%JT2aQ%7}JkpnkAAIhUsvwxx;!_K47C}J0;=kw5vixp5{na62X8orYQGkZZy4z*2wA*ZLXPB&*HPl8~c72v! z{faDs|DL6=;?fO)i*M1dMSkoH4cHHad3dMg7}^0H8}_q(2t?K#N`xMUXc}fr`m7B z{7!;pwp&PXG;)8QNPBCvmra&r|K%R zhPk|iZ#(LzuW*@v1kre2P~donSA1e`_Bzpnn3S|q!eO3dlV1PKvNX|2Cig1a=7w8@ z9-dLfX|g*DFy7QOE(y9Pwg06CMx;w{I{AKXZh#G49n7OnT6;)sW$(d7dC-FW6uF5*;HGVeF{Tlgaq;zECw1 zb)qh*o4C_z4XEa+YaxfT(bwn{-@-j~=?qNOx;pjVBBPh**selJ-(8aiuV~Dqeg&PT zp=a-Qa(3r!Vp|`ipqG9)fq>B#Ya#RTob5^hBtQ=$0O{B&gj@9O6}EfFRR_OP$p)UX zj*o&P5I#knl&;?qtKit0;DXCS@FmPo9V#~q1TzADoA*IkaS)dYPzmIut`RWKwGeMb zB{fC--0n$qkg@yjd;|c1yEf4Wf#m)1K~F^CRcbccFLEH=HK> zatLu60P~n}*1mvpSTi5szX!mUFWEQ@qu`qpd8{2tsZ zBE9cbP#4U`woT`~)(3pUogp;48RUMts-tvBKbqnbNQx{X@;jMJz7O2cpg3^Qlt$TF zV0bbV6mrCJ#-$Lx!x~SchbK6$xy5pw`1%lV{AaIIle3=M4nOdO2;B1v*ys069)fZB z&rO+iCu7iT|GDY$-;+a>cbCPYivrcnX%fSppj&@TQeczOqst@c-^9CPSI8t& zh80oz3G2arL<#7n=zR|3CixmJmzIqH_2M;dC2O!iOmH-SD*Z7j$1Nvr{5Fb#lz@FE z^7X<#tNnpO+C9N2f$_dl0hvU&C-Vz~^kt~_ZaTCZuvh5Y99a7+C~VIf(gxT7&*r^z zDY*Cu<|ifr#0Or0Fvo}-b2K+++qTcpH>9j~?bzxtX^Zv&Qb0sTb}7CEGjNuW{B&3+ z0#~JUFLIsIM<%0B;JLWKK;Pwy2Lb_+?#u1I0t23+z~JfopDfH9EBM244QC(TGrl{L`>)xZ+uLJ0%bekDbvA$~LWxZXfYU`D zI*MV?=}&ratCUc&(7@=1Un&N44hLNuGlj{P4zf`i2R-339eFm-riZ1P%$);R!0Vk> zFUP4fvPSXjFSm-1tp)YwLoO5-gB8`@wTadvF5=#mUo1SaNeps$h8|eatowCjTE;jlO4dfM47zM%)~8O^-75O!VmR$LjadV z$o65sK~*+UC`9)_pSlh48uJ03=5~4=~6QhACd`AQ=>!Uqy!>ZA?kEbk2C^NWq6p-K6xW`DD zyv0z*>ePF5J>?=)c1%x>#Fsrd>d+)P z69LRw@N_@@(0t)%a*d#n# zkkuh*9WU6N8Rt$0k0Kg31$c79IOsFpsIx_DICQ^4GYidHQ~Dk*#5RQ6+k8IarI)rMfsx~Lx)Vufi0XuP|DA@ z_^x4*CK7O06O&#P<@p{9O3I@KDqhQcEY;Kqg11Ptf)go~5L9tRvV>g~YAfjmhGD{@ zVQ+&jl6Pe&Z;KG-oN&s-`H0C|mUcMddI%$REYge7tCwIx8E5Bd^7B^S&Td;AJ^j!a zDIu^vXDLl^>B)Dx`*2xP4d(+SY6!iK{SFPZ%oNm_=~{ltgpF=E7UjlE^1Gj#-hko4 zccnJ$MJc=Kwda(E&u=am9^)9sw4;~t)8{2+JM1`(55?)O*$0N2P%4&4QYT8-MAwT} z^Z;TgumEz{1%!}AGL7aJ>0=tmgY1MADGL`XqGhGlQ?9i5`6_kBc{)DdhbI>Aa8b~N z%$48Z69X`6UlP!?RxMZ|^8?Xhik=PI#@fxp zsSlkC(7%=bLaz0MpuB^ozs>JT>K1_P1AgImKL$l=$T0kUP0y#b((~CWW*O@q()NL% zzmcz@D3KLyZN3VeYLoP-Rw}vM)F3D9UMSY!rJ`7k2G$mS?|FvxgPyjTx{lwQ6$d;v?+^-y4eLBq$amP5YgJjHpYQA4M)R8-(5`w@Y>OL{d{Pt;aSaJ6wiH zzSqe{eza!kCwT$?A*uG0DM8`pjpN3u>JassKWqo3`*RAp3ds=rV*|yRprwn&sr1%Q zPepEkhL^E4zL(!NFXPycdg1A$LkF)by;a6IlhDCdy}CgKORwBo{7Zw~+x5uG=U=_> zyV9iz;30(S7InJ^3(Eo5FlKd5Y0-^|g$T-v-W1S8(>4Cd{?O_Oxv=twa1F>n?Ci&bOo+HwRgb7ovl=5E3*@N=b6tn57PBcV~!uEvI0&;YSJP znw)iez)@L;nS>>fEHysBsj&#o-;TR?mdjKJgmr+t@qA|_VpDC(C?%$rtf=R#yo=b( z8@02%i17NW&i5>oi3Z^V$U_Fh=FsuReZ!$Y5vPk!P7#E^wJ^O~?YBAQS{%uE94U@i zS#P2o6w~D5ZO6S9T9SzT(6&BFZ!!xbliR)^s|Tkh#w-t~z3*4K#7K&ow{V?9*;TTR6g24OVD+011-qSFxN9wrLlmMbOlg7z zZh;WkU_|WO%NLGR4>5#gQTeZFHB9P6ZkP*F)?*A-#LSSo!! zckAfJ1~SrO%L)x1oTNqe9|Yy|N=bi4os=!k5R5mCXho9cnbN^ASuT{{+pV(Ggtxk^?*&O)r-33RDx9*rJf@4-{MpRV^CsbXbaYrz+`1|ue#7}(#g_LH>`*L zNR5z51!;wL&RmmcpowS#u&5S2(2q@q?Z%^XmW>VB{8ky&K81%TmV!`25Rg6B zNSO4ox{gMK=ZvH;qx|NPeXyzLYYlJm@wW)@4_No7s3^8I_7Ln}BQt{WoKrt1_`W#;xQhVEcaK*dP* zD|`6-y8T2!u2YB9>h4$e;bKB_M8CK{xc8FD)!eHK;rd7%Pi{s=6bYVo{v|O55eM9B zweiMLWm2NIMdpP#9x;@!Bl^vm%x24cj%#_39{@2ae0eS^TRl3EC@f$a&g59 zqdT(f=6eo;C)9cI?_ouno6TOJVAYgLA`Q7dI;z97#(t>a!X+{DN!+wTWN{#mQf|vK zeLi^_m|C+aSZCKiela{x)hcM%O|k_?*7~@2ext5h<%kW{(Q*b4{&mum;j3(W-p;>D zPj7YYP1_vW)p%ag{RRb<+roMh679b9CU+=x&`mC-F(GZyn+d#}cdG((Qq>ab+sz0b zJ0iIRJ&o2k3PsS1Nm;F$^;4eW8?;)WVVQ5Oa2CSk0tnd1exU~AYn zcudMvSh-DnBF{vBo|60a)uG38TgtVo-RJl}5aLYsIex%IV%eocMnXo8 z$t;7P^da2%8GUkmA9QQoP<6%ZXt^PgZ`i`)^$eNt_K+0O3HVR=Vq(uSHfJJmDe?3i zIi#OvWq|6pmXlWBHGgmqR2m8Fi=kk>G?>PZaL^Z?Vy1gCfHql12D!Gr0~W-BZsg(6 z;3xdP?wCyTqT{hjxPVpVGcu5XrfK-7I?1;=j@rT!svktE13B{V*&bq3N~-XnynGOp zZox&zAv9(SVX3mEj~rnN4atks-R9sJ@H#B$WYFD|<{srMr*;guxozz2y>;%-A^q&Z zDmfCaeD_9mt&o?8$Bm9$WzY!$7-Bh(2q^hO^;-~4CTnkHrex|sZL+E-uKm$Vl~hDQ zhrOE8UT(E-2(Rpd+B#$GgoLqsbmG^+>xyghcN8lO^n3@6f<~SaB%c!{-wG>h3V3h3 zWGX?LCVyE-uDV_Q@EpddjzlzB1liYK~8J zp2vDDi?u6L7tcep!l0AfcH!YV2gh1ly}hWmjwaPcm;lz*?xB#_(*_&eO_{)?9Qs=w6qt8+j|o8z@)frF9B_r?RwE8<=< zK(KbmHuuS3e{^8gX$&kcEOq z(R8~k2(S5_EL0QE!LV#=1@iRs?^@>_$aKI2VM*zQ7#uHCvsqY6F7xwX8c8>+`T|T z9iE|ec}g#Ygt0(i`jkIPQ1*z%Y)w_1PL-`qcc70hT)4?sto z0$BDM6@p8M9{G;YS+btc2_Ehl3kuCd)C(BS-jAQ;iaWvnN?e5TvnonT>akh#h`b|t z$#zSgC(Rbc{s|fct`HyfsnspwyGjZP`CauEZ$02KRhBI!jJi5Vp&1n1rxYq0IoJfB zyi1&dBE6h6Tm(H{5ESmBc zL47L8xBJKf!c^?CcId5H+3C>a%^QpZQHHH79|jYD2~@-#I{Pr30eQy}WDh{C=B5p` zszCvt&cXIyjvJD*J3cf+MKVP)0#aC7ScE|3lpQy>HVO_cHsU9ZrKqLNFKmfV;Cs~i z9;T(eHn)WBo|g(AaDe5s1&=2MA}6K`Yzm^!p*P##F<#|H5w(Vbea)OlxmZ#eu7NnP zLgcKpWW%gh5$&2Ds_g&}_5mIJ+ii&v>4V~#;PU~%Q3ygdMg3ax^d(i9fJnL-2N*jG zU3|49;%FNglQ~kqdPk&)yHd1vP~QFVoBi5My(@qJOEQ&)5)eOsuBf38p4W&t+Q-wq zx5Lc_v#oeZdQWBygU7}umcq~rg{mM>s0+B2&#!eP(Vrn{a6+%l-5LwW+nlx>FzM+C308unLB4wfyv`;qLcI zlh~fw@pR@y#Oc|`bf4me95>0e`>y;3gtN}s^ZKqHc4V?vPPtE^+Dxb+c_`)wfY!c? z+qm5ia}$A9N{Ga7jj*-sGzlTMZppZI>NA`L!9e)}aI zDXi{ifa)}o1PHmo%b>Nt}?Zx>Xrb3pUmmdl&a)#Hd`^ zX8i``e5rmgmXO?bT3mV-w|)d;+>1X{^S&B*o8d6*TxGtyj~|xW-r%Dob(q5B3DfTm zmThYe9}p3#NXbWwtO8uO0){)1kEqW|W#Urgh#EGGQ-OveC)iR0+k~~p!dNHDb6&m?L2co{$?M@T?1fY?u~mhzp`yRR|hLX`dF2}8Qi%05Fhk+V0l{F zt3YH}Sm*SHNFL0q+ z8_^|P1qMeLM|b}&)m-WUW&%u2U4K1*5eMOO5$U?{KNV@!k

ICwKb)mJ_ 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ⅈzI4fQT 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


deAW2ZR=gk9?4IT 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%0A$x+zCyy<>T-BYq&q&yh5rIs?^$eJN)thrJaI)br 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 z�=){-J`eRARwd*6h;WrKhb5fSnG_eA~V5Q($Z~CoC=yaM6ZMKYxvGu^x9z@1DiA z`^cbv!aCmG<;m3)w1h`c2^`2~GN|!u2cHsDr#{}BiQ;o68p6gWr6#qA27Yd*&yRLI zKbJ&mjTR2M{{uN3-|m6aE3rc93TmquE|h0n;GO^a7HDm|VN4?JebMZd5L`*^G!3d~ zO9CRoW@r|`0x0pj0Mkm4>vTb<`Yj63X3n>5X$c(9qwkqW^GLz<6mq&EJSHG2_T;UuuQGp^}uepn3foFBv5%lh6f{X53_6VO$N(nQ6vJlhl7R8Ks>FY67eq;g`DdE>R4my|H``?jI?Z#;R7|uUvqZZS03fI2G%- zk=2$$9Ywssa$+FiPX}g?(ieCUlYSaE$6Js|7_IFV!LO`;BFN=Zg7 zx5I2V4Qi!U7Qv}Q3!BpS39@u&NBwIYD}NDN&T;c%7{7Xp^wLp`6eh|C?&mXVEA?aK z0fv_1i8JZ%J^aenS;f6U*v#O}uKT@<|M7ep}<M_dGyjXhEbK4LU;+K-YW8y{GC}n)|3m z+hPhka`6w2R@)`!GdRI%Z8ds94Fj9qP&w5GalM`2@;9Z&uQL)Z#=FsE8A35RNOhtN-M6s?wu7;eg~9Y0Scf98DTi6D`Ld)CBWZ0fH}mi52vNF`Q++*fgS z=GB$H(ZgfVQtxp7_TNv$$Yab|>YTS=#U~rj>=dR22_o|ch=6jjjb%A)!w1lYKqyFj zgXM{Ab7DzOoUKf)KVJ3)hJ!7_knepT%3HGrsq*(m%&{G`a#>Jk@X@JT`W8!d?#j4d9#aD&=wxA1I10p;TS6^h4?}Y*v(P^*0m} zTuAc+`qm@;(nsH)0x01klibG0BWC78J|G7tU+QEp%P`i0sgX0=H)k(VQPAEE zqF|aLzj9G}OM}oQ-O{T*k1OMYv1YKq?>lO2$VNR>%-QiReVj$2mjkyh6XL?nu+-{? zhR{X{=IwlY2HL4B58Wt{k_SrSZJCZ`fR>060rJwb_ykj`=V%V_1$#mhE`J*g|LW@8 zCDy3uMRy$57+z9+{3L{=GDp!9ZC{EYP;=s2qrLhtDqVktCdl)#@$E7! zp-y}n3pkRHJco0;?Vk#|QFwgg!`wr8tIdMTW5g}ke8QQHR zTN8rr253rW0MyMw-RIoxyTbff5n+9WZfq&;RCndVCfx{_ku$-zLaP1*m$Wp#JvyN-I9bsx#_R;%r;K@tZTO|Bc!7uyKOp|yNt8eA*O?y+k zQg1~xm_$GG{yUJ_;Ea|XLews4E^Xa-nuO(BYe$0rVLx2soe#eO0$}X>eL9acJEJ~s z$rk83XS1s6xGRx-C;x~MzfIu5w=@$5c6eO?yy{& zSG3908#wFGG=QG0%}7g;?UdAJaILm}PYqysZUn%t3|}(h-o@|>h}%Ky1zl^F5k3R& z+C{@moLb6xLz}(Ru#Qi%q!&P;j^nm15qjz`a$dSliTc%+N|Nz(Dk7hb?ihut^8&mL zTXt^)MZ5R_=!k90KQk8XBrPjF47)-tks2yuhGB7W7$MJWzreKDQQ(gZvX;e)fq`5y zRkf_X4|8f(D`@X`fp zb1&F SA-44R*k_)y0htl9fUg8Q_2 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
<4_T}$GU|sUgzb3Tcw8TILz{S4) zD4d@ki(0B{mOz($vw63$<{H6!1Xm4!^$STo*3>A;9;Suv%ow5AoV4}!n zBl*Sk-PR#v$wbm=^&0AF==q~;PF31qQ9@1~DsJ_)?2A+q`q*2YSxmwmU=$l1!ws6X zKSY5N>FEP8*vIN5wvVIvr%y_vxRLC58zD+IAiu^$n%k8XfDCE7L=Y?mFtHbkpqliC zOzZ*)9fC+AHy>zPvf}z9vDm>-er?_6A3XmhN&}((WdE#9mth?&+atX58)`k~M?8P2 z2%b96mppl)y5jVYodz3GgGtozXnK>j%%gXr@JsizLmT z!Ri=VA8i9?a(Wd5=9-p`3Yws4e$?UyV~k)*z-LZmxShj6gq!Z20n}?LKON+;=BKkX z0T*PfBXt}=#Cr_JFI+ISuPj_+2Q=9p{^&Gsykso^vn!y7$;<7Cf$Ry@JkYD}M2m&- zzO8NK`_Xll>x_^JC2R0TwY)G-H+_{@oV@~?=^(boTQ$~x2?{UaCRKZ|PQ5V5%E;(u zI*PtlqpJ__vtEIHA{sS@;yU86l{;tJ}EqV)(n`nOO@WGzmn9t>}G zWbl9h64lz+h@OIdBS)4JknzJv0wSE%s2ZTVwzI)xIi@AEcd#{B6xZtS9dSQwc?~y*85W;JV~>@8Y0_3Sl#4ir!?Gc? zKwuR%#Dl3ZFF;4#*AOjyy@CA5j9RTHZe4e{K zE2gATm~|K{ce`Rbe4e@NZ@Yp9TP{N0S`8>k+AdF*nHaiWHvQq}8_G&QxT~JqXs?74 zoLIPNs(Z{PSe)u=b*jV;0MFB^Jr+C@9cL;0>-ncb^<3od^irF_N(X28I)0Bap25T; z(Liow9@^~e>P*e%`4E4E%GRhGqSxG)HJtOg6}Ic8rJl7-ZiX-&6C}ue{e8P~bfM72 zMQ5F+d{2YPIsD6@--n#W&b&0e;4ZdN{C9-2jtUKyO!HZ5ia3r4bgWm1o zs6{VxXMUORDy(%f?QP<}*IiE;>nH$`%=Nl%b$Xj2`D z0~eY4^(8EoEcA^LnmJ8FqZ0$BQ~{RgmL}@_eAwoRj%G7fTM!;6iI1W-7>axGh$MFq z`Jd%E(pU+eFMI4#UEIZX$y45Ys9|qzq!Wrx-u*80mw{ayh$HdX6BOK!w_*xR>rz^3 zGT$sD!JcbWs)o{}1Cup{2gpK31`Cpa4KCjbKCT0fn`ALRdC&o5fHumNu$v8CBJnL32!-j^pTEP`J%D!Q*Egz@L_vt z`{H-hp8+&`9!~6vwzRiG+>Xk4swJ3YcO=1a8-6^G5hiDuGUT`^jAH9&n^1Uc;xN+7%^6{ zxHBUwVmL{MK9jhrM*A!vhLbq+shQ~tONe*`Hj<*g_9L8y1?^+o@0tsI?3l3bGG3Q? zWCAh3I1S|N;ba$z=-gH^dYi1Z%uoVVOG-TShZi%c6zVBROcW>J`H}LbJK>68oaF8) zx9g-{lQeo@nFON+FI)Z0G6=vSyjDWzb{BedFwm)41;hdJtgsa zJU0z;$3GY;Z=C3vON~z$a=1(5_4S*Lqn_ z5<7z9RS%rjsX>oU!$c4QtO+NjeZ(|_&RM#ETF{#xPgHf3vdc~#oge(7E|>4H`?oTX{fJAgCnX0U}tI$t^%=|S7RJrUUhzrxOtEpwf|gGlWw*01Wm2J_I@4s zl6#4t5fXzl;~Aqn=)VlSA%Q0BQ4akLYVx_`$79H*DMR+EJLavm_axG-&H)pP@l7u# zTD2GJL)#%x*vNoj7NV!@r!=uLYRd>h`;xKmqg8X5QNAUfE?K2cM?CBr(F%>$XEG}Q zaUP2EIE>Wu>?daY*yG#wMM}Fg+|?g0JoL4c!@hQEh==qGS8gbP#R=*3T^~E-0Crh@ zX%+7rn+eaZKVF{u(6$rInmbDOfWUJgfWE64#8ee|Mw?m6hZAg6QUC$FjoTdKq7orEKW}P72~3(}Ii7GcAD- zeca|^X-I|x_l}tG1HcC=R#D4>-ZAennMzv)Nb4P@i*`ptK2#2FjeKjp{9bD~Ny0;- z@nS?z1-9eAIleXdiTJS??Kfzmkv_(iA9t6<5U-2S%yOP|&Cc(j^}~}V#Aj6PB^7w0 zWGHXd({p^UmRsrSm$bqG0oF_$&{!0$92Bs2pD z__jb1DZXA#n`X$5bp<61!&zSNAc3c4h~8ChQG9lP%T&vo84g(026Ry9b&YLa*bX^+ zofU5rh|Darb4myV%{F#IAeZdg`ubK;-3h#PiXCpK!lbQc}#c`^ccoSR(DO~Y&Q za$Zf1oMT=9Eb{q0*13Cd)+}d_38GTX_9`0a<<9u zH_X&Bd@7GGR*C{1mAL|%XUlgBoRV(!>nMf+;Fq5 z-#Dmxd2wz2>;YQv;=eYcan=2YqKE1vXrrU;(nBdWD0&|4$)IDY4Gd&%oHDM65^;0f zidK0g1gek*g^)ado0pMzN%B*NL5PN^17B!Th2-&Pa`i|1g!@&Ljxl>WL%LsKT_5~O z(O^D93Sr}@1eeG%_1QLiK@DLYL;un#yfMsle49}z(7U&%{^`aM=P1AAuVZ~O8%(LK z(Tp)3t+7ugAJ-A}!T}uMU%Q^GUPnXW{W1y$RBl<9%SACFkgN9%^`()4|W z=gH);fZQ+3V1U^|k4?xE8y$!yg=G|zJN37C=N|$SW=?k2e>?d1n$&+ui~MVN=PzXN zKiXx(@t5u8Z}86FyN3Td|G$fO{#Dm7$3Hc={sZs)dyMM8#XI|(;1}~6M2nSs1?uo% zUNW#~s~0!M)|vnrXojuAgx*e8ykZ%yF`dvVhtaH|C_Xw|tv12rZqavQ*0?PhvkylL z*QO@g9Z()yZIQMwY->Oi7522N3zlzYKGDB@gsg26HPHQpR3Yag5_^jWWJ69rPE%2s z9FqwiiH?XBseOkYhH^%ALb6#Z0Q)UE)6JL>Z#h7p5SU6PF)#@|o2(oH{WB*YM|@?y zBYB^Dc^3l`*FE@C=p&e%x*kC9K=qFR09df6TVI3)D>84!T>>sOd1|(Cp>`$a%QmT( zFOV2(%f6+_i4a|^XuYF+gUn+WsJuuRZr`Ce7u!RL5Z0%-X(V=xu}h;_+YaC2Z{`6Y zevY)!1=XG*w8unhL?G%1>`*k!zmPOF4mSCnCOcMiNeT?7`lnKzjX@)Y7C?-Qpg`eE z2~!1r`IFh4>@Th~VsBEzKr=}a{2;r%^mfKDJu%%HliJ^+7Ve0U@IlVq-i{$162L?vjB+Dnli0)D=Jh05gDr&ixlFz3c2I)S#-nWEe&T@{HnaNv^mY}u z|DaBj9?+qSzbD@ZeM&ochyGEB4XeItF#QXlUf6)*gK4`oF_5G%D6l#ni!A1)`MhGQ zQr~+kxD`~dskV+iyJLv34zX37%q(YdiP|$pZ6Nwo^vUzY+q$En&%q)2n7grXjB?J@j|KaYPf<%ed zE#0zh+gN4Wwr$&7W!tu0t8Cl0ZQH%}zJ29ffyjBJ?i{=+4zk~iJL_WQ<*sD2?pk#X`a>P zkdT;ax;!L(t8Yg3et=uQE)L!4-Kp;58A`6dc%F^@WZi05QnumIh4Z`!E)=CJn65ZL zQ|WbHAsghxCVy%$ssd(4et|W%s(3Fq_){Lt1!F##ha}dtLU>`2<n$A@>kzWW`=X?KucK1RC{hIbun8_!)BhR0?eu$&VVksXC)v zk_L{p(%>%oV&;1@9px3lr!{8G!aFpfpi}dJGU^~!y|x2*N8oyx2&i-x`;n{~wZ6Vo zp4h(}8a+a>@2k=sMYeGhtb7%L6N&Re^k@2(sMZJNTLrb1N2X$8y|0Tv9~ zNlZ>4fwT$3oc@ULv%-&irH@*|I2`L;Sjq@)W+h^7A(VR=GZn73!?9gPUTw z-3rhg#h^4H+%7GcS|W;$2Ry;O z=vKin$r#D^1*$TQkBt^WKaHR4z4orzYf~7QXlXs$yxO7u?XQew;Da7Cv7JL##eBgz z@v=X1pjsmGmo`W|V5jD@-3eei+QzZr?Hbi(xI9RSrZ)^Tih7CP(|JdF$E-3e7I)`_9hzg5R1A)k zbArPcc>XAz#OUV6SlyAHZNMeeN~TE###Qza8NG2FUhsLMmGG z7|D{YnG10A$ldHOVsPDE>NMgKjzbJ65d8aT(@Ke2M6xK(p{oZXQgY(LAK@)l=eD1u zkMnWSNm9WK;^*gnCw;p@8rI%bor(qRIGP{*wzD}gnCA5r@c6^rXqnZk3uF^pf%Lwp zra!+1la=Wtm>YrLn##}2QtRG$`f>3v)K@$#rI9F;z>(d2nbed*=zgY>7ONgaSOgei znI`N)?0C)<&1U`!n7uv|Aj*w`oer9+d+h*}cQ+ceW=!YDN?>OdQxCVMOP71|OP10+ zETJK0*)!+QO|xr!-dTf)9aD?wV`tSL{B_0zD)%gE9ZxI#{pgiv75sp|xwG_$N!ej2 zs+nKi!BG)Yv1pcZSc!(}EH&QRW%>T5n6WcNK)g<)q81*3iVF#C5n9KvN#&)t;!QN6 z^wr%wfI*sep&Xiq9D~^seQ2zGyuZJZdP)jlbD((FMvDQ;-&2BsP8kxSS4g=jS2}Cq zwuxOjUP@yyzAg84EN@ID7<;^zJ_ZYu#%o0*nOdpQ=cmktdZLcxN%F6s+m;b<8k5qG z0VlvEpg!NTy=1mk1WGi!4(hf?ZwAY_L4K1cO~j?bY%@|Q96yMuVx=N_-Ub8^0Lv!= zQg@{U$Vw&1*-S8OyXX+*aY-)&z&I#gZKG0#^JV4!n6ae_bjRNHSv_#Kr8;a`sm7cw zw|MpR8RMD7)87|O-b0rnY9rxnLchjFn(&nPQcwGP!pQ)*w-_DZPN>6OrYm6lcz3{D zg5qTwQHdx|h>x+CZ1JPkCNW_Bh)-S&tQf*g=U+fX#+`KJ>Bt`S*0Bh| zvR+(eMqeLudgXd4ZSl(2#fru$23 z`cM{gI1FZ)xU88bmXNT@q-aZHsIunPa9V;HL|(@guVns*hNTU|tKtg#YJ`}Y85d{`-Wj)*+VMz>jFPNur!`JCU+<7I2DB=r@tiT zf~7=GXkrWuquM9*4-4hRuUbk0{@41r&mXV5T&dn+tdTP*Y&lo|w&(J3v1sb#Du=uA zmCD)%h0>-*arGyM<@Oh$waTbWQ}_ zIOb(Z^Bs{Mx`dL9L^{Id)&x7c_`o1J+`?7wwK>ld7k^1cn&u3A&#cc#7y2CTF9z*kwwPr(LKeqwp?*6DwNK$b0 z-;7><_r>RCU-P_E|0ZZ=RBahi^gwxddJfB9(&|}A@(~PQvkDpY z{9PM%g$^-xkiQ^pr*XalI#zjP%e^#pCJ4X`_b?5Z6z8GSpwRSD8Ex+lt3XZpc)9a9 z1-OIWg61P>6I)eRZ6G!9t66J9mKK+|Whq^N)l?h?XWVdbjXX1zFiC^CDZ**JedgiV za|UK~gweLR&9PdvPM&UCIXHE>-%0iptC}eX61!1!%xgtX=S~L2L1D3Kq%S`pXYiuo zS=GRy#JMyB5!yv-h4VZA*FV!mQRwlLi(#^Af@XAqF3`(S$1TqymN`4)V8n0d=t z-q3im=L8;T^k5I=k4-&}S?(X@!X4jV<-pqPgeW!$+*pl(kh+?j^GvW|C<+p1mc?AA zx*$itb&0yC#Cnk0A#bDjE&9~CkMr~u7QaI`PZ9Rg!c-YQmjC6D`){EVCdU5+)cFs& zga4hZ$v+3D|06^0->M2aF-JQW`+uN&lnCgQ9Sv-q?EitgG4g<-6Z(5c*u>Ss$V5?0 z@E=S6GY*G^;a}ISvi}Eb$A6mx{~0#<|A=GYEc%9QZNlzcZOWcU&R@T_3@*?dwIFon z%_~cpz^CQ01)Y}1U)tl&-sLoaPmmYdakZC-D&ELD%N9F<6^lK|q5Z3%t{Za`R1Kpjnlt}~u145*mhdexAV|7GfF;a*fO%>kj zlbl$xUh{=~SS=KUgPg@%md-$%Q}{B~^Fo8)z%9G+a<9r7oTU`DAyszNz`;~#oUJ^! zE$28iuw)2(J}aEd9&x_b)|lpx@NkeZp+JYr85th+2foB}UtTqrbWkdt=y~}rgPCT> zHgeu@Z+fxZHSf^crur&kxh$T}wY(-4$snEa>xH6`R&;XHGh!GS*udLULW7>#a%^+3 z;%WW!fnO{vhL%~gLECMemof<-f$|f%OJ@_%8v1~$l;x-#cz+g{@^C3IWRE1G(G?L1 zYhBVWXm8`--`5|cX{@kwDqf67N{|WA0vc<^Pzr6&#r&rA(h*C{ui>Aq8Dr}*@R6~k7EgxnlT*YdWL%3LwbJL0Aro*A`--#3(dI0imu39qp_v~;%7pf<1qx`6&f6^nhx5B-p~ZF zMLH+J-=sN+FU1~s1heqbz4Y%4tR~eJ`!H!TSeu->MF2K!?zTSFodCCH>J>&L5-ZS` z3`p$IwmAfNJ`^ck1#xqkGO&XKsz`V>nRHUFKI!~WHC+KIc*QT<43HoAuv@om56(d#q(FBP)K0m=J ziKPR51f!LoGsHxQ9kZ*oHIKk7zFtIAUA=Bz3uzI(g521nb_>(S!E9?b8dBot-Bg+ZkP&_t0_A zKsD{V*N&;?R_Z9(z6vu*3DxtjQl zlPx5xL|aLLuul201g@fnK(r(ucBM%aDmhH@oEWjj<s#utb)64S3fHOd1J*y3?wqfUGd%X79rICc>6F4W-4zru^;Rv zIy14ECG{;6P2z#~LeGVmOU`1nG+G>Y^gzP}xu>tQ zYZlA7C4D7YX1&9{HPwx6g>Q3h1cvGt#8veD66D`pP*}GN_Z*d$pN&KxV)`BY>*{pm zB1%Ep1?FLtn|A2B^m(*2SBd}eFlxJ^>AAl&AIqV+0BlZCxhdZuP%N1-r{^{GO; zc{-rWrKxB7gW|dU+*IC)>H4M&`(6ko*6d6v&Ql9UOG6|4ducZ0U0RwccCD-b^7y9t zg8j)oAzew7FCzHT^ktu&bY(`%k@0R_EW#g@uJDikL5A45ofk~6uIk|OU{=o4=0|Ri zKM#)CIEwH!bO9sz?u6u%tBln=KPd1L-xI>=L&MvONaN_F%5L~P(e}q>3U0FwBDY5| zUC!D0vteQ^TL!bc2SSZ7(S)1APn*E6Rq)I#6MjATmB-QFoy=VIdd0Mh3rtTmGmk{$ z@rYXXIm@^SkeRu&^4#E(hM-1{oM5t?5}?-t5)k_&YmjgnL)D>qR1U5?GnglWK~e?N zcH9-)>tVAmk}b$xLRveftx>Oa$a)!nUDZByw+gy%zT|)afN6!AO}m8GuCCt2flE}^ zwAT8L^OUEf+V2Tz+u`I=dji3t6*c>k=?zcrY7w$P=XUlR&~~H%gF|aR6$QaN@kj;2 z-1cl$-3wtlRUAKfG367lV(FBhU3(aL#U0A5oxZU+9w%whc1lUeW>Xk%f_AN*7_hV& zIEheIu`|5j#hTrnLkB2*QCz`Mw^+6Wak88lJgM<1FQf5nrhOn2S@~sgVTP3SPMG2< zBfoW*rp-cKUj{Pt1~mNGA4b4RXU5kb7*bS&HV7c2?Zhwq3Sv4EzWt9b7Y`%}wu7_IpcJUkf&sX(96ePd>|9Ea;cwUHnClOScRh|$i!LEM6q+q$(oNgY`m|IA7m zA?L4((0z;QOjHR?4jio>pDpm^WgR%6k)F(GU}(0Y>?b^~M@WC?byYmRI2l`qx6wcI znk~rbv2*f^E;YF3ʐ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�zzQ$E>RPqD#Dz|86Y(K0OS31$kOyo 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 iADc#fau z(0uu zju1XMfq!0p2_NpPgD2B5evQ3|04M`Ozca?Y;mG~E%ms8XVd+0E*Rx{MkbK8H+1Z$8Oj$o!s{8rq zy(c4C>&@B-Q`e)wYBtlEp|G!zhc(IR0Rr^iSNE)sH+6(i%g` z?xj4%moF#yvn9(eSmwJCcR|zB<+HZhmaIZ7^IZ*4M?l^ohC#SCi(aZ3dUblbld0UrI$0ejZ6aU&giA_MD>!Y-=NHu@L-x zPHHCxP#+r9cX71|5G&XJHPVq%*qNqYRS|LD2# z7)Ry|+GT;qz)@nBsRoIzHkc4+^2OCj|bl|d3dmV;T_R;ne<+kezpFbECjup<0 ztV|(t9MFvHxgMlvkabIobgo^b%n#8BnkZD_|VoBlYDd_u|-7D)853 z>ym`$JiYBgw_>9k=aTtIND2C`-DtU8ABOEUxg1;=v%^EX=*a<*fp&!!x9EqS2|s{x zHi$^O2p22ejHa}dP%B!isYS}qku(WQzhmWk)H4XJZHZ%?@7O|CIt>{f#;S%=wjwqO zXJ5XPa$c0vqnrg>$~K5}Jm6v~ywd=UH@m{Fpu`N!F;zukE=Zm@As55*qrC|0LhR1$ ze=!q5oqznX9vuxSr1IGf7R?TB@%MnkwE8%D%!fOQ_QrnCxf>JT7;)wB?dbwXh<0aG zpC*8SbrW=|7aUIF`Rt43_xRB}U}#~uAJF6ssEKeLRyDXaoNDN370<<%&0xf~Xk3=@ zLYTml7R?~ip(F?l($Bq06_*?Bvypz?eO`7BpzzeFSnb6sNQZUT}-O`G>3oDM2 z?A#TYFf{X;h4U_SVbrOlKOBpg;pDS3iM7W!J8xqvL4RS{+zSQ36*##TFYppDs2G1h z(F>hZuo^{l{Ov-f<~sQ$d)HCWPN!`0l6lMTAkqDps(5W)D0lDh>$r@oNEMsFndeef z9ozBr`YWM})*BDSmKcb%{ zk`Uh(24DaS_ug(XApHHB6a zSf1uzrdG^t33OqHvc>*Dk$##0v`HXm(|51dXD>sUZ^gbH7)LiJqvV~MQ90U8Q)q5; zBF(^MC$H{RZW`26tfi#TS5wmChs zq?b_rnD&(?tGbMZu z8su=SeWNpWc~AD51+RB5TQ{dW`*Qw@$c#>ou*Q~O1Nbk3*I4CVqXN*iB`RNq>zP%V z0bMfM{i7b1X)JCE;rCm})y838<7`%x8#h8M*r9d21{<#eUmCN6M&aX2q{V8nA3TTo z*54E;9!~_PPVVsu7>ycY|wJX_uD=a9!ZdeJv9sf`wr3`B(Z?xE_i^3y+wOf;;1;&7*qlE0R zn6uoTAdp?Smu(LHm}~SY0NgN7QHPYFHQc-Jpm4o59KQ#%Or^k4Yp$M@YO|b$Gg&OL z$&#(-@Oc=$KOW&4I@)-E^0C(HnANRrPjq`^<@wnH#fer0!HqEE-{?D`sBM1?`l+tj zzsU0E&?I&L0@di;?^=a_vA$ObJJ;rt{K)~Z{Tz1frUgl&{TESY&5hsX1496R8}&KH zzh2cvKXVv8U3bY(DiUpuA8ADt#LM0zz9xJBm~#QSP}y_J%Z7Km4_D)VXNSHR8R{BK ze|BtVBa`opy1=Sqb;B!MdC6X3y>jGfWA`QJq#n;Vr0j5p0Oo_d-*#^`j)ZyW`-8RGBgO?lqp~v6 z;n1RYA9&fcu>SrjpG&ilugPVY=1b9Q(=SnyzhAq+i`hviK zdp@3RlQ29giFg6AhIGdSZOG@cM!QLpxA->t`(a!$ip_2aXKZGV3&#n z-MXV$N3rh=k-Ui{>W(W?0ZSBxh9WRSQ7J8Y(Y>c~Nu}$&9zfnW8a)XOW5w%aV!Ets{nf5DLW#>@lqR>6L2ofmeb}Q2due7F` zP^i~>Y&I4EhLgA%T!(uMLCJMIdldC>sy}HRYFXT$@YA(RhklboxqLE`!X!Dro!-ZP z1~9h?8Z|@S42LOvl9l0kkum@^STr@|QI1OtxtyUf``vA*+G`%HXe(&VU%6q8LJN?+ zg+ECG=Q3=LWpyc&-lPQ|I~_DcG~TaDz!~6lmciN+FuFV7FdfTD=!n?n0*ea*L|AycL zh3bTB$!|gSV6_3}{T`gc%4kF}(P57f6Vvn+7Y2EWz0kB%PivoXEQT5yACifdlH+W( zv`dt{rNnHk68vUy1huoMn@i2o__U%Or%U>m4D?{2E226 zpY?^uU@G=#xn;HmuCVc^t_&{#E_0}$+XL`}w{M;-)wOiW7ARTg6_Vv^P=rBuhN*J5 zkIJ_Z1tE*k>lg$M@G{ceWhVOwJO(0eeRjLO085B0Jj5xW*=I%#rQT+LW_3dJ|2-{> z>018IzRV$vGRt{a?$l6#ntbsw=Vqr+YCR*L8ObJ_nDj`ZwR3Y?&&{xqPxfg=k*}Y) zzug77`gc$7YeCpA%6ay!{e2K^%79coT;;F+u6KuKqEDNB$wgp%0vy#sJnTYH;oO?! zSB74m#_SFdX^zX+WlRRilQ;`n!w8Z@(t#qCxPBCZh*9k1a=gyqI^OU8O#t-_j^2`m z-5cCn{dXtlhABMkfTseyGDqj56a#l zShT2HvplwK+vYvCZQHhO+qP}n=N{X(&AhK(M%5otuaVhXv19diV?}&pj&IUN^NYid z2js(!?-Ku(nd^t>)v_RnB*kJupq(3PkIo|sVG&~Y2D_)d*Tg-S?VI?&2JWU-K~TV8 zpo_nkZ-HOeS0FNm^-gN|#@D9f-j2G;$E;7*e_P4aA9XZ!*c>tGe%{X<(86J&l>FR9 zn29${Z)E5xXbmpCg6LEVJz8@yP;KgUCmD!e8l zj)4-5zwet@rdvj2NvLFj=j%(n8(sB0i<_G`^A}Z|V2f598?kh0Yqo#ib z%CPQD0+(`_ZcI~f*?6_5*7|$r_CdIi5qJrf@VJb_8gb-+T5pAhiU+6XKH-vUKo@Ib zr(zGa`1}?IFVl~hsy<0boBRuL>wYzLJhYv?vT` zI5lJfnaodJpFc|UviMx2V*k9ON{gs)7KMyS7$K{xDK=O>f|;8##9z&1i0X^rM)?y3`cIavmYdJA`Bz*b5GwrgY?EkRYhy`pjLm^-E&|NC0vT zc2x(3stUwWE17(dWF0mYSkrsMTLC+$u2Jlr~SSOC3 z-V-g*wT?{a{esDNmIu znG7!h>=sO9V;UHKFbylWjMk*+BXFaMRG`U_0K$u+CrphP^7Sj6XsBbe;Kald%X0lV z@s_t$0ONR_6fK8yxgRpt2a`_Hwv@8W5h;$+g#@;0mFa;;l*6B50|sR(FhK4!=6?hp zPkk>%zjp_kIjK)vV!V1azsuU|4b$eJLn=7-TPZmF#G#&H=kmXWFz47~Z6Fljbrsma z7ytPzW7e3zma4e4`k4Z{OO&?BFu=OX@eC{b@`1%4-pD!X7#?zYXD@vbG9al3i(YT7 zM*K;Njp{_XaYe2(TzdTTa;4ej1}%xIO~a!Ca+Vx&vEkP{!X)Yq zI?e(-Ra+VP^!`p9PNndYAUErocHS*|(zYO$I|T84s&vSj_$>Dq6s{0O9N8b!)u$(w zKru{Bxw`FC!qMZU!j<}K8u2(c-$6)XZEub8yhB21(E`?zaqrj4p7m$pIkUBt<+jt=VcV7fTGhVOCp1llz=wLcZa# z10JN5XwsjyIy(%frX(F~X?aEpUSFE&GSM{fm`9BLz=kQM=BCpNa9J)D69DGMvU8Mb zVk!O2EK@F)>e%F)-*r|n#TdQ2etZ>2rAy+&{mh7IJXf~=yEd|l(WW+z9ItT}ec5(3 zLC1il*=iv5(&#p7yaR82%8A$#Ygb|5|3)Pq;fK=OJ$N zL%1JK+a#lITbV8UI0P#J^E8 zdh~8u%siQ8Gx4Z0{9-6=9AV?oFtv{R!X>MT#TQk)tEwzV#!7i=mm4_y`WG1?W?vIQ z4gC7;V>n?Nbd2Toem)NbiOi?yR$aD9FE)iu;^;=^)Tu{Mx#q_4`o0k1Aj@;WG2s5I^FG_PJZwpst*BpniQRS2w*{!269v6mQcNl9?S~fe z^Diq%Zys2@c$|^DY-VI+MRn9JI>W~u6Bo29?P7z>)@gMWpd{@bHMih7Mj6>$=QM#v z*@On9-;I+7{YsgJ7^K5r*78%?TJHrT?3r2HjEP3TXL%c#a_rt%6!UO8t6Ft&&L&1bAd{IBOoQo8LASndp0`^NyZxL$D1_QB;`CgA3|sx z#Bf083GY1Y*i$lk>}Xyx1zJ_1`$x}XDbMm%-Yy-5Z)s2|`iQoJL~hrSm!XYbs~3K1kz?cJw93w)t(}?-*fiHvkTB>zp;8UZ z;d_f!uG;qAG6&Qp9=b8|ThyTn?M_dEm;CfNSZrWWn2TN>mN4Q50xM+rz#`v$+}^`^ zuoN|p3K)2VkQas|jP9yiE;xV7KLd6!@Lq_l|vL+0n*QI~L*^aiv@WzA1x>SUv;9#Dwenhcy_@{RzXP1mmcD19P8@1QE2*P5D*=_C`JH*ghPxMM| z`zQ(%+C8xW`XADajZknFH<|^~>mL$kn4P8tS?FxC&+cc>VOSwRj@5tUf8mls9#!@a z34zG#XL7=N^9h=iy+5Xyu=k197cr1nm^&li_$bJj2_Z@Jfv`2`!G%LkS#4A1T`OXv zJoz|$k^m5T+KWsDru18|Mzdkb;c+Pv%O%>(4CHjOBn9Mm{gix%Jjw2Y5Ow-c(Qnu_ zxBJXx*q_09HrXf23>0HOaI= zR7ZGJ{S*`H#+>`|IJDP**E{Z{<;He?$NEkV^6;#sGVPyRk zJgSlyr7*T1oK6M-tEcS;GeJ)q(inDK_hY=oF$3fH!s(pvN~r}U_qB~r;UKs-?(js4 zIf)B|L(SR0$A`b5RqqafZqj;4G)Rn6utsjV~tp0U9TZ zmrtiCY=h?OBp4)TRqa{p5*4CODgsZh{!F3Zp@KQTG1}&;at0LwMRBp=;I3i}o@`&vH&PdYt+GnNP6W#5- z$J89M`xi`_tKfiuV;H&lWSnGo+G-JP!Y%Y)YccgF1CXtBC5|J~kh66opx1IA7^<{` z-b2e!vF;18F&3+U-N1_fCT@9(h&86%ZEoQcXCLtj1LA2;c4F+PR9Sb@?U2t zMpjnF|DipQm6M(0{{~>OvHX8F7X!zC0IdJb$NmFgoi76P-jIFTEG957I1HsC$)unF ztDI6jFApW*Mi(RN4^qH71#0xWMBSXiki5d5dyGsJR{~>C;8|#~TA~1z2M4C2Qh$~+4lY>zTZhR}I9V{>rV@fSfVt`%4uteP3cNm@!D->WR zY*pSxlAnvza!>n-$_VCZFl1D0HKt_A<6m#4_a3u}yXmE+^Mhdjhl(%=GrqQKXZg*O zj}{~k<~;tS1*n7%mU@gWvBhqbH`Jz(d$jck>6Lk@pXB(?h!KP&@TSmV4fC)gqc%?~ z?VCGm5iU(90+1ULqeGdei7X1d%nCXQ{VAuq0ew}{KYbt zmqL-X-#_Dq;&Y?6;62Xjimxyp0t5}FFeYYvj^(J3P@OsHO&u@rl|Df-$?8U%vXy(f zZ9lL-5>dk2dsZYI8_o{oh@OdkZv9=?@rp3$y!)g_2o+SFB6Q@KtCMGki2v&NS2K*9 z$*y*pw@l{3p$?G|a*bwkPr&?X zl(+XBZ4R1)NkRd&Hb2YW`P31x{DCXwhgb|q!*rv`=2_Fz2Zn>yA%fTrGdY5L;&@M7 z`bB~>w_Y{M4gJ(*oe^WbqFbGGY)_%rI}4tJ@>!&TEU&hp6ENftR$Z$yaDS@p6X&d7 z{_!a(wffomxy2&0GWC^e-;WF>&nlz~oCs+N%*+c0pF`HB#(vv8+W`Wr=0;7VF378b zTiQ`Zmd((VXjq!cobOG#fF!T4w%&mxHD73wk+CjXYJzq=n|ATUkFF>nCkDg+K%yqd!jL0jt&P=_5s zr}j~q*uM=rACPEYib^S;@d&=kocljqJM1KAMI}Np(`Z{wYojG9cS{0{r{>wZhld_I zQB27s@doiK99JU)jfmMqrvsnI4ofHg-R@vCn*p1c-&FlLk`k^=hpN&e>Y={&(s8i$ z&Ixqp0&64#0zjp`Lz<3>i_qIZL=Yl%s>GfP$33Fp3BWoRuC8(>9zL3bkM=ZST{-c1 z&Xko~BF}$kl|XJ8fEos?FPuqhPHc9+H|aKbMdCj=I_6Z{Np%FoMA*<`=JAi26PDiG zs>)oCYf1=fyZ9`;PLh6e?p#101=+#k}&VpDA;);d&T`MRNm+1$R;ieqC^q<|cQ8uc(J%u=EiMky^M5q>Vw zsS34pBtat|5g$Xu{1|?OZmQv>4xVIUlbNe!{#nhsuPgz{D(dAoyN)c)IXb`lwHb{w z>37oE*~~5yXoCsT+#378+8zgjKu`JPKD-UVoYGu*JR7>b}hu7L|wZJ|V1aXs|`wDmneOEvXks6sVtwLb%XLsN9#}D-nyx$~h zLUaRD&C7*qd0e;iPayExnyI#On_3KA*Z7qm5G_7zgS-ZF(nq!OyQOFvyoQ}jc)V8D_L(D_!|3h@LXH9OW^qdC>P}nL zm9yItMYc!4nk7EL$EfLqP?IO}il=HnKfzkKf2#Qm^#+?`toauMzqdww`~{dDk}S69 zVmHUl4MDnm@%iA>VEE!mY8dyMqMHa4xYyX%q#8yORp!uy;(;^Nh;h zUwaPinf@FCn*s6H_AO;WU&VE@LbbpR4^lWs4X{dJ1^!nsaCr$E()-Vp(5=*0GLU*S z;(2s)<&<+EI7|4|=FTT%v<8#Cy3+_DQdVI=8T}TWbv&n)yY1&5tM)}Um!en%^>B(JimiJk(ucVqG$L8%l^Wl3oW^TC=8Tcj8noUy z`%i7^8zE-YTRq&)tc>Ftl`A*OnWEf_?_1=wmiN(gWOfm<7_TU>vDSl2Oz#w%Y=PbD z`GRJ%6%Jcsck0ECe-5L(q?3rAj_4cwC%LZZsL(wySfN^GAYWWrk@pz=jA-vDUd!uY z)VO$3Ch+2>B88Y~23&2KBCj2%%65a0+?}VL8>)5FHKFTCZ|M|L$a1h zNFJtv3trN@V|n}qzz&O5D5qp*Za&Nr{-SL0onCeBFw}M;Gw#m(pEHk=yfwvVvoZG2 zv5snhQr0*iLU)_lSR^?Qo(nEGH%@k)b#A!x zGHX>QhR&*})c92@t02PD1YUEPV&y1HC$&1DgB&DZjA7eSMq+-Y=-KYJxKRIIs!7L%;yU_O#QO1D1lwgtsJ?lYODD_?5O~%jcI61%jEvc^^1YdeL}n1T7#fe63_})`tRm(!-nH7`_wm<`9AVaFjYMjWpjQ!gJb@@PDjZo7Z zP+EE`s-F`u>oxIPw<4sSjN>o;U=;MPucR(N45pAxBgMfWS=g~m?9g;R^ zq&#R!s_Pk0IvSMj7KallfCo~mY?Dz&VMi8|D2W;H_h&P_5Bb;6T@#f=B5l2Rbca#v z+a0c^hnn}I$iui3@jSkft%09+!pQpzs$KBgrhi6D85p%Q8cIXQcC{!(AeR^+ac~!- zCs_RILpPL|*ktqAH-SLb#%pB&WGoVtY$E8Ufo#nHOio@n>i^n7$!{}$ zOk6>S3!d;H#6j_3;S1=qL_}`rAR6o1c_X*-hCf<$`vxvQHr)aEzzIKA&wJBL zFDtoNZ%AC#bx%7N52Sv)4=BvtAK@&?lfk;;+4shi-jP<@-T-=yi{mD88i*KtA=Nr5w3z{58?(blio$+&**rL-p zMnxweo+N0oSY`mH^0emb3a^~i&qR|OlY#<*ByBpYZ4pmj1|0!RJY@<*{5r9=WkdFeGkLvPmgNBUEAMu5D~fo$PU8J%46G}TWd?#9h*|5CbBZ8>N| ztWGB0w+=WDszVb{ff)et`0AM|E+PiJ^T_p5U-G9durQ8X=}6(1CjzM0B+AN21^^ISyd1rY zoJO~}Z6P126DY^;=uqS?;SZ;ZRn2}%fR#M|GA$rEnH7Yt0&W}?FNF;_RLscSzVT|U z6~4-twLR20O`f&Q8Nr~Oc_hSlt6r7jZarkO5$#D)IU@2C&y1((Rz!vd^9+{q2+gYD zGbBz3Cdg;8Izy_cKQRA67Ljk?BUZLHt!OYxR~A2jGt>f~6<&;We~t^9HGQ=3g^`LYHQ&`l-6HhJE8R%38#I^vGwpDjR8rINW zPNim^Zx!AOE1_hOudYiuG^SmEALT+{GFK`~?i&U!h&blf%IP?WTV9*7Q`yM*t!Psd zVcI}_hN$D3=N?gtJ?O<(gMCtv8Tz(|xq^_@6vUj;v>i=ST`+#t!X5Si&J7vSHhW+G z4x{y6LP|u4Sy_BPDHKF{J!?o8EY4f)j7XzO4w3m88_AHQiJ>}K)@w$mxQCfLMRSU8 zM!p7sDZCAf67&%L*<$z$;dlpr(yL35k>WuUwk46uQ}f*1b@qEX8h2lRU#DTEf|UsQ zuSVl@b#v#d+D#v1p^v;p*`)(X2Ze}xnX{_f zAG$@j`X@X;Fgq%uFYFo3peqD;DXpTP%aAt~R0BSL8tjDqq)|cT3VmS+c%LdmJ2pXQ zX4-W2$!$N?!SHX(2Y?}o-9f1ZX-BeuP8^mn?lB}OuCYmKlGSn35rU~KO!Q*I>Ddv` z6sPcB&hCGS2nu|NQTqG5hEaMLl_X8aK^Y!UmgFGMY&P%bMw|(6GAuX|c$@05k6n&0 zt%lx~B!%%>e(tf3pS2(U$~|PmVn(tW>m2~ZLRB@{s|;PTpnr5j{k7kL_B~In7&wUr z+T5WyYFpX`?w_Y_qaFy-7%~SXbzDzs`9)E3=$cZJuEe}G^p3t^MxUp&jVGH>GE+*A zj$Ygv_edjpXGekURli)S4}s}$2P-_76I8qhBvScsf@RA2Ah&flYZKO{BOK3Ef;A)o z!PvOmGKZ@VH!Q1MI2sc@!WowP3WI2FjELGx1K=SgQu}$we;3ken-B@mz2QjFGb6n`h7!Ab0AuU*dgX(hLwNK zAfo~fg_MwTjq}}QGiunFtj^c(aBpyiTi*NHLQnzpUaVqT^61c0l&ha9-wkh!_7pGS zg30VfLW{kI#fU&1{Cak@z5>4QDqu3nBQvAI&fu>Q9Z*IQ_-aU6$w8xMFgTZx|%05ub1)!Cj5EtkS*K~FJ}Rk%9pqpPTxknxXOBahE49sTXh!*VO96Z=TN>$7Nq&_va{ z5+SjFTkGN9LWS`Jak&jrjK6(R8ZosVWJ{`Gi_k-?({DKCq-JiqpOV-gjxsSlJOUtd zm3_Q(tJkR;bNANjskV*|4Z|Xk|3WB&S~*LWis3ySWN-Lr=%c}3jPPKU`k|>KtCVxT z!H$3#f?GH7q#g;|^N*+km-bI*QKhV=D^1B7@JS(5EUNM|NDtcFvT_WsHy-bEk_x5a z>`iSqY|RamQ(3U-Og|M$;P>@v2@1hLv(phs=0|rz_V?lG(hnS~!8)2tKCBo=ed9!< zBR#K6a7b9dCtsn7je$@mPdROH1TO1p0ZcPD7=+QHp*AgJGL(1cok>w~)-?0KMKeCa zJ9yw`n64}S!$O_`h6i%Go2mZEDq2fYCQ+Y@DmD7*GgY>FilrrWD(&e$%{JaHHZw#XFg^DSFzxKuWjE{aNa9xc_nE0)9qvj+pjh1_^5RcfRy)Jx z0p1P^8ktbP)D57K)S9hitb@Y$SghljJ}0M>`XKYXlQTYZ@Hw-(7H)@o8h3|sVC{P) z)!2YTc8Snq%3IUFbVPb(`jWtW<_)2e|`h^nud(Ws-lcAm6M_aN~ zB8#@YY}bAZf<|O$+Zj0(r`C1O+*;Ry-8NiW#o+0YfTFM$hE%*+zBY`i$8Lq=T~spI^J0+{LR2q6MosNx6@k;_94Gp$FR2qLwLh|0PE9RJ&P1 zd`7${5S=xt1qc0J6;&C58Pum$wo)j}5yoR>bAFs=j!t1-QSU>=&t7{|8skZy)H#eB zCEg>G_+RezlVpZf^G?01vfxxzPZxGi+gl*^D`rM**}E5rH_xlzy(u}YC%R?cdRf(w zIjiMu2^=u9<)&WDJ9-y;o8Fefsp4<*y{+(m^AOLtCpNR03ABtFv7?AOeBjb3KjQ;% z{vs~!PI`__ls>zQRH7#9X4O)bC~rR{V!2|L9t`Q!&()Vt6xFkOkjJgC4CmvEiE{sNtL#1nTK0-X#B75sv;S25TVmhg z>|S;{#By=r>#grY07x_3K)7Jj;vj!$c^pW!T`a{qKA}V`&>CkVW)lUY8#|up$Stdu zNG?t_1UW1mV`Mr52T>fi4~Vw?p02(@k?z?NJEk|=^rfQ(&TY{AaHDp)UG{UW0{C6% zuWsC=Q6PAc9~HGKSX#ZQw_Y+d>X0<^71QdQyJT7_SqfgIYgioRKX-QbW9NK>{?6m}G;e8;y*Y95gq6w>7%80aBvOUZz>RP$ zasRlsgd!&kI=X%?K&~RQ#r^Y)N8d!SM|O`}nP6CCa`v_e^I_PQBVD>t1VBOKt`J7A z2eyx<#K_ro=u}Ad%^YS&<+@XqOiPz$zk3m#irELA@X|IP)B9qkkdkJbX~ekQiYsV@ z>$uzky@N89W`;zV%(wVkWf0nsj^c3tWVIkjZS`S>1-o3?p1Uvs^S8)yq$&P`qJ%B0 zHvW_P55FPWQsV*8#~y?00B$1EMz!H8Qp-l`t}ExKw8AKi-DI3KhbAufyi?Js!cK{t zJIn!W&PENDL)`IA#>=e;wkpQLUPl`<-0F}G99Ea{c6|$)H>50;L2RT~TG2Ne(}SW` zJaH`~{aZvlATOzgJOekXSx4GZn~V)Y(GH|)-!J4kH11QXz3S+*5P0%~=w2{a$MHY* zzGp-Y2a)!0@*p{880@nZ?_RZ!7vaD>XYdgkxlZ2hdtwBWgmK|I2N5RNpx4~$G-EO5 zKy;8IKl8esG>fgJC(6q6m~nY*=Yf61&>T?%7R;keK_VLs+3C1_Wioaho~x;bbcr(QzRSUJ@y63PN`-dD zMI$LKpN>iV&(2*Lxl^wfZlSot=SqP}l0;*uF`K|q{@&*~?IwW!{xV8eZ|Q18(rTUs!p0W5smlw{S;I!A)x5qwFT`hGQ#VP&c5^ase5<5Cf6& zsrKvkuEyY#&lyHTIUOoH>9&BqIAlpVkOsWez4cqK>lEN-J7eP@dhyF%{*rvSlJ!0PAhCK8V1Da-1st$q`lL;)P)W6ob@`+GMVkEMl z8*vMT%*&~R&NFI20G{H1>b-NhbiM&DVi5shHw}@ee^J0J1;dt8NQ{jniNFA!)crKs zmOw5gkr@l_rR}kQ^0jlOc+E>)gzLS1bA-GN;GCSu)7jCT`xePHS5N`0NXJs2Xt2pl zE}p#Q*VNx}bV48dmH9cp3YP2Dz6v+gHVsc}8e7|+Z7NfXMI~YK2HvWYlX0vCfZ8Sns}q}AZNEuGZRE0gZD>{MOu0jFETs>YhYR8S@hw+F z?ZG*e=RTw*Rh@)hP}am3Xm;wYInh!}ng*$VYtj|22#jr)D8h)F!wy=ZN@EJ@#I9!GJ7L@V}u||w0>cQ2oxW3 z@+XMuWkQbZ=METhJ=;$txiGOc469waI5U;B5J7%ye{Y9D`5_6b0EyV*7ZHTYE^g8& z$4iy2lfjBXip4aamq5xgitW}aR7p|u6=2sG3CpR?HRIZ*;ew#b{eighoSzO)QfG6@ zQ3$AwV3B)}P)C847wKi<+Hr!MJEd;WQ8?S}nYkZW+I76+Se@9j4WCT-c0nmQK=zN?dMMjmcg? zF@N`6YAOZqJJbjx)u3!1Gf&{RXL$*R+>BA_Jiy7<0DoinRw>6rua#!c5)e+Q`5nzF zG8p(cInbgl5|t^O$$N8KV_FiA>@_^aJy{#6^tk^0Kr$5Da^NxV5Cj+>JBB7!4-N4c zsnsrTYhbGCPl@`cR1~>RaD7G6CqF$R&s+bOH;&}a&pRkvBhxb+(o|WrSM)3+GV%mg zo1%WG1)32qI9PW52nm}OQsc-Zo~y_UmF&_lr8~(`d-egVw%@#_60YqAxw9 ziDXHcDt>XR#Ago-pZ8cy&IMboHuAV85g!~)Z!_pFn>9#F5f(%h-glzJT!5oqMg6~3 z>AAf92^&y3uNtzB$U2y0?o)rlii_AJB-cx>EH`_dhjFe)*N;b_K9AfcMXsY>Ph!B z)f%IWE0?^iuXm!~Ybq;V11+gh00 zk_=*w+H1y75GYLkDFm_1afLKMk<7H(?bN!v=R?xUHF zI%eZD>VpY7?&AQ=5@sn!`=j08ZXFXipVwBJj68d^jg)wig>cXFpj!Gz-0QU!r!Qwv z1c#2ZJD0sQS=UI&AZFt&ubY5A^Uvfs<5wmdX8eu)+C5(8zjyHp|Rr4x)tzWM$CDNFtQhZgMskvTxXvPmW?92;wTUwR@aDT;$8_5u^jcGw^ z1ufVo*6EcWr^%l2y`*HotgtM?y^X|pP_I-lqiAB=yig>GaE|4g>+Cxsi1nI4Y;|gs z9n#;I4<@PX;HdX7A$dotI(z@IT=>M?i3@6!>T6 zU6IGdkFHb{63f4F_&GMEMt{#=gm4|z?WP{K8F%$?YAJA-vDD7xOFN0T^qUnd$c7qEIe=1b5a~8qTA=+kmg4uF%&)3{<&T_ziF)uBf zF79p8k3fz|)U9-=63cg7_TzPWMy)xGVvKp~OtpxvSP%LEw4%Ks}&br+DkE_uP2YQ$StK>8W zX!eeX8UCiM)&NHTl;Wc&EToJe5wHn&Nn+DufX!J51>lnJpi21{*`XrfUH>b0i2qqN z24jA8f7pyEeXv05kJ~489p>QHI(N@tA=hV=O|VqRxv0N6h(WBSN0$D}l$TR(Y@X#x zO@;Y!8kJB64dshKRa_wJJ+bEqHnb3C5HO^ENV8L?*OmWkLD2^_oc6Of>T(lVhit+G zb}`~f11kxXu_iXp%h|4D)0H_0;rRRXCw?0WK2Zq#I#$s3nP?0~AUQr0DdPjk!Ea!8 zYjY^v5w^|?bJ>_VKLLuh_6l?=e z*_Vcbd0tqP?CUgk2J$yNkkI-sM-eBeIl4bM6njf7^JJ8=y5TN=;E-9a+oIMR z2N%x>o(!FA@ggJJqJ`ILnF?c0%GQ|`9f!V^;8t3%V{j(*!tio_wO2L}d()W%o|M?U z+~G&JU|Dl%7DUHe$jvYnf;Y*hHZrSsT&q}8OjU4_7J;Ape{IZvT31V>Pu3PS{1T>k z{{l3r6e`LFpR2Tj-(HtMgY>t?BmlxE#^{{_*zDy^;4SzJ*`-`{>o-Rrx-|>>%Yk`z zlIGOr_?ol4|M)tE*dcF*36|t;OY8e1h#aP~JkzQ~fvhw-0B_5kl0Fg52n}h#v?!3% zVd@xa_24A(tq6Z)7bu36{qc*$no14kC2`=g_^M*?W~9g2_M(j{{T8a`$P`Mae0GL( zo`wU@;z1iB$Sr|bns%Y(ouMC6zTppJ|1#9|5xJ*qIh{3aD3wLp9NdXzRO(g=HLG@F z^(x!UNi-qbw#|&-UKJX>a%fWRr9M`49k5{CV-AgCcNL`4L#k3bmK|(z|E198Y04Ku znit(6eX2AP#zoKfHlqbW1A}c~HM7o&3H7db^t=lEB%vyDm?%gM|yehS#`pe-*;4c<<0xP30;#HCBH1e)Rznsp9jO7HraOA*N)~ISS5L`%E#w&W#wR zT!wtZ>9QNBk;p=?+Y4P4U$zHqf}lpvDF*oBseT>M*yj7jca-qrhJ-wBiNqWH>_T02K3=FmuQZ$y4ve)$pYOQ`+-#d02AYp z$^AP?&cHmCc;nb04dxljb);}x_V&xz7RJtfdmqB(<0(0a7jD%3wa5{)nF(sfxeezI zs!=%X2Y9JeP?-xzh|;E+D2^_?V+XcI$1NvuQbfOc)%tmRd64TRe8di* z5J|EuRDzRE#*+V-15j|Ktfm(K^9(1xQOZJptjh1-o+l7Z!nQx|=x=<+080TdK2R-Y z=$yeLLW8lE3V*t9``_zLWgF-G5JcTPbUQc!@CPZ9fT&4Zt|U=v1tQ3|X7Sq{gguvJvt|et zTt*4EX(8BphCn(%z_#@S&sv8S49`c1?V=(rOB083OQt`MD?E`vDX(Sup5^}q2BLR+ z;){?<^9VM4=q3=4U=SpRJ^z~{3p-ZpL74N4ih(ocO;A!9MzHP~H)@*jep@X!MAO=V zSLxWRa1NLU11yCbEBtjd5dQqJ#l?+Fbjk&Dmi+$fiB#D3~%4h!II zs;QIoiff2^cnDdD;?)x77t}WAAaGx#aUgaHarP}+@|xJ@b^IFFne(`H1>U_B;wlX? z1hB}@sLMdBz6kNs1H7kSb=E%a$j&6V{RwRIL-_TK6vI?2$ZxbanF2nhvAk=n94^l( zrIoe)-N^k~ud=50R~4nrB2Y(6B$skxU8Dm+^PucR;NdY)va|A^S0;4!jY~S!fw?MkiQN3cb%<;+bYOd4<9i>$S5oRQCm$~q z8Ad-lf8td*ed%wMsH~D?YqLPR^qdiU^wxh^MRTG1>8Om;c$uJL8|odCtUMw*%fja8_g5te3M& z$OH-4j!c_{xJ#WkHRkY{qZsn>Rbc3ykz=LkAw=};GOCF`ea_erQ;70J^>f(w-Qzg7 z7ohXOf4_1>xfXz)-W2D5=?t9^tE>$^_sOK{AvW@OgP{+ekiVqL_U_Y+LI^3ENC+5L zzP8L*-F6P~ic$apLIb(fZ;cf?fS5g0NMY;)F+&WWlO%V#sEhRw=p1y3imm*rE+i|( ztP2J-KB@JM<4yLbYMc+QNh^#1fB+p{{9K=Sjcq~2aip0>#?@$Sj4sT(Fu%^;A*{ z<-Pz->$|iexuhw15PpLNYQEM~8Vgut(J7mEuAE0L87BMJnEMZEy~l!X>PK#_DTNLf zdoUJzY)#l3FfK>&@F&Qsc)uldl({vrgLw4TWQGi{rXTgPR0jE7W6>!Ewp!qcHTDzl z35Yoc%OHt#V)NVhwjL|&dqGn_H!^zVpQ%3qzy;1@xG%v=A#nmNwUtjO-f>^il%?ZD`KWHy8q z3w(>4=XdOdDJc^CeZ`&%Lw*$V=4ym)CqB?xm3;BwYYt=j?Sqt-^+4Eph*Cs1BB5Sd_rwR-WAS9el{lZyE}fukI>eIE>&L3 zQmv9EgP4?bzFL0O;>2TRkKO4rIJNnJ;m5JFhaT z`HMOO3e^K16Z03+w|ehKQQ3<6#Cj6um6yLZ8|3I-NbEuMEr*^}?acf_g;DW9=ibcG zz|J{U$XP}uS%MS%!pLwqK@J(inUuW08}-oC1$JAucNTBSFFgActiF}jgg!80_pxEl zeSy!U(?MHZqw081W6GraC&>~89%^n+wPM4nJTiTq^M%yoT|_J^jUM0#=IEo_E7E(| zeJAv#(u;@GI6Z%^BJSB4aACwjmS86TEcE~|9xli$U7OBpRVS81JxlN6gEd7TR-Z%8 zeuWwcg$j71Q$@@%H%Vyyu~H&z6Ii@XkYyfO_Rd%5;iWJ566Mx)Hahc{QDvp2jQY{% z?0s>L{yh@%7oP&LB3J=&R>7s?dtQjyFkn|uGOf3$ySA|i*9d}@8l04#jfNTxfbzJ` zcsGAAzU!bFQ{ew>?&zk}>NbO%)`Wm?KgOvU5JW4pz_O4RwMgBh*?Bx|e5v1N2GqY{ zaE(yz5j#hq-xy0;MfGqSG%2xdu$1s*W+(fQ4IRE+*#?F>95K?JW<$z5NRYmik>u_4 zbH1mS+t+Zk8Ra-;(<2Eb0BwxXnbU7ZWU?_W(ShfsZx@@h_dA$)&`175tVjova>SH^ z1A~gNPXJg&44UNq;+MZ_mfP+&Qzt*^xC6pkEhR`4n5w$0VUTaTW4!5Gk3_H^fJAyymhORwOiia8s!l)U zfIDD4ZC%&M9DI;Ca*z2%rf`e=o0r$8l#|A!$y-I4&~j5)@sZ!XWt;6VUXuVAUe`$l zLs@74{TWta+$7nhDLKv)%9h?n5xbougw{&Din&_*Ky5&-JpTaMGcC{n(WKI(O0~&JWlvQ~EyF2cU-WoD7?;w^-Dl{*Q!~ zkLpij2l#Xw+|`&N62>{&Bp3BMF`#9&nxTtT{6bR(Aolu-;~#1m*z22f{b`#!>Hf>$ zWXbsBPAhMV-R#XXsuL znnFh9DPJYBdM|Td>hf=KD1fot0( zG8L4;z>I%l0yJdKCiYl-$8 zUps>g3am}~sDPZ_;>7k(i`k+4e;vp2aV;)QzE{7|@~e&}!V#Ms<3aW$si1vs3u^Kp zCukCElX1uKRDj0kUFJkCPGMcw8sYHWiV!~ajso5@Np3M0v2G$-lRO)#^$Y~mL*kAS z0vCNtCxM6fP(lTjPZ)ntSX3sv6rApEr8^agRgqu>Jf!@+G5>LaJ!z2M^(HhRX=F+LsqP(fGiRPw2Ips z4Q%c@QoQApWYC|r-*?6CAe1r(-%MWL70=IqQV&#VudrNhswxLWwITTu_1Ko7Tcp0j z|5TDwP`u%!+Jx{6^Oe!*Enos6r+Rk$FUsC2NVF)*vQ6H!ZQHhO+qP}nwr$(CZ9DU( zt-e)V(On<)B3}RQwSUiv6KAYBW~+=9pxiN|qOiNxBeq~O^(4{YPjFWjS%LmAZAw`v z4?7FC?ZaTmwHu@3A`A}qqfaXuzs@m02SISB$N@nE|NjJ&{)-O%Crn~tWBI=@iItg+ z{(pc;9L#M0FEHu*e11)@@wUh0_oD>s;0rL2jQ@Pn(IpA?F9v5SaPX z7UZY~ZP>y`;T&-jAD$GA*&R_!I38H_CtwBIiUPxBvw`4ce$QtF^Ak8%z7>f&oF{DAI~f!*svPU5z#xicAFs-^5+`3iz#T&)I)6?EVJ%+RC?)-vT-eiJvtxt6X@iNYj^7n9FaL88^Hn zAN3AH;oJZrc<2T)$>Bih@z=ZaFU}UdXG26uG)2*D&QE!6a>p&e^00q>s)s*9(59x1 z))!xJJN|8IDm`(3C*WptHM|N~L_^ zK2e{F>#a;;2AgUIle%SQ6VcQ!uCp;;7WPgv7_-F^kAFr0#y}ppB0LLo0QmkIjF4dx zw(W@^`sc-o7s3bewmNJH!c&NR^F?tl{EDkjW`+F24Qy|AIG<7u&PakJokTrd2e$T_ zl)UX+1%l^O=?;lw7s?8lu&(mquO+ggPUu#8-=NVC;_ysJuHvL^g3*{!DRt9`7fT!S z9$nFrYdNznC?qQxF#X5>!-HfUsa+)fC)jJQAvue94h1UR z)2+K>{`(f>aIdd4N;=zOt5+1Jboa-)%%)tqN*kmO!9HRHo3aj$sXlIfXTb0Re7$_9 zNE`M5sCX?_{cO{>X8botoBsx_hk%XN^KSJvweyxxC*`T!a{67%j+ygmq`;%$*h*u( zJnO5!a^Ng{nLTL}yn<*xXs~k9QhllX^=JSSlYt7=i;S`0HZR&n z*BA#iO54Dorlgi4hZYk^5DmsxR#8@vOce$JJWNn8J>M4zCHEy`q9y5}A*Jf5x?D8H zb)KGX8_r*c6hQ=i?c{{VJ-w zM~dI?rA&g?67!GiByU+_y13YRTLAbIvz8`~1GhvVo@}OGgi@Hw!~zh+@z9=WM+|p4 zFx_q(?Ur+RweN}TiFH(S-&s_5bMd44uk7~Ds$EQae@*M>0kNin(ww2`e3(9i%-ulk zrAy6DHf1~LoG)gT6iHHFPq?S(04)XEO^;FBDfhVJ5KkO7I<)#&xl_>}oW>)7-GwLz zzjRby@&@@!0*lPgxVDARitjqgKkZAei#!H{$O@Ev{U3s_JK=5PP`ZzM)3-Fss#L35jIL+O=`^!-K+-Ce<089f`2~D(XW`=b`^$Zt5ycSvzUzUDxLW9Z>j` zCGKbmeJ52WSLI>#BL&-62wva~=M)oiy_*`vbNd%_M~ffxdX&)RPoU*Q%Ob;A327%! zB=YPO3n)Z_yt#Zk4lt=hIkp}9oEiyJo$No@A-CiS#R>UXspy2M$# zBH7N{GT}RG^OJts9pmfp^L@6*XfSVjMz!kUpDLHeru@=JfT_*B5t&SS;e0^J^7R#+ zTYoe0jn+LL&ioK^dF~>dh0sTzEBhfE6MBnBsl;5vEr+2|vrH$FSVe;ofu$^_t+(~s zOb8>naYHlAobNseN0Skn5MV-PiOsc56u}yj42odO6t33eGhEfO0VMv2?DLj9P*VS` zQ8{IIX`R$=5l7;=G>a85q`2Zq5@5aw_Y_@wYfJ;(H%NzMQ(7F@j&UFCztE&$ly=_< zf-}h4;FfAHBRHXXa~L!{$$)t^D*ywlSe9x)W73&$%KhcKj<= zYEU|Gi?cq>hX{;=b&fSdcX!tyN*;VQ8%K)=L>z?7(tm3^YU6kyS=gh+^ey|*07IHM z+7Z(AfkC;&0O?M$?w1`5rtj6>M3FL9wVCcy-7+iOg~VBpGe86|LYTl*qJ*7~_Dw-F*Ve<5joXq61E1T8xbJ;%aNh0H{_f4#ML?p$gEdVmx zT_*mXu2pGN9vB-v@)QW|!%N}hhPl~i-*Cw*oL4m_Jv*RMG`7YVlPUa#m486-(lCuk zncl37>&=i%b%7Z15gz~vsmTTvHL_w-R-@nty2UKi;MF~VO8l=rtD-WetaH6cO(oDP zVk_1G^Ga2;6peE($WpR`F^(6$#K2*^GAjWJa7yi6QRGI^b`3SqS4&TV_>2uld0_jb z!93PhuhvN7-iUhdGzYEa-G%U{jH}VNW6zu<=Qdv+Z4=W-Slfja5WK!E0HWz&=E-fq zI3nyK?&IG1=GhPKfHu|H7;bUuvnBSA{Ifv!0z?+oLit;IbQ~H?20@EIkslJso7uR!` z%q$LcVmv!WCME+zoRZNx(aTWuAS*~ImCBA%^$pqCO+Hz{-CYK#m73)HQDNV+0n<4K zHRy};*Sxr|7<2j)_i0n+vlDwzUYlS~n9ud-{)mtZ6@eh!Y_3*$riY+EkAwNo)@NbH z6Gf4s;J!GQ80h2)7p^W`}q|lMc3q?13FP zWnRR2J}`(#KZE};fnJnKzFt*w$0rqtZ$vETk(~cIn(faP-unhzBD)=}205CnpYOF7 zRMJ(Vjw>rkAHs!_gUR`J{kj6Uxz!j$f0KFb#0FGr+89W%b7Nu@7&K}0(hZB5GHT)4 z8K91qc4-V$76l`#Vq(8Y!4J}+BpM2bLcSWMXAfh*a4@=O9zwk@QLmGIp%{UqDp%CJ z4=)PZ2Q@pgYMJ)hZ;a?;%vljzAyeRW(Vc&fo8k{+JGh!-FtVv6$*|I1_*oI3p_ykP z^dAG=rBVc(cO6spZF8BR_`@r8L>``DN2s=RP$;Y3!=Vd%8oC1t;21xiu^^;o=?Hk4 zLel(46yTJ_+JP=QnKWp(7o9SI$Z(SiTz1F$5I$1ClxIj^`J@FjrhiszccTFyk2K@& zc@(a5agY-V5!1K~>U+`B$~dJ>44|_O%w=8K1s`oU!(7hyr@#o%HIzWUjsKU9-ja!l2%qOf=`aLY>FI=CE>(!_A}eBy!<^_%kW0=S}>ng$S*qP8=R;8p-FZui4}^L+?# zbbOP&s+O&^(8h>Tto@*fggJ@g;b%*l0C0*SjvI1Z-EfZM%mfh*mt>wfXyinPF=G&D zqf3vB&5Uv(Kn13+jhqM_IQSWgL)wtEm_#ouX-=D;5G7A3AaBT$pI9Yocz70oQj$VW zD#pmapmIV64zyxSWa0%fkPeIZl{yyfuoG5%_!BUFO_Bsl3z8+ys6DeeFM4-21 zdJ;APuUC!_?Iz+!Y7)SOF@h#Pzv@GnOs#1q&cqBUL4B5Vyr@d-NJamloUXdrnlQQl zh3UW|ya!I+nnYAV286c6>#oQUf9o`~A=ss3I;Spd0)*Ng-uD|gQET(%qpJy^nQY0t zZZ)Pzfgq(!kNhL%CN>J%o!nvY^>SEPW!A<5aoO-MX59o}E1`GcV^9Ywc!UzX@a^0o*m@=2*cw zC?u)xH7UJvysv#BRZht_gDM~HkVf(A1)n4`f#BZ18~9PJ)0T>F^oa19rBL)iRz#$2 zu#kTqsuH=GHda>Y?7<$dpApII3pWM}fBj2AShsdKmZRD@Af58>ZHzQPDP<2kYe8dco9}SM`q3QQ_L}G8NpqOhX4&) zC6h_Lfk~d28VFF3DSxY|p#uqgHGUAp-Y*5ouLoExy0H&~2xOS+uUrYo!^#Glmz(HV z&xAsDap?^NsOl91-zfs5#KbiW{qG3r+sMlKOx^c(cZQS$)T$W>LUKKyW=h;!@CFLF z5pG}W%ioc)mpg(9jKU%)2EE#g!9-nm06c?$eNT)Gu({$#3)r+8dbc~Qi3X*2j)8n6 z#zr3M>BOOC{p=?0%eBBqwyM!|S-1yXVL=(L!VnUah9uKbETEh*!Lr$cBC)iGx;< zMqxP*{p^}69M=Pl4WDOr3hSMMmcQl`A~hIeX~OKnYnYE8=h0oFyiaXk9eRz3VB)jZR@ZI6#f5|v*s)-5 z(mGf@{fJg913U0nQ7crCw^Vu>MfS|3sx*#$SmlRw_Z@2GR0hr0r7jtWj%4;iol6v{ zEFXy6X3x#Z-uxh7X6id>67g^jr7N8~TyLsC(OfM9!=0ca{Y+y{a<^1vi?nhTcs9UC zqI6UpQ3X(S!XfFgmCN6?)lty^{Jt=y2DHx?72R3{A9F=1w|&o6Ryk#`*!?BwG)8Z! zTtL$x)(YqpGIq9_y&V16e>SejpHx{s`QD7jB5sTD>d(r{AqIXqN}mAa%l&GK(zH~f z*Yu$Er46Op92(PGFPxG=6ZXMt8?*S+5B?m@4RO z@F9zaPp$BGQ&fJIchDg(cOYeEo_JWun|EFv_gmkyt`qY7hJ0~T1w{wW>FfstD8Hy- zCnMGYJ|gGf87yKAwf6@21)jQLEH1oK;4lNlWnm2=x*oBu+3OPnTS>Pa99rP&%8{8|W=D zz`lG+LTS*dwu2}Ol8hVSN#Tu%>!C2nSRy-N0}&RczoVZ>+7KaRa2T`olb~J7%qTUE z-}oJnSJ(MCmYZ{BRiTG-M@Xu8Q3hL`_YU*BAy=jn!dVIHe5uupMJ#vswywlFMD`g3Ha;6O^kQU{HJy~q*?Iz?r=Ziy3ssN>pBMXkwS}B z*=fK8E~$WjPq1#ImwtLN)gr;Rv?p#@!5VdK1!R68u-?Rs{3(4r){=P>@BNiPRWIA5 zp5C3)I!S_|4PD2^)}N)dlXA*j36=9Fnv0Oe`I&9xA>UhaQnv4$IH1Jhk9#iZ_hrUx z4vYFo$-yiL7Sc{q`=nN{g6-N&!Tq)s z{quWM@Qx^?_MpMnlDm{Z0g_STkSi9=2jU?dr3_n(E1V!`dgwPn4^bRC1M7D$oB?i-SUIca3OfsM8}OZ}*tY0lyQ_;#*P_Jmm&>H>upB5@{5ATmpES) zYwg(!y4zIMj93~k12>`_i{Xs`;K^O7FbJWeEbgF?K#(_K+_u1Om6PYoH+updd~^-+ z57;F5i8o-5-nS7r@%XzxE!=@Rm|YII_!K;$E(_ACT%?dkX^>C4iiL$-A;*5z4R5$& zWq)%Ure1&D|GWI2l=?Hd-h|cuaW=n^NPRM0Sxf z0ON7k2+s(0^7AKg6T;P+-l_y>Miv5Vjc+m$U5{p#XV;&e zJf+9*&9Agct_+b`hDITFgl6w5fIr)+0g{$RXJ1Nb>SI$FhGQ3lHO(J`yH2Ae?XD|u zgd*%3jHykhiE0mPA65KL7&KiYfZb4ADE-EYVY0=@wwms^wMe8CVIkG|gF4T}p#PM; z$Vh0Cz{|x4l;e^_b7nY%+##S>JO}%%ZmNf=uI6 zG!^P2UHQ}E8FshHB3`sZYWtCk>0q)O?tG?lMS=g&-`OUpS;uA}%IvawevvOgE81YO z3GRQdIv&cS6vhl_(z|7iDc-El!;ny88{|h938a#{9lcAXa-l`L<`c&8KUV}Sf*_i% zHYVPkZ^` zq*pY4)vaDA#B@>W(DcewBfp|a+WFIVdBk=^jVZ+Q>}?`*{tIfCO;_|2apPnftzHpW zw&xa{dPhnI@YH~dQ2&I!@_9W!q#k_pekp%gss7qoWoyN@c z(cSCky^w~&bo)p*cpppa zemErCM>%yDhBZTd_XJ2RHmTU3Zpc=$IjwUAq*o5O z>%!4P6$CD+moON|f$opFKP{|z%1w@O@so7e(L3mQ)V#GTFrGeGoBavd;&zJ=g*RSQ zT8MYJfjQ=}xjW88!MC*DHtc8`QX-6HJHDU2j!K+FcL3)jq=mFS*myvH6W()9{xo_U z3vyW^=-9~X&S|0gZ5s^KT_~>nO1ZkUvxfT*oCrx;ngsDN%p$_l%WNe#&Z>r1cG5%u zZVX)rC#cm~>Ie38g`7cLA7DRSNz;~Rmc2z3yH0CGT3W_K4Z?9u8Yfw3_EGta{wz6) zVDHJEak9#yK?sE-e}bCuB{gaN)-;MBmIX1-Yc)SVt(%#c%bro}s@;o0XB5Q)xp_5TWibwMSr{R@BV8q zWdX%e)vd5%N0Mnxr}>S|ReAP33S&%k{4@~P=`^7R>O!U@W?W95U_RvarB^QT(n*d< zF6x#565XjQmb4nhqUt&s{>{E2=fLHgNb1)fDgy|@sVkHM&G)OtX~y+*RPhFqGlkY? zpsGkaMAV=-qD*J9qm7(1q%Ohg-WASmkv2S@0*%hZ2RYoja#>;WiVbP40J}0jt&L;L zFv3wyCTsbPRs#udkSVzP9I+yn2*bu4!G(0>e8I9*%!vBy6swlamcKaIMWBUWYpJAd zAPylxxr{UjnPC@~ri(on#aQf_*g})2N(MX84Q-&fBkL`ZP9=qk*~3}0SL?ft-wnSe zb%n$g9s_OQ8{MKgzd$!eTAByI@2@@`m9~%$eh^ta=RNfd*;Qxfz)o$#$%b_Hh$8hb z0-BpSgWA?$hw8)30^*K+(z~=T{N(C{lX=##a+ftI(B$3}vw%isb>7Ak4~H_E_S~PF zGb}t?1#4B+50MlHGSqXlg(|hXHm1Ko*DKr$IV*b*FS>;@c+sa}>LQ9ItqY)$$Wqwe z6Ig2x!nNGC@r<)9v`l>B79Jaf)pNgBG>WjcKXEzN2x zdn}rF`OWws9{P*@yIGzsQ`U8Pzzk|k9^M{B(9yW8?$dM^753vG1@l6*kKVaUs)8aE0r2>Xyf#R0ORB0$Nye(X9jrmebv2 zf{$0feWD9(YQK78dA|4ue6q<{KJmCDMGDHy#oAL+mY#-9CZ1?_9!5}MI&!4KoFIy_OG&Fby)FF*1G`o2-vZs9r}0PkUWL$ZG9es*4GAUpI%8HqY$1N{SP5h^R6suK zRxFda?(oE?b}6L3K1QmePEG#o|z>gMx<8~RdLJ0xmuAQRp7Z=BY~oxqD3 zmqgXp{o+!@y0q@k1ST%ba-oxo{h4AccqZYPO{>L*5WSL=(RYT)Bj*AJoOuJo`_h=c zRC0@Gu7NL$vu66nUwt_kK&zVCJ$ZqFa*D$YYx*#*{>#G8unpdCb48#ySp?jdKprTG zhwP=HfUi<9_}y-`<({`XuUBa$YpmZxHCOjrYg;9b94Slu=Vm~DqQ76;nh-o>%%C?c zrP@^=KdriPW5bSW?l+to3#GLEJuwWq5)P4JqrSGLVD7a(& zuGB{9T@1UkI}Eb?AsOChAt)R>Df)gMwq;#@Yc{7ozT-Zr_J!luK6wz4y4dB&DiTeZ z(Y5!50fNST;GL4$l;!(d)*=vVId-{^o zY>o@8x_fIM!z`teiXoda=NKO~$2?Bea)Af!$;Y;fyv{2(4Fy_Ua5R;Jj}lA?(*FHA zgsP}+la5{CPzmj####E{9GNeOTewOyO&qMWjKEQ=JA4R=yCM4Gp+*LvzHK{YsDcpI zdpJvf(O;JVYb>IL;$P?t#G}^y6Bu1e3?4PUocodf__8t{S{bmrje{SSX$`V$+nRB# z0<88o;e|WJPrydX!fXEtmj;wy_-3AwZ_JkZp~sr7bf8EG6u$Xhi2NQ(_f*yjsp?yP zC|IvwxLRHux~(>y$3)ReLj@C8l^=ZoDMj;9xIwGH#{r-NQSQ%$gc9widvqn z1Z(&{XvX}freW}gW39j`^cF|Ct&;~!C|2M>a=}<)*;z(cBo=1>?YA?(LCslng-NF1 z@ytq%XzD=Z5sA0WMvlf3sG+QYg7eLjyg8GHG5sn<$}uk97mCNfDn~F_h@J5bmU!4@ zETx|I;1xHX5GdUSM~T0`fn{!0lEwhmI*vNF4I8kDfN6U@4aUC1tyiSK{fc0bPWL@K zRW!1E9T1w*k^rRQJIfW9*p$133J*2n6}Ej%;fMmf$hU~TqYYl}Yb7=JNr$l&V+%tN zl#(@-bbJt^W^b4nE85Ji`fCCK3JOp=YdnL236LYWYtTgobWlWqf?ETyYN)VTpuKaK z(vD#*Kzh~LSq!ZC7&H_w+L|`bD=}-B!iq{iF|rA+beMPtOz)~X@ui{3Vq*NV*a#BD z1WtyR%H8AIj=c|_tRbN5(cPsKLU~`f^^(HtC{AH#Ls0UyF{LD888-R!NlS^8maB(o zp>@@tdegxFQpJ5pr9?fa*U&gz>L-(CI(mdfuXV?Q|=xYLY-g~fRrO5E#g-AvEHjoe}jnr3L!|` zWaQaH^o85!K0qw&Gre^ob@mL@FGhx!5_!NEObGlb?5|OsFYhp0Dw@6#P50aBO|gwm?Fi@Lra_tq%GT( zqvdn;uS+14cR#KWUN6{yp@qGM{wt89a?Z7?jOo*&blT*;%b7VF)VCY>tM+G}kt zUD--4h$X<7qnfXi+cwoo3w>-yq{)&r*`R^r1o6{;9qzG_5L*e(K~N5XcQTbCCF~wo zq=^?!mnNX|XaIml7=AJ9Cz<-gC(KR#jG1&$#YVcUDV>|qA||T_V$+3tWzo`I%DXo@ zlqTDJg7>i`SsFFAYxncY2MU1TH8nCUc~d`FELEcFo|_;Wm8mqAR}4yTg02vT^5L~E z+ib}iRtxRR>Bjb~0}F{E+849^V`x)$y?VqSOpeIl4JqRgvE-9(;7KKmE;jh1c)0# z1{_bpv*vf&mjJ-s=+z|Rc(Is-%=g>IC57?<64am|+EBTrgXBntY1j`iYPi~kVuj&} z{QWQj_%W2A@YQ8z&KT>QFf%kv=h+Zrkk(}Fn?tARdXbvdlr^WnQ084g5Z99XS76$p zxB5Y6nJ?#Z*I(=`KmZQEOPwiYNB9j*7;Vd`oMvGc+mi;xqM<0}7K@7y=6Wmji?JBB zWJ{z)218}!IQ4bUISVTE<(lwXE8wUlj(BxmIrE<5H20L~`$Zw=*r2Bfna$9kH>WjT zsrFWi0-5__wzkA)=Mk(=ataH$I~2V6{f!URi}Ohw1>eL3A0Eyfe|cGZV+Anr2;Sk<&&^iTHn97RDz~v!5GhkSKcG;|t1pv@VAkFg8 zSatMG#Om(IFe)Mya=s(>lgU^cB`_JMpl_7sUe9P2`lEvk&$Xm5dKf7R?X3j#d6QXA z7O^%!HVDh8g@e4+1UDQ0q%7sKwKI_dZ&2XW62XrZC@S?R zb%0$e7LZrXSMyvL%0A~z(6CjOX~4GF^HV#1Tb=Y}xP0A~6-KP09YrUpj7D6e9>~Ae z=EZ>wn`Dg`lws)XDk32JK~VXq%MM=o+*ibH&du;eQ~V^!Eddzf)?HQN`wS%ALB}C1=-OTN~)wv4uh!KU3LYG@^jkO$8B2I5J(a8w@ z(p{$ozIWnW&6;3i4>zo#9RBd8(Qscxmb=m>%K245Y%2zkz5{p1axO8$FZu)!?fu)) z2-oFu?oiMhSote59`3}y)Vaf<1bWqjBDg7X2|u^>_9#pX-)};rG_7Z!&)Lyt+<5)? z`shSX2KhStJniRsx*iZSuxZR{~+=W&#nqgmNMk>)N<%iJ@ds){FoHzP@2*3{`1@Pak4pAw$0fLr&Iy^IeA``5F~)dfFw|kk_@Q_ z>VN})0UP~Vi%0dKd730HR1#ru;`-N!isEH=;Uw}~3Bg1Hcw2BbRg1Eqr9~Q}$9WHU zdkdsO!R_7y{*OPl#U@YRhbTUV2Ne#sIA~n^c|=X`I5gTSw5mQrgS@)EZ|)(-_gtHd z5Hk4b6j#I2UjHbc6?wmU9qI5*mPxZrKfd_pSZ6`kxqcWB^k-R0u*ND^=Z)P)wcCS? zJlIEd^be|oe7NX*t%u8fC||Y(X7Bh-+NJh0)u=0_u|I>Ft_Wp*+x(w+=)SxXoo(h* z_A^WC%!26}E?{U1HPu>-3n1#d`D-MzZUR8*M9P+WG~f|Zjaou?`f%&3bvqF=-BMt* z)V-Af;;W#DBx=0y-*C87|GxUaHAVxXKkWBb>fECA2O>4b*RaJZGt;d1(4N1!%;C)T z5ZvN<9c?+#nb^0=W|nx4&SOXlRRNZAWDlvsYAQeL@zHHGM}q!i$auLMU=B~%%}Ps_ z16vJ>8ofD8ubi^FsbM{7FcY@zI`V0~pz2Jx2-PnBAhAN%LF43Z|9vy=p{UsJC%l3& zHfY28_Y3j{Wsfu6Aip7KF~=|)P|etPS3c*hKZdK=bU*6=XL|H8#fz;>Ujf#%Qd_JS ze9sKP=KXn^g5*lmTJLD}kg0VGb(=QEBzbgZsLQVHj(I&hG}eb1mMJ#HD}E&!?r`k+ zd_2F26@e25j7D(5<3&KkQKE;PI*3|#TrJ#&+YA$-&p_txd$U9JBiNHN;Q`2NTT`jU7 z$Ijn||G8vR#i*qvET2y5a5aCN5X1V~3lR~7yx@V8)h;1i(wqhAbiRnb=AGXVEY;v3 zZb@hCAmxKknN%uUAiR2-;X70C zK+9$u3Q1hL46KSaP+RR+|7Hc`ZklG~r~RB=ECO;82+^aaR>p)$5iQfriz_)>tsSY& zfvz1$WuTdAH2G(QrAoCBG5+3)r%;%h!b=rO^@I^I)xav)sn2yhW^6TE1Kjhh!wM;` zA6N;*o^X!l7Im0lR=-;9JG+z@qF-D-MNo${KAifvdVv;v98h9q)+>!#xvj{y5|r0} zN9Q(7Q;tZcQ1iB59IRT{Cmz77+43j5!OVHG^ z1KlYE?yYKrmJ}JVU193_8bL2_R<=Ya9@~1VPhv8kSj#Get-vIGd782AHvoRVD{+%^ z6GOHKkcux9TLdj?@QOrh)4^B(`#$Z6%y)j{DJQJcw>pdQDurmxXw?*G-Mm9QE*vm8 zD}4OPfNkHW7D0ouO9!P{Vanvw1d0@Z{FURz{Ryk8R)gMA?3jI~ieY;pWrB=yYgR~w zHSiuF?+6#Hm#z;!OW%Qz}#n=p;Y@@ppQtkb&k#v zuN4c-6Vbnfi>+#!Wc}{MWup94PYB0!_&%m+QrIwb2JC~rPhPbLoQBLHM9EQUzM9^n z^h66h&zV4MtXQX}=KDPEYYk1qoG9dG3`mED%H?~|ZlK+D*6N8N&V?CCSQIcPf}%a0 zJO%fz83MXpL(?1$`Lcl{fyVP32S>B~uf6*)WU10br=uuF#m7h4gXqo*#O0kye!epH zZo0A6WU&uwk|ju0=}{76QuS4e4St|jeH((WXJN%loQPv0*9!V&M-{d3?9j4D|nT`v2dX`G2&TtZe_SypHvM1LFTi za0QMm$Q-i1R=9wGJw?Lhq)iYi63l@tZL#BW;NkAXUE(A{f+=GEK!Ir5M)$+PSx=Fa zcz2irvY@WKbPV1<`gJ|+)(UkAlvQZ$lYll0iP2) zS#ImvClu)X^MLa^JutsHkP`%SJ#TN~pw!|ytYEK|+;h6Gzio{znQ^PzT|D49toiU3 z6Z`*+YlUUETh8~ew+(f~X0}CJWIT9kYu!&&L?$}Rm8ZW?HW63uGsHXDKI^sIYq~zc zdBPfl*)%s&SBw4~0nZqJ;2xf(fq#M75l*!pv`5Nf`_5)o;6gInEqbK!+ju4fsJ?@! z{c-;iR=zg7GCV_Lg^A=jBFy~S@R~&V(~C0|olSPozStw2{DkyPr^yu`qKvuG!N@1A zZqUqX^|}$t;SAK}XXgq0ol38UfH`Mo>Jf*FS>Izk$9DmN(){Zn0Ws#haTD8;O;z@H z*R&qXG$h^2A6`;Z2YOJ2gYw-_TVzECD#8(|)4B1i-b07}XnBGkF970K&VSApQz=D$ zuqF?kmlH|{Nop^x2lK<@g&RT#RAQ5Sg-=z z{R4UYcLNH4_NU%%>iJrDVw#Gh)e{n#H8wxkzmvpib_P6+`^(an37}0i6^nB5216Ox zJ1<21cHD5MfNHP)V0lkP5i?RcB8Kqv#8!~KzMt{g7fh1r0VGH}w4Ri?FU|JxcVF!d z%I6M7ffVrtci`7}W9-Eog0y+SF-5V(yjS&sos#ONgfOy?$l=xm9740Mf(eMrXmOFs6%!k?7|z_;xA9l;jn%F_ZKNN zz-l=4cCQh|H&xPQ#K9TUgmUqZc!Yt_!cGFh=6BT($zUA5FAuW$P^2{^h)bUg$-x{IPeEx@g z6pPX~gWLx>bam-=7T0`DEA1|1R&3+he^I#S^p|APKavfn0)G_aptlt*H!1^(p~x<_aMAN6m&G^&&zZzJ%zjioTM+HrLno^)w9GLu_674*xMXBF|yr^yR7^Qo^DhG z?ZJ>B?rR5or~SPzg*Kw&;6Lg-SiB_(hYCBV6BajPhz$I;FM=IY&(@(3P4IfezCmX9 z6vY;VuaXD((sY?U-<^Ilf6X2)(Bm2SN0P)9z}q9em{@o?PDyqZp{I~TU{^!3HhTzg z8r6GVYKI|$D)Tm_$pQ`yeqMvR8@ZqNFX6Buj>P)6|I)Yiyg%g@MTL2l11xKuUgbxr z^s!VGhi+L=O@AG@v@J?7+?h3fFMuYRd+`0S1w7SyNhWpj_W02>+X9mf$|grOgPph? zDa1lrdZE#S*w{BM>t|K7sB4FzEb0Ny>lL;fx&jgQ4_L*s1pdouXG_F2zW@yiVU0%L zm|kTRKS>Cl&Gu%8O^~wPf^rAymJKc@RC;$#IbakydyQmxhV3?B6FNr5GlYO#X zLVMD15c>#Ml00BuX;;&h(W6*)Ub8;g~hy`l;vm)dHp(vECf@azI~6oS1T zsxyRy$2DM{sH_TQ&2oeNE~m?uW_f9JV*PT!FBFBZJ8l9F1L;#RDxbSFeGR5*I)@<6 zmveB4Mo?DPMcgZZKTi6vb#7?5>*Z20isD;fV*NQ=%%wJ`QK0`q`gJaMMfn!IpNaQ6 zW)jR>DSVRH=d3M|tsU~3egyX5H|peXiq?z!d?TNPgHw-MZRMiCVr$Ma{8gm*gyt98 zMd9alF7FF#^X@WGZ<%5dw%pvk(~>B zy*I|5^nE)G;t7cgaFN|8^!d0;6zIa(1REPX@}PGy^L*;^@>}MXUEYE{=uxZ3m-FC# zdmzYf-nqN~fFx=;#)WL$uN&76Y04BaBio_*8+*88w6*K(PFS>_BwJq0_>ilIdERDl zRROByJ1*I@%4>8apJzyF+Y|8ti>;(#Zw6@T~FBA!{- zz!8=CNp==4_&`TN-rj$pkB`9&#lFT^{h&rS1;)Qi6^%a}n~#%=2u%i?INk-REZGX3_Q1?D$rm>QGL({;vv!Wo?`tAv*Un4yrM)XK1Dl$?9dm$vd@Qitmz*J$S#Q4|$0S$tGf=D-Je=~C3OZVG?S@tU*#HIT{3 zxaJ+lulsPq1L|$u4pozjrp_*`bMS|ANP5U&?n!? zZ&6LZG;aEu7u_5uVV6oq%1bBgaL1l}A%S*H-zJ+Hk2=6Wwfi-{Guz4|fUq@Cb5a(= zt)ltzw-KZKXH`qIXNRnL*XNqbhw#IA2nz{$U)OtoCP)fJcVOPl&ZP9x=;%?1ZV#zNm#~G{Z zu6xZ{occJ|!W+>Lox}aZ^d#ux$Ca0JVQaTlkSLl1oM|uyr`}@+SOO9Tg5bA?rL!$i z+0DaFCn;}I8Z1ginFG7d*tM3kVH(oD$1lSfLn#5wJ4~Z8z{xKu-wnM8M0b5|Bu&jH zM<0DPXznobW&gvqdr{R1ZV3KHxxII#6F?ain+Gp>8JvksVWrNc8HfZ)VA$oPF3s03 zO-Qn`op0P&Kcj$8azgFYlg8{wI^lfs<2?hr`-GM2$yVDlW zloFbd$9XM>EIW0~>QcSMV~ z9d+B;>zYxob)Lw4rT9X5tI&;IUnnRU>?1p5+H+?X+Y#Tf*DormM$c4FP?87a$7Lky zos`kp2uJP6#P~g=Ol6YoQs*>S-}!F(x(arYx^GS44pX(<#~KsFj->>$DaD?kqy)WF z-n@^>uEqPbi-QJ*GrK(abj7xrW65z>TVSXMt!_9u95QsByMzFPhh=Kz91_ycnM(j& zNV{BANtJ!R%<(KvnXurz*V>(qqj;{3u}XcdGJLYHNYyOsil!vMOhZ-9EZUl0k!h1s zXM}EnI$v_R9p-%y9wIO;iJjJ9ami#&PpS8*5fcP4{8o_ICxl@yqFo<1U!##?IibRp zdAs83<$x+j-klu!kw>hn-0;GvbTeysgn?SCIEA?0EAb)t=>D#I=#88aH+^qg(y4z3Iego&Z!-yx315JStac_`*q?SN?&-6=F# z0&^kC_xjfNI>ofnU69n=Y}YRC<&0(dnpaVI*<7hGbzs>rkbVcKtR;`alB+**{p5>A zaC^xdkwa4n9;f0{uwfE6nl6R%)ej#8kFBk^7gP%i$b+b`iH?uKB*IS@vVrkP>?}xL zs!24q*(X%ufG@g)o2(#t@d?tsXzp^i#xmrj&N`@7Q#O9sQeq*G-T5?0%hkh=ZYRsq?<)8Z-pKk&;8zy2k>z&_Xz)g@u}hWNHr_IV{X_7GJ^Fr2-@5=NY1t0^G%O^nJLP6MSFOTf8Pg0e%ZYmCSby^%!gyI-)c z1AaS$hfi`feZHvT4E!_aaT@p|02$j*Cb_95RhcWVGPzsmAiMpE=>LVtnCfG6Ap~ws zxO+TztCo=@#{w;pRu1CYY7ou^m;NEw(vh3l=tu9fLn5x-f8!t(LuKS)e?A$=tq50y4!h0$OB9gBko0mlwUrV3N^7%N)qUVFAwn+5Vi z;lzQzjutQb+Ymq1`Qgyzi{_4>E>ow039e=E8o+ncD6M8AMtr=#TUtOWOPXrYI5FTfqf`Ed;$ zz21!WSXjdHVMdpe_7H!xK(iBir9MMR46HP77+^SQYU`)XT`-|Dd6TK(0mojto6|&I zCrR8)1#{v#hM4)|OXB9z6)!kZ`S=Z28rkP6QgQ@P)j1H~^aJ_%?YQC#oW{hFGOEQN zl;P2EMCFdV^@ig1aS@`nR?4~-@G!|<^-{z&96QJh-SSRqBg}pdQ{&4m;wl$AYhfT= z5Gs^Cr=8>TDKMiAMpY3pFK;C>pN+Z((!`J#?zC|_J~^eF%5Tdj$u!w;SINU{b`22E>DGQ@%Q@+QTpJ!yDa63^_Sg@pYktZ?BcdTRLeQm+{*kK z+*q?{d7Mu=;DmMU2iD?>Ps*Uv%Y#y8Qe`Hg1W)&}z&5oY@D<7P4Mnspr2MNBKSc$7 zR6g8Xx?_u7k(%SL2>%MJFH4g43eK;a2t%gIw_N^}`=VktAqQ}P-=F*+*_vt|NRHw# zY!zci%44@nK=Y?5S=tn3Qctu+8xqRrXP^f<_U=gn+fwUe z)EBN|?w=1s80G{JP-$)HzY-_#@lgV+js zpx&g&u!u@uan4Eqj>~MGJ755bYhNcp12IE=wIjE1H^=6y{o8<89O%!Qdd51y@0MAk zfgrx;<{G3UTcSMdm_^B?557dk%K_|MwzG^)?&$cIYQQ4fO$PBNVySRgfwpnp&P*{4 zzgDk&*}JSwPIn!=lN9W^x7h{Ay1SrlPwv>QgovFMPatoI?0|;I@D&0Xwl^)UkvzM* zS(}3ELe;#k?03UZfJ?~WE-`{O)G&y1&Y%wDynHQ{Qowr%n+!B8_(+BHPumwr85fq> znc&E7__th|!k$oP?S6>Jy_P&U+H@c&2ccw-U~JerIzvb|!F+gK4$aP)JZ3>a6ErJd zjTPCQ)dtSbtDVOV@z#u=LZxbP(aFV%p}0S)_VvEXgbNy8+Hc9Txt|4<;MtbDOxc3- zlD*R~i4#>o=6Ld-9ZHY}O`gN}QG0m~3vFOuFJBS?RD=3(_%V7lnu$R$ikf(?=6WTF z?d0@}$U0)4#b<`O>NXa~o)vPCya$-p0_m;RL5(G8g=ym(*-(3;UsWqjGxu>nSnR8? zk9TaA*<8mWu$uYbcsXMNC-G(&0*~D>i~{^nFE0m!!IXkbK{ZDLlS4uh3!5kOa3XxA z;`e`DN+IXePp+Q6fAURgi51)?@*gH}c`5eNTaxP*&TTw2WA8xPP<@JBR`8nn$?#>@ z591kAtFWQ=*jo1_y7S41p24Pr%yR;F0$?iTQrEv8)I9!x$vBZ({3h`=R)#0$MSi`b zbXt0kLG&l69-t2y&ZZf)pYa7zb@Cs=NTmtu1HDB@Xt zBc`35QN)=E!k3h#vEKl=elgyVqZz{Ey7}zajGf!<^aJIRBG5|Lgqx zPt2K_?SH|Xng8!p6En-dr--Ygv5k?#f7Orv3tj(za=j>N4+1bwBUwgcWouOqmNI5; zeH`n}CB7D8V!cx2m_2NTql|XbyXspW#`!vlWxlV=SxE7z=jH#NF682An;5Aa^+mFZE$YPBai3Sd3A zSR3=P+k|l-k?pL7ino??5Q*T4XR)J*7u9#p38ymiK0U57@d~Gw_vyuOJR!`BIG?Og z-@OoTlktH1drnOfzwh)aUn!|o^_+h`hi%VEK32=yf!pSY-|cc*=MAm4cE+1eBU>M}5-lQ{mBV-2U#j3E7B=~?6_p9B^U28vu zhG)(ieW1kkHtyJIzSp0pp^3|7olx#DRlAonesJr5-5nsph8Zm2tI_^h2cjm=!zy@; z3c{!B_fiY9?4w_9ON)WRF{#;@}&OjUk_-tsDI$p7*azx@&Z9xpt2 zms+Zl(0u;%{sdP3EMtkU)Wlxia2aZzkvFo7rYZknlUSlvy{%RZH)wlJNS(AS-2jX0 zLM)q4CC%X5){n0ZfLZC-3b3OV%UtRj^%VxoK>G&j6Wpo}?UxC*>b99quOs+r&x{!K z{`GvJexFqvN@HcsUbu#Iix0$aYX$HEu$>5a z%$}TkTGo{IUkEG=RZ0;_2E#qmId{nOM6X;w1N~Vj?HTU zr3QE4YRBmy^2c{!pqjZs4YeRM@0iYJhxRwi*%R$1a;%Ot6H2B9n*BwI$s#dm0A~BQ zkys*SR(>62^1;JNBUGb+u-_Ua zeZhlW?%R{4ZgS(B?UHz`%L~L$40V{{q&#%IS$+39$>!xW{U#`)Uu0i=FEq3{TV>ys zC6kPXf%T!Gt9=L$uV-a80XYsc5`vA`P;Rtg)IYO)@E&OSTe=pyi(a0+c=fp=;=J+B4`N{xy8Pit8QP^dh4 zk6lk2B4TEZ&oAIO+?0YlN>wZ5k-;lLRwOThc6XD*gn|y zfyfT%X2M6P8OGPb8G7Y<&{9YN+M(Rxai2BV7{1_j?j8dO70eYSj(=#SGjLzqxUI=L zD;QIP5ZJn>?c__VddQ80p(=70X{s#dkX!7DEs1LN0kIFy@XSvo{PcyE4#_81tV#|q z89B9C)$4zrHPWtgqeKI@9Fiwc#g+ zlovt&ZK9UvAvKC;)FO!##g1Hz2cCTTW=J@NX~iPO7z9+e34FCNZ<1%tI=Gf{;+uD( zLXPdgTcR+k;XqSjQ}FF%3~boch5O3NDoxtx@A&>|R0!Z>L&M|sKBxnia_(8g_7+u5 zo_!Su>wE$}V>2V28Sf3}7jmX!S`%_m9K(|)g~_wloFZrqKM}J4N24fRgd&i!#*_HR z&V|sV*4o1Gjea|n7W=fxoq-Pr%wuNVu5EeK1lha?xX)LwA(&O#6__ z;*)+nl1mEqJ6y~xN%5sbZAQ~gSvMD4ug2qWbE_^Q9%ox)Qs3Hy2!oI^)r_I!<<9`M zH3|Bn=m9Q%)p(zRcM3r+?DQqX4JeJ&n_~}{ndCiWiMq!#XbL$VDUqJ>k&)i+WeWcc zPp%Vq1eCZ-*3C*G>4=v5JIM^!V}s&!CSV1N%j0(&6Mpfmiiw>O3}*7$p;WIx7z(FGIBGD|eTxv`7trl1LVFV3`qv%& zaUX_yha?wD`&oSpQm_ih0|Qwmz4Cu}&KTUR`HV#>B6_J26maqZi%;)nll^GkhAh(W zeo&fdJ#){l!wLuOpC9OTlRw+U^Q2~f9evq#S=VZd$lGSdAa}F8LiOD06@QPA-O7tD zw1WlT_kHne6>ol)s}xjbK#&_X%%p4u`Ro)F+aPg)+)$AZA$k{4$_DTC z<=^F>HyoirR{r@rm5v!rF%@;{NJFYSZ1;@03f3}p(9S2fe^X1r$PUOA8el0VuMNM? zxSb;B#rDr;)hK$T%ZKEJ0ll=Qq!=P#Tfbm?cDhSL>wDWWrzw z+tU5?+yh+@yvxP5mfVA+{Z*whKuPec(ws6bWDXVW`f9E%Nwg6~**`@kLDk%(Vkeh_ z+zaK|9>Y}MfR7@Dz{O|4wn#AyTEQ9?Q$T~5`6p=OA@3Hp4L@$lnoxAIyE=Gxw(RfLD+qH=KKygz z=#G3Q&rPe2;dBBhX}wO>%?~5G5rB3tHERy!T<;z1&6;!uq->4Qql3PJ5YX zqAZ5a{_DvzcikNS@Y>^(Ppqw9HOU7SWDq8JjsC=NV~erw%sW2K8a`$J$T#FEZ!BrU zNrLqq+@xUAQJ)B^SoWM-%U!KC~5 zdasSVz*fNLr*e` zHTb(7`W+;t2M);e^1b=vW?7qmCq|)io*_>N*(B;>pepj@AAUl#G;Bm+8wUVUExBQ+ zZe&zp^6M7zScZ z>GFwKg&>Xy$JLQ45iwL^^z#QWus@TRxRv>&f$Y|bO-$Ke>dtKZ`}~(U*0DtWXTf(g z#_)AY%6&*k)~4>rmkrdBgm$x0vv?KQ1yQLxpXTYDn&ph@WR1U9Ho;{|tE)U2a;@$= zhu~2kU4Doj5-SZ0t?Qawl$oM=gO_+trEp@kCRN&a(zSMTh_I|vex^}~3wc!R#u~h* z_xS+43D#6_@e4}c!m9$QboDrjv16RiOVibbRrrn2FUs$gm7}oT;%7Ea<$`basC^S< zmFhC0xL^_^ZLCs6Y|$3!YQfc9Qs-sy&4@2imr^GCoa4U!Mk^;e67>6vfqfJI>~?-E zA;@XBVMLDR;WW1kh^J%CZIhrp9GX-s^uW06$Hi_71E03a&6|o04?I{_O&We_-rRBL zh8sT_6B-QO&BOqED5vLxW)eXj#8t&ghA{rI;6>Go*ZOujRk)IL;yHB<>B@=;_fG!; zTxIL&#VW6}nPeHT(wNUEx%W_*DKyOIjz2a_Iz6Cn;A(J*3+1=)V%4|r$r*2rF#DzlT zoXuVQ%5Aef=^B$D!1@V_%~0qfh%L>_%amkpd)Uz_i5x2FU|XWBxX|2Y)3l$C`(LTe zHrN&Sp&?P?9eFEKRsXrfu-iV7@RSK`0W=0ARd*QQgE$IP^fynA1&Kk=N#b{&4#mm@ zPvh3FMDOoV>r!h;%rk8D=+QaPYnzW@?TGP|1sXc!h;X43Mg4(`-zR9Y#loJnj9l^c ze8Pc{smO=%z|q{nFPYk2FSJ)QI8SAh z@w{#wShOASy{D2E!H%0tpxLPwZzz;|7lxV6Mu;x9XZNLE$Q6=o!&6; z4-5(9YTQ1iJEOs){^0a61Ni9C#A&CZj;Q2o{kZxU5->Vj(a_lQdrxA*f2Gq)sx5rT z6u_sBvqXB_K9xzQJ#wI@=^63O{aAEc+et2A2jBCYzJ%!IhQ^O~errt$7W+u>z8rG* zQ^lH+hMOs{N{+ePNza%YO7GPPF*IGzsw0;szdE^|psY$QE!7=Us0c9aj>_lc6j2Rr zmMNL)(HE&4iJ3mIV4b~^QfQc22!%yxQUs0B)ZxdzmrSxI#dAPwS2L?c(xJoLwURh_ynieNL5t{jy*Lz( z7v+B>xzz;ZHvPzxMSZt=(LFllG`)y^7uNw_Ldn9a?y^^j9o&3~r`496C%sOx4m9`m zep7O(_j13#(!(4rX8K({-oJNs2N7bt3QvOcBj>yP70nonXu6^zj@0M)t#?Q)bS@&cWgl3)CEBrUV6!payUE{bik6ls!+ z-fWjMWIx}YYK^}i#oO4(7Z#lz`B49K=9CBi+5&;XAy@>0eqm_2+3kajJA=1|a7WxF z`n$waaU>%lA|15q>n=mXDO!pf^zYhy+h8$DSv4!6u6MI2>mbVv zSea=pMB&{Kk?Y=k7}Cv~ygv0jW{?Qv{ecT-js2M&tq?J!os`kQZ4p6?mqVOFQ{RVG zQEVe3K%l;#3ZZU+YeWiV@TNh3E&3_;OSk3WxYvBXtd_cMRu|Wb_cCzwVXpmCbceX( zs|UP#&H(NRJ6}Y{DDoUc5kSaYc3+++MR51Di^fl8JWV{NgWx-W5{DQlWdHY5KQTxp znw7OW=oeSBvksnV`x+kAYkY=SPo3mK&1z!lmTH#oqJr+Mz&MF!bVIjSG19h^T{6;a ziE{HIIpwIba@Xux@GAQz`~|fLyS1)&P^C6naz%>IlRsRQFBZBnA-YiAEM}IpYRjop zBB>V|Sy#&?z!qfdNFH-!U3T3*BSJ93ZT8=)(C|_6ST!@W6qP;?$e$>*m+Q5(n3Cwp zINW4-!eNN%`jO*nnN`4SMI1s}#;o}XYy3hl>-Rp>IpK80wnRcZ274(iY-;7!GkjDY zdGt`(`i_;N#VlWh8u@aN2m$cnGQykT_3nAxy4Z~$1n$)lKB%!suuy;hmQ|kpNrG_l zHBnM1cate%PMjr?p4qjf9?}g?s|hp7O#g7ctmGAZRSgTO!X*bK)}qQc9=9Spx7!;m ze?7Hc)648tU8X>HPmQ5#)_6O!6|h5q=eC3<{I6wXmsAHqn|I8P zErIOnH#3;Kq)ZYLxF7k|VX?Bjn z9G{9A>z1>FTA17(zucF2y4dj>PI(BO9k=&BhrdMP7i7@dE(?0X*M=$G(o?n zy6vC$c`2ggEVaHw!%^uq@d3a8Mp5h*n|{!hg&^ahudYJQi|5N@C$;i54R6E1M92D` zUa@a>#0?>?8L?p3qR@oxMIp(2&ofbW;uQvs6Op0cQwtO55IVxJSmFdeMw}-2+8Dw2Dw$&S#l<71d20}SCg7?k-;z7ytJ$1&g)54m+VZ+5{7pHt4yAa)` z|92#6rL0LPh``GRA$lLFb{(v>5>=SgU0CZEN5VTlJ(@BFc9~wX#9gdkMB;$DD&D{q zGV(}He3L1Bg+UFO_^fH-r1Fc&ijv1HzX(=oOUv?|D{U>(Xre~Pxk<7QMG*6mt!ooF z+=rzTKT&v7#B*EUNE#_Xjp3SG8w)vUtLG?2rHe7yA#4;Wu`bG|i(Oj{sAFz4>z2*r z+g;(0DWmquCJ1&`SmHG48qUh**E4^8SOI1-q~H&$--st(t}Z!D6e+g(C2xpAa!Nrx@{qn zzQdViG=VtMHr{A*CAY$uj2#Nm5j)$>bw$sLnqHP;+Q=8zqS=y!tfa#Ec6>c_PNDElJvT$MJf?j@-Ogp0O0s)wg`he z9G0*~boA8{=4m&*(v}N-GQM^le$4OUihwHxX$yP8N83z`rLo93Gq66daGiZfhH7yd8+>_ct=a5<0J-Ab0c|4IB*=y7MX1^A; zNS_f@4bs6{pcc?n{Q;%z^cF;OD>+$hLsDNojfuD^)YFhwZyf@+7x1@2-I+GDjX1}F zA7IKK-O6Eo@gJCmA`vs%ri#{mKok3M*1KM`%vv>e8YyR>tEULRMwQ1zEajFODi_AL zZ}H7kUXkQ04cg5gJ{_1DCaHmmta=d0dmI*8zv$wLmV9e^#xa_1#GIEo$u?P@hM4NyL)H6$0nUe3dP2l4@Z&z8IM89$b0j9JFh}DZYcZe^n<>o6BHcNq?-Cm;;{3>k}pMGWf!YY?E{ERn-OYz#zk`% zs9E&u3}sNYF%p2|BWM3eJf!L#f4o~)YYOB@#=DaA#9rd8ok`ovidu3|qLPKJN&CG8s|j}peA4j zAqWkIvtt!!s;^FBuf|d4%VGgldc=eGL+ECUYFOd1v@-G!MVa9qW+_L4Pg={54NCzZ zKM3Aqe%%6xIv=u?1toc11A)*RK4-N%2w4-?srI#knLql=L?hN=8oi87N3!9n8LUgk z@hrG=LB$24^Tkja^hA+21X8uGH=(ZN&e`EX)8*Li;(%__xt6IVtbv#d5zyFOBO4I#m<6X$hf>6 zXZkC)AM!29rfLgRA6&!$b9*%Tpx64M4J$CLC&cF*w5Vbso4ez~zY>`hreS;GmPcA8 zPxMtJq~;<5UXKwpI_FuEw&s#cd&_3|xtiZW(MS_=pALaF`OuTliC0poFf2ZE1STL2>KbIE4=4O@(ZpSUt$!dGaNSdYz z&&;pms-c{%2%hqQE{B%}?shIWCX2PCf1llF23IOzmL})NgIR5?i>sM@1V#K7S|=^m zMETT~3!W$0hP#gpva^tR)(ZsgbCk+Jf2*HzEZ~pWi<4Swbj9jjLH{>;f614Oj0U$y z%1}crJM;g}(CJD{vTaX3sJDpEKP53T6M_-Vp15^oE$2+5e{u_kT5!_MaK#*y`8&-Jt{#~xHr=V zb)(Gr&f4${U95%6bG3pwg(fd0bDi}CUAc8!B9XVTp=ix(EJd$8y zc@AnW1!C-Wm$}jp8}yXRKp3NUz)^{DGbe#lclIy4)?0TQ;d8K%dAA>l#QAMA|0PWr zokJh$$)9z__o2bKDI?l`g78eBVAQ(P(mGANC316tUl5%O{0^-3**H|1K^I*f7$x4T zCZ_!Ozx5EES1EJ5vloxsk5$Aa#iguM*gf+JAAn?@pwvxFWXe@QFFj1{-X{OKKJ_)N z3hpK=L%b^Ye|w&A#WFLo8NOtbB#o`~JH5n0HQJT1?S-k8gg^S1P;=aiGW7%HbUe6x znOW(JyH;b64BY=|Z?+-c`~Lt7F%RLA`-yPT&!UN3 zpVmBO+cVD81kt7Hz zn(4*@g(vmNg@Xvz>5Q-h8yFXEEL5TcglF+@?k}Ff^Qx(fJU(U} zCoaNxUS&@_Kv$MQy>l}UekDC@Zftcxn*$h}a$M|iSiLFlbO(z+OyT^uE(o4)7|(Gj zLe^LwI#%*`pH^UBFv-XZ2XM8%W!n~3Jm?y~Lc;_iqwO3E-befTgWi#U140vmcV%ei z7qT~JJ78~MacRach34VIS$vbNUN5 zTf1D}fq9le^o_)zjW9Ck{8!=JVrIL3ARl5kx@D7k5H}8gON2dIWg~bP-A10+x=|Tb z4j{CdWXQkrz*P~S)l{7YTrXe)6Eg(mT?^~D+NOeex{^8oi_G@FC(DjDr? zu|5+}pS$zQz*h;MLG|zIq#KOHS@eAvd`?xJ#RSQ^TngEXozKd}&nb|uZ?PH!_ z?$D$kSuLGd*QABuUR~5FP|(O{o9s1U=qMF?xlY#YMmVgWcdVcKGcE6_munByB|Yg@ zhm)2B{gWCy;{jZ~79JxnM{vYfSTC@C-awxLM?trKkR zj?ujj!D)T>`-xSwko8yzs2b+OH^+Hlo5D~nrYGV$D?^`>BiV)dheQ244G?qwC(q*C z-)u)-WZ<|{TNgmea)u_ z5T4j<@xaM}2RlRQ+-Ga;Qq zB!gitf7|H2RO`ie)WwdWSU^S)n^#Ec!{j>8yo9yAI zW4;CCt!s{{r_enT!R-*tPL=o@W7G6aG|M*qv_EU~yJ{V`BG0A*@F%~Xl1M0GVUGPW zXb#SxbblQtt!tYBFw<1KTX|&GZ6Ws63JYndB*O8Up8NPahuOL&jrl}x?io!#!fYcr z9N;G%n2N9M?ubhT%N7J2>DRGC?1}6QV`z*^`oZ^ah1uF=958IhZ_vj72IM~HU`O*X z5M!n8XW)d76 zdlO|_CUJOq15d5{rZQ=0DqtX)Q6p|U`0b}eHzz&J(!6eT`F6Nbb)SRune1BD-vR%M zNsE*IC(ni3Ih~xy4H(1QIRF7nJbTrs+nPiuP4pK8-eu`b`C1v7C$ge3EhQ^0FvMsY zO0#uIRM()Pk_vlAQR}lUgLY0X(f$=U>t08z&jW*9#+wAUK==o_y1H2DJ9M}YNtg4HjlR@DM9fm{RF^Q=wuYwEu~hB&Wj9fVcVdQ zLE~GnT$pk4K%3RZ#WF@agoaI$W+-wjbf7t;)n~V%B(v9k1F;|6ECS*m({cAq*e{<& ztYbmcG)7;64y>U#^T%!TKJ1)&ehETud*Th1=+Wm3N=p(P`Tw+t8lC%R!O{vErUnhBP+dhOLqCtnxD_FeUx@X4b_IO zV&x{Wfc4fs`W=j%-Rk+L`xO8;D7jAkgC!in<5%tg=G-*RRIRr3;Ogu0T&TGQb$C#B zEii!0YX%p7$klYAd=Z}~ARK1nMKoNio;8)$!(p+Sp~O&&UpDpg_VaKFwU=eE!Pn0mU<9M7kOf1- zpX4>eH8xtRjaU(N8>qEFpr@x#H#k|T{zJVrad&!DuGLnIYzXry#T^lV#ib^x;561d zYhW(bZG6F?TAN4iOx5s*v=@d~UCx$tN{WgIQ49pI4Bgn{p&&J`%R>{H@Cd~r9Q4ac zM+2#6OlRW#es@Li#t)LPKgsOEyxF{UwR!zSSe~^c9xXnkr#7WX)I^Ra42T-8Dcc8? z3v^RN?9>S9J$E={XLO=5+y3HJt5LKk1@ff=i_rp4var=7JfBBK0|@hM@g4P0Mtz~^ z(gsD&ZY#N2QZZ{06Gfp)8b41%fh10`(~+8z@wk|7_u*6_Bf^q>QWx2HwGFBk;n!K^ z{S`|mvIc!RsiUT_I^5Jtq?M@FQ zFO`_e!)bUBNwr@e(-9ZC=`$XOJs~hBePx2lu)T_Y(HdYdRrxo92}As1*~l8WhB0(afw~P*0a-!i7^S)+$?3kEN=cMAd+4?jxR42TmWvZgWxDFA4yl-dBIAP0+ z5g+SpunBIC^&+aXXMiWITp1{ycHqs#%5T7J#$XxCg2n=gxXj9o2wH67iKgAvPBd5s zkrEBq&!!b4eSI0r^BanB4kFhFbGSAcqtD-gc}ki72qKqORZwF>-eb%YT&%ZFm9FGo zgBfw|X5XDqs!$_Ohc^B0PWgcSncWgixW#4+GRaqr7!&?7bqt7nxLyx)aY;)hm^KPv zIIy_Iuv4ovkgBbu39-9og6X&mQme8B8m}c5=-~>pn>O35fQ-vGgWH5=!#_5O5=7e$ z);Mp>DN2^B%aqjgdr&fOEnd@G^bq59Or8#m246jAWnvePaNExe&d!F(DTU zHyxO|FvYukphV5kuGzs~MA=lH6`S2rP1NoYqS<2NzCvLqK&WJU)Dk1 zh&R=@_<^zGy$GhmmX`CA9Co))itMeeFRtY~irO63p1%|A0#Xoa!)z0uct^p7uoYrpHHB(@B7^ zjUr$jNUxIWc=c=lJ;#@3yie+t3StDBQ;sx)Z=6;8SbR(y8X-ZHo+jD?{N^MT+>4Q} z(BJnp>0)%H6D_B6mEid-=t|}9IJ9PSp2~8v-=0HzfL+f!FRZyUwwAB`s?7QW6BiG? ze5V|>TG}pb2gngF!N6o)_X@5F>F8HN%02_CmrQ&o!cfTr?zScO)z ztL|JpiGnjG34KtM|L(uAVRg{vaOm44 zvkIW8K_J%Iyqs&k=X1oML}VBUucK`sAq*V0&>l+$xKaxJD&pxbpe)?|nG_RxM+VZ( zM57v_P%Gt&oOXQewowpWDdNGn)sqn3Mg+w?uo)a<+qFGHQo2Ob=mpG1N1dU`EneAy zRG=$qqU0Za7~Uo4rlC7(5?M?Kd}Sd#^JoX*(Mha;1Wms4r>O7kKDmw{7pP=Sd` z>!n!B`bfpC!VWIpZKey6-g6EqSI=qGRrWJ)+`FmsiuF_6@vUTng>T~88Ofe$1buqwM``wTI0sRNcYtM7p=BB+JE`R9I$k<_teUR_* zJX{NA^Sg_q+ugDj^ngcK9!i+>XB}{b1@zChM3RD+XZyHMM3R#KS=oQ$D`Q;1XYIT~U!;nBBi(olvI1aAB==25eFtGQvXljkw zEr~$~3kA1~5$*bA+m{599%WNUaxlPpU{xSqHmH(Wv?sT=QkU8KUz<2zd8nOK_}wR31znk5sN1^}mPX%@WF7L%XM zm!O}_A4b{@16m~+iZm7PFDU9_AelXQn)>%KQmg`Wm<|F^y^QMRmBhD!T#@j4%}@W4 z>S9b;HN-Fup6JFOGOx|DZBG|Y*u&2}oVBjM@BXQ`t@(G=w~@x5XR)(lS<5$v*X86#aO+O45{KBqP))2}g76|-rH2PRBEkT*Le!5UXSB#l|j zPp)_~bl>k_3b|I?N5lkvRv6g5%iJ%=)3jjd(x~*q5i)E!I#${ke(@!9Vvtix#J5O? zRyjPLBi|?+^sT!>guh093ch&_GEk+tg9>j^)mZZo_`GUNJ&UJM%6avHQW$+ZL@Nrk z^8>2*$RjotKGo^Q*=F4eb9%m1U*@B{jZ4f({-0G$UOz7!1Epb}gO2r;Ao>skCXe=&bvIrc`fOd{= z=p~xVBbHd}v{jKlEvVb%X%Nn31ltQRC;%5p7P=tz43A_c>|o`E=NSsY`iV?0C#CxF z@5ESUc`VrZFCbH~R^qAwzeyWwM7}1-@!Xrj{E+5Y04*T|C3FGe?`4HLb(X918=*V8~?|p znSWa||C`3h{~elP2C)5SW8}Y4=6}#e*!9`3BK`XBH4Xajxe;O*haHEh_zzR)LP)df zUd@lR7((P?$VGbOeQy%a>U7p%s8f|iQA{-bP&a(w={urx@kP`^XB$d&G!rXIG3Bvv)(c6s$-yL7FmNloHm%$(MMo_7yz7uv2Z?#!N8|_)G})uZkayP_u_}a z4xy5;Jq_KUPY6KmUKEBeQZA@p<9biBJSFbgd}&gaLrz7{&zt5C+}kp+@54#EpCC`4zhj%QNP-WQ2Q&uWkVT$ zj@CeaTh+0^f&Ap@qOQY9v>&O_w1S3n|Wuw>s@On6&KZ} z_77{jE+474IbO4yRcjebWxdN7|LlG7?2>~wD8aS+V(s~pbvoWEmiHnbCg-^LZCEBD za_-8D@rco01+wnJTOp@P6Sh#_AL#sBV^eRBX7|vKq#w(xn`<1E65I{(RyRHO4H%K@ zm)o7UeST+|Q>Yf9r)=_IaCym=C8Brq6W)Egcv9JCp5OMCMccz}-#D25px!F&qT?N_i(icM)V^U)KCoBx&cgV{-y+8Qv!DbyEJAt!g`Lu2wan8EP zuU#IyTel>xy|C-+ceU8_zqGu%{+@@MQ^OP;co9+Y&(M9|yE|#8#C7)^U`>m7X4*z^4uG@cIAgFZhh5}b$Pv$T!*8zZj4Ja``c}|&{f6_ zYPhJqFIDHSE;_Ku&~DntM^ET^^4)*k<(EHK`c9bX9qN+^ zNhZbCNq=>c8mX?lmOL-+>;1P%3U3cSbtrmCd6~hK5=v>B75>Kc;h^T|vTKIE4k59x zaY4r4zOK(tN}r|k>JEeW)cd}obBZ=0D^Jd1VYhF_FWS`g$dB0p6$6Gnt4yqI7A$L3 z)=z(SJmBuM=f$+99Jc3~4PD%fbv^6$Z`ih(HL_ycdh_Lhvo3kaTMeu>4_jr+9bXwq2v0UPv(;0%KmToM zgR1d#&q~eM-6IzQ`jy}GbR|S>_t|oSGs3Py+EF~YRP93!NWpx-sd;5%ZS9y@~iLI7cMn_xrkPNMMlSa<7?eq z(-;-apU3iq=5ACd-<>R3ec_H5?8;SzuxV>QmKt@ppWLYwNoc9-h8uf@Mzq* zV=nzW_PFFy6_{&GJsy!hPerQ8UG zcUp%YN`-w8SM!+l;$>jSNYmNb`FE#}ORZ?bG(W z(m!HDvQ;um44ktL;3!_C@BPx=tP5sct(pl-|#J~6lLZy!lrHVdEaPrduV-zr=t?~Q)Nr~LiySGc<*B>Yc4uyDO2*&lLihi%3^ z`x67NE$Ckc@5wmsv|yT#)HJ=jC&C*S-kN1M@Waul{!D!>vAg$dVwqFm*3;J4pIvm0 z*S1kwl;H0Z(RfzoQ1PsT`f(qsriBiNH}Gl>f70?dt1+TX?26#Is(!I)B;1&zH&CZX zmLGa=7q)G~Tsh@*a>l}YmW!u?;@;;!|FQbb#8~7fe`fl)N7#jvuAZx2m#y6FMBgTH zb^6m@;Vrpcy?0Ix^xnDrb$#ZY*^fN7$~iuFzilxUqWezy!-{F=@HX5(8>8pquN!`- z4mfM>D4!8A9u=JW;&9SANwe<5OC;)@mS51>7m>8E~3u1{Vqu(uKmxw z>k4W|?{8?2Fg&oKsWkRYp4mXFK0()2f$wE)%xL+E06_ zupFHdmD6_k`Q{5dZs;3^AMEqAJoNq~gZJwU`IWe-%n7~T&1b3n zM9&2_&daqOqz1jU0+Q-qy?>S#_v?qYJZ-mMY{Kc9OJ8QajW{^BV&mU7hgGagKK$L^ zzBsH=zp5GBzwo>EvXoufekc^`D z7J^*af?#7_#tFGcpRVTl2eaM(b|-8nl&?BuXK9dZvT$-Ko8vCJ?ONyq$zRKa^C#tg z#Vi#$r`K_^;Q9Na{g$f-S3msqI?(;aO6!vSLowNtxL41FvVWfXE8Y9)zI`v6V&8RE zi^jJpFJd3Q_%4|toX)Ra@#yL$*GYz@{^Z?^u)dM&4ae|zj7Dm-UWDwc=Bu{;wBKpF zVT+Ycqeh`ah^E4Xnqs&7)`udx8ZDuvtJN+XF^k_vyFay{f8@ZLTMLZhBo?0-*u1x_ z;by#q+%kicW4QNDiyL!DCzra_J$q4P7$RIWxB1eMVjtn+usJLlsq@>mztwy_w0#q4 zgHc$z@bxVxDGx4Rrj-Q@7r}b6u@SPsT zXT)Dp3kc(*R@$xoUQ2cp-}I|3FsIS`P{&kkimcFZ3!-MyH zTJ2X7*7K{xxbwM#*_4S+tFPb4iRl8nEx{ElSj;xC4>AN|L60PbZS-3`M@1i%C%K+fhgU0~?(#{JGBLR-q*oB}DBx1Yh>bt#ZTS`PY2bCb;Bp zqts@K2cPMT>NuLLT)9r;*+@l3&#A_@OAKD?hb#?NI9h#ptA?R+%<#mL?h;|GSB6pj z8jr||8hc|N#@V$0Bj>X-%lqkOTx`qn5zVBJ4?RSeEs2|-sw&%TDUs}#8|-v+pTwbu zyH`79XR44a84JEBw;#9l`9OO*pCaw&)HQk*N7<|e3o zwSMc|ddS%LvhxN@e?<{(kxl*+8bUiC|5zb?V7%$J$(Q}DH?Pa5d?ezY?p3Stdq3+b zyZb);==#2e&%BGAAOBc%pv3T6Ui9TN61&w$uMMdw1O<*5M%WA&FKl`kr}Lh`+hekH zZ`D1{=k6BAxkk@Vp2Z)%e852Tais66eMA4Nq$c0>!cLs8ySce)*0sw{IuGFMBWJD5 zeN-MK7WQm%VcMIn6YEyXt&Y7uUH87^L7De-@6EJ~_uiitu1}q{@2t*1wMzOrg4Jdz z)loIWpkv*k^PVnUSR7c`U>6%u_zQRK=Zc6^>yvY%Jr2vqUHvq^b+=gZ(&Gb978bkN z-QC*%r9C;yb8za{n}_9(zugg64t5>S%rviA-ez;=`urmA6+&i7TQon1nP*u}y?eB) zlV*E&#g3B~?ZYd&Itc~M>bqY(`g-=Y+qqZ!Yqv!P{%tb}U%9psS zYhgvfKd)>WiPwIWUK*HQevmd1zxR{$k7J_mG#+OZzW97zT(~>1yD;Ty+F!>qXPG&* zU0?q0gYTfDsD=5QZ9}@zz4*3QYG@Z)a`^I*YM@;7x*#ZNRCH=S8b^Oq% z?$C`I<^)}R68B-F0@2sWV6XL5!<(BY>sqhKKCf*tUDFrK95T;&lU-CYC;irjTDfOIC>)X*pCx5({&)QQss_!D+c$EIiB->Q zO)kksIKKWzvZF$Fy3%`jcD3%se~y^Ger!BM7Jk&N=s2OTeAa(pGJ^Nk$Lr_{shnqd z3(La}p4`{Ix2y1Mq@jw3+xHLq@E4w!if&o9XGQwvzdt!>Xy1JP;bmRL_0+?br8dvc ztT{Vz;);Bq;_4k0VzPc~-CrjDa94=mRdn#wxhKB6%4;s`2QMtE{^skr^f7hOl~q|g ze)hDpT61Q}f_0_iv=J(H zR#0nTeOl7tt4;@qx2d}`8&Ad*4KETu#Xeyj;YI!_6;Zo$_*s$B_x_4a6GuAqwr|=p zu;I4Uz5D)KBLhjlaQzggn=I&v7u;jak+*G{ zO%hcze|6KLaXBtC)bn!mM6KOu%xe$t)`jQhOS6gpj15(Xj5e#<(>~>8_q`2Vu!PeP zA6w~nW^Z9$%X`!GhcQ2^V>4&j`&w=Zf9=yS-(tstoh_-M`>#|?=dEV#cXoUG&Nk3` zky)8?wa<}Q@oIBBHHE-l5+)_I4oVvl}d$5+Gec2mR6S*x@u`aiV zUaHKK)>m}ZW>!q?f9-VS8TE%o`=jLkRaw8*oxH(%c&aF@ud-Q%-nQ$urH1$JtzId4 zUssQ)xrnWqvr?vCXeEDd{NW@1TTgyaYpxBxZ+S$wR_27^t%4ZlHL*iH-&@fQQF=v- ziQ1P#W|#7dRj!j3I$35u!`%*QsFBK8e@1uhQCmU*-HSjfNF=K14Z)=MvoiXC8j%KG9}&?|KFrYNBqA@kt?@t-ME7i zvCY7BiIazu)1t-pP9BZ~_`-EBoQEgD)6QnG%@PMsN1G*!>>NFC_MW!(Hjwv-ceHbY zmR@#Vb~bn~$HgA-P04VroejYazS0K1;|2{Yjd#R5qF>oY75MFKujttAFpzcNc2e9% z(zcD#)@u!Hq^$!CY^AMN7`WOx*xBP3d)hjAI@;SVcJ#n|;&DzkHXb&FB@PY__KOzT zdD+_9+j=d=+1e2n+uJ%2oNSlaF2;KFBk@hOpSnZi)R8yCshHghh6E2Rj@N>JDCBUW;&e907V+XKnIHHQ9jhzA19ibaLTLS{#23zId~ks8 z+_y)4;qgueb_AG<0}ejeqZv9t8v;z%-X8vgNx*Z5!*IkN{vvQW^zGybN8qj;?CfB6 zFepsj4lX6Y*51I;(FPBL;tdEkFpfRW!GPdsV*?)?Vft_<_Ba~@Cr4;#=LA#5 z+1Nrya1(f(BP9FU5#TQHHh9zn97DhJ4#yk~;E)q^Pk>`K4vsKS2RLSn2PJ>zlLH>E zg`2>`vqo1qz$bh3^c|cG@b<9cVEX8jJs!@&alE|~x>EuigI|D$(ctFr@Jj+vhX;g) zg)5)}Ny7F9HaPSF9{tP*IBtXAAZ@)4{`T;fx7qOTw?I*==Jf5L4Mi}rNf+vFXkNc@ zOAUR&I&!Gyd)?Zw-7HCd@#iG$57R1&1c%KsEE|>&51W3T$Fgw zm~db3O))7Zb-{glBcp`1NFzG|uV>ofNz*7JZS&oCI-U?mw``t$mAkXBL<%Qm+If(s znMg9U$Uf9KuZMm(NI{z-6PtG)uj4}0A1U!j(5PqG(bOK3_H?DyKC&g7b`?9}%pw`* zXmX#)Ze1l}@a2>&*C34o;wp<`lSb8YmQ9e}eBu&|yoe^9wXAtTa%U-)=ZbbTTJ^BS zdlj`wDzU|WO`2Dj4!vqGDJ~jJ}=<`{>TMw7W&s&{rWY_RY-0 z!=ut`A**-!ONhDi!7461Z54BGQ&B}1`dV%jQ zKCrX!GUbG>@du4)_Ok!Gho0l_6tCJ@c#(2Y_xOlL1beQF*Z;*s)qnGXU8=usE3BZj z=umnzF0p9#taJFtB796?Fr`cD|L>v5vEdv)cm9_Q+4g1)1s+A%H#ZN5H)Wil$(B*1 zee+J^?CTkqY4VRL;<7}quFOijOk`&)O*fI~FYESFM{k?Ff>TaTRlCQ1uHl=p=a1Z6 zUPLYZIkKrn_rs;*ei~btn^e4x;9g`tGA(oExMBjb;aAPGJJE6DRe zeDln4|Ks@;YvNTR+q-CDm&o#6Mb~g|8l}E%vedtqvm4i-zg{JVxWoMlPK}u!H0v`( z%A&ZlajqKUVvx8G#oQwAP@~aW`lldykG6-KgJz#4Mx4v|8~^1*3|THVQ?5yr58=JGG$z^BzgHyg8)L~y3Im-- zn?xu99wy+dJ4L$A}As-ZwqO-VN!7u92zj2pXVoE%q8DX!t3qzbh$ zt;bzc_PrUi2wHO-**YlKQv7TzswKyrTS8SIN{DNR)XbDZAB^ue;lqwaLUcoVeBEOPsn(Q6kUGc>PE7IzJPh2qnKgFLWU+VUt zC-M#zFDkJDt3^i%`b@8g{e7o9%p>zFv4P-R9nC!QPZRRYZ8A;D^CC*iPnbk|Zxr0- z;&Pm6p%jHl!_||p$2N1D*>#!bq~$c_dMJ!&lBVf-L?|4d;FNqtRT!Q)rICRQi8@C6 zKL$KfsH}&^yBF)+4$GF2m3<5IaE7Mz%QW#o$~*)-r$}a@23?k>_n2`YZj9!5YlJ3u ziLBODD28(%$`BdgJleYd8eYAeJ{TlhKvuFS%xW~i0CtzGX;D(x*G?`qX5B16(A*;led}y@HrfA0&od>GGxZf+~ zLY5fGxY?xstwXO@_Xd}!lPQug>l-_zSA8jOu1=nDJVCy_mLO`zp%&5;fI4utS7iq# zNc*$A2}%RZYXk@zT2$rP#!FeTmNYA>bCRlZ&c>Ux79D67uHe~(=4&U2v}U{q-q2~^ zthI}?voCvnf=nFCuUTRj&niiOpnX?@nI6l7s;Iz8>C4$WPMMVajXAz%O8zRoRCR|6 zRi}-fNL72liFVDZ;VqfevW6cBGO1?AP-i!AA|}O;k1MC-3=D2*$#NVQ4`bJiEo~{- zH6}5sH%%WHcbuG^%BUIFV{s^xD*9ZHq_pqjVs7jxzN&}!PjxrO^jLUO(KK;xG-dp? z!S59|z_}JTb~1@)JnS=3+Iqqoitg)|tUZ?`fl6HoHhz*dT{sD#2Ul`Z(y zk38eYmO1jb?Y79Novsu>;9VV{8e7rkk=-*WNv{a1-!p^V9m5;*D+Q4AG%e3tkKla( z?FNVIBGIZftuGd=(>&rf8tee*{=S%`3qXc83;`g>^?L-UM15YUiy014u5_+1iw=TY zs?WPkV*clH0b*}QoA1d^Ypv2yAuaYz8^^iTcc_AO zBPsjl594*~JMC!FffRsMCC)gKK5K|sMH9J1S=*J3VAkG31CD{W$Y0WkQ|nkPuwf!aGzO85W!Hjl^a^vF}qo(f@>6->l2T+>f9B-;6nS~&B_C;r_IvOIBI=`N8*j+ z=$Hv}=*z#6px#trgri z2yAc0Wn6Qj#%05FPSkF#ST`>1#WQIs9N=7~YB%ug0bFCI{hcm+-Kn$z9x`3I?z|OL z1&;$iBt7sG+HM{0V{UGAz?D94KqF(tm^IihZen4lI=_2)g0?GFu60stfYZjWS&<71 zRoOI73Tz7eA<@3dtlNRskKo`1lW232bOp|Iqj$(e1(+6OZ{C@}E(=gFNkr=hY|-t| zbSPk<+Q4>hopG{Zktfbc$MuNZVA7$owb#q1OyWGuE@IftE{;H}^j%$i-ui8{9+POa zU%x{(XQHA9t>7~i7wSBu!a`6Ja}ro5=r??@TxZ4}37Rm`Ttg~On53KcacZ|*?96F> zu5#*xb)}Eg9rHqO1|=C*F>!$aq6<%)Syurz|B0= zh}K+}7rj9mjh#nCHySs*F{A<>!fiO0ZBl3+>I{}D8G*LTB-}gPBfP3M=Lu{;!#<*A z?HjFrEC*YyYUSrE7;31r;e@q`uM`>z?06|O+4{&k94wS+qEuKn;t$aq`k#L;uW_8n z-ZmFHM#sR+ff+}(b~(*izWSDFFm+7B{uY6z+K$s>b@FM7DnujSLT}sx({=z;AbFl| zQ8ZqzzFmhVWJ{i9ON#8u55{RnvKP}-5-C<)1-o(jLu}z7MIQuB1-!Z|~Mj;N3>?HX>4} zCGc*^RT%)GKi;i$1qZCtZ|~M|@V9rnD_$h7-LF~mDraqy!d0GpU*70oSd#uOZd_jm zkiwKSi7^8`W;<21WDxJVPk(SJAFs!LFg7P8eHGt4C9j4DCMs&oqPpFB%r&f2hCe%{ zsA9~>i|0tyY~XyS>NarYTJo-rIb^4Qa+#C^I!IMdW$KUXO%=9r8ZMeD+jE!+7|l!T^8wnF?i7Y$I1Tg}*1p#}HZsn>_qk z^N54xzzV&?jnLNZ4a*q{^GJaKz-q`GU`+rms0p+*DIcC;V5b3dU@C^g^DD8=u9r*x z8R&MT5e+*h7!QH%_auhH&r}4#+Jat`1q9Bd+&cs)TV1BWydsvRT)zi_P%zySXjrT> zDau5}VUuKYlAvpH8j{DzE>GzFAq8p1vy

cNSv8t+2o6HWzM~>;*ZJBUB#L>V{x2HB+G&}`w~g0Yu`1T8AwGm_0Oafi#)L= z@WzaSR0~K67W)o?Zp7#gQoBpqeJ*Wwlk{5FM9^$xz4qBRIrK2E2T8mq`NXCbH5xjw zz;YcSCC2VM+Bo|Pqer6{$l(>Xe6P|^V$?|fhDPn3>}n8`NLxp8k`pw(v4seV62K7C zYuz^%)42rYrJT7sMU;4p;`U*J9{6HanPtEXJEIBuQ5+zJweBI+Gm6sucp)oh)*nSl z_rHpg%LTR^Up}tGuUX8Ix3({PbZ~F8%mDkJX7%r~HbJKuC3^JaX8jc$ylZaG7*3CI zoT`HeB4zTH`>2`Q9_bb2x33>Ij0aB2y0fjv?W!4#3MD zC$_GUOG^1<~oP6R@5if5+)JYC78>f@j78)&dd{=nf63Q>@eE;5g*))kUt!r z4vrk`Cd&Z}VEHD1VFH5flpm8+sK3!u~c zGTL4>OY(>sEVd|3QiV+RP4~t-AseO~NZR9@a~f}1&ydxi7t*9`ffE)#$ITz2SJ7k= zDSBN6KN=0x=#xQ`G883?{LV%~IlVMU+J|ChQ4rB+w3faN6j_SNx#BgAT5CH)f<$6~ z24aeA`$Vs-HrY6~(67;aXNOv^&U*6v*rF{sotI>n*b?1F+nt?Oy>feryGF7WG+BRR zxe;W3Qrva2!QGN)Eh2!hu}NoNd%~Pz<~RY|EclvEa{|!8IaP(W30nT0!vv8xoY<;@ ztz4n1lF#v)AZ#>isB;5C)8{8Rc@0V@X+Pu53(Yu-JS|IvC%I-#NABL{*;jcEN$R^e z{(U8*ytuxspYaMGJ2QX=@|0Zj*<&J;itfykaRPW+RAF~U8PLGulVf(Q!C==6j1Go# zD>OFWm*LxobpVna$85qFXQ^@xyakvQODP!Of}nwLWIUB=JsveF=Ak>GJyo2_Nlr>r z7+0FgE5VD`aKibHZk4@U=Lp{80lru~BV($QkKYO^zfeX|UR6Oft! zCgM*}JBY*9(;UkkzEXkAgE;srm%$=4@l|@mO%}z z$}z;3l;Ao*nv*XV0SAy4z|OP~0B(n`VBt;&oDeMPFV-J?y8>tCqQZCu?wmYw+58Zi zfYKqJw;ITw5t=oOfND>D@XIO;rVaqr%&GvHFfDH0j4=E#H!1oXF00 zP$NQVnzp31UFpy9+Cv>WG<^XsB-QBY2p8T0Tx>(Q(6lHx)a1IBo*yI?L!5ms|7oLh zPv_wvnHY+0Z06TSHwSuluZ}iFB{u(FqudpGd9U<(ii9ltO0WD&$~qLWu-(b{2u6mo zVkAqXQ2`zTs!O@c1V%=(FIy$S)t??r&@|(&u1bHLpmo1PvspNb z7h078T3>6{=Xf_OdRDUz7P(lDS6&B^3#kFdnr5wMoRH9*_X#3#9U%Da;_L)k$GgGT z`^ee=c7`L=m-BNRr`O@Z7t&);sH*NAD&Qj(vd8D7WY-W?Q}SyRx*s|YK6LyRNY#44 zadL%aj|mVyR3&T9Gpd+1#V#eoam+caGlp;3&pJYt8RdSbN~F>;Tzm&yfCe!zwrf&k znkj*#K9C}ig~>?e*(T*%k2$eG{Chp$ZuKQ#cS#x3KQcj6@(yRxnoZK9$=wy6Xg5Y8 zRBCh(Qv6a83Bl-}5jY6oL!iw(K6*npIO3VNLlM`?Lv9Af%A^q?LS*S(9SN~AQ-R1< zmxpS=9%noRa06^+l(!Jn#C)a~Z?FtsOsLUh>p~v zTy2MnX4G;BT?b79ZqBiRUb?TJuwLLd9q{7>i~x?#AE^Er9VUV1g2^^8Gc=cBpZDDz z*+!@K3s%xJU-d(`a3@y^cnpD+Te+7va zki1cB&$XPjElB(>dG@)qLrq3&nTLaB#}Mt$6@P71>tQ(uscTb`W7FiCl&;WCdsTs> z$+9uzXpiJ>Y0^a;P0WQ9HB!8xN&6d9uUF+KW$Q>rGDzeM0Y}S&V52-+i6Fj|yQwOd zlAzio1k)%D_d2Zn4pHFa)mcM<EsW_R3=rAkI5j-PSdq0YFsC~`;%)*UN~<_OXdL4E{qLwdBdQ6OP=GHT1v^)@%5AP z9&3Ks3arWZF@;H8gqn3N?#nzD{g6a%QE|!millTr-*GDI!I*g~qk=Cy%?L`$Y8ZE) zeAa-x4kH=|2?g(9?dKr(ehR#Na0W1;X*oD8RBxd1f<+GpZ-dUz18xz>xS$6_ZvdYF zB=LpmfTu`AhhVjMZ`=mw(oYA6fbw39IV~oI!*C8cG$BZw2aIBV1{x1%N=5wXf=Tje z3U&^SjyXbSK&Hq?YH;d!(an%FiBv95KY6(>a_qi z21{f*oqWd-NWlQBw9K&q(}DyHzyY$78vtd$YqgZs*nN5{J~7%N10vt$?9BqYa@V2REA(?Gi`bu6VXn$nrHmeMDejiKj%es+Z{jt4_s;IzWBjUA`DhlGk ztdah4mM?~=)u^qfgJo?8~86Nv2&xt zdG37usrM>8{#$K*?{E;p5c6lEb&TN#)uaJ1g_yBGDlviqEVg`*qoD@21~oy86a;8w zWcGN6z~x9mf|^O;X%Nt$hKvOih}@ah3*s|ioB&!T2Y$5r$|DZujaU$p$3O)~#WS?X zcA)JVq9?w6rLA*-=VL2&>o)I=*UP`4;1RNUg$RJz2(cg+qWB9ExsKh2;)}^fG&wMm zGu9DiwVcK@feX&Sj4{<2AnqL=f+UY&Y{pPCqFt!lGd%Ecd@g2rp5PIHz&HU1Q*POa znWIbS;6(TR)j%1)c3nZTk!4u2`Nc*wN_L(>~NIsZFND=KD2jUIF7Gyq+>2sn+r@$<`ye zx{WS7nfH6eZjc>8as%WrTYD9L@@DDedL#gHln`>}0&)^8iWvz6A>(*g{|;}0j2Tb0 zD*ti3^L=_HLHi9SG)YFCySOSx251>;S!lXXf~FOFHs9ew$Bt&TbzBI+z8}}^OVdu! zk7M3z7P~s=&{ymdZ`N8c%Kh0avx}$KSMYOOQjZ131ypOQY6(|@ZFaoJ#bk4f^! zPIvq-ZC6*hztA4+NWG=yiEW+0Xu8`FjfdS8Er2m)*1`F(p9W$~2qPiDB)V@S{yx^7 zi~QBT(p$)Fz&2U9yz~|lk_CjHi&|pRG1`?UO0T_wLR6*26ZhN~DA0`La1Dbg=|pZm*z0SaI&1x5x#`n*HH9L+;f_!0;mvL~R#9R?Ip5wt+$ zJ3V8E&|1afPZI!R0q%bn2=H(&nhZ^lxfN^_XczcB92@^fK#DWaGQ0?q&N{njVwWfmU3pG8^`Z7Y zn#5aTN4XAJB4m|48nae~Z>SZW3T9K?p@yMJonv zLW}3)kZUtl>(N%z01+VZfzGdBc{nc3Qpo(|zl?YJNIy!|*v0*cT$}~q;&4-3(ARh2W|rf1ebG6 zK$%)j^F))ttc+AJB5yD(6CD(U{*m(q<`Ho}XCyT*hd$G9uS2FM-FqVz;zUePvOX`5 zs8w!YRv1m*Mu0sc{-4RTf;SSOi`+Rj6GG3r6`GHw(9eGo`B zLTJ}xh32{xy5DE))X&MZy>BJ@4BR=TKZLG6!A^C47P)XtKVI`!TFkIS=t_4^J)G)P zXiiR{7kv?lJE0$M{3~t!JBdC!cg}q{^+2IH2Rrq#UO(RFSK5&wY#P!NLhBwXG?%B) z#lDKf!EbHDG+zFXX@sQEkIqa3PN8WmgLi!=uxZ4l(Em)sS4K{EZva?9Ac5g>DP+iY zpy}{{{iTiLe`jck`(~Mg&cL#xsXd0=$KpyPX3u13eWq9;M9ySr-6aZH6heN38so1Z z*#e4`MP6N_T@U?Jko;Y;*ty(8jW%l;XM*I;QdG_r{oQEV!?+%#@SY+Pn_JX~ztS<( zD|>`2Gm?KEBsXGAY{7@d1v}}*y;3d|^^u$fV9?sDdu8@g^hXLZ5)9<&Qv}JS9Gp(R zM?ArwaR3}8FlYrloG_awT9sQCZ*w0cHweSZR^?raceu~UB0w6^`sP^`T=13(;?3je zulWw3yM^YRjkmwR_`6yD8PBCz#gS*)m%BcGeq8&9W|3Vyz+Y>@jj>rD+ix~YeCK() z<}L*dn|Yin>rPh~H=fie;Yqm`)Q};ysD}H7D!qcIIVt^satdf+g+`G&e)T@}G37AE zUA|m@=UJ)vtIq-rZrw1NB}SH8&?D+ET$ zaAr>y)Q+N!TGh(rcauKkZkYHkEW3t`8{isoCrozE@^L|o53VbPa~S3ky>daqTqUq9 z7V`aXfzv;84r|%nCJG+-bijo_2mj1P<8dQ4f(i?X4A=;0N^o$dYwS8q^P3K6Moqq! z-aCkcfdW850N)0g&pdGT|D6jWnwLfG1UH5i81XB;#|V7bwN1LR zK+(!TQO=aYOVxvnrW{DzCP;Gi#qxM;$yQzY!LYpBM`$968!ZqOf)87Tj#gI2Z&Ri3|r#-uO)_aO^?7n-A<_?S@ zjpFl7v#)eG^eVlixWpD<6zu}&02D_^;Aw;`gMNY{I5#5&BJmpX34JK6;p{Qua=Xfa;p_!#lnPbI{XjWav(F)C) zKfWcjNISt2OW=v4Z$S|n)4u#su7BUYm*X4y;9c?KH*jAz>{QTWB_sDH#WhoZaK^&8 z=CM&O&kD{PzPT6I4Dqy+5Ef-TrpmXm8peEFOVr0~P<}z~07tGRdmR`V_UO22O2O4} zHHgk|H?(B9b4vKyh@~x`Ty7XpY#{slIOT^GP!ZEZMnonWbxd_f6Amun#KVk`bn1c{{My1i@9 zmxp_IEr%Qjuw9t&kP%hDsBx8N;tC7AA-+iG((qbYz ze1m3PBJS+U4#rCib%dg{n6R##A5Efati?f!1;kYr*_}-`<*a}p<-5dSi=5X@!fQL0 z2Z@{|tvQ$ew8^cf!#PMhhP2^aj%AaQLx*^;#t~v*Z1%k-u`8Vpy;|!@gq=+JUdWJH zI#P19NgIVkboUZL`UUSCC98{Kxt>Glbr2U z*?~ZkI)X7Dga5Le;W)j>im{|wQJq5$&AFSPncXUPfxe7?}8tzaAq=e5=-+QJz&_k^W#xAEckn0uh+1QNmf}nyt@?b}iNiZ(VrBpqWNi z&0rMYshatjD*s?mb5gj0R{=2*dc&Ae7<1F4xHWHfOa3$P$+H~C#rs)X$6Y4%Qt2)b z-0wiq#lr8fIfIKX;7ICNE?N!82ZH-NTO88w z3Ra#II17+V0-k{Q052*${**yqj~>mUD6#1OY$fyuU+o73Kq=XrVwsgN230$*$WY zMM2Uq=mG-PzquTF1dw=%9Xt#=T=HpPQJ4pUH9;Ad$O9R8s108LgM}T@Oa&9(Bll~| zr5=-GsCONKzk!?ykJQr^P;@(fX|4H!ZVM5!e`kws3wjXD;l)haO!~8o)(!QGG$eRr z2m(@RiYi3dvc2(Arfh7>-YlE!ct0B!eLef%IAFdQULulR1&%dE58{A0cQv|AkcJHD zzi~jG)VboPjjrYG`9VS`4w%1YjNm}WB&p^DCWdy~?oY zudpB;43ngeHW}|^_V><4l2q1$Ml*SqTd(?0t^p)CCm0kn3<;_^+)XH#MYNb1O+asI z_;*S{aGmQ}m0p%0gypil;l);EB__zH>T78`3M*s2I||)3pq&*9&nfxpmSNYmqlh=e2+`$OXy6HWtP|b! zXwL_kYBdUGbhn`dE$DNOjo(ZSvpC2zkh$Ha(q{-w9CY42q~5B>3Z1U|PzD(?QU4aJt&991LWzx_%*eDrHtim& z%`|zhueXJ~DNvt3_rEWp=$dxUp~?RDB^05@6vM7up{~M8-26z!2u&`LEZ|vgK16Sethy#yjN{KIE;*NZs7ZQl=jI??ZHnc&yuX_OPJ4p% zwTT|FnSM=DJK00Mvg^q*u|*ii$4JnEoy_7H5|p2TNKja>_D^E?NY1Z>S@IoCU{H7~ zb+X$5P93WVT5QgCl*O!P#__EBovWe}#aUiebSd8IK4Uju&5Hh`SyFuvIR4#u^9wT^ zKP0s1Y`k0?{cE%Q0K*b|?7>LaTzFrgulQxW*+=^Ku??>9zJTLLMsl-y33ruidd~Pm z1G(fKHEe}(kx31ArV6C2KxiF!5TsdFvjVAV4>;;n`G!G=A!g6}`X9M!6k*D7%(S2R z5+$h&@D!-}sU297O3nBTrtnYd74Qe^wgSh`#Pc<#nPy0@dc&6uACyVTYMNpA;o%8# zU@TTdXS@YWU@HR(lOrf__d6*IEf>H`edOt|ZAkT*$qB>?q~QksdmX5~u~?w+Pm}yg z$@&;1um0}3F2+3a-;^*&pq~NeZOF~SbS2?Km@z@|6tF4(EzD!EUXY%Q!jv=lQAjL? zuDus+F2|gA)XNbp)xO?ZDj3VS9|p|;^k1n>$cG1~|KdTU@viAc>7se-jgV(9MG+K> zj|hB!<@y+uCyMwXq-8RAFZ%)&Zmv5KAO%qwxZrdcxsp?diDCy$4}j?zE^9|2KqHkF z1eM=f)Ne@&5QV`AfTQbt3`U2W#%!Mv4U%cl(?vB1Il_(o-kUfNy+Iem(!~IK+4m!F z!zb^J}Bk6(%?x$b6;y zHEE($OywIyNX48szIK5ZX)f6&HysxOuTpBCxS>59w}0hI#RL04evCWt@#9*hhsV<| zAI!{M=FPtGtaUoHCb&9TK5A#==#OfMV>+-*dsQKh8M|*oqx}`8L$4ZU4k1Fblf?tK zoa{J~4?a3X+Bx`1VfXe2zz10kjn*l7zv30K%(EQcGlE7AS5YVb_zar$*qk7poWKNO z{|<8kWCX-kWj{_(Lm2^zAU%hseNND`V*fUd^YLAMv-y@6I@h3F0I$#-lnc;_Y$M0N zFB@#*$IcDS+TS^g`XCcvmR=`D0!ygEsr1ot7gwia+|yGcD|qIUnyJiioN#J;_&E47 ziF}tZ`e!hQgR@%-Q@QrQ0D=5CPO!q&`n2spJ99qOUO~ zoa2*})i5sC+PTY360CyqssFhX|EKmrng;7ddk(PaLCLawDg$#^F;HAqm`7Kxz zh`X2@`gEfh5CbK?dBQL8l-_zZKg&muz5~7%dPGp`fUG-+Rx+4JcK2};Ye{ET!||`( z9sd@0dFGH&^l2072)%UyhI~dohj4uwPFtwBB zv>ORvjyAk0IrXq^NBB0i@bC$d?8=`n9xanRPTW{n@(8cRqATD`SoS4VXlB+R?Niw-e^BZ-n|Jp@h zQ?QQl@U7&3$EkW-|Q zbg9^(EA`VM*dtCu;=sQJf+ysi{UN%;p)`#1lTE)Kp{^u?TK=z)ckM{KF@2fBE0_m1zMSe3G(+@y9w&>N>FH~Oai=h7tyTR#&`{;jb79Yp(4!fTM$P-+N|lwRTIR5 zGMcq_arGdY8t<-0Z>LH=-~dZyk87lq3~;3;g;orfP_u8MB=NTvEuNX6NV@L6Y z2L@x3vbKub#r^|8^ZDgd*!?%kUX+rcB&5Om20$Fz4}gHT6QFjR^r8}CH)yq^7rjt; zXDGcs0CCd)g)06BW`_|cMZRC&j17b$9Z-{wfw~)0#=tZ^!M|P(1(tBueH|@xuobG{ zqtzjA$lPyX85dSy49yK?DT6xvult$v66J-K{ooEadY@xXEO#2xj8 zRA|Inp+L0*=oQ`H@0voU_-!;n$UQ*06Dl)_vO}ei7y3(kR!Sz*WgS*0+ip!Y<^5jIOl0PM`un`U_xE}K`1yQx zpU##0Io|hmU*GF{UDtj8u)5*8@5Ac2%=E({(ZxGNl4-4f3J*G@2~4eMgbg!u;lp~0 z?&}Qi)OhbwuSv}xEgs5;bflTDCBoMmncaG}Cg^BZ@Y$-5MWe2_w%3I45mv-=_UQkZ z?ww+EI(+p-%Nk^ROq55RIkmp{xdsXE@U6(4O-dExQYu2BnvtY)DurPWZ^LrSS2l#M zZ~3up(8;V}cPip+quOFlszdIS9qbf!2X0ia?nag9BuD&@rXvk;e0;~RGqXFgv~wT~ znU6qm^J33gOklw~M`UcD1@l$%S=Zu> z{HQ#y4=wAO)<0z!>*&AAJiBS=iH`N{B@=)e%}Wqm?bzI2>Ic+lo~(-`2e9gz715ak zEpc6sgD`YR9~2GZD-5g=$>r*|4;c3822psmVxc{RNW&+uwk&pxIt{ik>Y@H*xbLlr z-G1NMn#1dEjoh>iDG5#k_I=sIgNKgT<4>EFj<9Rijo)4T$Tb|DefiORWGnah6$H6< z&lEfR*)>1+94L=PMMKV6D#mBn^NElAfG2ZNJMR;j!j+B9&(B7XBYbYQ>ldHGOrez# zbO%27;hm%%GcN1|Nr^1yod!D8&O1ya_Vb+vqN}~ruDl^ChS&8erJIFcG=2+i0%H{S zi>f%Tx*9o2H19AoDxG80MN7<2Qm1}OI)rBckDk|X!S_!*Ihip7_7;_@bO1+5b)-}3 z)=`~7N4)MPrLWe$bu-6sDJSpiH(+zAF!fiFFoZL5_@XM8_vvy;X-;|y)6Mc;7dZF? zd{8$R4|t)(3A}SD`G`0Fg}W6^`^-}uDHTOK!~xSxFNMcwI{a$9HJZeV!aR^}7H`m! z>a5g~8RAiOE#KAzq-8~>R^B8c{)ZZWX;yEh&#<+c@n;Kt#3|Pe{nCd}7^&bRB=@v- zrU%Z-@=vU+Z3tUnCWTT16v~M~iA)cA-!?rx?l!1+>D$(be-#Ba_Engt!3WD+n_B`? zb=YB>C>j@QjL?DAM|d=i~E5RedkyfaiLVKP`Vb{vyD`T1 zU4D?0iEw)HPCf&FyFk@tH+z5{-{C(=KzpEBbixtJszDOKXjuHi7%9j|D?`~SI0y`i zr!f0E>o`C4hOQ~nc*5-hc_j$(L}t%{io7H1ntgqzp-5cDn+8!{Zfvc5N5z41xQ@Zu_3+JpOV7j0w>zp$^DPPkuipKh0$^9@T_~7cCGyZ@K z)$65}C}$9e_<1NXP%ruY?z&x)mtY~^*mKD|Fk$g|ZG z8pnj0Mx+O(7zcxiRL@8(tnEd61pN{gSYA%|x}CMMzIa^&tz6<5q|lc*#EMpP8>JfL zR(;SAf4uclTkw@EzufA#;9RwyYx6p(UU;YK6MI^>_r|Qa?&uW5)wW^HEsfA2;{(S~ zPq#l2Yp^+DHdm)~_`|P43@d1hiMR~QQLo4YmS%hM0Yka2Z;~y(+v`XN zxD55$rIrTO>duv?ieK#trd3H|uUfX)`#vZS=^8Z2JjxMEY836pWt{sBLYuALQN#IM zQI{(5ai%}+?(O%(OC$I7dMPfSB`3W=nf`(ouLESf)}@Zxby@}r8kv+|iYLwnihBbY z$uVh12`}+pJL~{C?>wdO4)VfyIP=vk4S_EdAGjUBv|nr>+tOnKoes;VzgnW-46Hoi42dJDPBC6rf z$?A)!X+X%B%%y5RNb% z)|80PO@GFPE!_`R`%Js9VTD~8vwku`&5vIFWq5boH1lu5haSp&rJ^JbE>y7?-jlhA z^r>I!_A>FHgw{7|qIanSQY#OO;_6JYn%Il#X=k^-DMl(?Vol6Z^_;W$AB%@wHzh-# zGB+n~i_036STVKn@i0pkyeG}*`qE{MfqN`#(g%&rTvlK79PASGDRf09=~H8{!dOk! zL3M56w2oQX=Zz7^TVmV%CxEA@{8z&`0(yXV%kLB{K^_6%-Q4aWDG`6OXLJ2F+HN>} z;6ODdZ7%*ri^WQw<_7wK9UM~Hp^YxFoX@+R8T<1u<|Uld z|DE%@VM}h`Iv}qv<u{In@0{;v&0 zsY7zfbP$78DIF*yJhjdBD&Gz@b@_xMkNSIK|k14_hLz301j#a84F zp8>wWx&&v`&+I`uHlG)Vc^Vc6g$reiX=xjHQ>)6oQG~_>(|ST{mk5_3KY}0?KU8nd zx=i*0E(8txVmCUBM*lI_=y#f^U(v5(RA?T}-3lgycytsZ5swZPzxl$L-8_$O_<<7W zZjpcIPW{ub^<;l|`}v4x5ipe$1s+3&hqpMjyMEOaoW=712wHLwOLtmJWb}XRs^;rl`Vv#kE?4C2b5%RIV9{?#8G2IeC2ix>dW2E=)Ym zHSLa|lxRQml$s&CGS{S*j20scZhlSJ z#mv`IOBabkvyEqKypF0DoUPg*8g|{tyG%ZbTYqXC7-k%i9-d}TqA^+iJ)C43&-ZT0N>d?)SK=AELy50{B(zt0;+|JV|S`cw6++`*xU8kQd0^F?chXt8N7c9HQYZ{xy8DqJL)@Y3J3|4p99N} zjNF9!hlmHI=evSV>-Rb$uUQvg&e-Q0nrr{}#_6uX_TJt(D01Uh1mJ6Wcyf-G2mxc~ zc^I?%omzgaf*<0K-9**I{dXqOfKou+C}EYB*rD81oQF6X7MsdKM2c4E;?t&cvZ%g@ zKOJ1+$JPsVZieVTl;+J>d47pnQI}hebR-_fc^r^r?mfmuzky&UX1ezfda5-zYB;jD zk+~6%>}`5{KrcG*?odbV?9tgzVs)%7EGh6_t&I?55NV49%3JZvS5N zKlhYO_Q~~S@eSM_{myjXSsGPh`Ot>s1^VsjK4UfV`t9-t)T@4-KHzpHE$3q&nOjiV z@R-7!-8N)n=KlfV4NWoMMJ2Ztg*!hQCplD`OFn6g`_YtSpLM7D1?!aPZC>^j(M6NB ze5N-tnVyI)(?E#~ja*-gZT|j>UD|+i#+%5#>&V!Tz;keH%d(~+y@cK`O(A=2%BEop zJ5DqOEChXCxFT=jhX$%GvIe(TxROf;yxJMtUOAn#XR>Z!wXLyl(CVfeT^qZD=VDEf z!G=$hE8n#*@AfymUD1Nf(B$&v_UMw=H$)_L`kcZd%(-XA>V`fvMj@@60A5np_^YiO z9mB3#n!EbKSwazN1vyKt%dy-+%MC}^3viZfhKR7c8#mpky%oQTV17qD)|UDDjZ3tY z&3$G1b3kuCv56n_1(JK-i~2S^6ses&twrgSV0}Fg-auXZ<~fa#)BNyW3(*iTM!ZAA zCy2T+W-e5-dnU+cYI1+@*Q5xq&pSvevyV#JdWV#=a@+gjU#K=5tQh6qA!I}g3%JUR z?7lz0{D;p=Lu%*4Sn`OGk}^J_kS}98T>;>oeB5d2F3=WqNj$^UnLv#Ab=JnIo!KEg zAf?5@c;*o`85A!5s;4xg{Q|%qU)6eS^apqxB%@ZMoV8;J*E;JHsxHU6U}^f2_%EU1 zZ$`~Ql{;LzM^l0ISY-W?*4?p+&PCHh)sGkbRwS8b_*1yoAx&y`A7U2D^F))(hN7B2 zR0mNpLp+q2g~1oqU>0&32WMMyYX(U(v(FYS5)W8l45&eZ>V~t$AB&Njv8g6*fRhC8 zA7+~8cr47&2^g0ZfkGk#jDg&Sz7H5zCby5utt9f>^d!*>6l+pXhSD@fD3I*L8=dNv zjX}o^=h_BM$Q*U2Bu+Do5A6n<$>UYE0Q&?3LGt_-`)Q^cWX7 z-S(U4{6pGgp8v+0A{hm{@&=R5iFwzWxFT%C_!(I6jyR+|+2p74m0fdBm7cIGDBjeg zFz35qZRU3QpEeHjT4Rvce|gyvaIG_HQ}uVJrvArwSI$-em;I}7g{I39lvoGw5`5`G zpZ~=X#Y4WGNKqy4$>Ts(MJs16axRmAvJA3My$4b#cvigTmhKwu?p90@{qO1Fikuxk zm4v+g|EhKURz2}Wa0;I6DWsrhH1EJljSs-Hi*^`Xo6g;(Ra zG1htPh5=Xhz*Bh|_>O_@==RdXWdKw4ft%o zpqF&B-pV)Rg;yB|ago!l>CuI@yy!Vbe=cH_)x~JHF5*I$+xmfl%bPU5bt>osnQH*`^}txHZ7-m@p2 zs@`Jr>h_E4Y<7glS<^NZoVTZJDoyJ0Ijz6!@V)kz+pnx_DD_Qhe)VylTSILz&p!oU z|Dq54=d}mH=VCPjo>If%`sO)D5IYq8VVZt_MXz1nvf-`g;NSSy&3nnKHHP&%|<(1GAKz zlmG%=qtyiz+a;()c~mGFx`hR-R?n=ttEfLP=3N`1MbOn{5^jFv(zm~kyLWZeC) z8t%<_&gK5Rx7SSg^gR@m_Z}|n6$QWhEWt4>+TebmyUp)m*qoeNopT;>9RR{?S|7By zmN_nH(*7MCpG^v%S$IekNvbhalle+&u?ugFH@7;%LqfCqrB;-QMklm>TN9X;6>xTY zj!5oW$a~t^qBq3@!dmViw=Z)J*^iLxCfJWzSo$16RM?M@#_%x9U`i7I?-Gs_dSB3L z#%$<^CJjN<2Gw!n(`^wG)QfWq|J4|?-Wbdc+?YA6JNzV6qvUm3QULycTj)mXa;{Hv z%jvc_s0L^?!yh>0`d#*l-2BS&&i>B2ht@B+U<)k~yi3$=J_th+ImZ;i#q1^LWvzDn zIm1uRP*25*yom9pe>jjdzB(`dL;Y7xzOQz?mQfm|9l1*Xd6UnHPDOjwN$scu#)-V^ zlDzfju7R<}kw_G`{x-1rMzzK<^x?z@+eX=6CDb*lJ7T0W0amIDJ7U|ATsq7?VyXT! zozKIT_jN(v*=C>0-_kkmROPEEp)0;;U%hGT!=|T8^6w9PXtFr^AM6a>RPxX|U{lo* zM0;8pZxIr7x$_tc8+pszF5H-CikSUKyQ878(!xLEq+xD?=dbC>Q_UP#ApGN zV49~AR2&AwAOKoj_`~Dlz(YBMIXHYf_NSQ${~sIAJ03C=PJ~iShcaDp`pu|2C{hle zG;H2G-m4pQzWrg!FuW-R?^gUC*I+%o^cK~elaG$93Ci{BS&yMEd&b(GR~lZUiUllZ z%=>80YCGqI5Nw&l=hl%+@>GvY;+iX*hq~Sf&95-Y&YXC-LFA9{sd>GGq$@Yd@D_?? zUp#zOd&eW$7&4yyc1t!+I_Y2Pvx6rH5&s2ma(mqB2Pp)`5)3c#%2ZJnmzi5poCi+L z;+B10ryoMgC_c&O?q%x(X*C4#*~*VaV|x;1y9W-)j79RfI4;aoklw#MQ=M2@+weG+ z|8<01GWfmAR9w`+BXejgY{VKH^nr!Vc3r-q?V$72wYnJFHQ&MspzdE^F*5~ zCu^SwHdr|iQ1>X(J?r}Rk_p;TclF;i z`Q7WxBSjh>t2gMptFa(LY_p-9GVXSPQ8TAe*t8jVtfaYfQF7r8`>Ut6-sp-fv2Jie zvDG#tBmjy9-u`~lRnr6@F+(%bkoFw3NxO%|b&TwZoc{8)J=+mWBz5Hxd(7$96Ibh3 zklX$sD50$n`~h-G;G#IQ(t^`aFb04Wic}OBiCxEJSQYy=1u*&br-+_~BVHsfj!JFl zOG6ctJuXFS7g9bC*5O%GGlh~Fuy9Z9@fk1@NaUf_3((S^&$2~Y&olJPxi$hwg1`PA zMXH9UsU({iDgJCe4agaQDJ@&}vNI`&&vwPGb%u(XzEVxX+3kx&6S58a;k;Rtov|LCJ_$+f#V(C8`2QM%txH3Vn&`hi^k3%i@ zwx9;FLVtmr{1(bF?8=Y^UJcC7)XwF5KOR-p$xs2;O$|?(-oELDe?ku@4IHzmjI#qEo0HOqXHM+?ow zJhCAk)p|GknHl|}+co)1{}GDAr?t9xVQ{mq0PbPf9L(-? zF+CozBXeZXvsm7V{1_t+(G`EJJr^};``|x6-jm0J(CE%jTc<^Ke{Jt9L!us*GC9L5 z_6u|oSgf2SRCJ`v>C`?^tG&suhw|QNqL}F=@9%8_>Z2kmQmqlFLC5+AS#P2}X*4ox z&!`6jCZarxi07P}fNF>c2T5-X+O)DI=@?IN{Gs9Rz9=#2;QI+x0pUBNB4 z%($i<7k}iJZ`MVvp9~)52kfAQ2#(qKX}HfJ^?bPgz;D|cMG8bj;o4}D&u%XhiL=d* zlWX&GYVjHH&coNGVL60T1m3QiL{B_y`Ap|?q*G2-rzhdG8FhP5B4l_U zM7k-IsBBln_1jwN9)bGUQ;HfP}gl zN_)fnpOa2=w)2-WfrMXjjb?CuO^&7UwZQGOf(Cvq%WXK~`%erceoF=(Ezvaw*Uh8R zwT5Ez{5lE51;eBqUP((7VEKZXH8b%y&A)fUhjQ8r7>W@vPd%o=e?FCAU~K;$2Q0ck ze>+BFn_qESje(CN4yrT!05g-7Ksyzs5Mk!EHfy|Vr=o)NK4UfN#Ga$ruSvS+fL+(lAnC$!;4Mm8r=snvEi+mP<%y%Nm{8L(E+k#Gpyrf$e+PBbs{^|ix6TPX)d#_E>p6`*7{h?(YC}nVD zMT_$Wtg@_Za>hCRv~hP$zv#R}tWWdVHwO$z$$qf)nhn(uurq;acG)#xKKEV55tc&`tV@dab@2uB!aW8ZCH-m0U&(60}Vbxf0J7&AdDhJ1Ou;jR4!HJ3l6uMVzKT z1~7-{$QwwRL6O~%wW8uZS9EP%$439^#a%+gRYFhjjIJx{?>ra=pK2Wv`8Kc`x$s+P zTZJEJVR{M&!r5Pg?O2Y`->^MGPMYBdQaNUwoS=K;t2^ED-_^c08iW3n(_-*KSA~Up zo{_7}!&PtL9Q&``eBtXikYU5a)*c@pM)J|6aWQ`s+EV<+StLoNy#1-LOHVNxibU~- zib`d9vH}LwF!2pu$DCf;e1JT+K&(qs-`l&MxQ7duubi$N`SgzadmqsS#H7V#j!!M} z7b9yx7d|XBbJN+fGa_+9E3$C-YCsj}g4R1VJ{Q%`^K0;An^S9oj%IBR+$T*!cBmt1 zff4FN$!y!FHiU297SDueF17wO-T(c}=juzoYV^Hid_FyDpBkv`KV2hpw+1y1;tPr< zWFbTY)OOsgXba;}8%)mTVxpW&mH@w5oRo7H;+#Kcu11_QGo^d*^bTyk;FUKJoO53P zV3V4Q9%Vy_=1^W>l_}3v8~D9;%$(L7E@pX0>i*)RdBNvQK3tr#b413rSz7UUL#-nS zm@UueL;db1--Wg(dCvK+`ST|K6CDfMORnVk-8C-J4Y}7D+s>C087EUsc}{Yb#m?7- zhr+`#@*a-TKCCxB^Pq|lo4#DDwd(|`{-26{3;?YvPBC~I< z-BeO-e{52##Su5@KiNOMoZggVuib0VzYZ^FBD@^Oxy27c0w@EL{DF<*Rz}`w=nIfR z1DEHeW?+XKo~+`>HVx_~iiy96?KZG0!t+2V>&OlNTf*BpX$5=djl$^DbI}^lQRn*Q ziW>SmT?GmaVbqakJVn!f&nNAH|X5WV^hZOA)Nz5&O3J*G@$pu==O01~P6OE@pP5)5M26Ask_YiHV zm4_Rmv-Pjgj(O7(x4#LZ%~%i3(FA*LWmZt!AlgGj8?DB`SJD>B8+{j$){M>aso(xp z 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 A-T(jq literal 0 HcmV?d00001 From f49973528068ebfa8d43a96538b76e3dc430186c Mon Sep 17 00:00:00 2001 From: ellensp <530024+ellensp@users.noreply.github.com> Date: Sat, 14 Jun 2025 15:27:05 +1200 Subject: [PATCH 400/787] =?UTF-8?q?=F0=9F=A9=B9=20Fix=20Ender-3=20S1=20pin?= =?UTF-8?q?=20EXP3-4=20(#27915)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pins/stm32f4/pins_CREALITY_V24S1_301F4.h | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/Marlin/src/pins/stm32f4/pins_CREALITY_V24S1_301F4.h b/Marlin/src/pins/stm32f4/pins_CREALITY_V24S1_301F4.h index 40ea8ae9bc..5a42b1c72a 100644 --- a/Marlin/src/pins/stm32f4/pins_CREALITY_V24S1_301F4.h +++ b/Marlin/src/pins/stm32f4/pins_CREALITY_V24S1_301F4.h @@ -37,6 +37,34 @@ #define EEPROM_EXCL_ZONE 916,926 // Ender-3S1 STM32F401 Bootloader EEPROM exclusion zone + /** + * ------ + * PC6 | 1 2 | PB2 + * UART2_TX PA2 | 3 4 | PA3 UART2_RX + * PB14 5 6 | PB13 + * PB12 | 7 8 | PB15 + * GND | 9 10 | 5V + * ------ + * EXP3 + */ + #define EXP3_03_PIN PA2 +#define EXP3_04_PIN PA3 + + /** + * ---- + * VCC | 1 | + * VCC | 2 | + * GND | 3 | + * PA14 | 4 | + * PA13 | 5 | + * PB1 | 6 | + * PB2 | 7 | + * PA2 | 8 | UART2_TX + * PA3 | 9 | UART2_RX + * GND | 10 | + * ---- + * Touch screen Interface + */ #include "../stm32f1/pins_CREALITY_V24S1_301.h" From 7965e066c76a5d56d655fe83a2614da013ce00e1 Mon Sep 17 00:00:00 2001 From: Keith Bennett <13375512+thisiskeithb@users.noreply.github.com> Date: Sat, 14 Jun 2025 14:22:29 -0700 Subject: [PATCH 401/787] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Som?= =?UTF-8?q?e=20TMC2240=20updates=20(2)=20(#27919)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Followup to #27901 --- Marlin/Configuration_adv.h | 1 - docs/TMC2240_Datasheet.pdf | Bin 1171521 -> 0 bytes 2 files changed, 1 deletion(-) delete mode 100644 docs/TMC2240_Datasheet.pdf diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index ebea2a2faf..fd238dcc08 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -3502,7 +3502,6 @@ //#define W_STALL_SENSITIVITY 8 //#define SPI_ENDSTOPS // TMC2130, TMC2240, and TMC5160 //#define IMPROVE_HOMING_RELIABILITY - //#define PREFER_STALLGUARD4 // TMC2240 #endif // @section tmc/config diff --git a/docs/TMC2240_Datasheet.pdf b/docs/TMC2240_Datasheet.pdf deleted file mode 100644 index 89c9cf817e671daddfbe1d376cd0cd2a4ce99cd3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1171521 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

ICwKb)mJ_ z4K!BA&XcfXSW<-`I;)hR^g=9#YJ@) zw>wb@HhZ~g(imm~;yn~iiQ<@@JXAivVOh$&WKRuMAyp9xo;6#h+Fr~6XKa*J1zikF z^|SM`{&7Y-xl&%t?-&5#OO31B}ICgxI=$rkr3^eeh0thijV|k zuaKZ#Vq38d>ZDe1v$~XfJhud?_c1$oIqyhGv!d`ioj`_Oy~im?wxqy)tn2i9T7~j^ zNv_m%<>Ji=n+uwIn2D&WFaC!Ma=5ZN%nvgcE)VS@8rNbw1?-(46p)Z6yv>rvoT(u2 zLnkq)xGdSqUK%eL7GRdX8S__M!{E)9r5#GW^+=$(YCkB?mI+OfB}gMO0luzsit3zKp&ITPh6FW|UP0Ra?kbC+w`3K{o&wvVYH|UoWt=aAG)x>Cp>Cwt2^_ zMp=^Nr`)NLM~1NLD7>Hwb-&ZzIqNeWE*zw$eQ4DnfC$29nqZ@s?&+ObyURK<_wA6m zFp7$e=$7#&wC=`Iuk=s$s+ z3-wY49s#>NKl4~$a3FPJzul~(S6RhjGnQSxs1IZS(AD~3s8AvI77IRFuH=W2@N4mb zog&$14YFqMP*Sj8e^r8U%v6cD8^;Ax6Mi1)2O{J%n=4=@U(-^{i0aWOGh+g8Vv(&FdGlffd-w}YYd@jb_oP_5xu|=;_RLaN@(Ak8Lam@D z*5!sza&5%=l?9v5L>(A#4Z$2h4KNQ&?D`B}!yI)X_(jq5A98d29`W77as;sOd*N{m zDc@m9riWS_*r;@^3+mk(A`SDZAIMRcQYiaOP}Aa1X?V@Sw|Aw#D|b+T)d*bh2Nj-+~9YPes{=Uguwrz+3?SJ6Qqk1GU9wsfq94W%a>3jy);+8hBz6!ug(6&RoMH ze;JG^;0$QR>_$<5^I3H819ID~y4CHeMZGl?eh+gnlxdWsCm0Br$G6Tzl1=N?zDv+H z*9d(-nz7!v1>CYJOzRvpj5iA@p(`pW$#TGj^v)}RwV)+NzE(hxgHJTv_O#*wc-!jP z_E#?C4}~h_T?{KZd;Jw!m<@jii?uZ}@aj>T_>;G#sZ<(ERainNF8tLV!+eosEtKa$ zC3%nXoZJ((?q*e9)d{)Er5r=#3O!o85&RvJhy@$^4Z9)<*xipjlkWzpS|cO+Ys8Ak zCl&Xxv~sh_dWF@!oci}dJs+lN;6rzsCQnHLbl4fu4%#{r+G;;BiKx*^?|tkus@5OG zw$nzN{c~w(wYvkQw5uSW2lID!Gp&7uts~TB7t&~BU@ERFn2VKI!#qugq^zv{PDLhn zdM^NzNBdnm{T7L2!gxPyeUk^MH1{ve?nRX9nO3i*7%EKc0^ErwD9n~xAVd?dD zMU8c0vAA*zbtmbF^7w2bb-B=2JD0d33X5?725Kwnv8#%?+^N#!!bdBc8BVf2^W3xp zm_x5>jg^9S5f5)To;v9=OW92Nh6oc1cf&TBEyDj6W&T6ZU}F6zmE#|7i+|5p@fTM8 zzgn9AcNi;J{@UyCuPO(}->V#dZh!a}^!?W=h<{Jz7)3yD@M%X_yBXC^?u*X@=MPJJ zI&DQ-PfEr`)Iu|3@73;~ek)qqYnyT?7U{Ec83YXGH$-#O&)h(7%#IR=!+4vHulGlBVECma8o~mw?dbeQMdo$YJ^W)^R3y2SBp;WaX zr&*RwF2ljw`Kql?MCzHp+p2*s9$g*Epz-?&%|xEOtAHEFSrr#jaR@Hv8bhdd3~ob7 z)d`Lw@_js|sJ5dAHb{xW11y&kH`HI5Tk|qIS2}}67moi#gO-4xEaR06(Pq3^RV%YX zEMv)>J%1X4%LeIGaAEfpua~KSKUgLsHF{@`x#Qu(i2rwCGq5$40`zdxZi@p)<8~0&&nBLRn9{q;m3>8?E*0zdwAU_?J&+YR za!~{#CYqIa0Bhm4^D);>{(Wi(TU2AY^ck|^wCjCj_b*NI-T?+6Gm*1VI zVb}q|1a#QVkslBh($ZUEUg68lyMmhlCu>{%l`y#;n%#vMlN}&wGp{C%8)66pfCB_s zYzA}23m$9@07RYQVh^{)6!STgzsmC3EaxxMMWPpdpfO!7cYSzPlT6l7YBJiV@&{UlbSL`9XB>JtLVdaAVd^PiCkF~=(%j(h`yaw zcK=YatJbY()Q;lBovC@)=)PP3m!_8;3XCZoA4^tJDcT7YogSvIKuH1#(x=U zn|~Mheu*d6pgQ|Ry!7r9CEMa*MbW8%T>1_uwyjf< z){Ho+Qd#j>lT_jxhWvLcAS|n_5SmxYD8U_|L}o*B$#d(|L-TZnsS24WQ*GzlrNht# z{S&^vfsGS6WUb_=zCqL+2~;~$7?P^FEA|KP*Xe->O>6N+C~Bpp*kwyK!SV884Ygwo&ZoSfgvIw()Tki+Jsz zaitWQ%qAcxD$JIf{R|-0Hk9x1ccAt~jelG>pX@6JIbdkSnh%=0S^wP)^k@0}51r$` ztbHthZr1siO8eKEoxiQL|22EB`wM?z>_V(VZdZ!j`#7e>p3lMWGa>OTe&0z)wSgnW zqB6(DzR;tGagCqTL-$=Vut_~A=SUa?NvZOyI0epv46eW?oV=yH?s5J!~O`Mc2u}> zSRx@^B@!Zt%ocw)_;hG5v0zN>&I76CYJl^I}IW?l(fw^yZ%N~b_hH%Rcz){C6$h{8@UB0t(vRgWHlekZT z&69_gR_XD=vjv7eC6%5i?zm`}x4kGxb3SQ1&sOMKDM|(Ed@QsHsdjS_M&8DIxtJ>o z9i)UYkm7^Z@*M~vgmge;dRkE7v!)e6d#phb*Hm4&v4>NU+Kjh?P++-vQSU$zm=~Lu z;+6F9w_E(bZQWw|^I-mQSlJjj{`mZlmr#G?ll;d4{x@1he?18Q+dlD; zkHDU2NjErM4>T63@kw?lB{->SFLa5ZO~*jMXaMt$(Fz?kX?<32KE+wgqZUvOE+%E% zdcbxC=0Lk;yQMoGvU%a6Z`me})fM|R&m*}WHxrfMByer%VSU3XXv5+hq`Kr^uZU-> zEtxc1viKY>In&4-!OdJ5C`@-kPx5y1#U1J^l1Pwd37LmaYdoL1lOqPKu{-d$C+Q!a zX2ySt+F|)~YuLa3VE=E%<7$sh^gU-C&xt$s+0t!Q>_9il@$JhUhQ@xiMLrIbRh$Ra zi;2N49pi~9v@WU!TeR1~yDU1jN2#E!!j!l5pm>if6?=B&094;Zz?-de(1zJ~q? zwCz``hSJ#*7?MNgakQ3f?%p1G19sTd$mF9_Hc`tmCS_GT0Sm-H|nYc4C&{dCbAv zx(bt{7j?HpdWH_ps*C`xNkxfZ2WZ+|L&Gg3jwu`~VP%(V3cZy!2-MmD!APlDh&;_q zcXrgZ*+x1quZ^m(DbP!;oRE!gh<6h*wLKUhF@U_eEJzO=GZ@(#D@05`%AiiL{I9-^ zS_Nq36PcQG2;Bc(O2PRO3jP4AaQRakhxEtR@)CFW63t%YVFN|j<=)5Rhek}|{Er!Q z-bPn{1Mar`fl9V%zTI6#D?@-?bIEg{W+JU-lkPGq9{7hfc z@_l!$Q5tT*YuzhGj3ZyZWw+xp0sn2e&kMwtNLpvY03XirF#e1<9uh?9xF!=CW z1MNnKa_bP+*!Q?q?%cECC{8fyy57m$?TztFIM|a z7q0B!CmWK0X1+yiQOsY#uc@VqjUU6}0r8B{`bboT!cMJ0^= z0-N4{)-rcTpuZtYJY%FJbn%Gr=qnTzX~KX0UWv2!2vm@s+FbL7*T_p{vlQhG*QxQ@ zIX*S zC5k{SvDAj+xp4woEGxRWu$X|xFuYzv7=_2C6?p)4p0h9e!7V9$nJYO95W0F;|jPhTKPuMeLu$n9-MyafsEFJ_M%|Egx`%mM^0`l zWjF#@slILH%Z?R& zR6jL-s*=;twA{B6%WLA2yEoj7mNZWsA+9V7XPrYq!J^+PnwaB}ifNlw=!D#TTgjL_ z*stw+cmi6?cPLH5n~(hDxLGT#4Xl$CjG?0>c)k3FvX@0Xy#9tLFgnG<8*wDqhXuc; zEv)f+g!-}I$F_PriA3BKR|`^^=B4Sz-<|2kQX?BL?~_Pka5isP@D#SD`VCL-qzwbu zwnPKs;ahAxH2ZFh`4z;}{YmsO#c@t-@h7`iy?r;>blxzG_ii=y+LERE8E~F?BZ}}w z+8#Ol6|7YvLQK$dYhNUVQq z4kEU7|4^u>NXul|hVdYAo^n3oPd0soxd=e225e{^Q^2P?;1mf*8z(Mv2 zhfvk|UMprc7gioT6!i=87ltGV+>EQL;{DXstu_Y2-No>m|K$Lps2Tzz$6Zi(7K75x z^1AMB_vnv%c%d%zfI-hgj3mE9%Hhl~i^hhL7?3mYMToKbuD&bZxD0)Vhok7x^)cEo zEz9IbEI)NhU56Q9o|z!MNO*qR^4`_O7vD1DE+KNsc~g;#dzKmEGy>%-g15dGkE@mIAmCWOT&-tfVqHyi)dKM>7H*(*77j3S!Lm9HgjNId>TP3Fo{1AMnmjN!(MYUuN1?$n$Q(#A73+Yf+# z)L#fM*r}W7*THy;#KuMV!#Y%$KPr0nhswh})gNB@7?V zr?jF3Ut0^fc_}VR4^LAp7&u)9oyLv$ncH6Os^}=eQeq%SWc9`LF;?y1wr0weiOD_N z+)*0nNv8uPb2Z#^TPFfqzH9Xz@wy_}qb_O(HC9H-JiEI$Q@H}l)O3&*C*ZdA&wl2L zQOB5VpXfbn0qB(|)oz|m$QptT*! z$+~x)KJp3z%4jt9YU8XukzJ;pXP>Ls5~>Li1Wn=G$BUKewJV5k=XZ+B-fB^rroGfb z4}e*#)6*j49bCL*)LZmO7K5b}RqJHlM;-B_DuufU`IPUqKVb`XmOrUJF>FJaacUh- z;0ra~g7vcjL9|lD-6hFW;>H9|JA2ywsPU9L2aK$w@)e~OXKcMRzG=dJ9sFWrWz2V7 z9#|T@whZJV%K6OJ59%y9XK*g9I@1wmN658Ri~6KB%X7<5*|fBC{xHsBV5J(SlFTbpPOOj>3;XD@a*hK^ zMbw07_0&DB=I2@2`+t~wrzqL_ZQC<#J9DL-D{b4hZQHhO8!K(wwzbl>jaqx}v+sB6 z)OT*HYPTNFTeR6C=1WA3`5(VNM(;H+z*(7FZo^n(f!NuKQ~LgNem@FXMdSj$Ca;=m z^TZY;!|(S@1Z80KSAu*)-I#oJBT`syot%t-d56p{WQ=^OOjQ_tF}Y`1x@q(dn@lIU z6O$l}467md)EW(_D=yv_Jo*zGgUynFR zdx66;a|ORdvWIidQ*@PmTd5l1Fu1DY>>q*YuAtikIYF|e`!kRtZEaz?))3-W=6^?$ ziRvsB-jgw#Q?V9lbAiV7w8POW`OJv+{B8I0Z{dKEp5?EZm4BFX{{PSj|0_EAfB4Mg zzv7JlpN%l{-!{VkOg;WDecitzkpC8P{Y@jx_K!FI!^)G9@ju!6<2l_XLa#vVZ9#jM z#s=gE=so5WWYTFQGgO>49-8C2L0+tAykHn$GT~Mw#E9`jgad3Q6y$v(mS{-^RhiLR z(ltmV#X<_D1wvj6=c{?B1j8b*T$oPZapr{&<&&~E@*nYM8Vo&CA^9zLAv8@7AZvhA z3pIMaQZfn?&@4lJ)YNlJcklpIEKcGjRU`8ds8q&C!~Tk;jh57H94cKT*M8nu5_b5# zaMatUo2e-vDg7am!W@wvnmuO+Q&gEyW;9V5%LnZGC01tmaqgrqFwP{8igOhVc~Ua` zSQakGv6^zY_W7(A#7R4U%zbdn=b>)5oAXq~k_ zQ})1tJ->KD`&fW)s&jvf_yfR_-h6`?X+4KG8!f(ii6tX%Dv1jFv&TH2`q_f2bGtgP z_-7O<&uJyC)S`n`PJFz@??h{Z*%mk)2L;{<;oLLHVgWW#_FCv9MTA@M-Jj|8-piK| z^;7R#FfWEn8(hDArrC9De9sko`RB^-Je*`AJNKPMivlgEXIVQ%Me0?`llF3_^};xV z7>0B0o@{s7T$$lLkPq^~wu;+XGN<5F0n5rOu#7|)tEi>FMai^F@OJ#J2d_imp)%#C z^}Gi>K#V&Q-!-KQ@u)jAxW!<~?Tk(jVvmi#Q&wi+Ld)BTMynTJ zXUZ1|#B6q%+0EBxoO>O_+J<81B&!_OJz|$G-uuQTbDS_)zBjU(iI$C&dUg~~P5m*F zh~3=87b-9%_|4OxZjco-=v7w5MZ&?DW!%}|#jz!D;~PJQiF4PrRf&O??o%rvFxNWLlP=q( zYBu?fS>24JGG1XmLs%0%KYNJW$H{(1Ef66bB3AJqNE+J97i95$!TexXRaX#7-!>X| zfDMq{Szb}CG?zJ7BO9?X2>8YTTZ!%22wIdU4g+;TQh;N2GB5X@sn~c@oMA1>@ z=sH}ogagotrL@O+B8c)_8Xyfwn9(;@|AATgh(hI6wdf}>LMk;dPVQz?E+iGnVmXJ1 zP|zm3tjNN8Q!m%fMlrTBWzbv2^}u9()1@6e!rm{Kz`gcNYvP;!14Hps{cK~ova-Ry zw>VWF9f%%X#^w9uyeerO!$?#T!m*}QsI?#grEn)^jQAp2;yo#scZ#6Q?AQGmt^(%| zV7U9)AMm8sP2dG%_MSh1fU)g{u@yn#1Hkd+wjz-rV<@v7-@5{!L|W_b4)z5eZY8uX zhr@G}Wk72jlAeqOU2}E9yS`q+{Ia980rvmy8Su~g^^clH|0mb{f5A|ue@43h*HZUS z+vdM5b${`ERE6|@_&pv*Yi%za^B!h3R!bN`mU_Fyhd7Za3T+@+krXngA&JZ-;*?*T z;bx9s*&$YW^#bpmks^?Ffnb2;6Yp$+Ag(t?T5#@q2o;YZKR4cMB~a2y7eH^W2m~aM zUwZ0+9y%t>SW^W05D7a0aDwqZ56;dQrKWw*lJyF*Ts8%=p2y__=r-^S_z2?+GGecU z#2dHcVUhr+31DFVBw#!&^u>>2N#w)scL1X^?@FTm85h=Fj61dvD<J^iM3^!0;ttFS-Hwa&V&3SsC(??qFZpD39wg;$iodUY&Q;z2C@uxR?~ydx_^& z2WV6!SPSV5(2S65mhqPEcAtZ}f`4Mc^~)EW^wz`u6;ze}@bf>?q{_^ut&P8To_q`B zEt_?v0r&U!phw?qnihFH(@h&_Y<{}$-DZDY;MQS8^0v9E$irmpu%MT5KUPbXkBODk zCD+<@K!8&S5U0QwEE-|bBV{jlLHcM_MHex@w2KL{?uM&94JJg;lWF+IQk!>NlMlLR z-OpPCm36t_g%Y65Xm>i7B}H1_aqR3ZI8^?rXeSlak*VD4QJ~}CJVn=B%>H+m?gR5D zgV;F+bLu-4&8%UfJ?4|+)WY!A|4l0Ww$!IPJ_sriX^0AN5p{kF^1ufS4 z%(yE)m)MOSNp+D=ylP30;@PD`&Dgq4l;I-I%I1$P#2{@_qD*4X8Y^T#t)O7RE7+1W zA9NJmq7JI><^kb|PUn1_U{>TcI}eki$0|ZJ!j%3MO$YsyJh+_zxAvwhva7R&*9ZV?EpOvwl$C{!p?o!tun4TSfOtx-1AFc(8Y7&G z=h^S?ED4O;edJF{)UT0NPFyzO-i}ybU09e8CXejHK14Q3(mem6CoI%F+o;?)V^&{R zl$??!zf9+3`()@SA@s>$%%y08D9q+A4Y5S!KFO+&qkqWBM$M5?5Xga z?=LBU%xo$%O4=hP0u%PGLGI`bGEyLuZrMQ9FM{!`_`rj21cX|(o^Lf}>_D0G3-vpH zK;V#_JGnlEhAxPA$DclEg2z#)vC)GXQUcu|Pi;CW@Ezmw3++{_l3*n@@U@ZCy8w*N zil*ubB67k)@tseMi-;>Av=m!VaUX~8x;|*Rj;Hd^7<$ah^mrsQKfzK}&Vh1E_ivS( zMTKn`6sTbmRq#g#3xGUt=d6JY$DYG1u`{HP2ad-Yj(o`z7~eu*Q{dg?%MSdMt=+Ju z9_#+W`TE&LixuSd((P}1KzASPArFXRTBH}%AuO8UI|~m=_Ja$dRnWV$OQqPRScD8~ z9j+M0)o4uyPL*A*D^KV=AX~MBZ&Y0Y@n=6Cry<3YOKHk%+nNECG?! z2o~unZ~-?dQx4yRd`0w=@(t)YcbKch)l|Sx zg9`7IObl;l_rq0Hqrk$0@O8x;faOIr~Hk2$|+)IdsUTsPOvd*W0% z_uThv=Ymv7A~X31>Ea254W>}Yiynl-dKGN7bb?dBL#vjOT7oL--`g=aI)gKjUeP8R zWFBTmevY7}=5Bw_^_O5~OKS(T=ojFwFFt!b@|sPZy-ZZ8^Wsr?(m$IKvjqw>+FB*L zLQKgd2+|QFM(I*xI+w`g`4NhS>mMFrBY}b_lPbl#ku*$ck^*B70Uc^&uQp%VHOR;e83dJT!@_E;$O`mhKVE{RW<;#$&(4^0(rX0;j~A5cBJ|~N?NfMbJ8odPZ&sPS=dpr;OGoD({m)3 zO89D}ct<7$tJc|4cos6a`65w~F^e=cZov2v=JH$tEd1mr3JrD~Vc{0k^^I1SYqaL( zyBw)Q$AjFNf_+}&T1eX|^=h0j(4|Wz*^p$SW&K!!!=^M%5-maWr7qa=&6{Hzs{<1= zoP8Ho8SYDo11k0A8pLtUohtD#nmQ(<54hn64hYV`SAODoE)FKcT^5L{yUd|$xUBzU z2H1QWKJMO~W1NYt)Cuw246}nmx-8JVSwsYA6aWY&ddUr0Uqok3>Q0PKⅈzI4fQT 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


deAW2ZR=gk9?4IT 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%0A$x+zCyy<>T-BYq&q&yh5rIs?^$eJN)thrJaI)br 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 z�=){-J`eRARwd*6h;WrKhb5fSnG_eA~V5Q($Z~CoC=yaM6ZMKYxvGu^x9z@1DiA z`^cbv!aCmG<;m3)w1h`c2^`2~GN|!u2cHsDr#{}BiQ;o68p6gWr6#qA27Yd*&yRLI zKbJ&mjTR2M{{uN3-|m6aE3rc93TmquE|h0n;GO^a7HDm|VN4?JebMZd5L`*^G!3d~ zO9CRoW@r|`0x0pj0Mkm4>vTb<`Yj63X3n>5X$c(9qwkqW^GLz<6mq&EJSHG2_T;UuuQGp^}uepn3foFBv5%lh6f{X53_6VO$N(nQ6vJlhl7R8Ks>FY67eq;g`DdE>R4my|H``?jI?Z#;R7|uUvqZZS03fI2G%- zk=2$$9Ywssa$+FiPX}g?(ieCUlYSaE$6Js|7_IFV!LO`;BFN=Zg7 zx5I2V4Qi!U7Qv}Q3!BpS39@u&NBwIYD}NDN&T;c%7{7Xp^wLp`6eh|C?&mXVEA?aK z0fv_1i8JZ%J^aenS;f6U*v#O}uKT@<|M7ep}<M_dGyjXhEbK4LU;+K-YW8y{GC}n)|3m z+hPhka`6w2R@)`!GdRI%Z8ds94Fj9qP&w5GalM`2@;9Z&uQL)Z#=FsE8A35RNOhtN-M6s?wu7;eg~9Y0Scf98DTi6D`Ld)CBWZ0fH}mi52vNF`Q++*fgS z=GB$H(ZgfVQtxp7_TNv$$Yab|>YTS=#U~rj>=dR22_o|ch=6jjjb%A)!w1lYKqyFj zgXM{Ab7DzOoUKf)KVJ3)hJ!7_knepT%3HGrsq*(m%&{G`a#>Jk@X@JT`W8!d?#j4d9#aD&=wxA1I10p;TS6^h4?}Y*v(P^*0m} zTuAc+`qm@;(nsH)0x01klibG0BWC78J|G7tU+QEp%P`i0sgX0=H)k(VQPAEE zqF|aLzj9G}OM}oQ-O{T*k1OMYv1YKq?>lO2$VNR>%-QiReVj$2mjkyh6XL?nu+-{? zhR{X{=IwlY2HL4B58Wt{k_SrSZJCZ`fR>060rJwb_ykj`=V%V_1$#mhE`J*g|LW@8 zCDy3uMRy$57+z9+{3L{=GDp!9ZC{EYP;=s2qrLhtDqVktCdl)#@$E7! zp-y}n3pkRHJco0;?Vk#|QFwgg!`wr8tIdMTW5g}ke8QQHR zTN8rr253rW0MyMw-RIoxyTbff5n+9WZfq&;RCndVCfx{_ku$-zLaP1*m$Wp#JvyN-I9bsx#_R;%r;K@tZTO|Bc!7uyKOp|yNt8eA*O?y+k zQg1~xm_$GG{yUJ_;Ea|XLews4E^Xa-nuO(BYe$0rVLx2soe#eO0$}X>eL9acJEJ~s z$rk83XS1s6xGRx-C;x~MzfIu5w=@$5c6eO?yy{& zSG3908#wFGG=QG0%}7g;?UdAJaILm}PYqysZUn%t3|}(h-o@|>h}%Ky1zl^F5k3R& z+C{@moLb6xLz}(Ru#Qi%q!&P;j^nm15qjz`a$dSliTc%+N|Nz(Dk7hb?ihut^8&mL zTXt^)MZ5R_=!k90KQk8XBrPjF47)-tks2yuhGB7W7$MJWzreKDQQ(gZvX;e)fq`5y zRkf_X4|8f(D`@X`fp zb1&F SA-44R*k_)y0htl9fUg8Q_2 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
<4_T}$GU|sUgzb3Tcw8TILz{S4) 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ʐ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�zzQ$E>RPqD#Dz|86Y(K0OS31$kOyo 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 iADc#fau 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 z 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 A-T(jq From 29ceba972c4ea4141cf8fd5eb05762352989ba9e Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Sun, 15 Jun 2025 00:36:55 +0000 Subject: [PATCH 402/787] [cron] Bump distribution date (2025-06-15) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 90209ec147..0279e837ee 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-06-14" +//#define STRING_DISTRIBUTION_DATE "2025-06-15" /** * The protocol for communication to the host. Protocol indicates communication diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 607cd35bbe..7ff1e1c377 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-06-14" + #define STRING_DISTRIBUTION_DATE "2025-06-15" #endif /** From a7f12169b9bd38051e5b837340efb88579f391e6 Mon Sep 17 00:00:00 2001 From: Andrew <18502096+classicrocker883@users.noreply.github.com> Date: Mon, 16 Jun 2025 15:23:17 -0400 Subject: [PATCH 403/787] =?UTF-8?q?=F0=9F=93=9D=20Review=20&=20update=20G-?= =?UTF-8?q?code=20comments=20(#27921)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/HAL/DUE/usb/udc.h | 2 +- Marlin/src/feature/powerloss.cpp | 2 +- Marlin/src/gcode/bedlevel/M420.cpp | 10 +- Marlin/src/gcode/bedlevel/abl/G29.cpp | 135 ++++++++---------- Marlin/src/gcode/calibrate/G28.cpp | 9 +- Marlin/src/gcode/calibrate/G33.cpp | 112 ++++++++------- Marlin/src/gcode/calibrate/G34.cpp | 8 +- Marlin/src/gcode/calibrate/G34_M422.cpp | 29 ++-- Marlin/src/gcode/calibrate/G76_M871.cpp | 108 +++++++------- Marlin/src/gcode/calibrate/M100.cpp | 28 ++-- Marlin/src/gcode/calibrate/M666.cpp | 32 +++-- Marlin/src/gcode/calibrate/M852.cpp | 14 +- Marlin/src/gcode/config/M220.cpp | 15 +- Marlin/src/gcode/config/M301.cpp | 24 ++-- Marlin/src/gcode/control/M42.cpp | 15 +- Marlin/src/gcode/control/M605.cpp | 15 +- Marlin/src/gcode/control/T.cpp | 15 +- Marlin/src/gcode/feature/mixing/M163-M165.cpp | 43 +++--- Marlin/src/gcode/feature/mixing/M166.cpp | 24 ++-- .../src/gcode/feature/power_monitor/M430.cpp | 13 +- Marlin/src/gcode/feature/powerloss/M413.cpp | 11 +- .../gcode/feature/prusa_MMU2/M704-M709.cpp | 83 ++++++----- Marlin/src/gcode/gcode.h | 112 +++++++-------- Marlin/src/gcode/host/M113.cpp | 4 +- Marlin/src/gcode/host/M114.cpp | 22 +-- Marlin/src/gcode/host/M115.cpp | 8 +- Marlin/src/gcode/lcd/M73.cpp | 11 +- Marlin/src/gcode/queue.cpp | 2 +- Marlin/src/gcode/sd/M20.cpp | 4 +- Marlin/src/gcode/sd/M21_M22.cpp | 4 +- Marlin/src/gcode/sd/M23.cpp | 9 +- Marlin/src/gcode/sd/M24_M25.cpp | 13 +- Marlin/src/gcode/sd/M26.cpp | 7 +- Marlin/src/gcode/sd/M27.cpp | 9 +- Marlin/src/gcode/sd/M28_M29.cpp | 6 + Marlin/src/gcode/sd/M30.cpp | 5 +- Marlin/src/gcode/sd/M33.cpp | 4 +- Marlin/src/gcode/sd/M34.cpp | 23 +-- Marlin/src/gcode/temp/M106_M107.cpp | 18 +-- .../ftdi_eve_lib/basic/commands.h | 3 - .../lib-uhs3/dyn_SWI/SWI_INLINE.h | 2 +- .../usb_flashdrive/lib-uhs3/dyn_SWI/dyn_SWI.h | 2 +- 42 files changed, 558 insertions(+), 457 deletions(-) diff --git a/Marlin/src/HAL/DUE/usb/udc.h b/Marlin/src/HAL/DUE/usb/udc.h index aba08d956e..e8c0e7fbea 100644 --- a/Marlin/src/HAL/DUE/usb/udc.h +++ b/Marlin/src/HAL/DUE/usb/udc.h @@ -229,7 +229,7 @@ usb_iface_desc_t UDC_DESC_STORAGE *udc_get_interface_desc(void); * - USB Device Controller (UDC) provides USB chapter 9 compliance * - USB Device Interface (UDI) provides USB Class compliance * - USB Device Driver (UDD) provides USB Driver for each Atmel MCU - + * * Many USB Device applications can be implemented on Atmel MCU. * Atmel provides many application notes for different applications: * - AVR4900, provides general information about Device Stack diff --git a/Marlin/src/feature/powerloss.cpp b/Marlin/src/feature/powerloss.cpp index 27f3e44ca5..7cb826674a 100644 --- a/Marlin/src/feature/powerloss.cpp +++ b/Marlin/src/feature/powerloss.cpp @@ -529,7 +529,7 @@ void PrintJobRecovery::resume() { } #endif - // Restore retract and hop state from an active `G10` command + // Restore retract and hop state from an active 'G10' command #if ENABLED(FWRETRACT) EXTRUDER_LOOP() { if (info.retract[e] != 0.0) { diff --git a/Marlin/src/gcode/bedlevel/M420.cpp b/Marlin/src/gcode/bedlevel/M420.cpp index 7903cc623c..05fa98e459 100644 --- a/Marlin/src/gcode/bedlevel/M420.cpp +++ b/Marlin/src/gcode/bedlevel/M420.cpp @@ -45,14 +45,14 @@ /** * M420: Enable/Disable Bed Leveling and/or set the Z fade height. * - * S[bool] Turns leveling on or off - * Z[height] Sets the Z fade height (0 or none to disable) - * V[bool] Verbose - Print the leveling grid + * S Turns leveling on or off + * Z Sets the Z fade height (0 or none to disable) + * V Verbose - Print the leveling grid * * With AUTO_BED_LEVELING_UBL only: * - * L[index] Load UBL mesh from index (0 is default) - * T[map] 0:Human-readable 1:CSV 2:"LCD" 4:Compact + * L Load UBL mesh from index (0 is default) + * T 0:Human-readable 1:CSV 2:"LCD" 4:Compact * * With mesh-based leveling only: * diff --git a/Marlin/src/gcode/bedlevel/abl/G29.cpp b/Marlin/src/gcode/bedlevel/abl/G29.cpp index b25fe5ebe3..e0cf28156b 100644 --- a/Marlin/src/gcode/bedlevel/abl/G29.cpp +++ b/Marlin/src/gcode/bedlevel/abl/G29.cpp @@ -156,81 +156,72 @@ public: #endif /** - * G29: Detailed Z probe, probes the bed at 3 or more points. - * Will fail if the printer has not been homed with G28. + * G29: Bed Leveling * - * Enhanced G29 Auto Bed Leveling Probe Routine + * Enhanced G29 Auto Bed Leveling Probe Routine. + * Probes the bed at 3 or more points. + * Will fail if the printer has not been homed with G28. * - * O Auto-level only if needed + * Parameters: + * O Auto-level only if needed (Optional) * - * D Dry-Run mode. Just evaluate the bed Topology - Don't apply - * or alter the bed level data. Useful to check the topology - * after a first run of G29. + * D Dry-Run mode. Just evaluate the bed Topology - + * Don't apply or alter the bed level data. + * Useful to check the topology after a first run of G29. * - * J Jettison current bed leveling data + * J Jettison current bed leveling data * - * V Set the verbose level (0-4). Example: "G29 V3" + * V<0-4> Set the verbose level (0-4) + * Example: G29 V3 * - * Parameters With LINEAR leveling only: + * With AUTO_BED_LEVELING_LINEAR: + * P Set the size of the grid that will be probed (P x P points) + * Example: G29 P4 * - * P Set the size of the grid that will be probed (P x P points). - * Example: "G29 P4" + * X Set the X size of the grid that will be probed (X x Y points) + * Example: G29 X7 Y5 * - * X Set the X size of the grid that will be probed (X x Y points). - * Example: "G29 X7 Y5" + * Y Set the Y size of the grid that will be probed (X x Y points) * - * Y Set the Y size of the grid that will be probed (X x Y points). + * T Generate a Bed Topology Report + * Example: G29 P5 T - for a detailed report. + * This is useful for manual bed leveling and finding flaws in the bed + * (to assist with part placement). + * Not supported by non-linear delta printer bed leveling. * - * T Generate a Bed Topology Report. Example: "G29 P5 T" for a detailed report. - * This is useful for manual bed leveling and finding flaws in the bed (to - * assist with part placement). - * Not supported by non-linear delta printer bed leveling. + * With AUTO_BED_LEVELING_LINEAR and AUTO_BED_LEVELING_BILINEAR: + * S Set the XY travel speed between probe points (in units/min) + * H Set bounds to a centered square H x H units in size + * -or- + * F Set the Front limit of the probing grid + * B Set the Back limit of the probing grid + * L Set the Left limit of the probing grid + * R Set the Right limit of the probing grid * - * Parameters With LINEAR and BILINEAR leveling only: + * With AUTO_BED_LEVELING_BILINEAR: + * Z Supply additional Z offset to all probe points. + * W Write a mesh point. (If G29 is idle.) + * I Index for mesh point + * J Index for mesh point + * X For mesh point, overrides I + * Y For mesh point, overrides J + * Z For mesh point. If omitted, uses current position's raw Z * - * S Set the XY travel speed between probe points (in units/min) + * With DEBUG_LEVELING_FEATURE: + * C Make a totally fake grid with no actual probing. + * For use in testing when no probing is possible. * - * H Set bounds to a centered square H x H units in size + * With PROBE_MANUALLY: + * To do manual probing simply repeat G29 until the procedure is complete. + * The first G29 accepts parameters. 'G29 Q' for status, 'G29 A' to abort. * - * -or- + * Q Query leveling and G29 state + * A Abort current leveling procedure * - * F Set the Front limit of the probing grid - * B Set the Back limit of the probing grid - * L Set the Left limit of the probing grid - * R Set the Right limit of the probing grid - * - * Parameters with DEBUG_LEVELING_FEATURE only: - * - * C Make a totally fake grid with no actual probing. - * For use in testing when no probing is possible. - * - * Parameters with BILINEAR leveling only: - * - * Z Supply an additional Z probe offset - * - * Extra parameters with PROBE_MANUALLY: - * - * To do manual probing simply repeat G29 until the procedure is complete. - * The first G29 accepts parameters. 'G29 Q' for status, 'G29 A' to abort. - * - * Q Query leveling and G29 state - * - * A Abort current leveling procedure - * - * Extra parameters with BILINEAR only: - * - * W Write a mesh point. (If G29 is idle.) - * I X index for mesh point - * J Y index for mesh point - * X X for mesh point, overrides I - * Y Y for mesh point, overrides J - * Z Z for mesh point. Otherwise, raw current Z. - * - * Without PROBE_MANUALLY: - * - * E By default G29 will engage the Z probe, test the bed, then disengage. - * Include "E" to engage/disengage the Z probe for each sample. - * There's no extra effect if you have a fixed Z probe. + * Without PROBE_MANUALLY: + * E By default G29 will engage the Z probe, test the bed, then disengage + * Include "E" to engage/disengage the Z probe for each sample. + * There's no extra effect if you have a fixed Z probe. */ G29_TYPE GcodeSuite::G29() { @@ -855,15 +846,15 @@ G29_TYPE GcodeSuite::G29() { } #endif // !PROBE_MANUALLY - // - // G29 Finishing Code - // - // Unless this is a dry run, auto bed leveling will - // definitely be enabled after this point. - // - // If code above wants to continue leveling, it should - // return or loop before this point. - // + /** + * G29 Finishing Code + * + * Unless this is a dry run, auto bed leveling will + * definitely be enabled after this point. + * + * If code above wants to continue leveling, it should + * return or loop before this point. + */ if (DEBUGGING(LEVELING)) DEBUG_POS("> probing complete", current_position); @@ -892,12 +883,12 @@ G29_TYPE GcodeSuite::G29() { // For LINEAR leveling calculate matrix, print reports, correct the position /** - * solve the plane equation ax + by + d = z + * Solve the plane equation ax + by + d = z * A is the matrix with rows [x y 1] for all the probed points * B is the vector of the Z positions - * the normal vector to the plane is formed by the coefficients of the + * The normal vector to the plane is formed by the coefficients of the * plane equation in the standard form, which is Vx*x+Vy*y+Vz*z+d = 0 - * so Vx = -a Vy = -b Vz = 1 (we want the vector facing towards positive Z + * so Vx = -a Vy = -b Vz = 1 (we want the vector facing towards positive Z). */ struct { float a, b, d; } plane_equation_coefficients; diff --git a/Marlin/src/gcode/calibrate/G28.cpp b/Marlin/src/gcode/calibrate/G28.cpp index e9d72a83f6..6ac51e4235 100644 --- a/Marlin/src/gcode/calibrate/G28.cpp +++ b/Marlin/src/gcode/calibrate/G28.cpp @@ -200,11 +200,12 @@ #endif // IMPROVE_HOMING_RELIABILITY /** - * G28: Home all axes according to settings + * G28: Auto Home * - * Parameters + * Home all axes according to settings * - * None Home to all axes with no parameters. + * Parameters: + * None Home all axes * With QUICK_HOME enabled XY will home together, then Z. * * L Force leveling state ON (if possible) or OFF after homing (Requires RESTORE_LEVELING_AFTER_G28 or ENABLE_LEVELING_AFTER_G28) @@ -216,7 +217,7 @@ * fail with position unreachable due to probe/nozzle offset. This * can be used to avoid a model. * - * Cartesian/SCARA parameters + * Cartesian/SCARA parameters: * * X Home to the X endstop * Y Home to the Y endstop diff --git a/Marlin/src/gcode/calibrate/G33.cpp b/Marlin/src/gcode/calibrate/G33.cpp index 76bf250346..409a9c8707 100644 --- a/Marlin/src/gcode/calibrate/G33.cpp +++ b/Marlin/src/gcode/calibrate/G33.cpp @@ -41,8 +41,8 @@ constexpr uint8_t _7P_STEP = 1, // 7-point step - to change number of calibration points _4P_STEP = _7P_STEP * 2, // 4-point step - NPP = _7P_STEP * 6; // number of calibration points on the radius -enum CalEnum : char { // the 7 main calibration points - add definitions if needed + NPP = _7P_STEP * 6; // Number of calibration points on the radius +enum CalEnum : char { // The 7 main calibration points - add definitions if needed CEN = 0, __A = 1, _AB = __A + _7P_STEP, @@ -197,13 +197,13 @@ static bool probe_calibration_points(float z_pt[NPP + 1], const int8_t probe_poi if (!_0p_calibration) { - if (!_7p_no_intermediates && !_7p_4_intermediates && !_7p_11_intermediates) { // probe the center + if (!_7p_no_intermediates && !_7p_4_intermediates && !_7p_11_intermediates) { // Probe the center const xy_pos_t center{0}; z_pt[CEN] += calibration_probe(center, stow_after_each, probe_at_offset); if (isnan(z_pt[CEN])) return false; } - if (_7p_calibration) { // probe extra center points + if (_7p_calibration) { // Probe extra center points const float start = _7p_9_center ? float(_CA) + _7P_STEP / 3.0f : _7p_6_center ? float(_CA) : float(__C), steps = _7p_9_center ? _4P_STEP / 3.0f : _7p_6_center ? _7P_STEP : _4P_STEP; I_LOOP_CAL_PT(rad, start, steps) { @@ -216,7 +216,7 @@ static bool probe_calibration_points(float z_pt[NPP + 1], const int8_t probe_poi z_pt[CEN] /= float(_7p_2_intermediates ? 7 : probe_points); } - if (!_1p_calibration) { // probe the radius + if (!_1p_calibration) { // Probe the radius const CalEnum start = _4p_opposite_points ? _AB : __A; const float steps = _7p_14_intermediates ? _7P_STEP / 15.0f : // 15r * 6 + 10c = 100 _7p_11_intermediates ? _7P_STEP / 12.0f : // 12r * 6 + 9c = 81 @@ -254,10 +254,11 @@ static bool probe_calibration_points(float z_pt[NPP + 1], const int8_t probe_poi } /** - * kinematics routines and auto tune matrix scaling parameters: - * see https://github.com/LVD-AC/Marlin-AC/tree/1.1.x-AC/documentation for - * - formulae for approximative forward kinematics in the end-stop displacement matrix - * - definition of the matrix scaling parameters + * Kinematics routines and auto tune matrix scaling parameters + * + * NOTE: See https://github.com/LVD-AC/Marlin-AC/tree/1.1.x-AC/documentation for: + * - Formula for approximative forward kinematics in the end-stop displacement matrix + * - Definition of the matrix scaling parameters */ static void reverse_kinematics_probe_points(float z_pt[NPP + 1], abc_float_t mm_at_pt_axis[NPP + 1], const float dcr) { xyz_pos_t pos{0}; @@ -346,43 +347,43 @@ static float auto_tune_a(const float dcr) { } /** - * G33 - Delta '1-4-7-point' Auto-Calibration - * Calibrate height, z_offset, endstops, delta radius, and tower angles. + * G33: Delta Auto Calibration + * + * Calibrate height, z_offset, endstops, delta radius, and tower angles. * * Parameters: + * P Number of probe points: + * P0 Normalizes end-stops and tower angle corrections only (no probing) + * P1 Probe center and set height only + * P2 Probe center and towers. Set height, endstops, and delta radius + * P3 Probe all positions - center, towers and opposite towers. Set all + * P4-P10 Probe all positions with intermediate locations, averaging them * - * Pn Number of probe points: - * P0 Normalizes calibration. - * P1 Calibrates height only with center probe. - * P2 Probe center and towers. Calibrate height, endstops and delta radius. - * P3 Probe all positions: center, towers and opposite towers. Calibrate all. - * P4-P10 Probe all positions at different intermediate locations and average them. + * R Temporarily reduce the size of the probe grid by the specified amount * - * Rn.nn Temporary reduce the probe grid by the specified amount (mm) + * T Disable tower angle corrections calibration (P3-P7) * - * T Don't calibrate tower angle corrections + * C Calibration precision; if omitted iterations stop at best achievable precision * - * Cn.nn Calibration precision; when omitted calibrates to maximum precision + * F<1-30> Run (“force”) this number of iterations and take the best result * - * Fn Force to run at least n iterations and take the best result + * V Verbose level: + * V0 Dry-run mode. Report settings and probe results. No calibration + * V1 Report start and end settings only + * V2 Report settings at each iteration + * V3 Report settings and probe results * - * Vn Verbose level: - * V0 Dry-run mode. Report settings and probe results. No calibration. - * V1 Report start and end settings only - * V2 Report settings at each iteration - * V3 Report settings and probe results + * E Engage the probe for each point * - * E Engage the probe for each point + * O Probe at probe-offset-relative positions instead of the required kinematic points * - * O Probe at offsetted probe positions (this is wrong but it seems to work) - * - * With SENSORLESS_PROBING: - * Use these flags to calibrate stall sensitivity: (e.g., `G33 P1 Y Z` to calibrate X only.) - * X Don't activate stallguard on X. - * Y Don't activate stallguard on Y. - * Z Don't activate stallguard on Z. - * - * S Save offset_sensorless_adj + * With HAS_DELTA_SENSORLESS_PROBING: + * Use these flags to calibrate stall sensitivity: + * Example: G33 P1 Y Z - to calibrate X only + * X Don't activate stallguard on X + * Y Don't activate stallguard on Y + * Z Don't activate stallguard on Z + * S Save offset_sensorless_adj */ void GcodeSuite::G33() { @@ -481,11 +482,11 @@ void GcodeSuite::G33() { caltower({ false, true, false }); // B caltower({ false, false, true }); // C - probe.test_sensitivity = { true, true, true }; // reset to all + probe.test_sensitivity = { true, true, true }; // Reset to all } #endif - do { // start iterations + do { // Start iterations float z_at_pt[NPP + 1] = { 0.0f }; @@ -505,11 +506,11 @@ void GcodeSuite::G33() { if ((zero_std_dev < test_precision || iterations <= force_iterations) && zero_std_dev > calibration_precision) { #if !HAS_BED_PROBE - test_precision = 0.0f; // forced end + test_precision = 0.0f; // Forced end #endif if (zero_std_dev < zero_std_dev_min) { - // set roll-back point + // Set roll-back point e_old = delta_endstop_adj; r_old = delta_radius; h_old = delta_height; @@ -520,10 +521,11 @@ void GcodeSuite::G33() { float r_delta = 0.0f; /** - * convergence matrices: - * see https://github.com/LVD-AC/Marlin-AC/tree/1.1.x-AC/documentation for - * - definition of the matrix scaling parameters - * - matrices for 4 and 7 point calibration + * Convergence matrices + * + * NOTE: See https://github.com/LVD-AC/Marlin-AC/tree/1.1.x-AC/documentation for: + * - Definition of the matrix scaling parameters + * - Matrices for 4 and 7 point calibration */ #define ZP(N,I) ((N) * z_at_pt[I] / 4.0f) // 4.0 = divider to normalize to integers #define Z12(I) ZP(12, I) @@ -532,7 +534,7 @@ void GcodeSuite::G33() { #define Z1(I) ZP(1, I) #define Z0(I) ZP(0, I) - // calculate factors + // Calculate factors if (_7p_9_center) dcr *= 0.9f; h_factor = auto_tune_h(dcr); r_factor = auto_tune_r(dcr); @@ -541,22 +543,22 @@ void GcodeSuite::G33() { switch (probe_points) { case 0: - test_precision = 0.0f; // forced end + test_precision = 0.0f; // Forced end break; case 1: - test_precision = 0.0f; // forced end + test_precision = 0.0f; // Forced end LOOP_NUM_AXES(axis) e_delta[axis] = +Z4(CEN); break; case 2: - if (towers_set) { // see 4 point calibration (towers) matrix + if (towers_set) { // See 4 point calibration (towers) matrix e_delta.set((+Z4(__A) -Z2(__B) -Z2(__C)) * h_factor +Z4(CEN), (-Z2(__A) +Z4(__B) -Z2(__C)) * h_factor +Z4(CEN), (-Z2(__A) -Z2(__B) +Z4(__C)) * h_factor +Z4(CEN)); r_delta = (+Z4(__A) +Z4(__B) +Z4(__C) -Z12(CEN)) * r_factor; } - else { // see 4 point calibration (opposites) matrix + else { // See 4 point calibration (opposites) matrix e_delta.set((-Z4(_BC) +Z2(_CA) +Z2(_AB)) * h_factor +Z4(CEN), (+Z2(_BC) -Z4(_CA) +Z2(_AB)) * h_factor +Z4(CEN), (+Z2(_BC) +Z2(_CA) -Z4(_AB)) * h_factor +Z4(CEN)); @@ -564,13 +566,13 @@ void GcodeSuite::G33() { } break; - default: // see 7 point calibration (towers & opposites) matrix + default: // See 7 point calibration (towers & opposites) matrix e_delta.set((+Z2(__A) -Z1(__B) -Z1(__C) -Z2(_BC) +Z1(_CA) +Z1(_AB)) * h_factor +Z4(CEN), (-Z1(__A) +Z2(__B) -Z1(__C) +Z1(_BC) -Z2(_CA) +Z1(_AB)) * h_factor +Z4(CEN), (-Z1(__A) -Z1(__B) +Z2(__C) +Z1(_BC) +Z1(_CA) -Z2(_AB)) * h_factor +Z4(CEN)); r_delta = (+Z2(__A) +Z2(__B) +Z2(__C) +Z2(_BC) +Z2(_CA) +Z2(_AB) -Z12(CEN)) * r_factor; - if (towers_set) { // see 7 point tower angle calibration (towers & opposites) matrix + if (towers_set) { // See 7 point tower angle calibration (towers & opposites) matrix t_delta.set((+Z0(__A) -Z4(__B) +Z4(__C) +Z0(_BC) -Z4(_CA) +Z4(_AB) +Z0(CEN)) * a_factor, (+Z4(__A) +Z0(__B) -Z4(__C) +Z4(_BC) +Z0(_CA) -Z4(_AB) +Z0(CEN)) * a_factor, (-Z4(__A) +Z4(__B) +Z0(__C) -Z4(_BC) +Z4(_CA) +Z0(_AB) +Z0(CEN)) * a_factor); @@ -582,14 +584,14 @@ void GcodeSuite::G33() { delta_tower_angle_trim += t_delta; } else if (zero_std_dev >= test_precision) { - // roll back + // Roll back delta_endstop_adj = e_old; delta_radius = r_old; delta_height = h_old; delta_tower_angle_trim = a_old; } - if (verbose_level != 0) { // !dry run + if (verbose_level != 0) { // !Dry-run // Normalize angles to least-squares if (_angle_results) { @@ -620,7 +622,7 @@ void GcodeSuite::G33() { #endif } - if (verbose_level != 0) { // !dry run + if (verbose_level != 0) { // !Dry-run if ((zero_std_dev >= test_precision && iterations > force_iterations) || zero_std_dev <= calibration_precision) { // end iterations SERIAL_ECHOPGM("Calibration OK"); SERIAL_ECHO_SP(32); @@ -657,7 +659,7 @@ void GcodeSuite::G33() { print_calibration_settings(_endstop_results, _angle_results); } } - else { // dry run + else { // Dry-run FSTR_P const enddryrun = F("End DRY-RUN"); SERIAL_ECHO(enddryrun); SERIAL_ECHO_SP(35); diff --git a/Marlin/src/gcode/calibrate/G34.cpp b/Marlin/src/gcode/calibrate/G34.cpp index 0654eb0ec9..504dcd1c6f 100644 --- a/Marlin/src/gcode/calibrate/G34.cpp +++ b/Marlin/src/gcode/calibrate/G34.cpp @@ -40,7 +40,9 @@ #include "../../core/debug_out.h" /** - * G34 - Align the ends of the X gantry. See https://youtu.be/3jAFQdTk8iw + * G34: Mechanical Gantry Calibration + * + * Align the ends of the X gantry. See https://youtu.be/3jAFQdTk8iw * * - The carriage moves to GANTRY_CALIBRATION_SAFE_POSITION, also called the “pounce” position. * - If possible, the Z stepper current is reduced to the value specified by 'S' @@ -53,8 +55,8 @@ * - The machine is re-homed, according to GANTRY_CALIBRATION_COMMANDS_POST. * * Parameters: - * [S] - Current value to use for the raise move. (Default: GANTRY_CALIBRATION_CURRENT) - * [Z] - Extra distance past Z_MAX_POS to move the Z axis. (Default: GANTRY_CALIBRATION_EXTRA_HEIGHT) + * S Current value to use for the raise move. (Default: GANTRY_CALIBRATION_CURRENT) + * Z Extra distance past Z_MAX_POS to move the Z axis. (Default: GANTRY_CALIBRATION_EXTRA_HEIGHT) */ void GcodeSuite::G34() { diff --git a/Marlin/src/gcode/calibrate/G34_M422.cpp b/Marlin/src/gcode/calibrate/G34_M422.cpp index 41e5821450..9d8fd7b84b 100644 --- a/Marlin/src/gcode/calibrate/G34_M422.cpp +++ b/Marlin/src/gcode/calibrate/G34_M422.cpp @@ -56,23 +56,24 @@ #endif /** - * G34: Z-Stepper automatic alignment + * G34: Z Steppers Auto-Alignment * - * Manual stepper lock controls (reset by G28): - * L Unlock all steppers - * Z<1-4> Z stepper to lock / unlock - * S 0=UNLOCKED 1=LOCKED. If omitted, assume LOCKED. + * Parameters: + * Manual stepper lock controls (reset by G28): + * L Unlock all steppers + * Z Target specific Z stepper to lock/unlock (1-4) + * S Lock state; 0=UNLOCKED 1=LOCKED. If omitted, assume LOCKED * - * Examples: - * G34 Z1 ; Lock Z1 - * G34 L Z2 ; Unlock all, then lock Z2 - * G34 Z2 S0 ; Unlock Z2 + * With Z_STEPPER_AUTO_ALIGN: + * I Number of test iterations. If omitted, Z_STEPPER_ALIGN_ITERATIONS. (1-30) + * T Target Accuracy factor. If omitted, Z_STEPPER_ALIGN_ACC. (0.01-1.0) + * A Provide an Amplification value. If omitted, Z_STEPPER_ALIGN_AMP. (0.5-2.0) + * R Recalculate points based on current probe offsets * - * With Z_STEPPER_AUTO_ALIGN: - * I Number of tests. If omitted, Z_STEPPER_ALIGN_ITERATIONS. - * T Target Accuracy factor. If omitted, Z_STEPPER_ALIGN_ACC. - * A Provide an Amplification value. If omitted, Z_STEPPER_ALIGN_AMP. - * R Flag to recalculate points based on current probe offsets + * Example: + * G34 Z1 ; Lock Z1 + * G34 L Z2 ; Unlock all, then lock Z2 + * G34 Z2 S0 ; Unlock Z2 */ void GcodeSuite::G34() { diff --git a/Marlin/src/gcode/calibrate/G76_M871.cpp b/Marlin/src/gcode/calibrate/G76_M871.cpp index bb69b75d50..7051540e7b 100644 --- a/Marlin/src/gcode/calibrate/G76_M871.cpp +++ b/Marlin/src/gcode/calibrate/G76_M871.cpp @@ -38,47 +38,53 @@ #include "../../lcd/marlinui.h" /** - * G76: calibrate probe and/or bed temperature offsets - * Notes: - * - When calibrating probe, bed temperature is held constant. - * Compensation values are deltas to first probe measurement at probe temp. = 30°C. - * - When calibrating bed, probe temperature is held constant. - * Compensation values are deltas to first probe measurement at bed temp. = 60°C. - * - The hotend will not be heated at any time. - * - On my Průša MK3S clone I put a piece of paper between the probe and the hotend - * so the hotend fan would not cool my probe constantly. Alternatively you could just - * make sure the fan is not running while running the calibration process. + * G76: Probe Temperature Calibration * - * Probe calibration: - * - Moves probe to cooldown point. - * - Heats up bed to 100°C. - * - Moves probe to probing point (1mm above heatbed). - * - Waits until probe reaches target temperature (30°C). - * - Does a z-probing (=base value) and increases target temperature by 5°C. - * - Waits until probe reaches increased target temperature. - * - Does a z-probing (delta to base value will be a compensation value) and increases target temperature by 5°C. - * - Repeats last two steps until max. temperature reached or timeout (i.e. probe does not heat up any further). - * - Compensation values of higher temperatures will be extrapolated (using linear regression first). - * While this is not exact by any means it is still better than simply using the last compensation value. + * Calibrate probe and/or bed temperature offsets. * - * Bed calibration: - * - Moves probe to cooldown point. - * - Heats up bed to 60°C. - * - Moves probe to probing point (1mm above heatbed). - * - Waits until probe reaches target temperature (30°C). - * - Does a z-probing (=base value) and increases bed temperature by 5°C. - * - Moves probe to cooldown point. - * - Waits until probe is below 30°C and bed has reached target temperature. - * - Moves probe to probing point and waits until it reaches target temperature (30°C). - * - Does a z-probing (delta to base value will be a compensation value) and increases bed temperature by 5°C. - * - Repeats last four points until max. bed temperature reached (110°C) or timeout. - * - Compensation values of higher temperatures will be extrapolated (using linear regression first). - * While this is not exact by any means it is still better than simply using the last compensation value. + * Probe calibration: + * - Moves probe to cooldown point. + * - Heats up bed to 100°C. + * - Moves probe to probing point (1mm above heatbed). + * - Waits until probe reaches target temperature (30°C). + * - Does a z-probing (=base value) and increases target temperature by 5°C. + * - Waits until probe reaches increased target temperature. + * - Does a z-probing (delta to base value will be a compensation value) and increases target temperature by 5°C. + * - Repeats last two steps until max. temperature reached or timeout (i.e. probe does not heat up any further). + * - Compensation values of higher temperatures will be extrapolated (using linear regression first). + * While this is not exact by any means it is still better than simply using the last compensation value. * - * G76 [B | P] - * - no flag - Both calibration procedures will be run. - * - `B` - Run bed temperature calibration. - * - `P` - Run probe temperature calibration. + * Bed calibration: + * - Moves probe to cooldown point. + * - Heats up bed to 60°C. + * - Moves probe to probing point (1mm above heatbed). + * - Waits until probe reaches target temperature (30°C). + * - Does a z-probing (=base value) and increases bed temperature by 5°C. + * - Moves probe to cooldown point. + * - Waits until probe is below 30°C and bed has reached target temperature. + * - Moves probe to probing point and waits until it reaches target temperature (30°C). + * - Does a z-probing (delta to base value will be a compensation value) and increases bed temperature by 5°C. + * - Repeats last four points until max. bed temperature reached (110°C) or timeout. + * - Compensation values of higher temperatures will be extrapolated (using linear regression first). + * While this is not exact by any means it is still better than simply using the last compensation value. + * + * Usage: + * G76 [ B | P ] + * + * Parameters: + * None Run Both calibration procedures + * B Calibrate bed only + * P Calibrate probe only + * + * NOTES: + * - When calibrating probe, bed temperature is held constant. + * Compensation values are deltas to first probe measurement at probe temp. = 30°C. + * - When calibrating bed, probe temperature is held constant. + * Compensation values are deltas to first probe measurement at bed temp. = 60°C. + * - The hotend will not be heated at any time. + * - On my Průša MK3S clone I put a piece of paper between the probe and the hotend + * so the hotend fan would not cool my probe constantly. Alternatively you could just + * make sure the fan is not running while running the calibration process. */ #if ALL(PTC_PROBE, PTC_BED) @@ -291,22 +297,26 @@ #endif // PTC_PROBE && PTC_BED /** - * M871: Report / reset temperature compensation offsets. - * Note: This does not affect values in EEPROM until M500. + * M871: Probe Temperature Config * + * Report / reset temperature compensation offsets. + * NOTE: This does not affect values in EEPROM until M500. + * + * Usage: * M871 [ R | B | P | E ] * - * No Parameters - Print current offset values. + * Parameters: + * None Print current offset values * - * Select only one of these flags: - * R - Reset all offsets to zero (i.e., disable compensation). - * B - Manually set offset for bed - * P - Manually set offset for probe - * E - Manually set offset for extruder + * Select only one of these flags: + * R Reset all offsets to zero (i.e., disable compensation) + * B Manually set offset for bed + * P Manually set offset for probe + * E Manually set offset for extruder * - * With B, P, or E: - * I[index] - Index in the array - * V[value] - Adjustment in µm + * With B, P, or E: + * I Index in the array + * V Adjustment in µm */ void GcodeSuite::M871() { diff --git a/Marlin/src/gcode/calibrate/M100.cpp b/Marlin/src/gcode/calibrate/M100.cpp index 93045e955c..ddfed4afe1 100644 --- a/Marlin/src/gcode/calibrate/M100.cpp +++ b/Marlin/src/gcode/calibrate/M100.cpp @@ -31,32 +31,32 @@ #include "../../MarlinCore.h" // for idle() /** - * M100 Free Memory Watcher + * M100: Free Memory Watcher * * This code watches the free memory block between the bottom of the heap and the top of the stack. * This memory block is initialized and watched via the M100 command. * - * M100 I Initializes the free memory block and prints vitals statistics about the area + * Parameters: + * I Initializes the free memory block and prints vitals statistics about the area * - * M100 F Identifies how much of the free memory block remains free and unused. It also - * detects and reports any corruption within the free memory block that may have - * happened due to errant firmware. + * F Identifies how much of the free memory block remains free and unused. It also + * detects and reports any corruption within the free memory block that may have + * happened due to errant firmware. * - * M100 D Does a hex display of the free memory block along with a flag for any errant - * data that does not match the expected value. + * D Does a hex display of the free memory block along with a flag for any errant + * data that does not match the expected value. * - * M100 C x Corrupts x locations within the free memory block. This is useful to check the - * correctness of the M100 F and M100 D commands. + * C x Corrupts x locations within the free memory block. This is useful to check the + * correctness of the M100 F and M100 D commands. * * Also, there are two support functions that can be called from a developer's C code. - * - * uint16_t check_for_free_memory_corruption(PGM_P const free_memory_start); - * void M100_dump_routine(FSTR_P const title, const char * const start, const uintptr_t size); + * uint16_t check_for_free_memory_corruption(PGM_P const free_memory_start); + * void M100_dump_routine(FSTR_P const title, const char * const start, const uintptr_t size); * * Initial version by Roxy-3D */ -#define M100_FREE_MEMORY_DUMPER // Enable for the `M100 D` Dump sub-command -#define M100_FREE_MEMORY_CORRUPTOR // Enable for the `M100 C` Corrupt sub-command +#define M100_FREE_MEMORY_DUMPER // Enable for the 'M100 D' Dump sub-command +#define M100_FREE_MEMORY_CORRUPTOR // Enable for the 'M100 C' Corrupt sub-command #define TEST_BYTE ((char) 0xE5) diff --git a/Marlin/src/gcode/calibrate/M666.cpp b/Marlin/src/gcode/calibrate/M666.cpp index 4186290154..2584782cf3 100644 --- a/Marlin/src/gcode/calibrate/M666.cpp +++ b/Marlin/src/gcode/calibrate/M666.cpp @@ -39,7 +39,15 @@ #if ENABLED(DELTA) /** - * M666: Set delta endstop adjustment + * M666: Set Delta endstop adjustments + * + * Adjust the endstop offsets on a Delta printer. + * + * Parameters: + * None Report current offsets + * X Adjustment for the X actuator endstop + * Y Adjustment for the Y actuator endstop + * Z Adjustment for the Z actuator endstop */ void GcodeSuite::M666() { DEBUG_SECTION(log_M666, "M666", DEBUGGING(LEVELING)); @@ -74,14 +82,22 @@ #else /** - * M666: Set Dual Endstops offsets for X, Y, and/or Z. - * With no parameters report current offsets. + * M666: Set Dual Endstop Offsets * - * For Triple / Quad Z Endstops: - * Set Z2 Only: M666 S2 Z - * Set Z3 Only: M666 S3 Z - * Set Z4 Only: M666 S4 Z - * Set All: M666 Z + * Adjust the offsets for dual (or multiple) endstops. + * + * Parameters: + * None Report current offsets + * X Offset for the X axis endstops + * Y Offset for the Y axis endstops + * Z Offset for the Z axis endstops + * + * Example: + * For Triple / Quad Z Endstops: + * M666 S2 Z ; Set Z2 Only + * M666 S3 Z ; Set Z3 Only + * M666 S4 Z ; Set Z4 Only + * M666 Z ; Set All */ void GcodeSuite::M666() { if (!parser.seen_any()) return M666_report(); diff --git a/Marlin/src/gcode/calibrate/M852.cpp b/Marlin/src/gcode/calibrate/M852.cpp index 001160ae72..7cd9aaf718 100644 --- a/Marlin/src/gcode/calibrate/M852.cpp +++ b/Marlin/src/gcode/calibrate/M852.cpp @@ -28,12 +28,16 @@ #include "../../module/planner.h" /** - * M852: Get or set the machine skew factors. Reports current values with no arguments. + * M852: Bed Skew Compensation * - * S[xy_factor] - Alias for 'I' - * I[xy_factor] - New XY skew factor - * J[xz_factor] - New XZ skew factor - * K[yz_factor] - New YZ skew factor + * Get or set the machine skew factors; correct for misalignment + * + * Parameters: + * None Report current values + * S Alias for 'I' + * I New XY skew factor + * J New XZ skew factor + * K New YZ skew factor */ void GcodeSuite::M852() { if (!parser.seen("SIJK")) return M852_report(); diff --git a/Marlin/src/gcode/config/M220.cpp b/Marlin/src/gcode/config/M220.cpp index 6797df25d5..0d1e204800 100644 --- a/Marlin/src/gcode/config/M220.cpp +++ b/Marlin/src/gcode/config/M220.cpp @@ -24,16 +24,15 @@ #include "../../module/motion.h" /** - * M220: Set speed percentage factor, aka "Feed Rate" + * M220: Set Feedrate Percentage * - * Parameters - * S : Set the feed rate percentage factor + * Parameters: + * None Report the current speed percentage factor + * S Set the feed rate percentage factor * - * Report the current speed percentage factor if no parameter is specified - * - * For MMU2 and MMU2S devices... - * B : Flag to back up the current factor - * R : Flag to restore the last-saved factor + * For MMU2 and MMU2S devices: + * B Back up the current factor + * R Restore the last-saved factor */ void GcodeSuite::M220() { if (!parser.seen_any()) { diff --git a/Marlin/src/gcode/config/M301.cpp b/Marlin/src/gcode/config/M301.cpp index fe0eef772f..a47c03a8d4 100644 --- a/Marlin/src/gcode/config/M301.cpp +++ b/Marlin/src/gcode/config/M301.cpp @@ -28,22 +28,22 @@ #include "../../module/temperature.h" /** - * M301: Set PID parameters P I D (and optionally C, L) + * M301: Set Hotend PID * - * E[extruder] Default: 0 + * Set PID parameters P I D (and optionally C, L) * - * P[float] Kp term - * I[float] Ki term (unscaled) - * D[float] Kd term (unscaled) + * Parameters: + * E Default: 0 + * P Kp term + * I Ki term (unscaled) + * D Kd term (unscaled) * - * With PID_EXTRUSION_SCALING: + * With PID_EXTRUSION_SCALING: + * C Kc term + * L LPQ length * - * C[float] Kc term - * L[int] LPQ length - * - * With PID_FAN_SCALING: - * - * F[float] Kf term + * With PID_FAN_SCALING: + * F Kf term */ void GcodeSuite::M301() { // multi-extruder PID patch: M301 updates or prints a single extruder's PID values diff --git a/Marlin/src/gcode/control/M42.cpp b/Marlin/src/gcode/control/M42.cpp index b995f208f5..4ac7834f90 100644 --- a/Marlin/src/gcode/control/M42.cpp +++ b/Marlin/src/gcode/control/M42.cpp @@ -46,15 +46,16 @@ void protected_pin_err() { /** * M42: Change pin status via G-Code * - * P Pin number (LED if omitted) - * For LPC1768 specify pin P1_02 as M42 P102, - * P1_20 as M42 P120, etc. + * Parameters: + * P Pin number (LED if omitted) + * For LPC1768 specify pin P1_02 as M42 P102, + * P1_20 as M42 P120, etc. * - * S Pin status from 0 - 255 - * I Flag to ignore Marlin's pin protection + * S Pin status from 0-255 + * I Flag to ignore Marlin's pin protection * - * T Pin mode: 0=INPUT 1=OUTPUT 2=INPUT_PULLUP 3=INPUT_PULLDOWN - * 4=INPUT_ANALOG 5=OUTPUT_OPEN_DRAIN + * T Pin mode: 0=INPUT | 1=OUTPUT | 2=INPUT_PULLUP | 3=INPUT_PULLDOWN + * 4=INPUT_ANALOG | 5=OUTPUT_OPEN_DRAIN */ void GcodeSuite::M42() { const int pin_index = PARSED_PIN_INDEX('P', GET_PIN_MAP_INDEX(LED_PIN)); diff --git a/Marlin/src/gcode/control/M605.cpp b/Marlin/src/gcode/control/M605.cpp index 4679422dfb..bf5549262d 100644 --- a/Marlin/src/gcode/control/M605.cpp +++ b/Marlin/src/gcode/control/M605.cpp @@ -155,13 +155,16 @@ #elif ENABLED(MULTI_NOZZLE_DUPLICATION) /** - * M605: Set multi-nozzle duplication mode + * M605: Multi Nozzle Mode * - * S2 - Enable duplication mode - * P[mask] - Bit-mask of nozzles to include in the duplication set. - * A value of 0 disables duplication. - * E[index] - Last nozzle index to include in the duplication set. - * A value of 0 disables duplication. + * Set multi-nozzle duplication mode. + * + * Parameters: + * S2 Enable duplication mode + * P Bit-mask of nozzles to include in the duplication set + * A value of 0 disables duplication + * E Last nozzle index to include in the duplication set + * A value of 0 disables duplication */ void GcodeSuite::M605() { bool ena = false; diff --git a/Marlin/src/gcode/control/T.cpp b/Marlin/src/gcode/control/T.cpp index ce6428950e..d5affa37e2 100644 --- a/Marlin/src/gcode/control/T.cpp +++ b/Marlin/src/gcode/control/T.cpp @@ -43,14 +43,15 @@ /** * T0-T: Switch tool, usually switching extruders * - * F[units/min] Set the movement feedrate - * S1 Don't move the tool in XY after change + * Parameters: + * F Set the movement feedrate + * S1 Don't move the tool in XY after change * - * For PRUSA_MMU2(S) and EXTENDABLE_EMU_MMU2(S) - * T[n] G-code to extrude at least 38.10 mm at feedrate 19.02 mm/s must follow immediately to load to extruder wheels. - * T? G-code to extrude shouldn't have to follow. Load to extruder wheels is done automatically. - * Tx Same as T?, but nozzle doesn't have to be preheated. Tc requires a preheated nozzle to finish filament load. - * Tc Load to nozzle after filament was prepared by Tc and nozzle is already heated. + * For PRUSA_MMU2(S) and EXTENDABLE_EMU_MMU2(S) + * T G-code to extrude at least 38.10 mm at feedrate 19.02 mm/s must follow immediately to load to extruder wheels. + * T? G-code to extrude shouldn't have to follow. Load to extruder wheels is done automatically. + * Tx Same as T?, but nozzle doesn't have to be preheated. Tc requires a preheated nozzle to finish filament load. + * Tc Load to nozzle after filament was prepared by Tc and nozzle is already heated. */ void GcodeSuite::T(const int8_t tool_index) { diff --git a/Marlin/src/gcode/feature/mixing/M163-M165.cpp b/Marlin/src/gcode/feature/mixing/M163-M165.cpp index f4ea52df0a..f2fc12faab 100644 --- a/Marlin/src/gcode/feature/mixing/M163-M165.cpp +++ b/Marlin/src/gcode/feature/mixing/M163-M165.cpp @@ -28,12 +28,15 @@ #include "../../../feature/mixing.h" /** - * M163: Set a single mix factor for a mixing extruder - * This is called "weight" by some systems. - * Must be followed by M164 to normalize and commit them. + * M163: Set Mix Factor * - * S[index] The channel index to set - * P[float] The mix value + * Set a single mix factor for a mixing extruder + * This is called "weight" by some systems. + * Must be followed by M164 to normalize and commit them. + * + * Parameters: + * S The channel index to set + * P The mix value */ void GcodeSuite::M163() { const int mix_index = parser.intval('S'); @@ -42,10 +45,13 @@ void GcodeSuite::M163() { } /** - * M164: Normalize and commit the mix. + * M164: Save Mix * - * S[index] The virtual tool to store - * If 'S' is omitted update the active virtual tool. + * Normalize and commit the mix. + * + * Parameters: + * S The virtual tool to store + * If 'S' is omitted update the active virtual tool. */ void GcodeSuite::M164() { #if MIXING_VIRTUAL_TOOLS > 1 @@ -64,16 +70,19 @@ void GcodeSuite::M164() { #if ENABLED(DIRECT_MIXING_IN_G1) /** - * M165: Set multiple mix factors for a mixing extruder. - * Omitted factors will be set to 0. - * The mix is normalized and stored in the current virtual tool. + * M165: Set Mix * - * A[factor] Mix factor for extruder stepper 1 - * B[factor] Mix factor for extruder stepper 2 - * C[factor] Mix factor for extruder stepper 3 - * D[factor] Mix factor for extruder stepper 4 - * H[factor] Mix factor for extruder stepper 5 - * I[factor] Mix factor for extruder stepper 6 + * Set multiple mix factors for a mixing extruder. + * Omitted factors will be set to 0. + * The mix is normalized and stored in the current virtual tool. + * + * Parameters: + * A Mix factor for extruder stepper 1 + * B Mix factor for extruder stepper 2 + * C Mix factor for extruder stepper 3 + * D Mix factor for extruder stepper 4 + * H Mix factor for extruder stepper 5 + * I Mix factor for extruder stepper 6 */ void GcodeSuite::M165() { // Get mixing parameters from the G-Code diff --git a/Marlin/src/gcode/feature/mixing/M166.cpp b/Marlin/src/gcode/feature/mixing/M166.cpp index 29411f2122..39fa4ac734 100644 --- a/Marlin/src/gcode/feature/mixing/M166.cpp +++ b/Marlin/src/gcode/feature/mixing/M166.cpp @@ -40,19 +40,23 @@ inline void echo_zt(const int t, const_float_t z) { } /** - * M166: Set a simple gradient mix for a two-component mixer - * based on the Geeetech A10M implementation by Jone Liu. + * M166: Gradient Mix * - * S[bool] - Enable / disable gradients - * A[float] - Starting Z for the gradient - * Z[float] - Ending Z for the gradient. (Must be greater than the starting Z.) - * I[index] - V-Tool to use as the starting mix. - * J[index] - V-Tool to use as the ending mix. + * Set a simple gradient mix for a two-component mixer + * based on the Geeetech A10M implementation by Jone Liu. * - * T[index] - A V-Tool index to use as an alias for the Gradient (Requires GRADIENT_VTOOL) - * T with no index clears the setting. Note: This can match the I or J value. + * Parameters: + * S Enable / disable gradients + * A Starting Z for the gradient + * Z Ending Z for the gradient. (Must be greater than the starting Z.) + * I V-Tool to use as the starting mix + * J V-Tool to use as the ending mix + * T A V-Tool index to use as an alias for the Gradient (Requires GRADIENT_VTOOL) + * T T with no index clears the setting + * NOTE: This can match the I or J value. * - * Example: M166 S1 A0 Z20 I0 J1 + * Example: + * M166 S1 A0 Z20 I0 J1 */ void GcodeSuite::M166() { if (parser.seenval('A')) mixer.gradient.start_z = parser.value_float(); diff --git a/Marlin/src/gcode/feature/power_monitor/M430.cpp b/Marlin/src/gcode/feature/power_monitor/M430.cpp index 0f3bb40914..6bbb475a7d 100644 --- a/Marlin/src/gcode/feature/power_monitor/M430.cpp +++ b/Marlin/src/gcode/feature/power_monitor/M430.cpp @@ -29,12 +29,15 @@ #include "../../gcode.h" /** - * M430: Enable/disable current LCD display - * With no parameters report the system current draw (in Amps) + * M430: Power Monitor * - * I[bool] - Set Display of current on the LCD - * V[bool] - Set Display of voltage on the LCD - * W[bool] - Set Display of power on the LCD + * Enable/disable power monitor on LCD display. + * + * Parameters: + * None Report the system current draw in Amps/Volts/Watts + * I Display current (A) on the LCD + * V Display voltage (V) on the LCD + * W Display power/watts (W) on the LCD */ void GcodeSuite::M430() { bool do_report = true; diff --git a/Marlin/src/gcode/feature/powerloss/M413.cpp b/Marlin/src/gcode/feature/powerloss/M413.cpp index 68cdc01668..fe26c04752 100644 --- a/Marlin/src/gcode/feature/powerloss/M413.cpp +++ b/Marlin/src/gcode/feature/powerloss/M413.cpp @@ -30,14 +30,17 @@ #include "../../../lcd/marlinui.h" /** - * M413: Enable / Disable power-loss recovery + * M413: Power-loss Recovery + * + * Enable/Disable power-loss recovery * * Parameters - * S[bool] - Flag to enable / disable. - * If omitted, report current state. + * None Report power-loss recovery state + * S Flag to enable/disable + * If omitted, report current state. * * With PLR_BED_THRESHOLD: - * B Bed Temperature above which recovery will proceed without asking permission. + * B Bed Temperature above which recovery will proceed without asking permission. */ void GcodeSuite::M413() { diff --git a/Marlin/src/gcode/feature/prusa_MMU2/M704-M709.cpp b/Marlin/src/gcode/feature/prusa_MMU2/M704-M709.cpp index 19aea31ff1..ef248902fd 100644 --- a/Marlin/src/gcode/feature/prusa_MMU2/M704-M709.cpp +++ b/Marlin/src/gcode/feature/prusa_MMU2/M704-M709.cpp @@ -49,59 +49,57 @@ static void gcodes_M704_M705_M706(uint16_t gcode) { } /** - * ### M704 - Preload to MMU - * #### Usage + * M704: Preload to MMU * + * Usage: * M704 [ P ] * - * #### Parameters - * - `P` - n index of slot (zero based, so 0-4 like T0 and T4) + * Parameters: + * P Index of slot (zero based, 0-4, i.e., T0 and T4) */ void GcodeSuite::M704() { gcodes_M704_M705_M706(704); } /** - * ### M705 - Eject filament - * #### Usage + * M705: Eject Filament * + * Usage: * M705 [ P ] * - * #### Parameters - * - `P` - n index of slot (zero based, so 0-4 like T0 and T4) + * Parameters: + * P Index of slot (zero based, 0-4, i.e., T0 and T4) */ void GcodeSuite::M705() { gcodes_M704_M705_M706(705); } -/*! - * ### M706 - Cut filament - * #### Usage +/** + * M706: Cut Filament * + * Usage: * M706 [ P ] * - * #### Parameters - * - `P` - n index of slot (zero based, so 0-4 like T0 and T4) + * Parameters: + * P Index of slot (zero based, 0-4, i.e., T0 and T4) */ void GcodeSuite::M706() { gcodes_M704_M705_M706(706); } /** - * ### M707 - Read from MMU register - * #### Usage + * M707: Read from MMU Register * + * Usage: * M707 [ A ] * - * #### Parameters - * - `A` - Address of register in hexidecimal. + * Parameters: + * A Address of register in hexidecimal * - * #### Example - * - * M707 A0x1b - Read a 8bit integer from register 0x1b and prints the result onto the serial line. + * Example: + * M707 A0x1b - Read a 8bit integer from register 0x1b and prints the result onto the serial line. * * Does nothing if the A parameter is not present or if MMU is not enabled. - * */ void GcodeSuite::M707() { if (mmu3.enabled() && parser.seenval('A')) { @@ -111,17 +109,17 @@ void GcodeSuite::M707() { } /** - * ### M708 - Write to MMU register - * #### Usage + * M708: Write to MMU Register * + * Usage: * M708 [ A | X ] * - * #### Parameters - * - `A` - Address of register in hexidecimal. - * - `X` - Data to write (16-bit integer). Default value 0. + * Parameters: + * A Address of register in hexidecimal + * X Data to write (16-bit integer). Default value 0 * - * #### Example - * M708 A0x1b X05 - Write to register 0x1b the value 05. + * Example: + * M708 A0x1b X05 - Write to register 0x1b the value 05. * * Does nothing if A parameter is missing or if MMU is not enabled. */ @@ -137,27 +135,26 @@ void GcodeSuite::M708() { } /** - * ### M709 - MMU power & reset - * The MK3S cannot not power off the MMU, but we can en- and disable the MMU. + * M709: MMU Power & Reset * + * The MK3S cannot not power off the MMU, but we can enable/disable the MMU. * The new state of the MMU is stored in printer's EEPROM. - * i.e., If you disable the MMU via M709, it will not be activated after the printer resets. - * Usage + * (i.e., If you disable the MMU via M709, it will not be activated after the printer resets.) * + * Usage: * M709 [ S | X ] * - * Parameters - * - `X` - Reset MMU (0:soft reset | 1:hardware reset | 42: erase MMU eeprom) - * - `S` - En-/disable the MMU (0:off | 1:on) + * Parameters: + * X Reset MMU (0:soft reset | 1:hardware reset | 42: erase MMU eeprom) + * S Enable/Disable the MMU (1=ON | 0=OFF) * - * Examples - * - * M709 X0 ; issue an X0 command via communication into the MMU (soft reset) - * M709 X1 ; toggle the MMU's reset pin (hardware reset) - * M709 X42 ; erase MMU EEPROM - * M709 S1 ; enable MMU - * M709 S0 ; disable MMU - * M709 ; Serial message if en- or disabled + * Examples: + * M709 X0 ; Issue an X0 command via communication into the MMU (soft reset) + * M709 X1 ; Toggle the MMU's reset pin (hardware reset) + * M709 X42 ; Erase MMU EEPROM + * M709 S1 ; Enable MMU + * M709 S0 ; Disable MMU + * M709 ; Serial message if enabled/disabled */ void GcodeSuite::M709() { if (parser.seenval('S')) { diff --git a/Marlin/src/gcode/gcode.h b/Marlin/src/gcode/gcode.h index 61782d7d3d..0e5d8f5681 100644 --- a/Marlin/src/gcode/gcode.h +++ b/Marlin/src/gcode/gcode.h @@ -65,7 +65,7 @@ * G38 - Probe in any direction using the Z_MIN_PROBE (Requires G38_PROBE_TARGET) * G42 - Coordinated move to a mesh point (Requires MESH_BED_LEVELING, AUTO_BED_LEVELING_BLINEAR, or AUTO_BED_LEVELING_UBL) * G60 - Save current position. (Requires SAVED_POSITIONS) - * G61 - Apply/restore saved coordinates. (Requires SAVED_POSITIONS) + * G61 - Apply/Restore saved coordinates. (Requires SAVED_POSITIONS) * G76 - Calibrate first layer temperature offsets. (Requires PTC_PROBE and PTC_BED) * G80 - Cancel current motion mode (Requires GCODE_MOTION_MODES) * G90 - Use Absolute Coordinates @@ -91,12 +91,12 @@ * *** Print from Media (SDSUPPORT) *** * M20 - List SD card. (Requires SDSUPPORT) - * M21 - Init SD card. (Requires SDSUPPORT) With MULTI_VOLUME select a drive with `M21 Pn` / 'M21 S' / 'M21 U'. + * M21 - Init SD card. (Requires SDSUPPORT) With MULTI_VOLUME select a drive with 'M21 Pn' / 'M21 S' / 'M21 U'. * M22 - Release SD card. (Requires SDSUPPORT) * M23 - Select SD file: "M23 /path/file.gco". (Requires SDSUPPORT) - * M24 - Start/resume SD print. (Requires SDSUPPORT) + * M24 - Start/Resume SD print. (Requires SDSUPPORT) * M25 - Pause SD print. (Requires SDSUPPORT) - * M26 - Set SD position in bytes: "M26 S12345". (Requires SDSUPPORT) + * M26 - Set SD position in bytes: 'M26 S12345'. (Requires SDSUPPORT) * M27 - Report SD print status. (Requires SDSUPPORT) * OR, with 'S' set the SD status auto-report interval. (Requires AUTO_REPORT_SD_STATUS) * OR, with 'C' get the current filename. @@ -104,8 +104,8 @@ * M29 - Stop SD write. (Requires SDSUPPORT) * M30 - Delete file from SD: "M30 /path/file.gco" (Requires SDSUPPORT) * M31 - Report time since last M109 or SD card start to serial. - * M32 - Select file and start SD print: "M32 [S] !/path/file.gco#". (Requires SDSUPPORT) - * Use P to run other files as sub-programs: "M32 P !filename#" + * M32 - Select file and start SD print: 'M32 [S] !/path/file.gco#'. (Requires SDSUPPORT) + * Use P to run other files as sub-programs: 'M32 P !filename#' * The '#' is necessary when calling from within sd files, as it stops buffer prereading * M33 - Get the longname version of a path. (Requires LONG_FILENAME_HOST_SUPPORT) * M34 - Set SD Card sorting options. (Requires SDCARD_SORT_ALPHA) @@ -145,11 +145,11 @@ * R Wait for extruder current temp to reach target temp. ** Wait for heating or cooling. ** * If AUTOTEMP is enabled, S B F. Exit autotemp by any M109 without F * - * M110 - Get or set the current line number. (Used by host printing) - * M111 - Set debug flags: "M111 S". See flag bits defined in enum.h. + * M110 - Set / Report the current line number. (Used by host printing) + * M111 - Set debug flags: 'M111 S'. See flag bits defined in enum.h. * M112 - Full Shutdown. * - * M113 - Get or set the timeout interval for Host Keepalive "busy" messages. (Requires HOST_KEEPALIVE_FEATURE) + * M113 - Set / Report the timeout interval for Host Keepalive "busy" messages. (Requires HOST_KEEPALIVE_FEATURE) * M114 - Report current position. * M115 - Report capabilities. (Requires CAPABILITIES_REPORT) * M117 - Display a message on the controller screen. (Requires an LCD) @@ -184,9 +184,9 @@ * M192 - Wait for probe to reach target temperature. (Requires TEMP_SENSOR_PROBE) * M193 - R Wait for cooler to reach target temp. ** Wait for cooling. ** * M200 - Set filament diameter, D, setting E axis units to cubic. (Use S0 to revert to linear units.) - * M201 - Set max acceleration in units/s^2 for print moves: "M201 X Y Z E" - * M202 - Set max acceleration in units/s^2 for travel moves: "M202 X Y Z E" ** UNUSED IN MARLIN! ** - * M203 - Set maximum feedrate: "M203 X Y Z E" in units/sec. + * M201 - Set max acceleration in units/s^2 for print moves: 'M201 X Y Z E' + * M202 - Set max acceleration in units/s^2 for travel moves: 'M202 X Y Z E' ** UNUSED IN MARLIN! ** + * M203 - Set maximum feedrate: 'M203 X Y Z E' in units/sec. * M204 - Set default acceleration in units/sec^2: P R T * M205 - Set advanced settings. Current units apply: S T minimum speeds @@ -197,23 +197,23 @@ * M208 - Set Recover (unretract) Additional (!) Length: S and Feedrate: F. (Requires FWRETRACT) * M209 - Turn Automatic Retract Detection on/off: S<0|1> (For slicers that don't support G10/11). (Requires FWRETRACT_AUTORETRACT) Every normal extrude-only move will be classified as retract depending on the direction. - * M210 - Set or Report the homing feedrate (Requires EDITABLE_HOMING_FEEDRATE) + * M210 - Set / Report the homing feedrate (Requires EDITABLE_HOMING_FEEDRATE) * M211 - Enable, Disable, and/or Report software endstops: S<0|1> (Requires MIN_SOFTWARE_ENDSTOPS or MAX_SOFTWARE_ENDSTOPS) - * M217 - Set filament swap parameters: "M217 S P R". (Requires SINGLENOZZLE) - * M218 - Set/get a tool offset: "M218 T X Y". (Requires 2 or more extruders) - * M220 - Set Feedrate Percentage: "M220 S" (i.e., "FR" on the LCD) - * Use "M220 B" to back up the Feedrate Percentage and "M220 R" to restore it. (Requires an MMU_MODEL version 2 or 2S) - * M221 - Set Flow Percentage: "M221 S" (Requires an extruder) - * M226 - Wait until a pin is in a given state: "M226 P S" (Requires DIRECT_PIN_CONTROL) + * M217 - Set filament swap parameters: 'M217 S P R'. (Requires SINGLENOZZLE) + * M218 - Set / Report a tool offset: 'M218 T X Y'. (Requires 2 or more extruders) + * M220 - Set Feedrate Percentage: 'M220 S' (i.e., "FR" on the LCD) + * Use 'M220 B' to back up the Feedrate Percentage and 'M220 R' to restore it. (Requires an MMU_MODEL version 2 or 2S) + * M221 - Set Flow Percentage: 'M221 S' (Requires an extruder) + * M226 - Wait until a pin is in a given state: 'M226 P S' (Requires DIRECT_PIN_CONTROL) * M240 - Trigger a camera to take a photograph. (Requires PHOTO_GCODE) - * M250 - Set LCD contrast: "M250 C" (0-63). (Requires LCD support) - * M255 - Set LCD sleep time: "M255 S" (0-99). (Requires an LCD with brightness or sleep/wake) - * M256 - Set LCD brightness: "M256 B" (0-255). (Requires an LCD with brightness control) + * M250 - Set LCD contrast: 'M250 C' (0-63). (Requires LCD support) + * M255 - Set LCD sleep time: 'M255 S' (0-99). (Requires an LCD with brightness or sleep/wake) + * M256 - Set LCD brightness: 'M256 B' (0-255). (Requires an LCD with brightness control) * M260 - i2c Send Data (Requires EXPERIMENTAL_I2CBUS) * M261 - i2c Request Data (Requires EXPERIMENTAL_I2CBUS) - * M280 - Set servo position absolute: "M280 P S". (Requires servos) - * M281 - Set servo min|max position: "M281 P L U". (Requires EDITABLE_SERVO_ANGLES) - * M282 - Detach servo: "M282 P". (Requires SERVO_DETACH_GCODE) + * M280 - Set servo position absolute: 'M280 P S'. (Requires servos) + * M281 - Set servo min|max position: 'M281 P L U'. (Requires EDITABLE_SERVO_ANGLES) + * M282 - Detach servo: 'M282 P'. (Requires SERVO_DETACH_GCODE) * M290 - Babystepping (Requires BABYSTEPPING) * M293 - Babystep Z UP (Requires EP_BABYSTEPPING) * M294 - Babystep Z DOWN (Requires EP_BABYSTEPPING) @@ -234,13 +234,13 @@ * M401 - Deploy and activate Z probe. (Requires a probe) * M402 - Deactivate and stow Z probe. (Requires a probe) * M403 - Set filament type for PRUSA MMU2 - * M404 - Display or set the Nominal Filament Width: "W". (Requires FILAMENT_WIDTH_SENSOR) - * M405 - Enable Filament Sensor flow control. "M405 D". (Requires FILAMENT_WIDTH_SENSOR) + * M404 - Set / Report the Nominal Filament Width: 'W'. (Requires FILAMENT_WIDTH_SENSOR) + * M405 - Enable Filament Sensor flow control. 'M405 D'. (Requires FILAMENT_WIDTH_SENSOR) * M406 - Disable Filament Sensor flow control. (Requires FILAMENT_WIDTH_SENSOR) * M407 - Display measured filament diameter in millimeters. (Requires FILAMENT_WIDTH_SENSOR) * M410 - Quickstop. Abort all planned moves. - * M412 - Enable / Disable Filament Runout Detection. (Requires FILAMENT_RUNOUT_SENSOR) - * M413 - Enable / Disable Power-Loss Recovery. (Requires POWER_LOSS_RECOVERY) + * M412 - Enable/Disable Filament Runout Detection. (Requires FILAMENT_RUNOUT_SENSOR) + * M413 - Enable/Disable Power-Loss Recovery. (Requires POWER_LOSS_RECOVERY) * M414 - Set language by index. (Requires LCD_LANGUAGE_2...) * M420 - Enable/Disable Leveling (with current values) S1=enable S0=disable (Requires MESH_BED_LEVELING or ABL) * M421 - Set a single Z coordinate in the Mesh Leveling grid. X Y Z (Requires MESH_BED_LEVELING, AUTO_BED_LEVELING_BILINEAR, or AUTO_BED_LEVELING_UBL) @@ -250,32 +250,32 @@ * M430 - Read the system current, voltage, and power (Requires POWER_MONITOR_CURRENT, POWER_MONITOR_VOLTAGE, or POWER_MONITOR_FIXED_VOLTAGE) * M485 - Send RS485 packets (Requires RS485_SERIAL_PORT) * M486 - Identify and cancel objects. (Requires CANCEL_OBJECTS) - * M493 - Get or set input FT Motion / Shaping parameters. (Requires FT_MOTION) + * M493 - Set / Report input FT Motion/Shaping parameters. (Requires FT_MOTION) * M500 - Store parameters in EEPROM. (Requires EEPROM_SETTINGS) * M501 - Restore parameters from EEPROM. (Requires EEPROM_SETTINGS) * M502 - Revert to the default "factory settings". ** Does not write them to EEPROM! ** - * M503 - Print the current settings (in memory): "M503 S". S0 specifies compact output. + * M503 - Print the current settings (in memory): 'M503 S'. S0 specifies compact output. * M504 - Validate EEPROM contents. (Requires EEPROM_SETTINGS) * M510 - Lock Printer (Requires PASSWORD_FEATURE) * M511 - Unlock Printer (Requires PASSWORD_UNLOCK_GCODE) * M512 - Set/Change/Remove Password (Requires PASSWORD_CHANGE_GCODE) * M524 - Abort the current SD print job started with M24. (Requires SDSUPPORT) - * M540 - Enable/disable SD card abort on endstop hit: "M540 S". (Requires SD_ABORT_ON_ENDSTOP_HIT) - * M550 - Set the machine name: "M550 P". (Requires CONFIGURABLE_MACHINE_NAME) - * M552 - Get or set IP address. Enable/disable network interface. (Requires enabled Ethernet port) - * M553 - Get or set IP netmask. (Requires enabled Ethernet port) - * M554 - Get or set IP gateway. (Requires enabled Ethernet port) + * M540 - Enable/Disable SD card abort on endstop hit: 'M540 S'. (Requires SD_ABORT_ON_ENDSTOP_HIT) + * M550 - Set the machine name: 'M550 P'. (Requires CONFIGURABLE_MACHINE_NAME) + * M552 - Set / Report IP address. Enable/Disable network interface. (Requires enabled Ethernet port) + * M553 - Set / Report IP netmask. (Requires enabled Ethernet port) + * M554 - Set / Report IP gateway. (Requires enabled Ethernet port) * M569 - Enable stealthChop on an axis. (Requires *_DRIVER_TYPE TMC(2130|2160|2208|2209|2240|5130|5160)) * M575 - Change the serial baud rate. (Requires BAUD_RATE_GCODE) - * M592 - Get or set Nonlinear Extrusion parameters. (Requires NONLINEAR_EXTRUSION) - * M593 - Get or set input shaping parameters. (Requires INPUT_SHAPING_[XY]) - * M600 - Pause for filament change: "M600 X Y Z E L". (Requires ADVANCED_PAUSE_FEATURE) - * M603 - Configure filament change: "M603 T U L". (Requires ADVANCED_PAUSE_FEATURE) - * M605 - Set Dual X-Carriage movement mode: "M605 S [X] [R]". (Requires DUAL_X_CARRIAGE) - * M665 - Set delta configurations: "M665 H L R S B X Y Z (Requires DELTA) - * Set SCARA configurations: "M665 S P T Z (Requires MORGAN_SCARA or MP_SCARA) - * Set Polargraph draw area and belt length: "M665 S L R T B H" - * M666 - Set/get offsets for delta (Requires DELTA) or dual endstops. (Requires [XYZ]_DUAL_ENDSTOPS) + * M592 - Set / Report Nonlinear Extrusion parameters. (Requires NONLINEAR_EXTRUSION) + * M593 - Set / Report input shaping parameters. (Requires INPUT_SHAPING_[XY]) + * M600 - Pause for filament change: 'M600 X Y Z E L'. (Requires ADVANCED_PAUSE_FEATURE) + * M603 - Configure filament change: 'M603 T U L'. (Requires ADVANCED_PAUSE_FEATURE) + * M605 - Set Dual X-Carriage movement mode: 'M605 S [X] [R]'. (Requires DUAL_X_CARRIAGE) + * M665 - Set Delta configurations: 'M665 H L R S B X Y Z' (Requires DELTA) + * Set SCARA configurations: 'M665 S P T Z' (Requires MORGAN_SCARA or MP_SCARA) + * Set Polargraph draw area and belt length: 'M665 S L R T B H' + * M666 - Set / Report offsets for delta (Requires DELTA) or dual endstops. (Requires [XYZ]_DUAL_ENDSTOPS) * M672 - Set/Reset Duet Smart Effector's sensitivity. (Requires DUET_SMART_EFFECTOR and SMART_EFFECTOR_MOD_PIN) * M701 - Load filament (Requires FILAMENT_LOAD_UNLOAD_GCODES) * M702 - Unload filament (Requires FILAMENT_LOAD_UNLOAD_GCODES) @@ -289,10 +289,10 @@ * M709 - MMU power & reset * * M808 - Set or Goto a Repeat Marker (Requires GCODE_REPEAT_MARKERS) - * M810-M819 - Define/execute a G-code macro (Requires GCODE_MACROS) + * M810-M819 - Define/Execute a G-code macro (Requires GCODE_MACROS) * M820 - Report all defined M810-M819 G-code macros (Requires GCODE_MACROS) * M851 - Set Z probe's XYZ offsets in current units. (Negative values: X=left, Y=front, Z=below) - * M852 - Set skew factors: "M852 [I] [J] [K]". (Requires SKEW_CORRECTION_GCODE, plus SKEW_CORRECTION_FOR_Z for IJ) + * M852 - Set skew factors: 'M852 I J K'. (Requires SKEW_CORRECTION_GCODE, plus SKEW_CORRECTION_FOR_Z for IJ) * *** I2C_POSITION_ENCODERS *** * M860 - Report the position of position encoder modules. @@ -301,15 +301,15 @@ * M863 - Perform steps-per-mm calibration for position encoder modules. * M864 - Change position encoder module I2C address. * M865 - Check position encoder module firmware version. - * M866 - Report or reset position encoder module error count. - * M867 - Enable/disable or toggle error correction for position encoder modules. - * M868 - Report or set position encoder module error correction threshold. + * M866 - Report/Reset position encoder module error count. + * M867 - Enable/Disable or toggle error correction for position encoder modules. + * M868 - Set / Report position encoder module error correction threshold. * M869 - Report position encoder module error. * - * M871 - Print/reset/clear first layer temperature offset values. (Requires PTC_PROBE, PTC_BED, or PTC_HOTEND) + * M871 - Print/Reset/Clear first layer temperature offset values. (Requires PTC_PROBE, PTC_BED, or PTC_HOTEND) * M876 - Handle Prompt Response. (Requires HOST_PROMPT_SUPPORT and not EMERGENCY_PARSER) - * M900 - Set or Report Linear Advance K-factor. (Requires LIN_ADVANCE) - * M906 - Set or Report motor current in milliamps using axis codes XYZE, etc. Report values if no axis codes given. (Requires *_DRIVER_TYPE TMC(2130|2160|5130|5160|2208|2209|2240|2660)) + * M900 - Set / Report Linear Advance K-factor. (Requires LIN_ADVANCE) + * M906 - Set / Report motor current in milliamps using axis codes XYZE, etc. Report values if no axis codes given. (Requires *_DRIVER_TYPE TMC(2130|2160|5130|5160|2208|2209|2240|2660)) * M907 - Set digital trimpot motor current using axis codes. (Requires a board with digital trimpots) * M908 - Control digital trimpot directly. (Requires HAS_MOTOR_CURRENT_DAC or DIGIPOTSS_PIN) * M909 - Print digipot/DAC current value. (Requires HAS_MOTOR_CURRENT_DAC) @@ -318,7 +318,7 @@ * M912 - Clear stepper driver overtemperature pre-warn condition flag. (Requires *_DRIVER_TYPE TMC(2130|2160|5130|5160|2208|2209|2240|2660)) * M913 - Set HYBRID_THRESHOLD speed. (Requires HYBRID_THRESHOLD) * M914 - Set StallGuard sensitivity. (Requires SENSORLESS_HOMING or SENSORLESS_PROBING) - * M919 - Set or Report motor Chopper Times (time_off, hysteresis_end, hysteresis_start) using axis codes XYZE, etc. + * M919 - Set / Report motor Chopper Times (time_off, hysteresis_end, hysteresis_start) using axis codes XYZE, etc. * If no parameters are given, report. (Requires *_DRIVER_TYPE TMC(2130|2160|5130|5160|2208|2209|2240|2660)) * M920 - Set Homing Current. (Requires distinct *_CURRENT_HOME settings) * M936 - OTA update firmware. (Requires OTA_FIRMWARE_UPDATE) @@ -342,12 +342,12 @@ * M997 - Perform in-application firmware update * M999 - Restart after being stopped by error * - * D... - Custom Development G-code. Add hooks to 'gcode_D.cpp' for developers to test features. (Requires MARLIN_DEV_MODE) + * D... - Custom Development G-code. Add hooks to "gcode_D.cpp" for developers to test features. (Requires MARLIN_DEV_MODE) * D576 - Set buffer monitoring options. (Requires BUFFER_MONITORING) * *** "T" Codes *** * - * T0-T3 - Select an extruder (tool) by index: "T F" + * T0-T3 - Select an extruder (tool) by index: 'T F' */ #include "../inc/MarlinConfig.h" diff --git a/Marlin/src/gcode/host/M113.cpp b/Marlin/src/gcode/host/M113.cpp index ddabcefb13..6da353f05c 100644 --- a/Marlin/src/gcode/host/M113.cpp +++ b/Marlin/src/gcode/host/M113.cpp @@ -29,7 +29,9 @@ /** * M113: Get or set Host Keepalive interval (0 to disable) * - * S Optional. Set the keepalive interval. + * Parameters: + * None Report current keepalive interval + * S Set the keepalive interval (0-60) */ void GcodeSuite::M113() { diff --git a/Marlin/src/gcode/host/M114.cpp b/Marlin/src/gcode/host/M114.cpp index 2a46de9c86..6ec6c2f3ca 100644 --- a/Marlin/src/gcode/host/M114.cpp +++ b/Marlin/src/gcode/host/M114.cpp @@ -69,7 +69,7 @@ #if IS_KINEMATIC // Kinematics applied to the leveled position - SERIAL_ECHOPGM(TERN(POLAR, "Polar", TERN(IS_SCARA, "Scara", "Delta")) "K: " ); + SERIAL_ECHOPGM(TERN(POLAR, "Polar", TERN(IS_SCARA, "SCARA", "Delta")) "K: " ); inverse_kinematics(leveled); // writes delta[] report_linear_axis_pos(delta); #endif @@ -92,7 +92,7 @@ #endif SERIAL_ECHOPGM("FromStp:"); - get_cartesian_from_steppers(); // writes 'cartes' (with forward kinematics) + get_cartesian_from_steppers(); // Writes 'cartes' (with forward kinematics) xyze_pos_t from_steppers = LOGICAL_AXIS_ARRAY( planner.get_axis_position_mm(E_AXIS), cartes.x, cartes.y, cartes.z, @@ -115,12 +115,18 @@ #endif // M114_DETAIL /** - * M114: Report the current position to host. - * Since steppers are moving, the count positions are - * projected by using planner calculations. - * D - Report more detail. This syncs the planner. (Requires M114_DETAIL) - * E - Report E stepper position (Requires M114_DETAIL) - * R - Report the realtime position instead of projected. + * M114: Get Current Position + * + * Report the current tool position to the host. + * Since steppers are moving, the count positions are + * projected by using planner calculations. + * + * With M114_DETAIL: + * D - Report detailed information + * E - Report E stepper position + * + * With M114_REALTIME: + * R - Report real position information */ void GcodeSuite::M114() { diff --git a/Marlin/src/gcode/host/M115.cpp b/Marlin/src/gcode/host/M115.cpp index 6f38a65ae6..e86819b84e 100644 --- a/Marlin/src/gcode/host/M115.cpp +++ b/Marlin/src/gcode/host/M115.cpp @@ -54,9 +54,11 @@ #endif /** - * M115: Capabilities string and extended capabilities report - * If a capability is not reported, hosts should assume - * the capability is not present. + * M115: Firmware Info + * + * Capabilities string and extended capabilities report. + * If a capability is not reported, hosts should assume + * the capability is not present. * * NOTE: Always make sure to add new capabilities to the RepRap Wiki * at https://reprap.org/wiki/Firmware_Capabilities_Protocol diff --git a/Marlin/src/gcode/lcd/M73.cpp b/Marlin/src/gcode/lcd/M73.cpp index 5d9b3bd107..a5772fdcaf 100644 --- a/Marlin/src/gcode/lcd/M73.cpp +++ b/Marlin/src/gcode/lcd/M73.cpp @@ -30,7 +30,16 @@ #include "../../libs/numtostr.h" /** - * M73: Set percentage complete (for display on LCD) + * M73: Set Print Progress + * + * Set next interaction countdown, current print progress + * percentage, and/or remaining time for display on the LCD. + * + * Parameters: + * None Report current values + * C Set next interaction countdown + * P Set current print progress percentage (0-100) + * R Set remaining time * * Example: * M73 P25.63 ; Set progress to 25.63% diff --git a/Marlin/src/gcode/queue.cpp b/Marlin/src/gcode/queue.cpp index 7fa55b70e8..632e3173ea 100644 --- a/Marlin/src/gcode/queue.cpp +++ b/Marlin/src/gcode/queue.cpp @@ -232,7 +232,7 @@ void GCodeQueue::enqueue_now_P(PGM_P const pgcode) { * Send an "ok" message to the host, indicating * that a command was successfully processed. * - * If ADVANCED_OK is enabled also include: + * With ADVANCED_OK: * N Line number of the command, if any * P Planner space remaining * B Block queue space remaining diff --git a/Marlin/src/gcode/sd/M20.cpp b/Marlin/src/gcode/sd/M20.cpp index 9dca2bb3e0..e794e4097c 100644 --- a/Marlin/src/gcode/sd/M20.cpp +++ b/Marlin/src/gcode/sd/M20.cpp @@ -28,7 +28,9 @@ #include "../../sd/cardreader.h" /** - * M20: List SD card to serial output in [name] [size] format. + * M20: List Media Files + * + * By default output in [name] [size] format. * * With CUSTOM_FIRMWARE_UPLOAD: * F - List BIN files only, for use with firmware upload diff --git a/Marlin/src/gcode/sd/M21_M22.cpp b/Marlin/src/gcode/sd/M21_M22.cpp index eb1594fbaf..61fa04d678 100644 --- a/Marlin/src/gcode/sd/M21_M22.cpp +++ b/Marlin/src/gcode/sd/M21_M22.cpp @@ -28,7 +28,7 @@ #include "../../sd/cardreader.h" /** - * M21: Init SD Card + * M21: Mount Media * * With MULTI_VOLUME: * P0 or S - Change to the SD Card and mount it @@ -46,7 +46,7 @@ void GcodeSuite::M21() { } /** - * M22: Release SD Card + * M22: Release Media */ void GcodeSuite::M22() { if (!card.isStillPrinting()) card.release(); diff --git a/Marlin/src/gcode/sd/M23.cpp b/Marlin/src/gcode/sd/M23.cpp index 7727d4958f..5a7d450e09 100644 --- a/Marlin/src/gcode/sd/M23.cpp +++ b/Marlin/src/gcode/sd/M23.cpp @@ -29,9 +29,14 @@ #include "../../lcd/marlinui.h" /** - * M23: Open a file + * M23: Select File * - * The path is relative to the root directory + * Select a file on mounted media for printing or processing. + * Follow with M24 to run the selected file. + * + * Parameters: + * The filename of the file to open + * (The path is relative to the root directory) */ void GcodeSuite::M23() { // Simplify3D includes the size, so zero out all spaces (#7227) diff --git a/Marlin/src/gcode/sd/M24_M25.cpp b/Marlin/src/gcode/sd/M24_M25.cpp index f4ad7c7dab..9c230947a6 100644 --- a/Marlin/src/gcode/sd/M24_M25.cpp +++ b/Marlin/src/gcode/sd/M24_M25.cpp @@ -48,7 +48,12 @@ #include "../../MarlinCore.h" // for startOrResumeJob /** - * M24: Start or Resume SD Print + * M24: Start or Resume Media Print + * + * Parameters: + * With POWER_LOSS_RECOVERY: + * S Position in file to resume from + * T

+ Licença GPL-V3.0 + Contribuidores + Data do Último Lançamento + Status do CI + Patrocínios no GitHub +
+ Siga marlinfw.org no Bluesky + Siga MarlinFirmware no Mastodon +