My Marlin configs for Fabrikator Mini and CTC i3 Pro B
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

M906.cpp 13KB

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