My Marlin configs for Fabrikator Mini and CTC i3 Pro B
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. /**
  2. * Marlin 3D Printer Firmware
  3. * Copyright (c) 2019 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. #if HAS_L64XX
  24. #include "../../gcode.h"
  25. #include "../../../libs/L64XX/L64XX_Marlin.h"
  26. #include "../../../module/stepper/indirection.h"
  27. #include "../../../module/planner.h"
  28. #define DEBUG_OUT ENABLED(L6470_CHITCHAT)
  29. #include "../../../core/debug_out.h"
  30. /**
  31. *
  32. * M906: report or set KVAL_HOLD which sets the maximum effective voltage provided by the
  33. * PWMs to the steppers
  34. *
  35. * On L6474 this sets the TVAL register (same address).
  36. *
  37. * J - select which driver(s) to monitor on multi-driver axis
  38. * 0 - (default) monitor all drivers on the axis or E0
  39. * 1 - monitor only X, Y, Z or E1
  40. * 2 - monitor only X2, Y2, Z2 or E2
  41. * 3 - monitor only Z3 or E3
  42. * 4 - monitor only E4
  43. * 5 - monitor only E5
  44. * Xxxx, Yxxx, Zxxx, Exxx - axis to be monitored with displacement
  45. * xxx (1-255) is distance moved on either side of current position
  46. *
  47. * I - over current threshold
  48. * optional - will report current value from driver if not specified
  49. *
  50. * K - value for KVAL_HOLD (0 - 255) (optional)
  51. * optional - will report current value from driver if not specified
  52. *
  53. */
  54. /**
  55. * Sets KVAL_HOLD wich affects the current being driven through the stepper.
  56. *
  57. * L6470 is used in the STEP-CLOCK mode. KVAL_HOLD is the only KVAL_xxx
  58. * that affects the effective voltage seen by the stepper.
  59. *
  60. */
  61. /**
  62. * MACRO to fetch information on the items associated with current limiting
  63. * and maximum voltage output.
  64. *
  65. * L6470 can be setup to shutdown if either current threshold is exceeded.
  66. *
  67. * L6470 output current can not be set directly. It is set indirectly by
  68. * setting the maximum effective output voltage.
  69. *
  70. * Effective output voltage is set by PWM duty cycle.
  71. *
  72. * Maximum effective output voltage is affected by MANY variables. The main ones are:
  73. * KVAL_HOLD
  74. * KVAL_RUN
  75. * KVAL_ACC
  76. * KVAL_DEC
  77. * Vs compensation (if enabled)
  78. */
  79. void L6470_report_current(L64XX &motor, const L64XX_axis_t axis) {
  80. if (L64xxManager.spi_abort) return; // don't do anything if set_directions() has occurred
  81. const L64XX_Marlin::L64XX_shadow_t &sh = L64xxManager.shadow;
  82. const uint16_t status = L64xxManager.get_status(axis); //also populates shadow structure
  83. const uint8_t OverCurrent_Threshold = uint8_t(motor.GetParam(L6470_OCD_TH));
  84. auto say_axis_status = [](const L64XX_axis_t axis, const uint16_t status) {
  85. L64xxManager.say_axis(axis);
  86. #if ENABLED(L6470_CHITCHAT)
  87. char tmp[10];
  88. sprintf_P(tmp, PSTR("%4x "), status);
  89. DEBUG_ECHOPAIR(" status: ", tmp);
  90. print_bin(status);
  91. #else
  92. UNUSED(status);
  93. #endif
  94. SERIAL_EOL();
  95. };
  96. char temp_buf[10];
  97. switch (sh.STATUS_AXIS_LAYOUT) {
  98. case L6470_STATUS_LAYOUT: // L6470
  99. case L6480_STATUS_LAYOUT: { // L6480 & powerstep01
  100. const uint16_t Stall_Threshold = (uint8_t)motor.GetParam(L6470_STALL_TH),
  101. motor_status = (status & (STATUS_MOT_STATUS)) >> 5,
  102. L6470_ADC_out = motor.GetParam(L6470_ADC_OUT),
  103. L6470_ADC_out_limited = constrain(L6470_ADC_out, 8, 24);
  104. const float comp_coef = 1600.0f / L6470_ADC_out_limited;
  105. const uint16_t MicroSteps = _BV(motor.GetParam(L6470_STEP_MODE) & 0x07);
  106. say_axis_status(axis, status);
  107. SERIAL_ECHOPGM("...OverCurrent Threshold: ");
  108. sprintf_P(temp_buf, PSTR("%2d ("), OverCurrent_Threshold);
  109. SERIAL_ECHO(temp_buf);
  110. SERIAL_ECHO((OverCurrent_Threshold + 1) * motor.OCD_CURRENT_CONSTANT_INV);
  111. SERIAL_ECHOPGM(" mA)");
  112. SERIAL_ECHOPGM(" Stall Threshold: ");
  113. sprintf_P(temp_buf, PSTR("%2d ("), Stall_Threshold);
  114. SERIAL_ECHO(temp_buf);
  115. SERIAL_ECHO((Stall_Threshold + 1) * motor.STALL_CURRENT_CONSTANT_INV);
  116. SERIAL_ECHOPGM(" mA)");
  117. SERIAL_ECHOPGM(" Motor Status: ");
  118. switch (motor_status) {
  119. case 0: SERIAL_ECHOPGM("stopped"); break;
  120. case 1: SERIAL_ECHOPGM("accelerating"); break;
  121. case 2: SERIAL_ECHOPGM("decelerating"); break;
  122. case 3: SERIAL_ECHOPGM("at constant speed"); break;
  123. }
  124. SERIAL_EOL();
  125. SERIAL_ECHOPAIR("...MicroSteps: ", MicroSteps,
  126. " ADC_OUT: ", L6470_ADC_out);
  127. SERIAL_ECHOPGM(" Vs_compensation: ");
  128. serialprintPGM((motor.GetParam(sh.L6470_AXIS_CONFIG) & CONFIG_EN_VSCOMP) ? PSTR("ENABLED ") : PSTR("DISABLED"));
  129. SERIAL_ECHOLNPAIR(" Compensation coefficient: ~", comp_coef * 0.01f);
  130. SERIAL_ECHOPAIR("...KVAL_HOLD: ", motor.GetParam(L6470_KVAL_HOLD),
  131. " KVAL_RUN : ", motor.GetParam(L6470_KVAL_RUN),
  132. " KVAL_ACC: ", motor.GetParam(L6470_KVAL_ACC),
  133. " KVAL_DEC: ", motor.GetParam(L6470_KVAL_DEC),
  134. " V motor max = ");
  135. switch (motor_status) {
  136. case 0: SERIAL_ECHO(motor.GetParam(L6470_KVAL_HOLD) * 100 / 256); SERIAL_ECHOPGM("% (KVAL_HOLD)"); break;
  137. case 1: SERIAL_ECHO(motor.GetParam(L6470_KVAL_RUN) * 100 / 256); SERIAL_ECHOPGM("% (KVAL_RUN)"); break;
  138. case 2: SERIAL_ECHO(motor.GetParam(L6470_KVAL_ACC) * 100 / 256); SERIAL_ECHOPGM("% (KVAL_ACC)"); break;
  139. case 3: SERIAL_ECHO(motor.GetParam(L6470_KVAL_DEC) * 100 / 256); SERIAL_ECHOPGM("% (KVAL_HOLD)"); break;
  140. }
  141. SERIAL_EOL();
  142. #if ENABLED(L6470_CHITCHAT)
  143. DEBUG_ECHOPGM("...SLEW RATE: ");
  144. switch (sh.STATUS_AXIS_LAYOUT) {
  145. case L6470_STATUS_LAYOUT: {
  146. switch ((motor.GetParam(sh.L6470_AXIS_CONFIG) & CONFIG_POW_SR) >> CONFIG_POW_SR_BIT) {
  147. case 0: { DEBUG_ECHOLNPGM("320V/uS") ; break; }
  148. case 1: { DEBUG_ECHOLNPGM("75V/uS") ; break; }
  149. case 2: { DEBUG_ECHOLNPGM("110V/uS") ; break; }
  150. case 3: { DEBUG_ECHOLNPGM("260V/uS") ; break; }
  151. }
  152. break;
  153. }
  154. case L6480_STATUS_LAYOUT: {
  155. switch (motor.GetParam(L6470_GATECFG1) & CONFIG1_SR ) {
  156. case CONFIG1_SR_220V_us: { DEBUG_ECHOLNPGM("220V/uS") ; break; }
  157. case CONFIG1_SR_400V_us: { DEBUG_ECHOLNPGM("400V/uS") ; break; }
  158. case CONFIG1_SR_520V_us: { DEBUG_ECHOLNPGM("520V/uS") ; break; }
  159. case CONFIG1_SR_980V_us: { DEBUG_ECHOLNPGM("980V/uS") ; break; }
  160. default: { DEBUG_ECHOLNPGM("unknown") ; break; }
  161. }
  162. }
  163. }
  164. #endif
  165. SERIAL_EOL();
  166. break;
  167. }
  168. case L6474_STATUS_LAYOUT: { // L6474
  169. const uint16_t L6470_ADC_out = motor.GetParam(L6470_ADC_OUT) & 0x1F,
  170. L6474_TVAL_val = motor.GetParam(L6474_TVAL) & 0x7F;
  171. say_axis_status(axis, status);
  172. SERIAL_ECHOPGM("...OverCurrent Threshold: ");
  173. sprintf_P(temp_buf, PSTR("%2d ("), OverCurrent_Threshold);
  174. SERIAL_ECHO(temp_buf);
  175. SERIAL_ECHO((OverCurrent_Threshold + 1) * motor.OCD_CURRENT_CONSTANT_INV);
  176. SERIAL_ECHOPGM(" mA)");
  177. SERIAL_ECHOPGM(" TVAL: ");
  178. sprintf_P(temp_buf, PSTR("%2d ("), L6474_TVAL_val);
  179. SERIAL_ECHO(temp_buf);
  180. SERIAL_ECHO((L6474_TVAL_val + 1) * motor.STALL_CURRENT_CONSTANT_INV);
  181. SERIAL_ECHOLNPGM(" mA Motor Status: NA)");
  182. const uint16_t MicroSteps = _BV(motor.GetParam(L6470_STEP_MODE) & 0x07); //NOMORE(MicroSteps, 16);
  183. SERIAL_ECHOLNPAIR("...MicroSteps: ", MicroSteps,
  184. " ADC_OUT: ", L6470_ADC_out);
  185. SERIAL_ECHOLNPGM(" Vs_compensation: NA\n"
  186. "...KVAL_HOLD: NA"
  187. " KVAL_RUN : NA"
  188. " KVAL_ACC: NA"
  189. " KVAL_DEC: NA"
  190. " V motor max = NA");
  191. #if ENABLED(L6470_CHITCHAT)
  192. DEBUG_ECHOPGM("...SLEW RATE: ");
  193. switch ((motor.GetParam(sh.L6470_AXIS_CONFIG) & CONFIG_POW_SR) >> CONFIG_POW_SR_BIT) {
  194. case 0: DEBUG_ECHOLNPGM("320V/uS") ; break;
  195. case 1: DEBUG_ECHOLNPGM("75V/uS") ; break;
  196. case 2: DEBUG_ECHOLNPGM("110V/uS") ; break;
  197. case 3: DEBUG_ECHOLNPGM("260V/uS") ; break;
  198. default: DEBUG_ECHOLNPAIR("slew rate: ", (motor.GetParam(sh.L6470_AXIS_CONFIG) & CONFIG_POW_SR) >> CONFIG_POW_SR_BIT); break;
  199. }
  200. #endif
  201. SERIAL_EOL();
  202. SERIAL_EOL();
  203. break;
  204. }
  205. }
  206. }
  207. void GcodeSuite::M906() {
  208. L64xxManager.pause_monitor(true); // Keep monitor_driver() from stealing status
  209. #define L6470_SET_KVAL_HOLD(Q) stepper##Q.SetParam(L6470_KVAL_HOLD, value)
  210. DEBUG_ECHOLNPGM("M906");
  211. uint8_t report_current = true;
  212. #if HAS_L64XX
  213. const uint8_t index = parser.byteval('I');
  214. #endif
  215. LOOP_XYZE(i) if (uint8_t value = parser.byteval(axis_codes[i])) {
  216. report_current = false;
  217. if (planner.has_blocks_queued() || planner.cleaning_buffer_counter) {
  218. SERIAL_ECHOLNPGM("Test aborted. Can't set KVAL_HOLD while steppers are moving.");
  219. return;
  220. }
  221. switch (i) {
  222. case X_AXIS:
  223. #if AXIS_IS_L64XX(X)
  224. if (index == 0) L6470_SET_KVAL_HOLD(X);
  225. #endif
  226. #if AXIS_IS_L64XX(X2)
  227. if (index == 1) L6470_SET_KVAL_HOLD(X2);
  228. #endif
  229. break;
  230. case Y_AXIS:
  231. #if AXIS_IS_L64XX(Y)
  232. if (index == 0) L6470_SET_KVAL_HOLD(Y);
  233. #endif
  234. #if AXIS_IS_L64XX(Y2)
  235. if (index == 1) L6470_SET_KVAL_HOLD(Y2);
  236. #endif
  237. break;
  238. case Z_AXIS:
  239. #if AXIS_IS_L64XX(Z)
  240. if (index == 0) L6470_SET_KVAL_HOLD(Z);
  241. #endif
  242. #if AXIS_IS_L64XX(Z2)
  243. if (index == 1) L6470_SET_KVAL_HOLD(Z2);
  244. #endif
  245. #if AXIS_IS_L64XX(Z3)
  246. if (index == 2) L6470_SET_KVAL_HOLD(Z3);
  247. #endif
  248. break;
  249. case E_AXIS: {
  250. const int8_t target_extruder = get_target_extruder_from_command();
  251. if (target_extruder < 0) return;
  252. switch (target_extruder) {
  253. #if AXIS_IS_L64XX(E0)
  254. case 0: L6470_SET_KVAL_HOLD(E0); break;
  255. #endif
  256. #if AXIS_IS_L64XX(E1)
  257. case 1: L6470_SET_KVAL_HOLD(E1); break;
  258. #endif
  259. #if AXIS_IS_L64XX(E2)
  260. case 2: L6470_SET_KVAL_HOLD(E2); break;
  261. #endif
  262. #if AXIS_IS_L64XX(E3)
  263. case 3: L6470_SET_KVAL_HOLD(E3); break;
  264. #endif
  265. #if AXIS_IS_L64XX(E4)
  266. case 4: L6470_SET_KVAL_HOLD(E4); break;
  267. #endif
  268. #if AXIS_IS_L64XX(E5)
  269. case 5: L6470_SET_KVAL_HOLD(E5); break;
  270. #endif
  271. }
  272. } break;
  273. }
  274. }
  275. if (report_current) {
  276. #define L6470_REPORT_CURRENT(Q) L6470_report_current(stepper##Q, Q)
  277. L64xxManager.spi_active = true; // Tell set_directions() a series of SPI transfers is underway
  278. #if AXIS_IS_L64XX(X)
  279. L6470_REPORT_CURRENT(X);
  280. #endif
  281. #if AXIS_IS_L64XX(X2)
  282. L6470_REPORT_CURRENT(X2);
  283. #endif
  284. #if AXIS_IS_L64XX(Y)
  285. L6470_REPORT_CURRENT(Y);
  286. #endif
  287. #if AXIS_IS_L64XX(Y2)
  288. L6470_REPORT_CURRENT(Y2);
  289. #endif
  290. #if AXIS_IS_L64XX(Z)
  291. L6470_REPORT_CURRENT(Z);
  292. #endif
  293. #if AXIS_IS_L64XX(Z2)
  294. L6470_REPORT_CURRENT(Z2);
  295. #endif
  296. #if AXIS_IS_L64XX(Z3)
  297. L6470_REPORT_CURRENT(Z3);
  298. #endif
  299. #if AXIS_IS_L64XX(E0)
  300. L6470_REPORT_CURRENT(E0);
  301. #endif
  302. #if AXIS_IS_L64XX(E1)
  303. L6470_REPORT_CURRENT(E1);
  304. #endif
  305. #if AXIS_IS_L64XX(E2)
  306. L6470_REPORT_CURRENT(E2);
  307. #endif
  308. #if AXIS_IS_L64XX(E3)
  309. L6470_REPORT_CURRENT(E3);
  310. #endif
  311. #if AXIS_IS_L64XX(E4)
  312. L6470_REPORT_CURRENT(E4);
  313. #endif
  314. #if AXIS_IS_L64XX(E5)
  315. L6470_REPORT_CURRENT(E5);
  316. #endif
  317. L64xxManager.spi_active = false; // done with all SPI transfers - clear handshake flags
  318. L64xxManager.spi_abort = false;
  319. L64xxManager.pause_monitor(false);
  320. }
  321. }
  322. #endif // HAS_L64XX