Bladeren bron

G6 Direct Stepping (#17853)

Colin Godsey 4 jaren geleden
bovenliggende
commit
8a22ef0c83
No account linked to committer's email address

+ 18
- 6
Marlin/Configuration_adv.h Bestand weergeven

1664
 //#define BEZIER_CURVE_SUPPORT
1664
 //#define BEZIER_CURVE_SUPPORT
1665
 
1665
 
1666
 /**
1666
 /**
1667
+ * Direct Stepping
1668
+ *
1669
+ * Comparable to the method used by Klipper, G6 direct stepping significantly
1670
+ * reduces motion calculations, increases top printing speeds, and results in
1671
+ * less step aliasing by calculating all motions in advance.
1672
+ * Preparing your G-code: https://github.com/colinrgodsey/step-daemon
1673
+ */
1674
+//#define DIRECT_STEPPING
1675
+
1676
+/**
1667
  * G38 Probe Target
1677
  * G38 Probe Target
1668
  *
1678
  *
1669
  * This option adds G38.2 and G38.3 (probe towards target)
1679
  * This option adds G38.2 and G38.3 (probe towards target)
1731
 //================================= Buffers =================================
1741
 //================================= Buffers =================================
1732
 //===========================================================================
1742
 //===========================================================================
1733
 
1743
 
1734
-// @section hidden
1744
+// @section motion
1735
 
1745
 
1736
-// The number of linear motions that can be in the plan at any give time.
1737
-// THE BLOCK_BUFFER_SIZE NEEDS TO BE A POWER OF 2 (e.g. 8, 16, 32) because shifts and ors are used to do the ring-buffering.
1738
-#if ENABLED(SDSUPPORT)
1739
-  #define BLOCK_BUFFER_SIZE 16 // SD,LCD,Buttons take more memory, block buffer needs to be smaller
1746
+// The number of lineear moves that can be in the planner at once.
1747
+// The value of BLOCK_BUFFER_SIZE must be a power of 2 (e.g. 8, 16, 32)
1748
+#if BOTH(SDSUPPORT, DIRECT_STEPPING)
1749
+  #define BLOCK_BUFFER_SIZE  8
1750
+#elif ENABLED(SDSUPPORT)
1751
+  #define BLOCK_BUFFER_SIZE 16
1740
 #else
1752
 #else
1741
-  #define BLOCK_BUFFER_SIZE 16 // maximize block buffer
1753
+  #define BLOCK_BUFFER_SIZE 16
1742
 #endif
1754
 #endif
1743
 
1755
 
1744
 // @section serial
1756
 // @section serial

+ 16
- 8
Marlin/src/HAL/AVR/MarlinSerial.cpp Bestand weergeven

43
   #include "MarlinSerial.h"
43
   #include "MarlinSerial.h"
44
   #include "../../MarlinCore.h"
44
   #include "../../MarlinCore.h"
45
 
45
 
46
+  #if ENABLED(DIRECT_STEPPING)
47
+    #include "../../feature/direct_stepping.h"
48
+  #endif
49
+
46
   template<typename Cfg> typename MarlinSerial<Cfg>::ring_buffer_r MarlinSerial<Cfg>::rx_buffer = { 0, 0, { 0 } };
50
   template<typename Cfg> typename MarlinSerial<Cfg>::ring_buffer_r MarlinSerial<Cfg>::rx_buffer = { 0, 0, { 0 } };
47
   template<typename Cfg> typename MarlinSerial<Cfg>::ring_buffer_t MarlinSerial<Cfg>::tx_buffer = { 0 };
51
   template<typename Cfg> typename MarlinSerial<Cfg>::ring_buffer_t MarlinSerial<Cfg>::tx_buffer = { 0 };
48
   template<typename Cfg> bool     MarlinSerial<Cfg>::_written = false;
52
   template<typename Cfg> bool     MarlinSerial<Cfg>::_written = false;
131
 
135
 
132
     static EmergencyParser::State emergency_state; // = EP_RESET
136
     static EmergencyParser::State emergency_state; // = EP_RESET
133
 
137
 
138
+    // This must read the R_UCSRA register before reading the received byte to detect error causes
139
+    if (Cfg::DROPPED_RX && B_DOR && !++rx_dropped_bytes) --rx_dropped_bytes;
140
+    if (Cfg::RX_OVERRUNS && B_DOR && !++rx_buffer_overruns) --rx_buffer_overruns;
141
+    if (Cfg::RX_FRAMING_ERRORS && B_FE && !++rx_framing_errors) --rx_framing_errors;
142
+
143
+    // Read the character from the USART
144
+    uint8_t c = R_UDR;
145
+
146
+    #if ENABLED(DIRECT_STEPPING)
147
+      if (page_manager.maybe_store_rxd_char(c)) return;
148
+    #endif
149
+
134
     // Get the tail - Nothing can alter its value while this ISR is executing, but there's
150
     // Get the tail - Nothing can alter its value while this ISR is executing, but there's
135
     // a chance that this ISR interrupted the main process while it was updating the index.
151
     // a chance that this ISR interrupted the main process while it was updating the index.
136
     // The backup mechanism ensures the correct value is always returned.
152
     // The backup mechanism ensures the correct value is always returned.
142
     // Get the next element
158
     // Get the next element
143
     ring_buffer_pos_t i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1);
159
     ring_buffer_pos_t i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1);
144
 
160
 
145
-    // This must read the R_UCSRA register before reading the received byte to detect error causes
146
-    if (Cfg::DROPPED_RX && B_DOR && !++rx_dropped_bytes) --rx_dropped_bytes;
147
-    if (Cfg::RX_OVERRUNS && B_DOR && !++rx_buffer_overruns) --rx_buffer_overruns;
148
-    if (Cfg::RX_FRAMING_ERRORS && B_FE && !++rx_framing_errors) --rx_framing_errors;
149
-
150
-    // Read the character from the USART
151
-    uint8_t c = R_UDR;
152
-
153
     if (Cfg::EMERGENCYPARSER) emergency_parser.update(emergency_state, c);
161
     if (Cfg::EMERGENCYPARSER) emergency_parser.update(emergency_state, c);
154
 
162
 
155
     // If the character is to be stored at the index just before the tail
163
     // If the character is to be stored at the index just before the tail

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

59
 #include "gcode/parser.h"
59
 #include "gcode/parser.h"
60
 #include "gcode/queue.h"
60
 #include "gcode/queue.h"
61
 
61
 
62
+#if ENABLED(DIRECT_STEPPING)
63
+  #include "feature/direct_stepping.h"
64
+#endif
65
+
62
 #if ENABLED(TOUCH_BUTTONS)
66
 #if ENABLED(TOUCH_BUTTONS)
63
   #include "feature/touch/xpt2046.h"
67
   #include "feature/touch/xpt2046.h"
64
 #endif
68
 #endif
713
 
717
 
714
   // Handle Joystick jogging
718
   // Handle Joystick jogging
715
   TERN_(POLL_JOG, joystick.inject_jog_moves());
719
   TERN_(POLL_JOG, joystick.inject_jog_moves());
720
+
721
+  // Direct Stepping
722
+  TERN_(DIRECT_STEPPING, page_manager.write_responses());
716
 }
723
 }
717
 
724
 
718
 /**
725
 /**
1124
     SETUP_RUN(max7219.init());
1131
     SETUP_RUN(max7219.init());
1125
   #endif
1132
   #endif
1126
 
1133
 
1134
+  #if ENABLED(DIRECT_STEPPING)
1135
+    SETUP_RUN(page_manager.init());
1136
+  #endif
1137
+
1127
   marlin_state = MF_RUNNING;
1138
   marlin_state = MF_RUNNING;
1128
 
1139
 
1129
   SETUP_LOG("setup() completed.");
1140
   SETUP_LOG("setup() completed.");

+ 273
- 0
Marlin/src/feature/direct_stepping.cpp Bestand weergeven

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 <http://www.gnu.org/licenses/>.
20
+ *
21
+ */
22
+#include "../inc/MarlinConfigPre.h"
23
+
24
+#if ENABLED(DIRECT_STEPPING)
25
+
26
+#include "direct_stepping.h"
27
+
28
+#include "../MarlinCore.h"
29
+
30
+#define CHECK_PAGE(I, R) do{                                \
31
+  if (I >= sizeof(page_states) / sizeof(page_states[0])) {  \
32
+    fatal_error = true;                                     \
33
+    return R;                                               \
34
+  }                                                         \
35
+}while(0)
36
+
37
+#define CHECK_PAGE_STATE(I, R, S) do { \
38
+  CHECK_PAGE(I, R);                    \
39
+  if (page_states[I] != S) {           \
40
+    fatal_error = true;                \
41
+    return R;                          \
42
+  }                                    \
43
+}while(0)
44
+
45
+namespace DirectStepping {
46
+
47
+  template<typename Cfg>
48
+  State SerialPageManager<Cfg>::state;
49
+
50
+  template<typename Cfg>
51
+  volatile bool SerialPageManager<Cfg>::fatal_error;
52
+
53
+  template<typename Cfg>
54
+  volatile PageState SerialPageManager<Cfg>::page_states[Cfg::NUM_PAGES];
55
+
56
+  template<typename Cfg>
57
+  volatile bool SerialPageManager<Cfg>::page_states_dirty;
58
+
59
+  template<typename Cfg>
60
+  millis_t SerialPageManager<Cfg>::next_response;
61
+
62
+  template<typename Cfg>
63
+  uint8_t SerialPageManager<Cfg>::pages[Cfg::NUM_PAGES][Cfg::PAGE_SIZE];
64
+          
65
+  template<typename Cfg>
66
+  uint8_t SerialPageManager<Cfg>::checksum;
67
+
68
+  template<typename Cfg>
69
+  typename Cfg::write_byte_idx_t SerialPageManager<Cfg>::write_byte_idx;
70
+
71
+  template<typename Cfg>
72
+  typename Cfg::page_idx_t SerialPageManager<Cfg>::write_page_idx;
73
+
74
+  template<typename Cfg>
75
+  typename Cfg::write_byte_idx_t SerialPageManager<Cfg>::write_page_size;
76
+
77
+  template <typename Cfg>
78
+  void SerialPageManager<Cfg>::init() {
79
+    for (int i = 0 ; i < Cfg::NUM_PAGES ; i++)
80
+      page_states[i] = PageState::FREE;
81
+
82
+    fatal_error = false;
83
+    next_response = 0;
84
+    state = State::NEWLINE;
85
+
86
+    page_states_dirty = false;
87
+
88
+    SERIAL_ECHOLNPGM("pages_ready");
89
+  }
90
+
91
+  template<typename Cfg>
92
+  FORCE_INLINE bool SerialPageManager<Cfg>::maybe_store_rxd_char(uint8_t c) {
93
+    switch (state) {
94
+      default:
95
+      case State::MONITOR:
96
+        switch (c) {
97
+          case '\n':
98
+          case '\r':
99
+            state = State::NEWLINE;
100
+          default:
101
+            return false;
102
+        }
103
+      case State::NEWLINE:
104
+        switch (c) {
105
+          case Cfg::CONTROL_CHAR:
106
+            state = State::ADDRESS;
107
+            return true;
108
+          case '\n':
109
+          case '\r':
110
+            state = State::NEWLINE;
111
+            return false;
112
+          default:
113
+            state = State::MONITOR;
114
+            return false;
115
+        }
116
+      case State::ADDRESS:
117
+        //TODO: 16 bit address, State::ADDRESS2
118
+        write_page_idx = c;
119
+        write_byte_idx = 0;
120
+        checksum = 0;
121
+
122
+        CHECK_PAGE(write_page_idx, true);
123
+
124
+        if (page_states[write_page_idx] == PageState::FAIL) {
125
+          // Special case for fail
126
+          state = State::UNFAIL;
127
+          return true;
128
+        }
129
+
130
+        set_page_state(write_page_idx, PageState::WRITING);
131
+
132
+        state = Cfg::DIRECTIONAL ? State::COLLECT : State::SIZE;
133
+
134
+        return true;
135
+      case State::SIZE:
136
+        // Zero means full page size
137
+        write_page_size = c;
138
+        state = State::COLLECT;
139
+        return true;
140
+      case State::COLLECT:
141
+        pages[write_page_idx][write_byte_idx++] = c;
142
+        checksum ^= c;
143
+
144
+        // check if still collecting
145
+        if (Cfg::PAGE_SIZE == 256) {
146
+          // special case for 8-bit, check if rolled back to 0
147
+          if (Cfg::DIRECTIONAL || !write_page_size) { // full 256 bytes
148
+            if (write_byte_idx) return true;
149
+          } else {
150
+            if (write_byte_idx < write_page_size) return true;
151
+          }
152
+        } else if (Cfg::DIRECTIONAL) {
153
+          if (write_byte_idx != Cfg::PAGE_SIZE) return true;
154
+        } else {
155
+          if (write_byte_idx < write_page_size) return true;
156
+        }
157
+
158
+        state = State::CHECKSUM;
159
+        return true;
160
+      case State::CHECKSUM: {
161
+        const PageState page_state = (checksum == c) ? PageState::OK : PageState::FAIL;
162
+        set_page_state(write_page_idx, page_state);
163
+        state = State::MONITOR;
164
+        return true;
165
+      }
166
+      case State::UNFAIL:
167
+        if (c == 0) {
168
+          set_page_state(write_page_idx, PageState::FREE);
169
+        } else {
170
+          fatal_error = true;
171
+        }
172
+        state = State::MONITOR;
173
+        return true;
174
+    }
175
+  }
176
+
177
+  template <typename Cfg>
178
+  void SerialPageManager<Cfg>::write_responses() {
179
+    if (fatal_error) {
180
+      kill(GET_TEXT(MSG_BAD_PAGE));
181
+      return;
182
+    }
183
+
184
+    // Runs on a set interval also, as responses may get lost.
185
+    if (next_response && next_response < millis()) {
186
+      page_states_dirty = true;
187
+    }
188
+
189
+    if (!page_states_dirty) return;
190
+
191
+    page_states_dirty = false;
192
+    next_response = millis() + Cfg::RESPONSE_INTERVAL_MS;
193
+
194
+    SERIAL_ECHO(Cfg::CONTROL_CHAR);
195
+    constexpr int state_bits = 2;
196
+    constexpr int n_bytes = Cfg::NUM_PAGES >> state_bits;
197
+    volatile uint8_t bits_b[n_bytes] = { 0 };
198
+
199
+    for (page_idx_t i = 0 ; i < Cfg::NUM_PAGES ; i++) {
200
+      bits_b[i >> state_bits] |= page_states[i] << ((i * state_bits) & 0x7);
201
+    }
202
+
203
+    uint8_t crc = 0;
204
+    for (uint8_t i = 0 ; i < n_bytes ; i++) {
205
+      crc ^= bits_b[i];
206
+      SERIAL_ECHO(bits_b[i]);
207
+    }
208
+
209
+    SERIAL_ECHO(crc);
210
+    SERIAL_EOL();
211
+  }
212
+
213
+  template <typename Cfg>
214
+  FORCE_INLINE void SerialPageManager<Cfg>::set_page_state(const page_idx_t page_idx, const PageState page_state) {
215
+    CHECK_PAGE(page_idx,);
216
+
217
+    page_states[page_idx] = page_state;
218
+    page_states_dirty = true;
219
+  }
220
+
221
+  template <>
222
+  FORCE_INLINE uint8_t *PageManager::get_page(const page_idx_t page_idx) {
223
+    CHECK_PAGE(page_idx, nullptr);
224
+
225
+    return pages[page_idx];
226
+  }
227
+
228
+  template <>
229
+  FORCE_INLINE void PageManager::free_page(const page_idx_t page_idx) {
230
+    set_page_state(page_idx, PageState::FREE);
231
+  }
232
+
233
+};
234
+
235
+DirectStepping::PageManager page_manager;
236
+
237
+const uint8_t segment_table[DirectStepping::Config::NUM_SEGMENTS][DirectStepping::Config::SEGMENT_STEPS] PROGMEM = {
238
+
239
+  #if STEPPER_PAGE_FORMAT == SP_4x4D_128
240
+
241
+    { 1, 1, 1, 1, 1, 1, 1, 0 }, //  0 = -7
242
+    { 1, 1, 1, 0, 1, 1, 1, 0 }, //  1 = -6
243
+    { 0, 1, 1, 0, 1, 0, 1, 1 }, //  2 = -5
244
+    { 0, 1, 0, 1, 0, 1, 0, 1 }, //  3 = -4
245
+    { 0, 1, 0, 0, 1, 0, 0, 1 }, //  4 = -3
246
+    { 0, 0, 1, 0, 0, 0, 1, 0 }, //  5 = -2
247
+    { 0, 0, 0, 0, 1, 0, 0, 0 }, //  6 = -1
248
+    { 0, 0, 0, 0, 0, 0, 0, 0 }, //  7 =  0
249
+    { 0, 0, 0, 0, 1, 0, 0, 0 }, //  8 =  1
250
+    { 0, 0, 1, 0, 0, 0, 1, 0 }, //  9 =  2
251
+    { 0, 1, 0, 0, 1, 0, 0, 1 }, // 10 =  3
252
+    { 0, 1, 0, 1, 0, 1, 0, 1 }, // 11 =  4
253
+    { 0, 1, 1, 0, 1, 0, 1, 1 }, // 12 =  5
254
+    { 1, 1, 1, 0, 1, 1, 1, 0 }, // 13 =  6
255
+    { 1, 1, 1, 1, 1, 1, 1, 0 }, // 14 =  7
256
+    { 0 }
257
+
258
+  #elif STEPPER_PAGE_FORMAT == SP_4x2_256
259
+
260
+    { 0, 0, 0, 0 }, // 0
261
+    { 0, 1, 0, 0 }, // 1
262
+    { 1, 0, 1, 0 }, // 2
263
+    { 1, 1, 1, 0 }, // 3
264
+
265
+  #elif STEPPER_PAGE_FORMAT == SP_4x1_512
266
+
267
+    {0} // Uncompressed format, table not used
268
+
269
+  #endif
270
+
271
+};
272
+
273
+#endif // DIRECT_STEPPING

+ 137
- 0
Marlin/src/feature/direct_stepping.h Bestand weergeven

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 <http://www.gnu.org/licenses/>.
20
+ *
21
+ */
22
+#pragma once
23
+
24
+#include "../inc/MarlinConfig.h"
25
+
26
+namespace DirectStepping {
27
+
28
+  enum State : char {
29
+    MONITOR, NEWLINE, ADDRESS, SIZE, COLLECT, CHECKSUM, UNFAIL
30
+  };
31
+
32
+  enum PageState : uint8_t {
33
+    FREE, WRITING, OK, FAIL
34
+  };
35
+
36
+  // Static state used for stepping through direct stepping pages
37
+  struct page_step_state_t {
38
+    // Current page
39
+    uint8_t *page;
40
+    // Current segment
41
+    uint16_t segment_idx;
42
+    // Current steps within segment
43
+    uint8_t segment_steps;
44
+    // Segment delta
45
+    xyze_uint8_t sd;
46
+    // Block delta
47
+    xyze_int_t bd;
48
+  };
49
+
50
+  template<typename Cfg>
51
+  class SerialPageManager {
52
+  public:
53
+
54
+    typedef typename Cfg::page_idx_t page_idx_t;
55
+
56
+    static bool maybe_store_rxd_char(uint8_t c);
57
+    static void write_responses();
58
+
59
+    // common methods for page managers
60
+    static void init();
61
+    static uint8_t *get_page(const page_idx_t page_idx);
62
+    static void free_page(const page_idx_t page_idx);
63
+
64
+  protected:
65
+
66
+    typedef typename Cfg::write_byte_idx_t write_byte_idx_t;
67
+
68
+    static State state;
69
+    static volatile bool fatal_error;
70
+
71
+    static volatile PageState page_states[Cfg::NUM_PAGES];
72
+    static volatile bool page_states_dirty;
73
+    static millis_t next_response;
74
+
75
+    static uint8_t pages[Cfg::NUM_PAGES][Cfg::PAGE_SIZE];
76
+    static uint8_t checksum;
77
+    static write_byte_idx_t write_byte_idx;
78
+    static page_idx_t write_page_idx;
79
+    static write_byte_idx_t write_page_size;
80
+
81
+    static void set_page_state(const page_idx_t page_idx, const PageState page_state);
82
+  };
83
+
84
+  template<bool b, typename T, typename F> struct TypeSelector { typedef T type;} ;
85
+  template<typename T, typename F> struct TypeSelector<false, T, F> { typedef F type; };
86
+
87
+  template <int num_pages, int num_axes, int bits_segment, bool dir, int segments>
88
+  struct config_t {
89
+    static constexpr char CONTROL_CHAR  = '!';
90
+
91
+    static constexpr int NUM_PAGES      = num_pages;
92
+    static constexpr int NUM_AXES       = num_axes;
93
+    static constexpr int BITS_SEGMENT   = bits_segment;
94
+    static constexpr int DIRECTIONAL    = dir ? 1 : 0;
95
+    static constexpr int SEGMENTS       = segments;
96
+
97
+    static constexpr int RAW            = (BITS_SEGMENT == 1) ? 1 : 0;
98
+    static constexpr int NUM_SEGMENTS   = 1 << BITS_SEGMENT;
99
+    static constexpr int SEGMENT_STEPS  = 1 << (BITS_SEGMENT - DIRECTIONAL - RAW);
100
+    static constexpr int TOTAL_STEPS    = SEGMENT_STEPS * SEGMENTS;
101
+    static constexpr int PAGE_SIZE      = (NUM_AXES * BITS_SEGMENT * SEGMENTS) / 8;
102
+
103
+    static constexpr millis_t RESPONSE_INTERVAL_MS = 50;
104
+
105
+    typedef typename TypeSelector<(PAGE_SIZE>256), uint16_t, uint8_t>::type write_byte_idx_t;
106
+    typedef typename TypeSelector<(NUM_PAGES>256), uint16_t, uint8_t>::type page_idx_t;
107
+  };
108
+
109
+  template <uint8_t num_pages>
110
+  using SP_4x4D_128 = config_t<num_pages, 4, 4, true,  128>;
111
+
112
+  template <uint8_t num_pages>
113
+  using SP_4x2_256  = config_t<num_pages, 4, 2, false, 256>;
114
+
115
+  template <uint8_t num_pages>
116
+  using SP_4x1_512  = config_t<num_pages, 4, 1, false, 512>;
117
+
118
+  // configured types
119
+  typedef STEPPER_PAGE_FORMAT<STEPPER_PAGES> Config;
120
+
121
+  template class PAGE_MANAGER<Config>;
122
+  typedef PAGE_MANAGER<Config> PageManager;
123
+};
124
+
125
+#define SP_4x4D_128 1
126
+//#define SP_4x4_128 2
127
+//#define SP_4x2D_256 3
128
+#define SP_4x2_256 4
129
+#define SP_4x1_512 5
130
+
131
+typedef typename DirectStepping::Config::page_idx_t page_idx_t;
132
+
133
+// TODO: use config
134
+typedef DirectStepping::page_step_state_t page_step_state_t;
135
+
136
+extern const uint8_t segment_table[DirectStepping::Config::NUM_SEGMENTS][DirectStepping::Config::SEGMENT_STEPS];
137
+extern DirectStepping::PageManager page_manager;

+ 4
- 0
Marlin/src/gcode/gcode.cpp Bestand weergeven

261
         case 5: G5(); break;                                      // G5: Cubic B_spline
261
         case 5: G5(); break;                                      // G5: Cubic B_spline
262
       #endif
262
       #endif
263
 
263
 
264
+      #if ENABLED(DIRECT_STEPPING)
265
+        case 6: G6(); break;                                      // G6: Direct Stepper Move
266
+      #endif
267
+
264
       #if ENABLED(FWRETRACT)
268
       #if ENABLED(FWRETRACT)
265
         case 10: G10(); break;                                    // G10: Retract / Swap Retract
269
         case 10: G10(); break;                                    // G10: Retract / Swap Retract
266
         case 11: G11(); break;                                    // G11: Recover / Swap Recover
270
         case 11: G11(); break;                                    // G11: Recover / Swap Recover

+ 2
- 0
Marlin/src/gcode/gcode.h Bestand weergeven

402
 
402
 
403
   TERN_(BEZIER_CURVE_SUPPORT, static void G5());
403
   TERN_(BEZIER_CURVE_SUPPORT, static void G5());
404
 
404
 
405
+  TERN_(DIRECT_STEPPING, static void G6());
406
+
405
   #if ENABLED(FWRETRACT)
407
   #if ENABLED(FWRETRACT)
406
     static void G10();
408
     static void G10();
407
     static void G11();
409
     static void G11();

+ 3
- 1
Marlin/src/gcode/geometry/G92.cpp Bestand weergeven

99
   if    (sync_XYZ) sync_plan_position();
99
   if    (sync_XYZ) sync_plan_position();
100
   else if (sync_E) sync_plan_position_e();
100
   else if (sync_E) sync_plan_position_e();
101
 
101
 
102
-  report_current_position();
102
+  #if DISABLED(DIRECT_STEPPING)
103
+    report_current_position();
104
+  #endif
103
 }
105
 }

+ 61
- 0
Marlin/src/gcode/motion/G6.cpp Bestand weergeven

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 <http://www.gnu.org/licenses/>.
20
+ *
21
+ */
22
+#include "../../inc/MarlinConfig.h"
23
+
24
+#if ENABLED(DIRECT_STEPPING)
25
+
26
+#include "../../feature/direct_stepping.h"
27
+
28
+#include "../gcode.h"
29
+#include "../../module/planner.h"
30
+
31
+/**
32
+ * G6: Direct Stepper Move
33
+ */
34
+void GcodeSuite::G6() {
35
+  // TODO: feedrate support?
36
+  if (parser.seen('R'))
37
+    planner.last_page_step_rate = parser.value_ulong();
38
+
39
+  if (!DirectStepping::Config::DIRECTIONAL) {
40
+    if (parser.seen('X')) planner.last_page_dir.x = !!parser.value_byte();
41
+    if (parser.seen('Y')) planner.last_page_dir.y = !!parser.value_byte();
42
+    if (parser.seen('Z')) planner.last_page_dir.z = !!parser.value_byte();
43
+    if (parser.seen('E')) planner.last_page_dir.e = !!parser.value_byte();
44
+  }
45
+
46
+  // No index means we just set the state
47
+  if (!parser.seen('I')) return;
48
+
49
+  // No speed is set, can't schedule the move
50
+  if (!planner.last_page_step_rate) return;
51
+
52
+  const page_idx_t page_idx = (page_idx_t) parser.value_ulong();
53
+
54
+  uint16_t num_steps = DirectStepping::Config::TOTAL_STEPS;
55
+  if (parser.seen('S')) num_steps = parser.value_ushort();
56
+
57
+  planner.buffer_page(page_idx, 0, num_steps);
58
+  reset_stepper_timeout();
59
+}
60
+
61
+#endif // DIRECT_STEPPING

+ 12
- 0
Marlin/src/inc/Conditionals_adv.h Bestand weergeven

323
   #endif
323
   #endif
324
 #endif
324
 #endif
325
 
325
 
326
+#if ENABLED(DIRECT_STEPPING)
327
+  #ifndef STEPPER_PAGES
328
+    #define STEPPER_PAGES 16
329
+  #endif
330
+  #ifndef STEPPER_PAGE_FORMAT
331
+    #define STEPPER_PAGE_FORMAT SP_4x2_256
332
+  #endif
333
+  #ifndef PAGE_MANAGER
334
+    #define PAGE_MANAGER SerialPageManager
335
+  #endif
336
+#endif
337
+
326
 //
338
 //
327
 // SD Card connection methods
339
 // SD Card connection methods
328
 // Defined here so pins and sanity checks can use them
340
 // Defined here so pins and sanity checks can use them

+ 9
- 0
Marlin/src/inc/SanityCheck.h Bestand weergeven

2923
 #if SAVED_POSITIONS > 256
2923
 #if SAVED_POSITIONS > 256
2924
   #error "SAVED_POSITIONS must be an integer from 0 to 256."
2924
   #error "SAVED_POSITIONS must be an integer from 0 to 256."
2925
 #endif
2925
 #endif
2926
+
2927
+/**
2928
+ * Sanity checks for stepper chunk support
2929
+ */
2930
+#if ENABLED(DIRECT_STEPPING)
2931
+  #if ENABLED(LIN_ADVANCE)
2932
+    #error "DIRECT_STEPPING is incompatible with LIN_ADVANCE. Enable in external planner if possible."
2933
+  #endif
2934
+#endif

+ 3
- 0
Marlin/src/lcd/language/language_en.h Bestand weergeven

577
   PROGMEM Language_Str MSG_SNAKE                           = _UxGT("Sn4k3");
577
   PROGMEM Language_Str MSG_SNAKE                           = _UxGT("Sn4k3");
578
   PROGMEM Language_Str MSG_MAZE                            = _UxGT("Maze");
578
   PROGMEM Language_Str MSG_MAZE                            = _UxGT("Maze");
579
 
579
 
580
+  PROGMEM Language_Str MSG_BAD_PAGE                        = _UxGT("Bad page index");
581
+  PROGMEM Language_Str MSG_BAD_PAGE_SPEED                  = _UxGT("Bad page speed");
582
+
580
   //
583
   //
581
   // Filament Change screens show up to 3 lines on a 4-line display
584
   // Filament Change screens show up to 3 lines on a 4-line display
582
   //                        ...or up to 2 lines on a 3-line display
585
   //                        ...or up to 2 lines on a 3-line display

+ 79
- 7
Marlin/src/module/planner.cpp Bestand weergeven

151
   uint8_t Planner::last_extruder = 0;     // Respond to extruder change
151
   uint8_t Planner::last_extruder = 0;     // Respond to extruder change
152
 #endif
152
 #endif
153
 
153
 
154
+#if ENABLED(DIRECT_STEPPING)
155
+  uint32_t Planner::last_page_step_rate = 0;
156
+  xyze_bool_t Planner::last_page_dir{0};
157
+#endif
158
+
154
 #if EXTRUDERS
159
 #if EXTRUDERS
155
   int16_t Planner::flow_percentage[EXTRUDERS] = ARRAY_BY_EXTRUDERS1(100); // Extrusion factor for each extruder
160
   int16_t Planner::flow_percentage[EXTRUDERS] = ARRAY_BY_EXTRUDERS1(100); // Extrusion factor for each extruder
156
   float Planner::e_factor[EXTRUDERS] = ARRAY_BY_EXTRUDERS1(1.0f); // The flow percentage and volumetric multiplier combine to scale E movement
161
   float Planner::e_factor[EXTRUDERS] = ARRAY_BY_EXTRUDERS1(1.0f); // The flow percentage and volumetric multiplier combine to scale E movement
235
   TERN_(ABL_PLANAR, bed_level_matrix.set_to_identity());
240
   TERN_(ABL_PLANAR, bed_level_matrix.set_to_identity());
236
   clear_block_buffer();
241
   clear_block_buffer();
237
   delay_before_delivering = 0;
242
   delay_before_delivering = 0;
243
+  #if ENABLED(DIRECT_STEPPING)
244
+    last_page_step_rate = 0;
245
+    last_page_dir.reset();
246
+  #endif
238
 }
247
 }
239
 
248
 
240
 #if ENABLED(S_CURVE_ACCELERATION)
249
 #if ENABLED(S_CURVE_ACCELERATION)
906
       streaming operating conditions. Use for planning optimizations by avoiding recomputing parts of the
915
       streaming operating conditions. Use for planning optimizations by avoiding recomputing parts of the
907
       planner buffer that don't change with the addition of a new block, as describe above. In addition,
916
       planner buffer that don't change with the addition of a new block, as describe above. In addition,
908
       this block can never be less than block_buffer_tail and will always be pushed forward and maintain
917
       this block can never be less than block_buffer_tail and will always be pushed forward and maintain
909
-      this requirement when encountered by the Planner::discard_current_block() routine during a cycle.
918
+      this requirement when encountered by the Planner::release_current_block() routine during a cycle.
910
 
919
 
911
   NOTE: Since the planner only computes on what's in the planner buffer, some motions with lots of short
920
   NOTE: Since the planner only computes on what's in the planner buffer, some motions with lots of short
912
   line segments, like G2/3 arcs or complex curves, may seem to move slow. This is because there simply isn't
921
   line segments, like G2/3 arcs or complex curves, may seem to move slow. This is because there simply isn't
994
     // Perform the reverse pass
1003
     // Perform the reverse pass
995
     block_t *current = &block_buffer[block_index];
1004
     block_t *current = &block_buffer[block_index];
996
 
1005
 
997
-    // Only consider non sync blocks
998
-    if (!TEST(current->flag, BLOCK_BIT_SYNC_POSITION)) {
1006
+    // Only consider non sync and page blocks
1007
+    if (!TEST(current->flag, BLOCK_BIT_SYNC_POSITION) && !IS_PAGE(current)) {
999
       reverse_pass_kernel(current, next);
1008
       reverse_pass_kernel(current, next);
1000
       next = current;
1009
       next = current;
1001
     }
1010
     }
1089
     // Perform the forward pass
1098
     // Perform the forward pass
1090
     block = &block_buffer[block_index];
1099
     block = &block_buffer[block_index];
1091
 
1100
 
1092
-    // Skip SYNC blocks
1093
-    if (!TEST(block->flag, BLOCK_BIT_SYNC_POSITION)) {
1101
+    // Skip SYNC and page blocks
1102
+    if (!TEST(block->flag, BLOCK_BIT_SYNC_POSITION) && !IS_PAGE(block)) {
1094
       // If there's no previous block or the previous block is not
1103
       // If there's no previous block or the previous block is not
1095
       // BUSY (thus, modifiable) run the forward_pass_kernel. Otherwise,
1104
       // BUSY (thus, modifiable) run the forward_pass_kernel. Otherwise,
1096
       // the previous block became BUSY, so assume the current block's
1105
       // the previous block became BUSY, so assume the current block's
1139
 
1148
 
1140
     next = &block_buffer[block_index];
1149
     next = &block_buffer[block_index];
1141
 
1150
 
1142
-    // Skip sync blocks
1143
-    if (!TEST(next->flag, BLOCK_BIT_SYNC_POSITION)) {
1151
+    // Skip sync and page blocks
1152
+    if (!TEST(next->flag, BLOCK_BIT_SYNC_POSITION) && !IS_PAGE(next)) {
1144
       next_entry_speed = SQRT(next->entry_speed_sqr);
1153
       next_entry_speed = SQRT(next->entry_speed_sqr);
1145
 
1154
 
1146
       if (block) {
1155
       if (block) {
2717
   #endif
2726
   #endif
2718
 } // buffer_line()
2727
 } // buffer_line()
2719
 
2728
 
2729
+#if ENABLED(DIRECT_STEPPING)
2730
+
2731
+  void Planner::buffer_page(const page_idx_t page_idx, const uint8_t extruder, const uint16_t num_steps) {
2732
+    if (!last_page_step_rate) {
2733
+      kill(GET_TEXT(MSG_BAD_PAGE_SPEED));
2734
+      return;
2735
+    }
2736
+
2737
+    uint8_t next_buffer_head;
2738
+    block_t * const block = get_next_free_block(next_buffer_head);
2739
+
2740
+    block->flag = BLOCK_FLAG_IS_PAGE;
2741
+
2742
+    #if FAN_COUNT > 0
2743
+      FANS_LOOP(i) block->fan_speed[i] = thermalManager.fan_speed[i];
2744
+    #endif
2745
+
2746
+    #if EXTRUDERS > 1
2747
+      block->extruder = extruder;
2748
+    #endif
2749
+
2750
+    block->page_idx = page_idx;
2751
+
2752
+    block->step_event_count = num_steps;
2753
+    block->initial_rate =
2754
+      block->final_rate =
2755
+      block->nominal_rate = last_page_step_rate; // steps/s
2756
+
2757
+    block->accelerate_until = 0;
2758
+    block->decelerate_after = block->step_event_count;
2759
+
2760
+    // Will be set to last direction later if directional format.
2761
+    block->direction_bits = 0;
2762
+
2763
+    #define PAGE_UPDATE_DIR(AXIS) \
2764
+      if (!last_page_dir[_AXIS(AXIS)]) SBI(block->direction_bits, _AXIS(AXIS));
2765
+
2766
+    if (!DirectStepping::Config::DIRECTIONAL) {
2767
+      PAGE_UPDATE_DIR(X);
2768
+      PAGE_UPDATE_DIR(Y);
2769
+      PAGE_UPDATE_DIR(Z);
2770
+      PAGE_UPDATE_DIR(E);
2771
+    }
2772
+
2773
+    // If this is the first added movement, reload the delay, otherwise, cancel it.
2774
+    if (block_buffer_head == block_buffer_tail) {
2775
+      // If it was the first queued block, restart the 1st block delivery delay, to
2776
+      // give the planner an opportunity to queue more movements and plan them
2777
+      // As there are no queued movements, the Stepper ISR will not touch this
2778
+      // variable, so there is no risk setting this here (but it MUST be done
2779
+      // before the following line!!)
2780
+      delay_before_delivering = BLOCK_DELAY_FOR_1ST_MOVE;
2781
+    }
2782
+
2783
+    // Move buffer head
2784
+    block_buffer_head = next_buffer_head;
2785
+
2786
+    enable_all_steppers();
2787
+    stepper.wake_up();
2788
+  }
2789
+
2790
+#endif // DIRECT_STEPPING
2791
+
2720
 /**
2792
 /**
2721
  * Directly set the planner ABC position (and stepper positions)
2793
  * Directly set the planner ABC position (and stepper positions)
2722
  * converting mm (or angles for SCARA) into steps.
2794
  * converting mm (or angles for SCARA) into steps.

+ 34
- 6
Marlin/src/module/planner.h Bestand weergeven

66
   #include "../feature/spindle_laser_types.h"
66
   #include "../feature/spindle_laser_types.h"
67
 #endif
67
 #endif
68
 
68
 
69
+#if ENABLED(DIRECT_STEPPING)
70
+  #include "../feature/direct_stepping.h"
71
+  #define IS_PAGE(B) TEST(B->flag, BLOCK_BIT_IS_PAGE)
72
+#else
73
+  #define IS_PAGE(B) false
74
+#endif
75
+
69
 // Feedrate for manual moves
76
 // Feedrate for manual moves
70
 #ifdef MANUAL_FEEDRATE
77
 #ifdef MANUAL_FEEDRATE
71
   constexpr xyze_feedrate_t _mf = MANUAL_FEEDRATE,
78
   constexpr xyze_feedrate_t _mf = MANUAL_FEEDRATE,
90
 
97
 
91
   // Sync the stepper counts from the block
98
   // Sync the stepper counts from the block
92
   BLOCK_BIT_SYNC_POSITION
99
   BLOCK_BIT_SYNC_POSITION
100
+
101
+  // Direct stepping page
102
+  #if ENABLED(DIRECT_STEPPING)
103
+    , BLOCK_BIT_IS_PAGE
104
+  #endif
93
 };
105
 };
94
 
106
 
95
 enum BlockFlag : char {
107
 enum BlockFlag : char {
96
-  BLOCK_FLAG_RECALCULATE          = _BV(BLOCK_BIT_RECALCULATE),
97
-  BLOCK_FLAG_NOMINAL_LENGTH       = _BV(BLOCK_BIT_NOMINAL_LENGTH),
98
-  BLOCK_FLAG_CONTINUED            = _BV(BLOCK_BIT_CONTINUED),
99
-  BLOCK_FLAG_SYNC_POSITION        = _BV(BLOCK_BIT_SYNC_POSITION)
108
+    BLOCK_FLAG_RECALCULATE          = _BV(BLOCK_BIT_RECALCULATE)
109
+  , BLOCK_FLAG_NOMINAL_LENGTH       = _BV(BLOCK_BIT_NOMINAL_LENGTH)
110
+  , BLOCK_FLAG_CONTINUED            = _BV(BLOCK_BIT_CONTINUED)
111
+  , BLOCK_FLAG_SYNC_POSITION        = _BV(BLOCK_BIT_SYNC_POSITION)
112
+  #if ENABLED(DIRECT_STEPPING)
113
+    , BLOCK_FLAG_IS_PAGE            = _BV(BLOCK_BIT_IS_PAGE)
114
+  #endif
100
 };
115
 };
101
 
116
 
102
 #if ENABLED(LASER_POWER_INLINE)
117
 #if ENABLED(LASER_POWER_INLINE)
180
            final_rate,                      // The minimal rate at exit
195
            final_rate,                      // The minimal rate at exit
181
            acceleration_steps_per_s2;       // acceleration steps/sec^2
196
            acceleration_steps_per_s2;       // acceleration steps/sec^2
182
 
197
 
198
+  #if ENABLED(DIRECT_STEPPING)
199
+    page_idx_t page_idx;                    // Page index used for direct stepping
200
+  #endif
201
+
183
   #if HAS_CUTTER
202
   #if HAS_CUTTER
184
     cutter_power_t cutter_power;            // Power level for Spindle, Laser, etc.
203
     cutter_power_t cutter_power;            // Power level for Spindle, Laser, etc.
185
   #endif
204
   #endif
296
       static uint8_t last_extruder;                 // Respond to extruder change
315
       static uint8_t last_extruder;                 // Respond to extruder change
297
     #endif
316
     #endif
298
 
317
 
318
+    #if ENABLED(DIRECT_STEPPING)
319
+      static uint32_t last_page_step_rate;          // Last page step rate given
320
+      static xyze_bool_t last_page_dir;             // Last page direction given
321
+    #endif
322
+
299
     #if EXTRUDERS
323
     #if EXTRUDERS
300
       static int16_t flow_percentage[EXTRUDERS];    // Extrusion factor for each extruder
324
       static int16_t flow_percentage[EXTRUDERS];    // Extrusion factor for each extruder
301
       static float e_factor[EXTRUDERS];             // The flow percentage and volumetric multiplier combine to scale E movement
325
       static float e_factor[EXTRUDERS];             // The flow percentage and volumetric multiplier combine to scale E movement
726
       );
750
       );
727
     }
751
     }
728
 
752
 
753
+    #if ENABLED(DIRECT_STEPPING)
754
+      static void buffer_page(const page_idx_t page_idx, const uint8_t extruder, const uint16_t num_steps);
755
+    #endif
756
+
729
     /**
757
     /**
730
      * Set the planner.position and individual stepper positions.
758
      * Set the planner.position and individual stepper positions.
731
      * Used by G92, G28, G29, and other procedures.
759
      * Used by G92, G28, G29, and other procedures.
811
     static block_t* get_current_block();
839
     static block_t* get_current_block();
812
 
840
 
813
     /**
841
     /**
814
-     * "Discard" the block and "release" the memory.
842
+     * "Release" the current block so its slot can be reused.
815
      * Called when the current block is no longer needed.
843
      * Called when the current block is no longer needed.
816
      */
844
      */
817
-    FORCE_INLINE static void discard_current_block() {
845
+    FORCE_INLINE static void release_current_block() {
818
       if (has_blocks_queued())
846
       if (has_blocks_queued())
819
         block_buffer_tail = next_block_index(block_buffer_tail);
847
         block_buffer_tail = next_block_index(block_buffer_tail);
820
     }
848
     }

+ 179
- 34
Marlin/src/module/stepper.cpp Bestand weergeven

230
   uint32_t Stepper::nextBabystepISR = BABYSTEP_NEVER;
230
   uint32_t Stepper::nextBabystepISR = BABYSTEP_NEVER;
231
 #endif
231
 #endif
232
 
232
 
233
+#if ENABLED(DIRECT_STEPPING)
234
+  page_step_state_t Stepper::page_step_state;
235
+#endif
236
+
233
 int32_t Stepper::ticks_nominal = -1;
237
 int32_t Stepper::ticks_nominal = -1;
234
 #if DISABLED(S_CURVE_ACCELERATION)
238
 #if DISABLED(S_CURVE_ACCELERATION)
235
   uint32_t Stepper::acc_step_rate; // needed for deceleration start point
239
   uint32_t Stepper::acc_step_rate; // needed for deceleration start point
1520
   // If we must abort the current block, do so!
1524
   // If we must abort the current block, do so!
1521
   if (abort_current_block) {
1525
   if (abort_current_block) {
1522
     abort_current_block = false;
1526
     abort_current_block = false;
1523
-    if (current_block) {
1524
-      axis_did_move = 0;
1525
-      current_block = nullptr;
1526
-      planner.discard_current_block();
1527
-    }
1527
+    if (current_block) discard_current_block();
1528
   }
1528
   }
1529
 
1529
 
1530
   // If there is no current block, do nothing
1530
   // If there is no current block, do nothing
1558
       } \
1558
       } \
1559
     }while(0)
1559
     }while(0)
1560
 
1560
 
1561
-    // Start an active pulse, if Bresenham says so, and update position
1561
+    // Start an active pulse if needed
1562
     #define PULSE_START(AXIS) do{ \
1562
     #define PULSE_START(AXIS) do{ \
1563
       if (step_needed[_AXIS(AXIS)]) { \
1563
       if (step_needed[_AXIS(AXIS)]) { \
1564
         _APPLY_STEP(AXIS, !_INVERT_STEP_PIN(AXIS), 0); \
1564
         _APPLY_STEP(AXIS, !_INVERT_STEP_PIN(AXIS), 0); \
1565
       } \
1565
       } \
1566
     }while(0)
1566
     }while(0)
1567
 
1567
 
1568
-    // Stop an active pulse, if any, and adjust error term
1568
+    // Stop an active pulse if needed
1569
     #define PULSE_STOP(AXIS) do { \
1569
     #define PULSE_STOP(AXIS) do { \
1570
       if (step_needed[_AXIS(AXIS)]) { \
1570
       if (step_needed[_AXIS(AXIS)]) { \
1571
         _APPLY_STEP(AXIS, _INVERT_STEP_PIN(AXIS), 0); \
1571
         _APPLY_STEP(AXIS, _INVERT_STEP_PIN(AXIS), 0); \
1572
       } \
1572
       } \
1573
     }while(0)
1573
     }while(0)
1574
 
1574
 
1575
-    // Determine if pulses are needed
1576
-    #if HAS_X_STEP
1577
-      PULSE_PREP(X);
1578
-    #endif
1579
-    #if HAS_Y_STEP
1580
-      PULSE_PREP(Y);
1581
-    #endif
1582
-    #if HAS_Z_STEP
1583
-      PULSE_PREP(Z);
1584
-    #endif
1575
+    // Direct Stepping page?
1576
+    const bool is_page = IS_PAGE(current_block);
1577
+
1578
+    #if ENABLED(DIRECT_STEPPING)
1579
+
1580
+      if (is_page) {
1581
+
1582
+        #if STEPPER_PAGE_FORMAT == SP_4x4D_128
1583
+
1584
+          #define PAGE_SEGMENT_UPDATE(AXIS, VALUE, MID) do{ \
1585
+                 if ((VALUE) == MID) {}                     \
1586
+            else if ((VALUE) <  MID) SBI(dm, _AXIS(AXIS));  \
1587
+            else                     CBI(dm, _AXIS(AXIS));  \
1588
+            page_step_state.sd[_AXIS(AXIS)] = VALUE;        \
1589
+            page_step_state.bd[_AXIS(AXIS)] += VALUE;       \
1590
+          }while(0)
1591
+
1592
+          #define PAGE_PULSE_PREP(AXIS) do{ \
1593
+            step_needed[_AXIS(AXIS)] =      \
1594
+              pgm_read_byte(&segment_table[page_step_state.sd[_AXIS(AXIS)]][page_step_state.segment_steps & 0x7]); \
1595
+          }while(0)
1596
+
1597
+          switch (page_step_state.segment_steps) {
1598
+            case 8:
1599
+              page_step_state.segment_idx += 2;
1600
+              page_step_state.segment_steps = 0;
1601
+              // fallthru
1602
+            case 0: {
1603
+              const uint8_t low = page_step_state.page[page_step_state.segment_idx],
1604
+                           high = page_step_state.page[page_step_state.segment_idx + 1];
1605
+              uint8_t dm = last_direction_bits;
1606
+
1607
+              PAGE_SEGMENT_UPDATE(X, low >> 4, 7);
1608
+              PAGE_SEGMENT_UPDATE(Y, low & 0xF, 7);
1609
+              PAGE_SEGMENT_UPDATE(Z, high >> 4, 7);
1610
+              PAGE_SEGMENT_UPDATE(E, high & 0xF, 7);
1611
+
1612
+              if (dm != last_direction_bits) {
1613
+                last_direction_bits = dm;
1614
+                set_directions();
1615
+              }
1616
+            } break;
1617
+
1618
+            default: break;
1619
+          }
1620
+
1621
+          PAGE_PULSE_PREP(X),
1622
+          PAGE_PULSE_PREP(Y),
1623
+          PAGE_PULSE_PREP(Z),
1624
+          PAGE_PULSE_PREP(E);
1625
+
1626
+          page_step_state.segment_steps++;
1627
+
1628
+        #elif STEPPER_PAGE_FORMAT == SP_4x2_256
1629
+
1630
+          #define PAGE_SEGMENT_UPDATE(AXIS, VALUE) \
1631
+            page_step_state.sd[_AXIS(AXIS)] = VALUE; \
1632
+            page_step_state.bd[_AXIS(AXIS)] += VALUE;
1633
+
1634
+          #define PAGE_PULSE_PREP(AXIS) do{ \
1635
+            step_needed[_AXIS(AXIS)] =      \
1636
+              pgm_read_byte(&segment_table[page_step_state.sd[_AXIS(AXIS)]][page_step_state.segment_steps & 0x3]); \
1637
+          }while(0)
1638
+
1639
+          switch (page_step_state.segment_steps) {
1640
+            case 4:
1641
+              page_step_state.segment_idx++;
1642
+              page_step_state.segment_steps = 0;
1643
+              // fallthru
1644
+            case 0: {
1645
+              const uint8_t b = page_step_state.page[page_step_state.segment_idx];
1646
+              PAGE_SEGMENT_UPDATE(X, (b >> 6) & 0x3);
1647
+              PAGE_SEGMENT_UPDATE(Y, (b >> 4) & 0x3);
1648
+              PAGE_SEGMENT_UPDATE(Z, (b >> 2) & 0x3);
1649
+              PAGE_SEGMENT_UPDATE(E, (b >> 0) & 0x3);
1650
+            } break;
1651
+            default: break;
1652
+          }
1653
+
1654
+          PAGE_PULSE_PREP(X);
1655
+          PAGE_PULSE_PREP(Y);
1656
+          PAGE_PULSE_PREP(Z);
1657
+          PAGE_PULSE_PREP(E);
1658
+
1659
+          page_step_state.segment_steps++;
1660
+
1661
+        #elif STEPPER_PAGE_FORMAT == SP_4x1_512
1662
+
1663
+          #define PAGE_PULSE_PREP(AXIS, BITS) do{             \
1664
+            step_needed[_AXIS(AXIS)] = (steps >> BITS) & 0x1; \
1665
+            if (step_needed[_AXIS(AXIS)])                     \
1666
+              page_step_state.bd[_AXIS(AXIS)]++;              \
1667
+          }while(0)
1668
+
1669
+          uint8_t steps = page_step_state.page[page_step_state.segment_idx >> 1];
1670
+
1671
+          if (page_step_state.segment_idx & 0x1) steps >>= 4;
1672
+
1673
+          PAGE_PULSE_PREP(X, 3);
1674
+          PAGE_PULSE_PREP(Y, 2);
1675
+          PAGE_PULSE_PREP(Z, 1);
1676
+          PAGE_PULSE_PREP(E, 0);
1677
+
1678
+          page_step_state.segment_idx++;
1585
 
1679
 
1586
-    #if EITHER(LIN_ADVANCE, MIXING_EXTRUDER)
1587
-      delta_error.e += advance_dividend.e;
1588
-      if (delta_error.e >= 0) {
1589
-        count_position.e += count_direction.e;
1590
-        #if ENABLED(LIN_ADVANCE)
1591
-          delta_error.e -= advance_divisor;
1592
-          // Don't step E here - But remember the number of steps to perform
1593
-          motor_direction(E_AXIS) ? --LA_steps : ++LA_steps;
1594
         #else
1680
         #else
1595
-          step_needed.e = true;
1681
+          #error "Unknown direct stepping page format!"
1596
         #endif
1682
         #endif
1597
       }
1683
       }
1598
-    #elif HAS_E0_STEP
1599
-      PULSE_PREP(E);
1600
-    #endif
1684
+
1685
+    #endif // DIRECT_STEPPING
1686
+
1687
+    if (!is_page) {
1688
+      // Determine if pulses are needed
1689
+      #if HAS_X_STEP
1690
+        PULSE_PREP(X);
1691
+      #endif
1692
+      #if HAS_Y_STEP
1693
+        PULSE_PREP(Y);
1694
+      #endif
1695
+      #if HAS_Z_STEP
1696
+        PULSE_PREP(Z);
1697
+      #endif
1698
+
1699
+      #if EITHER(LIN_ADVANCE, MIXING_EXTRUDER)
1700
+        delta_error.e += advance_dividend.e;
1701
+        if (delta_error.e >= 0) {
1702
+          count_position.e += count_direction.e;
1703
+          #if ENABLED(LIN_ADVANCE)
1704
+            delta_error.e -= advance_divisor;
1705
+            // Don't step E here - But remember the number of steps to perform
1706
+            motor_direction(E_AXIS) ? --LA_steps : ++LA_steps;
1707
+          #else
1708
+            step_needed.e = true;
1709
+          #endif
1710
+        }
1711
+      #elif HAS_E0_STEP
1712
+        PULSE_PREP(E);
1713
+      #endif
1714
+    }
1601
 
1715
 
1602
     #if ISR_MULTI_STEPS
1716
     #if ISR_MULTI_STEPS
1603
       if (firstStep)
1717
       if (firstStep)
1676
   // If there is a current block
1790
   // If there is a current block
1677
   if (current_block) {
1791
   if (current_block) {
1678
 
1792
 
1679
-    // If current block is finished, reset pointer
1793
+    // If current block is finished, reset pointer and finalize state
1680
     if (step_events_completed >= step_event_count) {
1794
     if (step_events_completed >= step_event_count) {
1795
+      #if ENABLED(DIRECT_STEPPING)
1796
+        #if STEPPER_PAGE_FORMAT == SP_4x4D_128
1797
+          #define PAGE_SEGMENT_UPDATE_POS(AXIS) \
1798
+            count_position[_AXIS(AXIS)] += page_step_state.bd[_AXIS(AXIS)] - 128 * 7;
1799
+        #elif STEPPER_PAGE_FORMAT == SP_4x1_512 || STEPPER_PAGE_FORMAT == SP_4x2_256
1800
+          #define PAGE_SEGMENT_UPDATE_POS(AXIS) \
1801
+            count_position[_AXIS(AXIS)] += page_step_state.bd[_AXIS(AXIS)] * count_direction[_AXIS(AXIS)];
1802
+        #endif
1803
+
1804
+        if (IS_PAGE(current_block)) {
1805
+          PAGE_SEGMENT_UPDATE_POS(X);
1806
+          PAGE_SEGMENT_UPDATE_POS(Y);
1807
+          PAGE_SEGMENT_UPDATE_POS(Z);
1808
+          PAGE_SEGMENT_UPDATE_POS(E);
1809
+        }
1810
+      #endif
1681
       #ifdef FILAMENT_RUNOUT_DISTANCE_MM
1811
       #ifdef FILAMENT_RUNOUT_DISTANCE_MM
1682
         runout.block_completed(current_block);
1812
         runout.block_completed(current_block);
1683
       #endif
1813
       #endif
1684
-      axis_did_move = 0;
1685
-      current_block = nullptr;
1686
-      planner.discard_current_block();
1814
+      discard_current_block();
1687
     }
1815
     }
1688
     else {
1816
     else {
1689
       // Step events not completed yet...
1817
       // Step events not completed yet...
1867
       // Sync block? Sync the stepper counts and return
1995
       // Sync block? Sync the stepper counts and return
1868
       while (TEST(current_block->flag, BLOCK_BIT_SYNC_POSITION)) {
1996
       while (TEST(current_block->flag, BLOCK_BIT_SYNC_POSITION)) {
1869
         _set_position(current_block->position);
1997
         _set_position(current_block->position);
1870
-        planner.discard_current_block();
1998
+        discard_current_block();
1871
 
1999
 
1872
         // Try to get a new block
2000
         // Try to get a new block
1873
         if (!(current_block = planner.get_current_block()))
2001
         if (!(current_block = planner.get_current_block()))
1878
 
2006
 
1879
       TERN_(POWER_LOSS_RECOVERY, recovery.info.sdpos = current_block->sdpos);
2007
       TERN_(POWER_LOSS_RECOVERY, recovery.info.sdpos = current_block->sdpos);
1880
 
2008
 
2009
+      #if ENABLED(DIRECT_STEPPING)
2010
+        if (IS_PAGE(current_block)) {
2011
+          page_step_state.segment_steps = 0;
2012
+          page_step_state.segment_idx = 0;
2013
+          page_step_state.page = page_manager.get_page(current_block->page_idx);
2014
+          page_step_state.bd.reset();
2015
+
2016
+          if (DirectStepping::Config::DIRECTIONAL)
2017
+            current_block->direction_bits = last_direction_bits;
2018
+
2019
+          if (!page_step_state.page) {
2020
+            discard_current_block();
2021
+            return interval;
2022
+          }
2023
+        }
2024
+      #endif
2025
+
1881
       // Flag all moving axes for proper endstop handling
2026
       // Flag all moving axes for proper endstop handling
1882
 
2027
 
1883
       #if IS_CORE
2028
       #if IS_CORE

+ 15
- 0
Marlin/src/module/stepper.h Bestand weergeven

334
       static uint32_t nextBabystepISR;
334
       static uint32_t nextBabystepISR;
335
     #endif
335
     #endif
336
 
336
 
337
+    #if ENABLED(DIRECT_STEPPING)
338
+      static page_step_state_t page_step_state;
339
+    #endif
340
+
337
     static int32_t ticks_nominal;
341
     static int32_t ticks_nominal;
338
     #if DISABLED(S_CURVE_ACCELERATION)
342
     #if DISABLED(S_CURVE_ACCELERATION)
339
       static uint32_t acc_step_rate; // needed for deceleration start point
343
       static uint32_t acc_step_rate; // needed for deceleration start point
426
     static void report_a_position(const xyz_long_t &pos);
430
     static void report_a_position(const xyz_long_t &pos);
427
     static void report_positions();
431
     static void report_positions();
428
 
432
 
433
+    // Discard current block and free any resources
434
+    FORCE_INLINE static void discard_current_block() {
435
+      #if ENABLED(DIRECT_STEPPING)
436
+        if (IS_PAGE(current_block))
437
+          page_manager.free_page(current_block->page_idx);
438
+      #endif
439
+      current_block = nullptr;
440
+      axis_did_move = 0;
441
+      planner.release_current_block();
442
+    }
443
+
429
     // Quickly stop all steppers
444
     // Quickly stop all steppers
430
     FORCE_INLINE static void quick_stop() { abort_current_block = true; }
445
     FORCE_INLINE static void quick_stop() { abort_current_block = true; }
431
 
446
 

+ 3
- 2
buildroot/share/tests/mega2560-tests Bestand weergeven

71
 opt_enable ZONESTAR_LCD Z_PROBE_SERVO_NR Z_SERVO_ANGLES DEACTIVATE_SERVOS_AFTER_MOVE BOOT_MARLIN_LOGO_ANIMATED \
71
 opt_enable ZONESTAR_LCD Z_PROBE_SERVO_NR Z_SERVO_ANGLES DEACTIVATE_SERVOS_AFTER_MOVE BOOT_MARLIN_LOGO_ANIMATED \
72
            AUTO_BED_LEVELING_3POINT DEBUG_LEVELING_FEATURE EEPROM_SETTINGS EEPROM_CHITCHAT M114_DETAIL \
72
            AUTO_BED_LEVELING_3POINT DEBUG_LEVELING_FEATURE EEPROM_SETTINGS EEPROM_CHITCHAT M114_DETAIL \
73
            NO_VOLUMETRICS EXTENDED_CAPABILITIES_REPORT AUTO_REPORT_TEMPERATURES AUTOTEMP G38_PROBE_TARGET JOYSTICK \
73
            NO_VOLUMETRICS EXTENDED_CAPABILITIES_REPORT AUTO_REPORT_TEMPERATURES AUTOTEMP G38_PROBE_TARGET JOYSTICK \
74
-           PRUSA_MMU2 MMU2_MENUS PRUSA_MMU2_S_MODE FILAMENT_RUNOUT_SENSOR NOZZLE_PARK_FEATURE ADVANCED_PAUSE_FEATURE Z_SAFE_HOMING
75
-exec_test $1 $2 "RAMPS | ZONESTAR_LCD | MMU2 | Servo Probe | ABL 3-Pt | Debug Leveling | EEPROM | G38 ..."
74
+           PRUSA_MMU2 MMU2_MENUS PRUSA_MMU2_S_MODE DIRECT_STEPPING \
75
+           FILAMENT_RUNOUT_SENSOR NOZZLE_PARK_FEATURE ADVANCED_PAUSE_FEATURE Z_SAFE_HOMING
76
+exec_test $1 $2 "RAMPS | ZONESTAR + Chinese | MMU2 | Servo | 3-Point + Debug | G38 ..."
76
 
77
 
77
 #
78
 #
78
 # Test MINIRAMBO with PWM_MOTOR_CURRENT and many features
79
 # Test MINIRAMBO with PWM_MOTOR_CURRENT and many features

Laden…
Annuleren
Opslaan