Bladeren bron

Fix ARM delay function (#20901)

X-Ryl669 4 jaren geleden
bovenliggende
commit
1c19af2c8f
No account linked to committer's email address

+ 4
- 4
Marlin/src/HAL/DUE/HAL_SPI.cpp Bestand weergeven

@@ -240,7 +240,7 @@
240 240
   }
241 241
 
242 242
   // all the others
243
-  static uint32_t spiDelayCyclesX4 = (F_CPU) / 1000000; // 4µs => 125khz
243
+  static uint32_t spiDelayCyclesX4 = 4 * (F_CPU) / 1000000; // 4µs => 125khz
244 244
 
245 245
   static uint8_t spiTransferX(uint8_t b) { // using Mode 0
246 246
     int bits = 8;
@@ -249,12 +249,12 @@
249 249
       b <<= 1; // little setup time
250 250
 
251 251
       WRITE(SD_SCK_PIN, HIGH);
252
-      __delay_4cycles(spiDelayCyclesX4);
252
+      DELAY_CYCLES(spiDelayCyclesX4);
253 253
 
254 254
       b |= (READ(SD_MISO_PIN) != 0);
255 255
 
256 256
       WRITE(SD_SCK_PIN, LOW);
257
-      __delay_4cycles(spiDelayCyclesX4);
257
+      DELAY_CYCLES(spiDelayCyclesX4);
258 258
     } while (--bits);
259 259
     return b;
260 260
   }
@@ -510,7 +510,7 @@
510 510
         spiRxBlock = (pfnSpiRxBlock)spiRxBlockX;
511 511
         break;
512 512
       default:
513
-        spiDelayCyclesX4 = ((F_CPU) / 1000000) >> (6 - spiRate);
513
+        spiDelayCyclesX4 = ((F_CPU) / 1000000) >> (6 - spiRate) << 2; // spiRate of 2 gives the maximum error with current CPU
514 514
         spiTransferTx = (pfnSpiTransfer)spiTransferX;
515 515
         spiTransferRx = (pfnSpiTransfer)spiTransferX;
516 516
         spiTxBlock = (pfnSpiTxBlock)spiTxBlockX;

+ 1
- 0
Marlin/src/HAL/DUE/dogm/u8g_com_HAL_DUE_st7920_sw_spi.cpp Bestand weergeven

@@ -59,6 +59,7 @@
59 59
 
60 60
 #if ENABLED(U8GLIB_ST7920)
61 61
 
62
+#include "../../../inc/MarlinConfig.h"
62 63
 #include "../../shared/Delay.h"
63 64
 
64 65
 #include <U8glib.h>

+ 1
- 0
Marlin/src/HAL/DUE/dogm/u8g_com_HAL_DUE_sw_spi_shared.cpp Bestand weergeven

@@ -59,6 +59,7 @@
59 59
 
60 60
 #if HAS_MARLINUI_U8GLIB
61 61
 
62
+#include "../../../inc/MarlinConfig.h"
62 63
 #include "../../shared/Delay.h"
63 64
 
64 65
 #include <U8glib.h>

+ 0
- 11
Marlin/src/HAL/STM32/HAL.cpp Bestand weergeven

@@ -57,17 +57,6 @@ uint16_t HAL_adc_result;
57 57
 // Public functions
58 58
 // ------------------------
59 59
 
60
-// Needed for DELAY_NS() / DELAY_US() on CORTEX-M7
61
-#if (defined(__arm__) || defined(__thumb__)) && __CORTEX_M == 7
62
-  // HAL pre-initialization task
63
-  // Force the preinit function to run between the premain() and main() function
64
-  // of the STM32 arduino core
65
-  __attribute__((constructor (102)))
66
-  void HAL_preinit() {
67
-    enableCycleCounter();
68
-  }
69
-#endif
70
-
71 60
 // HAL initialization task
72 61
 void HAL_init() {
73 62
   FastIO_init();

+ 1
- 0
Marlin/src/HAL/STM32/HAL.h Bestand weergeven

@@ -194,6 +194,7 @@ void flashFirmware(const int16_t);
194 194
 typedef void (*systickCallback_t)(void);
195 195
 void systick_attach_callback(systickCallback_t cb);
196 196
 void HAL_SYSTICK_Callback();
197
+
197 198
 extern volatile uint32_t systick_uptime_millis;
198 199
 
199 200
 #define HAL_CAN_SET_PWM_FREQ   // This HAL supports PWM Frequency adjustment

+ 20
- 10
Marlin/src/HAL/STM32/HAL_SPI.cpp Bestand weergeven

@@ -51,18 +51,28 @@ static SPISettings spiConfig;
51 51
     OUT_WRITE(SD_MOSI_PIN, HIGH);
52 52
   }
53 53
 
54
-  static uint16_t delay_STM32_soft_spi;
54
+  // Use function with compile-time value so we can actually reach the desired frequency
55
+  // Need to adjust this a little bit: on a 72MHz clock, we have 14ns/clock
56
+  // and we'll use ~3 cycles to jump to the method and going back, so it'll take ~40ns from the given clock here
57
+  #define CALLING_COST_NS  (3U * 1000000000U) / (F_CPU)
58
+  void (*delaySPIFunc)();
59
+  void delaySPI_125()  { DELAY_NS(125 - CALLING_COST_NS); }
60
+  void delaySPI_250()  { DELAY_NS(250 - CALLING_COST_NS); }
61
+  void delaySPI_500()  { DELAY_NS(500 - CALLING_COST_NS); }
62
+  void delaySPI_1000() { DELAY_NS(1000 - CALLING_COST_NS); }
63
+  void delaySPI_2000() { DELAY_NS(2000 - CALLING_COST_NS); }
64
+  void delaySPI_4000() { DELAY_NS(4000 - CALLING_COST_NS); }
55 65
 
56 66
   void spiInit(uint8_t spiRate) {
57 67
     // Use datarates Marlin uses
58 68
     switch (spiRate) {
59
-      case SPI_FULL_SPEED:   delay_STM32_soft_spi =  125; break;  // desired: 8,000,000  actual: ~1.1M
60
-      case SPI_HALF_SPEED:   delay_STM32_soft_spi =  125; break;  // desired: 4,000,000  actual: ~1.1M
61
-      case SPI_QUARTER_SPEED:delay_STM32_soft_spi =  250; break;  // desired: 2,000,000  actual: ~890K
62
-      case SPI_EIGHTH_SPEED: delay_STM32_soft_spi =  500; break;  // desired: 1,000,000  actual: ~590K
63
-      case SPI_SPEED_5:      delay_STM32_soft_spi = 1000; break;  // desired:   500,000  actual: ~360K
64
-      case SPI_SPEED_6:      delay_STM32_soft_spi = 2000; break;  // desired:   250,000  actual: ~210K
65
-      default:               delay_STM32_soft_spi = 4000; break;  // desired:   125,000  actual: ~123K
69
+      case SPI_FULL_SPEED:   delaySPIFunc =  &delaySPI_125; break;  // desired: 8,000,000  actual: ~1.1M
70
+      case SPI_HALF_SPEED:   delaySPIFunc =  &delaySPI_125; break;  // desired: 4,000,000  actual: ~1.1M
71
+      case SPI_QUARTER_SPEED:delaySPIFunc =  &delaySPI_250; break;  // desired: 2,000,000  actual: ~890K
72
+      case SPI_EIGHTH_SPEED: delaySPIFunc =  &delaySPI_500; break;  // desired: 1,000,000  actual: ~590K
73
+      case SPI_SPEED_5:      delaySPIFunc = &delaySPI_1000; break;  // desired:   500,000  actual: ~360K
74
+      case SPI_SPEED_6:      delaySPIFunc = &delaySPI_2000; break;  // desired:   250,000  actual: ~210K
75
+      default:               delaySPIFunc = &delaySPI_4000; break;  // desired:   125,000  actual: ~123K
66 76
     }
67 77
     SPI.begin();
68 78
   }
@@ -75,9 +85,9 @@ static SPISettings spiConfig;
75 85
       WRITE(SD_SCK_PIN, LOW);
76 86
       WRITE(SD_MOSI_PIN, b & 0x80);
77 87
 
78
-      DELAY_NS(delay_STM32_soft_spi);
88
+      delaySPIFunc();
79 89
       WRITE(SD_SCK_PIN, HIGH);
80
-      DELAY_NS(delay_STM32_soft_spi);
90
+      delaySPIFunc();
81 91
 
82 92
       b <<= 1;        // little setup time
83 93
       b |= (READ(SD_MISO_PIN) != 0);

+ 176
- 0
Marlin/src/HAL/shared/Delay.cpp Bestand weergeven

@@ -0,0 +1,176 @@
1
+/**
2
+ * Marlin 3D Printer Firmware
3
+ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
4
+ *
5
+ * Based on Sprinter and grbl.
6
+ * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
7
+ *
8
+ * This program is free software: you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation, either version 3 of the License, or
11
+ * (at your option) any later version.
12
+ *
13
+ * This program is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
+ * GNU General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU General Public License
19
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
20
+ *
21
+ */
22
+#include "Delay.h"
23
+
24
+#include "../../inc/MarlinConfig.h"
25
+
26
+#if defined(__arm__) || defined(__thumb__)
27
+
28
+  static uint32_t ASM_CYCLES_PER_ITERATION = 4;   // Initial bet which will be adjusted in calibrate_delay_loop
29
+
30
+  // Simple assembler loop counting down
31
+  void delay_asm(uint32_t cy) {
32
+    cy = _MAX(cy / ASM_CYCLES_PER_ITERATION, 1U); // Zero is forbidden here
33
+    __asm__ __volatile__(
34
+      A(".syntax unified") // is to prevent CM0,CM1 non-unified syntax
35
+      L("1")
36
+      A("subs %[cnt],#1")
37
+      A("bne 1b")
38
+      : [cnt]"+r"(cy)   // output: +r means input+output
39
+      :                 // input:
40
+      : "cc"            // clobbers:
41
+    );
42
+  }
43
+
44
+  // We can't use CMSIS since it's not available on all platform, so fallback to hardcoded register values
45
+  #define HW_REG(X)   *(volatile uint32_t *)(X)
46
+  #define _DWT_CTRL   0xE0001000
47
+  #define _DWT_CYCCNT 0xE0001004      // CYCCNT is 32bits, takes 37s or so to wrap.
48
+  #define _DEM_CR     0xE000EDFC
49
+  #define _LAR        0xE0001FB0
50
+
51
+  // Use hardware cycle counter instead, it's much safer
52
+  void delay_dwt(uint32_t count) {
53
+    // Reuse the ASM_CYCLES_PER_ITERATION variable to avoid wasting another useless variable
54
+    register uint32_t start = HW_REG(_DWT_CYCCNT) - ASM_CYCLES_PER_ITERATION, elapsed;
55
+    do {
56
+      elapsed = HW_REG(_DWT_CYCCNT) - start;
57
+    } while (elapsed < count);
58
+  }
59
+
60
+  // Pointer to asm function, calling the functions has a ~20 cycles overhead
61
+  DelayImpl DelayCycleFnc = delay_asm;
62
+
63
+  void calibrate_delay_loop() {
64
+    // Check if we have a working DWT implementation in the CPU (see https://developer.arm.com/documentation/ddi0439/b/Data-Watchpoint-and-Trace-Unit/DWT-Programmers-Model)
65
+    if (!HW_REG(_DWT_CTRL)) {
66
+      // No DWT present, so fallback to plain old ASM nop counting
67
+      // Unfortunately, we don't exactly know how many iteration it'll take to decrement a counter in a loop
68
+      // It depends on the CPU architecture, the code current position (flash vs SRAM)
69
+      // So, instead of wild guessing and making mistake, instead
70
+      // compute it once for all
71
+      ASM_CYCLES_PER_ITERATION = 1;
72
+      // We need to fetch some reference clock before waiting
73
+      cli();
74
+        uint32_t start = micros();
75
+        delay_asm(1000); // On a typical CPU running in MHz, waiting 1000 "unknown cycles" means it'll take between 1ms to 6ms, that's perfectly acceptable
76
+        uint32_t end = micros();
77
+      sei();
78
+      uint32_t expectedCycles = (end - start) * ((F_CPU) / 1000000UL); // Convert microseconds to cycles
79
+      // Finally compute the right scale
80
+      ASM_CYCLES_PER_ITERATION = (uint32_t)(expectedCycles / 1000);
81
+
82
+      // No DWT present, likely a Cortex M0 so NOP counting is our best bet here
83
+      DelayCycleFnc = delay_asm;
84
+    }
85
+    else {
86
+      // Enable DWT counter
87
+      // From https://stackoverflow.com/a/41188674/1469714
88
+      HW_REG(_DEM_CR) = HW_REG(_DEM_CR) | 0x01000000;   // Enable trace
89
+      #if __CORTEX_M == 7
90
+        HW_REG(_LAR) = 0xC5ACCE55;                      // Unlock access to DWT registers, see https://developer.arm.com/documentation/ihi0029/e/ section B2.3.10
91
+      #endif
92
+      HW_REG(_DWT_CYCCNT) = 0;                          // Clear DWT cycle counter
93
+      HW_REG(_DWT_CTRL) = HW_REG(_DWT_CTRL) | 1;        // Enable DWT cycle counter
94
+
95
+      // Then calibrate the constant offset from the counter
96
+      ASM_CYCLES_PER_ITERATION = 0;
97
+      uint32_t s = HW_REG(_DWT_CYCCNT);
98
+      uint32_t e = HW_REG(_DWT_CYCCNT);  // (e - s) contains the number of cycle required to read the cycle counter
99
+      delay_dwt(0);
100
+      uint32_t f = HW_REG(_DWT_CYCCNT);  // (f - e) contains the delay to call the delay function + the time to read the cycle counter
101
+      ASM_CYCLES_PER_ITERATION = (f - e) - (e - s);
102
+
103
+      // Use safer DWT function
104
+      DelayCycleFnc = delay_dwt;
105
+    }
106
+  }
107
+
108
+  #if ENABLED(MARLIN_DEV_MODE)
109
+    void dump_delay_accuracy_check()
110
+    {
111
+      auto report_call_time = [](PGM_P const name, const uint32_t cycles, const uint32_t total, const bool do_flush=true) {
112
+        SERIAL_ECHOPGM("Calling ");
113
+        serialprintPGM(name);
114
+        SERIAL_ECHOLNPAIR(" for ", cycles, "cycles took: ", total, "cycles");
115
+        if (do_flush) SERIAL_FLUSH();
116
+      };
117
+
118
+      uint32_t s, e;
119
+
120
+      SERIAL_ECHOLNPAIR("Computed delay calibration value: ", ASM_CYCLES_PER_ITERATION);
121
+      SERIAL_FLUSH();
122
+      // Display the results of the calibration above
123
+      constexpr uint32_t testValues[] = { 1, 5, 10, 20, 50, 100, 150, 200, 350, 500, 750, 1000 };
124
+      for (auto i : testValues) {
125
+        s = micros(); DELAY_US(i); e = micros();
126
+        report_call_time(PSTR("delay"), i, e - s);
127
+      }
128
+
129
+      if (HW_REG(_DWT_CTRL)) {
130
+        for (auto i : testValues) {
131
+          s = HW_REG(_DWT_CYCCNT); DELAY_CYCLES(i); e = HW_REG(_DWT_CYCCNT);
132
+          report_call_time(PSTR("delay"), i, e - s);
133
+        }
134
+
135
+        // Measure the delay to call a real function compared to a function pointer
136
+        s = HW_REG(_DWT_CYCCNT); delay_dwt(1); e = HW_REG(_DWT_CYCCNT);
137
+        report_call_time(PSTR("delay_dwt"), 1, e - s);
138
+
139
+        static PGMSTR(dcd, "DELAY_CYCLES directly ");
140
+
141
+        s = HW_REG(_DWT_CYCCNT); DELAY_CYCLES( 1); e = HW_REG(_DWT_CYCCNT);
142
+        report_call_time(dcd,  1, e - s, false);
143
+
144
+        s = HW_REG(_DWT_CYCCNT); DELAY_CYCLES( 5); e = HW_REG(_DWT_CYCCNT);
145
+        report_call_time(dcd,  5, e - s, false);
146
+
147
+        s = HW_REG(_DWT_CYCCNT); DELAY_CYCLES(10); e = HW_REG(_DWT_CYCCNT);
148
+        report_call_time(dcd, 10, e - s, false);
149
+
150
+        s = HW_REG(_DWT_CYCCNT); DELAY_CYCLES(20); e = HW_REG(_DWT_CYCCNT);
151
+        report_call_time(dcd, 20, e - s, false);
152
+
153
+        s = HW_REG(_DWT_CYCCNT); DELAY_CYCLES(50); e = HW_REG(_DWT_CYCCNT);
154
+        report_call_time(dcd, 50, e - s, false);
155
+
156
+        s = HW_REG(_DWT_CYCCNT); DELAY_CYCLES(100); e = HW_REG(_DWT_CYCCNT);
157
+        report_call_time(dcd, 100, e - s, false);
158
+
159
+        s = HW_REG(_DWT_CYCCNT); DELAY_CYCLES(200); e = HW_REG(_DWT_CYCCNT);
160
+        report_call_time(dcd, 200, e - s, false);
161
+      }
162
+    }
163
+  #endif // MARLIN_DEV_MODE
164
+
165
+
166
+#else
167
+
168
+  void calibrate_delay_loop() {}
169
+  #if ENABLED(MARLIN_DEV_MODE)
170
+    void dump_delay_accuracy_check() {
171
+      static PGMSTR(none, "N/A on this platform");
172
+      serialprintPGM(none);
173
+    }
174
+  #endif
175
+
176
+#endif

+ 61
- 65
Marlin/src/HAL/shared/Delay.h Bestand weergeven

@@ -21,6 +21,8 @@
21 21
  */
22 22
 #pragma once
23 23
 
24
+#include "../../inc/MarlinConfigPre.h"
25
+
24 26
 /**
25 27
  * Busy wait delay cycles routines:
26 28
  *
@@ -31,79 +33,68 @@
31 33
 
32 34
 #include "../../core/macros.h"
33 35
 
34
-#if defined(__arm__) || defined(__thumb__)
35
-
36
-  #if __CORTEX_M == 7
36
+void calibrate_delay_loop();
37 37
 
38
-    // Cortex-M3 through M7 can use the cycle counter of the DWT unit
39
-    // https://www.anthonyvh.com/2017/05/18/cortex_m-cycle_counter/
38
+#if defined(__arm__) || defined(__thumb__)
40 39
 
41
-    FORCE_INLINE static void enableCycleCounter() {
42
-      CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
40
+  // We want to have delay_cycle function with the lowest possible overhead, so we adjust at the function at runtime based on the current CPU best feature
41
+  typedef void (*DelayImpl)(uint32_t);
42
+  extern DelayImpl DelayCycleFnc;
43 43
 
44
-      #if __CORTEX_M == 7
45
-        DWT->LAR = 0xC5ACCE55; // Unlock DWT on the M7
46
-      #endif
44
+  // I've measured 36 cycles on my system to call the cycle waiting method, but it shouldn't change much to have a bit more margin, it only consume a bit more flash
45
+  #define TRIP_POINT_FOR_CALLING_FUNCTION   40
47 46
 
48
-      DWT->CYCCNT = 0;
49
-      DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
47
+  // A simple recursive template class that output exactly one 'nop' of code per recursion
48
+  template <int N> struct NopWriter {
49
+    FORCE_INLINE static void build() {
50
+      __asm__ __volatile__("nop");
51
+      NopWriter<N-1>::build();
50 52
     }
53
+  };
54
+  // End the loop
55
+  template <> struct NopWriter<0> { FORCE_INLINE static void build() {} };
56
+
57
+  namespace Private {
58
+    // Split recursing template in 2 different class so we don't reach the maximum template instantiation depth limit
59
+    template <bool belowTP, int N> struct Helper {
60
+      FORCE_INLINE static void build() {
61
+        DelayCycleFnc(N - 2); //  Approximative cost of calling the function (might be off by one or 2 cycles)
62
+      }
63
+    };
51 64
 
52
-    FORCE_INLINE volatile uint32_t getCycleCount() { return DWT->CYCCNT; }
65
+    template <int N> struct Helper<true, N> {
66
+      FORCE_INLINE static void build() {
67
+        NopWriter<N - 1>::build();
68
+      }
69
+    };
53 70
 
54
-    FORCE_INLINE static void DELAY_CYCLES(const uint32_t x) {
55
-      const uint32_t endCycles = getCycleCount() + x;
56
-      while (PENDING(getCycleCount(), endCycles)) {}
57
-    }
71
+    template <> struct Helper<true, 0> {
72
+      FORCE_INLINE static void build() {}
73
+    };
58 74
 
59
-  #else
60
-
61
-    // https://blueprints.launchpad.net/gcc-arm-embedded/+spec/delay-cycles
62
-
63
-    #define nop() __asm__ __volatile__("nop;\n\t":::)
64
-
65
-    FORCE_INLINE static void __delay_4cycles(uint32_t cy) { // +1 cycle
66
-      #if ARCH_PIPELINE_RELOAD_CYCLES < 2
67
-        #define EXTRA_NOP_CYCLES A("nop")
68
-      #else
69
-        #define EXTRA_NOP_CYCLES ""
70
-      #endif
71
-
72
-      __asm__ __volatile__(
73
-        A(".syntax unified") // is to prevent CM0,CM1 non-unified syntax
74
-        L("1")
75
-        A("subs %[cnt],#1")
76
-        EXTRA_NOP_CYCLES
77
-        A("bne 1b")
78
-        : [cnt]"+r"(cy)   // output: +r means input+output
79
-        :                 // input:
80
-        : "cc"            // clobbers:
81
-      );
75
+  }
76
+  // Select a behavior based on the constexpr'ness of the parameter
77
+  // If called with a compile-time parameter, then write as many NOP as required to reach the asked cycle count
78
+  // (there is some tripping point here to start looping when it's more profitable than gruntly executing NOPs)
79
+  // If not called from a compile-time parameter, fallback to a runtime loop counting version instead
80
+  template <bool compileTime, int Cycles>
81
+  struct SmartDelay {
82
+    FORCE_INLINE SmartDelay(int) {
83
+      if (Cycles == 0) return;
84
+      Private::Helper<Cycles < TRIP_POINT_FOR_CALLING_FUNCTION, Cycles>::build();
82 85
     }
86
+  };
87
+  // Runtime version below. There is no way this would run under less than ~TRIP_POINT_FOR_CALLING_FUNCTION cycles
88
+  template <int T>
89
+  struct SmartDelay<false, T> {
90
+    FORCE_INLINE SmartDelay(int v) { DelayCycleFnc(v); }
91
+  };
83 92
 
84
-    // Delay in cycles
85
-    FORCE_INLINE static void DELAY_CYCLES(uint32_t x) {
86
-
87
-      if (__builtin_constant_p(x)) {
88
-        #define MAXNOPS 4
89
-
90
-        if (x <= (MAXNOPS)) {
91
-          switch (x) { case 4: nop(); case 3: nop(); case 2: nop(); case 1: nop(); }
92
-        }
93
-        else { // because of +1 cycle inside delay_4cycles
94
-          const uint32_t rem = (x - 1) % (MAXNOPS);
95
-          switch (rem) { case 3: nop(); case 2: nop(); case 1: nop(); }
96
-          if ((x = (x - 1) / (MAXNOPS)))
97
-            __delay_4cycles(x); // if need more then 4 nop loop is more optimal
98
-        }
99
-        #undef MAXNOPS
100
-      }
101
-      else if ((x >>= 2))
102
-        __delay_4cycles(x);
103
-    }
104
-    #undef nop
93
+  #define DELAY_CYCLES(X) do { SmartDelay<IS_CONSTEXPR(X), IS_CONSTEXPR(X) ? X : 0> _smrtdly_X(X); } while(0)
105 94
 
106
-  #endif
95
+  // For delay in microseconds, no smart delay selection is required, directly call the delay function
96
+  // Teensy compiler is too old and does not accept smart delay compile-time / run-time selection correctly
97
+  #define DELAY_US(x) DelayCycleFnc((x) * ((F_CPU) / 1000000UL))
107 98
 
108 99
 #elif defined(__AVR__)
109 100
 
@@ -144,10 +135,15 @@
144 135
   }
145 136
   #undef nop
146 137
 
138
+  // Delay in microseconds
139
+  #define DELAY_US(x) DELAY_CYCLES((x) * ((F_CPU) / 1000000UL))
140
+
147 141
 #elif defined(__PLAT_LINUX__) || defined(ESP32)
148 142
 
149
-  // specified inside platform
143
+  // DELAY_CYCLES specified inside platform
150 144
 
145
+  // Delay in microseconds
146
+  #define DELAY_US(x) DELAY_CYCLES((x) * ((F_CPU) / 1000000UL))
151 147
 #else
152 148
 
153 149
   #error "Unsupported MCU architecture"
@@ -157,5 +153,5 @@
157 153
 // Delay in nanoseconds
158 154
 #define DELAY_NS(x) DELAY_CYCLES((x) * ((F_CPU) / 1000000UL) / 1000UL)
159 155
 
160
-// Delay in microseconds
161
-#define DELAY_US(x) DELAY_CYCLES((x) * ((F_CPU) / 1000000UL))
156
+
157
+

+ 3
- 0
Marlin/src/MarlinCore.cpp Bestand weergeven

@@ -1005,6 +1005,9 @@ void setup() {
1005 1005
   SERIAL_ECHO_MSG("Compiled: " __DATE__);
1006 1006
   SERIAL_ECHO_MSG(STR_FREE_MEMORY, freeMemory(), STR_PLANNER_BUFFER_BYTES, (int)sizeof(block_t) * (BLOCK_BUFFER_SIZE));
1007 1007
 
1008
+  // Some HAL need precise delay adjustment
1009
+  calibrate_delay_loop();
1010
+
1008 1011
   // Init buzzer pin(s)
1009 1012
   #if USE_BEEPER
1010 1013
     SETUP_RUN(buzzer.init());

+ 2
- 0
Marlin/src/core/macros.h Bestand weergeven

@@ -61,6 +61,8 @@
61 61
 #define _O2          __attribute__((optimize("O2")))
62 62
 #define _O3          __attribute__((optimize("O3")))
63 63
 
64
+#define IS_CONSTEXPR(...) __builtin_constant_p(__VA_ARGS__) // Only valid solution with C++14. Should use std::is_constant_evaluated() in C++20 instead
65
+
64 66
 #ifndef UNUSED
65 67
   #define UNUSED(x) ((void)(x))
66 68
 #endif

+ 7
- 1
Marlin/src/gcode/gcode_d.cpp Bestand weergeven

@@ -30,6 +30,8 @@
30 30
   #include "../HAL/shared/eeprom_if.h"
31 31
   #include "../HAL/shared/Delay.h"
32 32
 
33
+  extern void dump_delay_accuracy_check();
34
+
33 35
   /**
34 36
    * Dn: G-code for development and testing
35 37
    *
@@ -141,7 +143,7 @@
141 143
         }
142 144
       } break;
143 145
 
144
-      case 5: { // D4 Read / Write onboard Flash
146
+      case 5: { // D5 Read / Write onboard Flash
145 147
         #define FLASH_SIZE 1024
146 148
         uint8_t *pointer = parser.hex_adr_val('A');
147 149
         uint16_t len = parser.ushortval('C', 1);
@@ -162,6 +164,10 @@
162 164
         }
163 165
       } break;
164 166
 
167
+      case 6: // D6 Check delay loop accuracy
168
+        dump_delay_accuracy_check();
169
+      break;
170
+
165 171
       case 100: { // D100 Disable heaters and attempt a hard hang (Watchdog Test)
166 172
         SERIAL_ECHOLNPGM("Disabling heaters and attempting to trigger Watchdog");
167 173
         SERIAL_ECHOLNPGM("(USE_WATCHDOG " TERN(USE_WATCHDOG, "ENABLED", "DISABLED") ")");

Laden…
Annuleren
Opslaan