mirror of
https://github.com/bdring/Grbl_Esp32.git
synced 2025-09-02 19:02:35 +02:00
Laser mode fix (#541)
* Changed header guards to #pragma once form In the Machines directory, also added // clang-format off because it will have to be done eventually and is safe, so it was easy to do systematically during this edit. * Clang Format (#514) * Apply clang-format * Fixed conflict between "print.h" and <print.h> print.h and print.cpp are not used. * machine.h: clang-format off is unnecessary * ifdef ARDUINO_ARCH_ESP32 is unnecessary and causes irritiating indentation of other includes * Revert formatting of nofile.h But leave pragma changes. * Fix nofile.h again * Some files were not formatted ... and .clang-format needed to be tweaked to give the same results with clang-format v6 and v10 * clang-format v6 vs v10 compatibility * Fixed C++ includes (#518) * Moved all files to the src folder * Removed all cpp includes; fixed by including the header file where needed * Fixed build scripts and machine.h * Removed temp file. sigh. Co-authored-by: Stefan de Bruijn <stefan@nubilosoft.com> * Split motor files into separate files and introduced namespace Motors (#522) * Renamed some files to match the class name. * Split out motor class into different files. * Fixed last newline in cpp/h files Co-authored-by: Stefan de Bruijn <stefan@nubilosoft.com> * Fixed compile error with parking enabled (#524) * Fix the I2S stream generates a 3x faster pulse. (#525) I completely misunderstood the calculation of the interruption interval. Change to calculate the correct μsec interval from the tick value. * Bump build date * Eliminated unused USE_GANGED_AXES (#526) * Updated style of Spindles according to style doc. Added namespace Spindles. (#529) * Renamed spindleclass file. * Added (empty) header files; renamed SpindleClass.cpp * Moved spindle classes, introduced namespaces * Fixed forward declaration. * Removed obsolete commented out code * Fixed overrides and constructors * Applied clang-format * Fixed 10vspindle set_spindle_dir_pin and set_enable_pin. Co-authored-by: Stefan de Bruijn <stefan@nubilosoft.com> * Avoid reiterationIteration in spindle names (#530) * File name changes (#532) * Renamed files in the root folder. Haven't fixed includes yet. * Renamed SD to SDCard to avoid name conflict * Fixed all includes * Fixed some "..." / <...> includes. * Updated <Print.h> (caps!). Co-authored-by: Stefan de Bruijn <stefan@nubilosoft.com> * Move more files to WebUI (#534) Now everything with Luc's copyright is in WebUI/ * Fix file names in comment blocks The recent rename made nearly all of the file names included in header comments incorrect. * Fixed .c -> .cpp interior names * A few more interior name fixes * Added second limit switch I/O option (#537) - Added X2_LIMIT_PIN thru C2_LIMIT_PIN - The 2 switches are simply or'd in the logic - Limit pin difintion now prints in boot MSG's - Cleaned up MS3 logic to use an array and defaults like limit switches - Added a new machine definition file to test new features * Fixed Laser Mode Enablin pin was turning off, but not back on in laser mode * Added Settings - $Spindle/Enable/Invert=Off - $Spindle/Enable/OffWithSpeed=Off - $Spindle/PWM/Invert=Off * Update build date Co-authored-by: Mitch Bradley <wmb@firmworks.com> Co-authored-by: Stefan de Bruijn <atlaste@users.noreply.github.com> Co-authored-by: Stefan de Bruijn <stefan@nubilosoft.com>
This commit is contained in:
92
.clang-format
Normal file
92
.clang-format
Normal file
@@ -0,0 +1,92 @@
|
||||
---
|
||||
AccessModifierOffset: '-4'
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: 'true'
|
||||
AlignConsecutiveDeclarations: 'true'
|
||||
AlignEscapedNewlines: Right
|
||||
AlignOperands: 'true'
|
||||
AlignTrailingComments: 'true'
|
||||
AllowShortBlocksOnASingleLine: 'true'
|
||||
AllowShortCaseLabelsOnASingleLine: 'true'
|
||||
AllowShortFunctionsOnASingleLine: Inline
|
||||
AllowShortIfStatementsOnASingleLine: 'false'
|
||||
AllowShortLoopsOnASingleLine: 'false'
|
||||
AlwaysBreakBeforeMultilineStrings: 'false'
|
||||
AlwaysBreakTemplateDeclarations: 'true'
|
||||
BinPackArguments: 'false'
|
||||
BinPackParameters: 'false'
|
||||
BreakBeforeBinaryOperators: None
|
||||
BraceWrapping:
|
||||
AfterClass: 'true'
|
||||
AfterControlStatement: 'true'
|
||||
AfterEnum: 'true'
|
||||
AfterFunction: 'true'
|
||||
AfterNamespace: 'true'
|
||||
AfterObjCDeclaration: 'true'
|
||||
AfterStruct: 'true'
|
||||
AfterUnion: 'true'
|
||||
AfterExternBlock: 'true'
|
||||
BeforeCatch: 'true'
|
||||
BeforeElse: 'true'
|
||||
SplitEmptyFunction: 'false'
|
||||
SplitEmptyRecord: 'false'
|
||||
SplitEmptyNamespace: 'false'
|
||||
BreakBeforeInheritanceComma: 'true'
|
||||
BreakBeforeTernaryOperators: 'false'
|
||||
BreakConstructorInitializers: AfterColon
|
||||
BreakInheritanceList: AfterColon
|
||||
ColumnLimit: '140'
|
||||
CommentPragmas: '^ :: '
|
||||
CompactNamespaces: 'false'
|
||||
Cpp11BracedListStyle: 'false'
|
||||
FixNamespaceComments: 'false'
|
||||
IncludeCategories:
|
||||
- Regex: '^".*'
|
||||
Priority: 1
|
||||
- Regex: '^"(.*)/'
|
||||
Priority: 2
|
||||
- Regex: '^<(.*)/'
|
||||
Priority: 3
|
||||
- Regex: '.*'
|
||||
Priority: 4
|
||||
IncludeBlocks: Regroup
|
||||
IndentCaseLabels: 'true'
|
||||
IndentPPDirectives: AfterHash
|
||||
IndentWidth: '4'
|
||||
IndentWrappedFunctionNames: 'true'
|
||||
JavaScriptQuotes: Leave
|
||||
KeepEmptyLinesAtTheStartOfBlocks: 'false'
|
||||
Language: Cpp
|
||||
MaxEmptyLinesToKeep: '1'
|
||||
NamespaceIndentation: All
|
||||
PenaltyBreakBeforeFirstCallParameter: 7
|
||||
PenaltyBreakAssignment: 8
|
||||
PenaltyBreakComment: 200
|
||||
PenaltyBreakFirstLessLess: 50
|
||||
PenaltyBreakString: 100
|
||||
PenaltyBreakTemplateDeclaration: 10
|
||||
PenaltyExcessCharacter: 10
|
||||
PenaltyReturnTypeOnItsOwnLine: 1000000
|
||||
PointerAlignment: Left
|
||||
ReflowComments: 'false'
|
||||
SortIncludes: 'false'
|
||||
SortUsingDeclarations: 'true'
|
||||
SpaceAfterTemplateKeyword: 'true'
|
||||
SpaceBeforeAssignmentOperators: 'true'
|
||||
SpaceBeforeCpp11BracedList: 'true'
|
||||
SpaceBeforeCtorInitializerColon: 'true'
|
||||
SpaceBeforeInheritanceColon: 'true'
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeRangeBasedForLoopColon: 'true'
|
||||
SpaceInEmptyParentheses: 'false'
|
||||
SpacesBeforeTrailingComments: '2'
|
||||
SpacesInAngles: 'false'
|
||||
SpacesInCStyleCastParentheses: 'false'
|
||||
SpacesInContainerLiterals: 'false'
|
||||
SpacesInParentheses: 'false'
|
||||
SpacesInSquareBrackets: 'false'
|
||||
Standard: Cpp11
|
||||
TabWidth: '4'
|
||||
UseTab: Never
|
||||
|
||||
...
|
4
.editorconfig
Normal file
4
.editorconfig
Normal file
@@ -0,0 +1,4 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
insert_final_newline = true
|
80
CodingStyle.md
Normal file
80
CodingStyle.md
Normal file
@@ -0,0 +1,80 @@
|
||||
# Coding style guidelines
|
||||
|
||||
While most software developers have a strong opinion about coding
|
||||
style and conventions, the general agreement is that having a single
|
||||
coding style in your project is beneficial for the readability and
|
||||
maintainability.
|
||||
|
||||
Coding style of this project is enforced through `.clang-format`.
|
||||
Most IDE's nowadays pick up the clang-format file automatically. If
|
||||
this is not the case, please run it manually before committing code.
|
||||
|
||||
Note that different IDE's are compiled against different versions of
|
||||
clang-format. This clang-format file is created in such a way, that
|
||||
it should work with most IDE's out-of-the-box, and can apply changes
|
||||
when the file is saved.
|
||||
|
||||
There may be violations of these guidelines in the code, due to
|
||||
historical reasons or, in rare instances, other considerations.
|
||||
We intend to fix such violations; patches that correct them
|
||||
are most welcome - but should be tested carefully across the
|
||||
supported compilation environments (Arduino and platformio).
|
||||
|
||||
## Guidelines
|
||||
|
||||
A few guidelines need to be taken into consideration while using
|
||||
clang-format:
|
||||
|
||||
1. Include order and `".."` vs `<...>` matters. Clang-format
|
||||
automatically re-orders your include files. This configuration
|
||||
is created in such a way that header file includes always add
|
||||
the minimum number of implicit dependencies. If this generates
|
||||
problems, you should be fixing your includes, instead of disabling
|
||||
clang-format.
|
||||
2. Preprocessor commands are not formatted nicely in some cases.
|
||||
This can hurt readibility in rare cases, in which case it's
|
||||
okay to disable clang-format temporarily with
|
||||
`// clang-format off` and `// clang-format on`. Most notably,
|
||||
machine definitions should have clang-format off.
|
||||
3. Use `#pragma once` in all header files. The reason is that
|
||||
preprocessor `#ifdef`s are nested automatically, which making
|
||||
things messy when using the alternative.
|
||||
|
||||
## Classes and namespaces
|
||||
|
||||
Filenames should correspond with clas names, folder names should
|
||||
correspond with namespace names. This implies that a file should
|
||||
have a single class.
|
||||
|
||||
## Naming
|
||||
|
||||
- Class names and namespace names are named `CamelCase`. Note that
|
||||
class and namespace names should only start with an `_` if they are
|
||||
(A) not in the global namespace and (b) should otherwise start with a digit.
|
||||
For example `_10V`.
|
||||
- Class member functions should be `snake_case`
|
||||
- Class member variables should be `_snake_case` with a leading `_`.
|
||||
|
||||
Namespaces should have classes, and classes should have members. Avoid
|
||||
using functions that have no class attached to them.
|
||||
|
||||
## Using namespace
|
||||
|
||||
- `using namespace` is not allowed in header files, except when
|
||||
using it in the body of a function.
|
||||
- Try to be conservative with `using namespace` in cpp files.
|
||||
Prefer to use it in a function body whenever possible for clarity
|
||||
what is used where.
|
||||
|
||||
## Including files
|
||||
|
||||
- It's a good practice to include just what you need. In general,
|
||||
try to include as much as possible in the cpp file, and as little
|
||||
as possible in the header file.
|
||||
- A CPP file should normally include the corresponding header file
|
||||
first (e.g. `WebSettings.cpp` should include `WebSettings.h`)
|
||||
and then everything else.
|
||||
- When including a system or library file, use `<...>` syntax;
|
||||
when including a local file, use `"..."` syntax. Some IDE's
|
||||
actually have trouble compiling if not done correctly.
|
||||
- Never include a cpp file; always header files!
|
@@ -28,60 +28,60 @@
|
||||
// in Machines/atari_1020.h, thus causing this file to be included
|
||||
// from ../custom_code.cpp
|
||||
|
||||
#define HOMING_PHASE_FULL_APPROACH 0 // move to right end
|
||||
#define HOMING_PHASE_CHECK 1 // check reed switch
|
||||
#define HOMING_PHASE_RETRACT 2 // retract
|
||||
#define HOMING_PHASE_SHORT_APPROACH 3 // retract
|
||||
#define HOMING_PHASE_FULL_APPROACH 0 // move to right end
|
||||
#define HOMING_PHASE_CHECK 1 // check reed switch
|
||||
#define HOMING_PHASE_RETRACT 2 // retract
|
||||
#define HOMING_PHASE_SHORT_APPROACH 3 // retract
|
||||
|
||||
static TaskHandle_t solenoidSyncTaskHandle = 0;
|
||||
static TaskHandle_t atariHomingTaskHandle = 0;
|
||||
int8_t solenoid_pwm_chan_num;
|
||||
uint16_t solenoid_pull_count;
|
||||
bool atari_homing = false;
|
||||
uint8_t homing_phase = HOMING_PHASE_FULL_APPROACH;
|
||||
uint8_t current_tool;
|
||||
static TaskHandle_t atariHomingTaskHandle = 0;
|
||||
int8_t solenoid_pwm_chan_num;
|
||||
uint16_t solenoid_pull_count;
|
||||
bool atari_homing = false;
|
||||
uint8_t homing_phase = HOMING_PHASE_FULL_APPROACH;
|
||||
uint8_t current_tool;
|
||||
|
||||
void machine_init() {
|
||||
solenoid_pull_count = 0; // initialize
|
||||
solenoid_pull_count = 0; // initialize
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Atari 1020 Solenoid");
|
||||
// setup PWM channel
|
||||
solenoid_pwm_chan_num = sys_get_next_PWM_chan_num();
|
||||
ledcSetup(solenoid_pwm_chan_num, SOLENOID_PWM_FREQ, SOLENOID_PWM_RES_BITS);
|
||||
ledcAttachPin(SOLENOID_PEN_PIN, solenoid_pwm_chan_num);
|
||||
pinMode(SOLENOID_DIRECTION_PIN, OUTPUT); // this sets the direction of the solenoid current
|
||||
pinMode(REED_SW_PIN, INPUT_PULLUP); // external pullup required
|
||||
pinMode(SOLENOID_DIRECTION_PIN, OUTPUT); // this sets the direction of the solenoid current
|
||||
pinMode(REED_SW_PIN, INPUT_PULLUP); // external pullup required
|
||||
// setup a task that will calculate solenoid position
|
||||
xTaskCreatePinnedToCore(solenoidSyncTask, // task
|
||||
"solenoidSyncTask", // name for task
|
||||
4096, // size of task stack
|
||||
NULL, // parameters
|
||||
1, // priority
|
||||
xTaskCreatePinnedToCore(solenoidSyncTask, // task
|
||||
"solenoidSyncTask", // name for task
|
||||
4096, // size of task stack
|
||||
NULL, // parameters
|
||||
1, // priority
|
||||
&solenoidSyncTaskHandle,
|
||||
0 // core
|
||||
);
|
||||
0 // core
|
||||
);
|
||||
// setup a task that will do the custom homing sequence
|
||||
xTaskCreatePinnedToCore(atari_home_task, // task
|
||||
"atari_home_task", // name for task
|
||||
4096, // size of task stack
|
||||
NULL, // parameters
|
||||
1, // priority
|
||||
xTaskCreatePinnedToCore(atari_home_task, // task
|
||||
"atari_home_task", // name for task
|
||||
4096, // size of task stack
|
||||
NULL, // parameters
|
||||
1, // priority
|
||||
&atariHomingTaskHandle,
|
||||
0 // core
|
||||
);
|
||||
0 // core
|
||||
);
|
||||
}
|
||||
|
||||
// this task tracks the Z position and sets the solenoid
|
||||
void solenoidSyncTask(void* pvParameters) {
|
||||
int32_t current_position[N_AXIS]; // copy of current location
|
||||
float m_pos[N_AXIS]; // machine position in mm
|
||||
TickType_t xLastWakeTime;
|
||||
const TickType_t xSolenoidFrequency = SOLENOID_TASK_FREQ; // in ticks (typically ms)
|
||||
xLastWakeTime = xTaskGetTickCount(); // Initialise the xLastWakeTime variable with the current time.
|
||||
int32_t current_position[N_AXIS]; // copy of current location
|
||||
float m_pos[N_AXIS]; // machine position in mm
|
||||
TickType_t xLastWakeTime;
|
||||
const TickType_t xSolenoidFrequency = SOLENOID_TASK_FREQ; // in ticks (typically ms)
|
||||
xLastWakeTime = xTaskGetTickCount(); // Initialise the xLastWakeTime variable with the current time.
|
||||
while (true) {
|
||||
// don't ever return from this or the task dies
|
||||
memcpy(current_position, sys_position, sizeof(sys_position)); // get current position in step
|
||||
system_convert_array_steps_to_mpos(m_pos, current_position); // convert to millimeters
|
||||
calc_solenoid(m_pos[Z_AXIS]); // calculate kinematics and move the servos
|
||||
memcpy(current_position, sys_position, sizeof(sys_position)); // get current position in step
|
||||
system_convert_array_steps_to_mpos(m_pos, current_position); // convert to millimeters
|
||||
calc_solenoid(m_pos[Z_AXIS]); // calculate kinematics and move the servos
|
||||
vTaskDelayUntil(&xLastWakeTime, xSolenoidFrequency);
|
||||
}
|
||||
}
|
||||
@@ -94,7 +94,7 @@ bool user_defined_homing() {
|
||||
// create and start a task to do the special homing
|
||||
homing_phase = HOMING_PHASE_FULL_APPROACH;
|
||||
atari_homing = true;
|
||||
return true; // this does it...skip the rest of mc_homing_cycle(...)
|
||||
return true; // this does it...skip the rest of mc_homing_cycle(...)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -113,54 +113,54 @@ bool user_defined_homing() {
|
||||
|
||||
*/
|
||||
void atari_home_task(void* pvParameters) {
|
||||
uint8_t homing_attempt = 0; // how many times have we tried to home
|
||||
TickType_t xLastWakeTime;
|
||||
const TickType_t xHomingTaskFrequency = 100; // in ticks (typically ms) .... need to make sure there is enough time to get out of idle
|
||||
char gcode_line[20];
|
||||
uint8_t homing_attempt = 0; // how many times have we tried to home
|
||||
TickType_t xLastWakeTime;
|
||||
const TickType_t xHomingTaskFrequency = 100; // in ticks (typically ms) .... need to make sure there is enough time to get out of idle
|
||||
char gcode_line[20];
|
||||
while (true) {
|
||||
// this task will only last as long as it is homing
|
||||
if (atari_homing) {
|
||||
// must be in idle or alarm state
|
||||
if (sys.state == STATE_IDLE) {
|
||||
switch (homing_phase) {
|
||||
case HOMING_PHASE_FULL_APPROACH: // a full width move to insure it hits left end
|
||||
inputBuffer.push("G90G0Z1\r"); // lift the pen
|
||||
sprintf(gcode_line, "G91G0X%3.2f\r", -ATARI_PAPER_WIDTH + ATARI_HOME_POS - 3.0); // plus a little extra
|
||||
inputBuffer.push(gcode_line);
|
||||
homing_attempt = 1;
|
||||
homing_phase = HOMING_PHASE_CHECK;
|
||||
break;
|
||||
case HOMING_PHASE_CHECK: // check the limits switch
|
||||
if (digitalRead(REED_SW_PIN) == 0) {
|
||||
// see if reed switch is grounded
|
||||
inputBuffer.push("G4P0.1\n"); // dramtic pause
|
||||
sys_position[X_AXIS] = ATARI_HOME_POS * axis_settings[X_AXIS]->steps_per_mm->get();
|
||||
sys_position[Y_AXIS] = 0.0;
|
||||
sys_position[Z_AXIS] = 1.0 * axis_settings[Y_AXIS]->steps_per_mm->get();
|
||||
gc_sync_position();
|
||||
plan_sync_position();
|
||||
sprintf(gcode_line, "G90G0X%3.2f\r", ATARI_PAPER_WIDTH); // alway return to right side to reduce home travel stalls
|
||||
case HOMING_PHASE_FULL_APPROACH: // a full width move to insure it hits left end
|
||||
inputBuffer.push("G90G0Z1\r"); // lift the pen
|
||||
sprintf(gcode_line, "G91G0X%3.2f\r", -ATARI_PAPER_WIDTH + ATARI_HOME_POS - 3.0); // plus a little extra
|
||||
inputBuffer.push(gcode_line);
|
||||
current_tool = 1; // local copy for reference...until actual M6 change
|
||||
gc_state.tool = current_tool;
|
||||
atari_homing = false; // done with homing sequence
|
||||
} else {
|
||||
homing_phase = HOMING_PHASE_RETRACT;
|
||||
homing_attempt++;
|
||||
}
|
||||
break;
|
||||
case HOMING_PHASE_RETRACT:
|
||||
sprintf(gcode_line, "G0X%3.2f\r", -ATARI_HOME_POS);
|
||||
inputBuffer.push(gcode_line);
|
||||
sprintf(gcode_line, "G0X%3.2f\r", ATARI_HOME_POS);
|
||||
inputBuffer.push(gcode_line);
|
||||
homing_phase = HOMING_PHASE_CHECK;
|
||||
break;
|
||||
default:
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Homing phase error %d", homing_phase);
|
||||
atari_homing = false;
|
||||
; // kills task
|
||||
break;
|
||||
homing_attempt = 1;
|
||||
homing_phase = HOMING_PHASE_CHECK;
|
||||
break;
|
||||
case HOMING_PHASE_CHECK: // check the limits switch
|
||||
if (digitalRead(REED_SW_PIN) == 0) {
|
||||
// see if reed switch is grounded
|
||||
inputBuffer.push("G4P0.1\n"); // dramtic pause
|
||||
sys_position[X_AXIS] = ATARI_HOME_POS * axis_settings[X_AXIS]->steps_per_mm->get();
|
||||
sys_position[Y_AXIS] = 0.0;
|
||||
sys_position[Z_AXIS] = 1.0 * axis_settings[Y_AXIS]->steps_per_mm->get();
|
||||
gc_sync_position();
|
||||
plan_sync_position();
|
||||
sprintf(gcode_line, "G90G0X%3.2f\r", ATARI_PAPER_WIDTH); // alway return to right side to reduce home travel stalls
|
||||
inputBuffer.push(gcode_line);
|
||||
current_tool = 1; // local copy for reference...until actual M6 change
|
||||
gc_state.tool = current_tool;
|
||||
atari_homing = false; // done with homing sequence
|
||||
} else {
|
||||
homing_phase = HOMING_PHASE_RETRACT;
|
||||
homing_attempt++;
|
||||
}
|
||||
break;
|
||||
case HOMING_PHASE_RETRACT:
|
||||
sprintf(gcode_line, "G0X%3.2f\r", -ATARI_HOME_POS);
|
||||
inputBuffer.push(gcode_line);
|
||||
sprintf(gcode_line, "G0X%3.2f\r", ATARI_HOME_POS);
|
||||
inputBuffer.push(gcode_line);
|
||||
homing_phase = HOMING_PHASE_CHECK;
|
||||
break;
|
||||
default:
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Homing phase error %d", homing_phase);
|
||||
atari_homing = false;
|
||||
; // kills task
|
||||
break;
|
||||
}
|
||||
if (homing_attempt > ATARI_HOMING_ATTEMPTS) {
|
||||
// try all positions plus 1
|
||||
@@ -177,25 +177,25 @@ void atari_home_task(void* pvParameters) {
|
||||
|
||||
// calculate and set the PWM value for the servo
|
||||
void calc_solenoid(float penZ) {
|
||||
bool isPenUp;
|
||||
bool isPenUp;
|
||||
static bool previousPenState = false;
|
||||
uint32_t solenoid_pen_pulse_len; // duty cycle of solenoid
|
||||
isPenUp = ((penZ > 0) || (sys.state == STATE_ALARM)); // is pen above Z0 or is there an alarm
|
||||
uint32_t solenoid_pen_pulse_len; // duty cycle of solenoid
|
||||
isPenUp = ((penZ > 0) || (sys.state == STATE_ALARM)); // is pen above Z0 or is there an alarm
|
||||
// if the state has not change, we only count down to the pull time
|
||||
if (previousPenState == isPenUp) {
|
||||
// if state is unchanged
|
||||
if (solenoid_pull_count > 0) {
|
||||
solenoid_pull_count--;
|
||||
solenoid_pen_pulse_len = SOLENOID_PULSE_LEN_PULL; // stay at full power while counting down
|
||||
solenoid_pen_pulse_len = SOLENOID_PULSE_LEN_PULL; // stay at full power while counting down
|
||||
} else {
|
||||
solenoid_pen_pulse_len = SOLENOID_PULSE_LEN_HOLD; // pull in delay has expired so lower duty cycle
|
||||
solenoid_pen_pulse_len = SOLENOID_PULSE_LEN_HOLD; // pull in delay has expired so lower duty cycle
|
||||
}
|
||||
} else {
|
||||
// pen direction has changed
|
||||
solenoid_pen_pulse_len = SOLENOID_PULSE_LEN_PULL; // go to full power
|
||||
solenoid_pull_count = SOLENOID_PULL_DURATION; // set the time to count down
|
||||
solenoid_pen_pulse_len = SOLENOID_PULSE_LEN_PULL; // go to full power
|
||||
solenoid_pull_count = SOLENOID_PULL_DURATION; // set the time to count down
|
||||
}
|
||||
previousPenState = isPenUp; // save the prev state
|
||||
previousPenState = isPenUp; // save the prev state
|
||||
digitalWrite(SOLENOID_DIRECTION_PIN, isPenUp);
|
||||
// skip setting value if it is unchanged
|
||||
if (ledcRead(solenoid_pwm_chan_num) == solenoid_pen_pulse_len)
|
||||
@@ -214,8 +214,8 @@ void calc_solenoid(float penZ) {
|
||||
*/
|
||||
void user_tool_change(uint8_t new_tool) {
|
||||
uint8_t move_count;
|
||||
char gcode_line[20];
|
||||
protocol_buffer_synchronize(); // wait for all previous moves to complete
|
||||
char gcode_line[20];
|
||||
protocol_buffer_synchronize(); // wait for all previous moves to complete
|
||||
if ((new_tool < 1) || (new_tool > MAX_PEN_NUMBER)) {
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Requested Pen#%d is out of 1-4 range", new_tool);
|
||||
return;
|
||||
@@ -226,10 +226,10 @@ void user_tool_change(uint8_t new_tool) {
|
||||
move_count = BUMPS_PER_PEN_CHANGE * (new_tool - current_tool);
|
||||
else
|
||||
move_count = BUMPS_PER_PEN_CHANGE * ((MAX_PEN_NUMBER - current_tool) + new_tool);
|
||||
sprintf(gcode_line, "G0Z%3.2f\r", ATARI_TOOL_CHANGE_Z); // go to tool change height
|
||||
sprintf(gcode_line, "G0Z%3.2f\r", ATARI_TOOL_CHANGE_Z); // go to tool change height
|
||||
inputBuffer.push(gcode_line);
|
||||
for (uint8_t i = 0; i < move_count; i++) {
|
||||
sprintf(gcode_line, "G0X%3.2f\r", ATARI_HOME_POS); //
|
||||
sprintf(gcode_line, "G0X%3.2f\r", ATARI_HOME_POS); //
|
||||
inputBuffer.push(gcode_line);
|
||||
inputBuffer.push("G0X0\r");
|
||||
}
|
||||
@@ -251,38 +251,36 @@ void user_defined_macro(uint8_t index) {
|
||||
char gcode_line[20];
|
||||
switch (index) {
|
||||
#ifdef MACRO_BUTTON_0_PIN
|
||||
case CONTROL_PIN_INDEX_MACRO_0:
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Pen switch");
|
||||
inputBuffer.push("$H\r");
|
||||
break;
|
||||
case CONTROL_PIN_INDEX_MACRO_0:
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Pen switch");
|
||||
inputBuffer.push("$H\r");
|
||||
break;
|
||||
#endif
|
||||
#ifdef MACRO_BUTTON_1_PIN
|
||||
case CONTROL_PIN_INDEX_MACRO_1:
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Color switch");
|
||||
atari_next_pen();
|
||||
sprintf(gcode_line, "G90G0X%3.2f\r", ATARI_PAPER_WIDTH); // alway return to right side to reduce home travel stalls
|
||||
inputBuffer.push(gcode_line);
|
||||
break;
|
||||
case CONTROL_PIN_INDEX_MACRO_1:
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Color switch");
|
||||
atari_next_pen();
|
||||
sprintf(gcode_line, "G90G0X%3.2f\r", ATARI_PAPER_WIDTH); // alway return to right side to reduce home travel stalls
|
||||
inputBuffer.push(gcode_line);
|
||||
break;
|
||||
#endif
|
||||
#ifdef MACRO_BUTTON_2_PIN
|
||||
case CONTROL_PIN_INDEX_MACRO_2:
|
||||
// feed out some paper and reset the Y 0
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Paper switch");
|
||||
inputBuffer.push("G0Y-25\r");
|
||||
inputBuffer.push("G4P0.1\r"); // sync...forces wait for planner to clear
|
||||
sys_position[Y_AXIS] = 0.0; // reset the Y position
|
||||
gc_sync_position();
|
||||
plan_sync_position();
|
||||
break;
|
||||
case CONTROL_PIN_INDEX_MACRO_2:
|
||||
// feed out some paper and reset the Y 0
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Paper switch");
|
||||
inputBuffer.push("G0Y-25\r");
|
||||
inputBuffer.push("G4P0.1\r"); // sync...forces wait for planner to clear
|
||||
sys_position[Y_AXIS] = 0.0; // reset the Y position
|
||||
gc_sync_position();
|
||||
plan_sync_position();
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Unknown Switch %d", index);
|
||||
break;
|
||||
default: grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Unknown Switch %d", index); break;
|
||||
}
|
||||
}
|
||||
|
||||
void user_m30() {
|
||||
char gcode_line[20];
|
||||
sprintf(gcode_line, "G90G0X%3.2f\r", ATARI_PAPER_WIDTH); //
|
||||
sprintf(gcode_line, "G90G0X%3.2f\r", ATARI_PAPER_WIDTH); //
|
||||
inputBuffer.push(gcode_line);
|
||||
}
|
||||
|
@@ -51,9 +51,7 @@ enabled with USE_ defines in Machines/my_machine.h
|
||||
machine_init() is called when Grbl_ESP32 first starts. You can use it to do any
|
||||
special things your machine needs at startup.
|
||||
*/
|
||||
void machine_init()
|
||||
{
|
||||
}
|
||||
void machine_init() {}
|
||||
#endif
|
||||
|
||||
#ifdef USE_CUSTOM_HOMING
|
||||
@@ -64,10 +62,9 @@ void machine_init()
|
||||
example, if you need to manually prep the machine for homing, you could implement
|
||||
user_defined_homing() to wait for some button to be pressed, then return true.
|
||||
*/
|
||||
bool user_defined_homing()
|
||||
{
|
||||
// True = done with homing, false = continue with normal Grbl_ESP32 homing
|
||||
return true;
|
||||
bool user_defined_homing() {
|
||||
// True = done with homing, false = continue with normal Grbl_ESP32 homing
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -89,10 +86,9 @@ bool user_defined_homing()
|
||||
pl_data = planner data (see the definition of this type to see what it is)
|
||||
position = an N_AXIS array of where the machine is starting from for this move
|
||||
*/
|
||||
void inverse_kinematics(float *target, plan_line_data_t *pl_data, float *position)
|
||||
{
|
||||
// this simply moves to the target. Replace with your kinematics.
|
||||
mc_line(target, pl_data);
|
||||
void inverse_kinematics(float* target, plan_line_data_t* pl_data, float* position) {
|
||||
// this simply moves to the target. Replace with your kinematics.
|
||||
mc_line(target, pl_data);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -103,15 +99,13 @@ void inverse_kinematics(float *target, plan_line_data_t *pl_data, float *positio
|
||||
*/
|
||||
bool kinematics_pre_homing(uint8_t cycle_mask))
|
||||
{
|
||||
return false; // finish normal homing cycle
|
||||
return false; // finish normal homing cycle
|
||||
}
|
||||
|
||||
/*
|
||||
kinematics_post_homing() is called at the end of normal homing
|
||||
*/
|
||||
void kinematics_post_homing()
|
||||
{
|
||||
}
|
||||
void kinematics_post_homing() {}
|
||||
#endif
|
||||
|
||||
#ifdef USE_FWD_KINEMATIC
|
||||
@@ -121,10 +115,9 @@ void kinematics_post_homing()
|
||||
|
||||
Convert the N_AXIS array of motor positions to cartesian in your code.
|
||||
*/
|
||||
void forward_kinematics(float *position)
|
||||
{
|
||||
// position[X_AXIS] =
|
||||
// position[Y_AXIS] =
|
||||
void forward_kinematics(float* position) {
|
||||
// position[X_AXIS] =
|
||||
// position[Y_AXIS] =
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -133,9 +126,7 @@ void forward_kinematics(float *position)
|
||||
user_tool_change() is called when tool change gcode is received,
|
||||
to perform appropriate actions for your machine.
|
||||
*/
|
||||
void user_tool_change(uint8_t new_tool)
|
||||
{
|
||||
}
|
||||
void user_tool_change(uint8_t new_tool) {}
|
||||
#endif
|
||||
|
||||
#if defined(MACRO_BUTTON_0_PIN) || defined(MACRO_BUTTON_1_PIN) || defined(MACRO_BUTTON_2_PIN)
|
||||
@@ -143,18 +134,14 @@ void user_tool_change(uint8_t new_tool)
|
||||
options. user_defined_macro() is called with the button number to
|
||||
perform whatever actions you choose.
|
||||
*/
|
||||
void user_defined_macro(uint8_t index)
|
||||
{
|
||||
}
|
||||
void user_defined_macro(uint8_t index) {}
|
||||
#endif
|
||||
|
||||
#ifdef USE_M30
|
||||
/*
|
||||
user_m30() is called when an M30 gcode signals the end of a gcode file.
|
||||
*/
|
||||
void user_m30()
|
||||
{
|
||||
}
|
||||
void user_m30() {}
|
||||
#endif
|
||||
|
||||
#ifdef USE_MACHINE_TRINAMIC_INIT
|
||||
@@ -162,9 +149,7 @@ void user_m30()
|
||||
machine_triaminic_setup() replaces the normal setup of trinamic
|
||||
drivers with your own code. For example, you could setup StallGuard
|
||||
*/
|
||||
void machine_trinamic_setup()
|
||||
{
|
||||
}
|
||||
void machine_trinamic_setup() {}
|
||||
#endif
|
||||
|
||||
// If you add any additional functions specific to your machine that
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
custom_code_template.cpp (copy and use your machine name)
|
||||
esp32_printer_controller.cpp (copy and use your machine name)
|
||||
Part of Grbl_ESP32
|
||||
|
||||
copyright (c) 2020 - Bart Dring. This file was intended for use on the ESP32
|
||||
@@ -51,33 +51,32 @@ enabled with USE_ defines in Machines/my_machine.h
|
||||
machine_init() is called when Grbl_ESP32 first starts. You can use it to do any
|
||||
special things your machine needs at startup.
|
||||
*/
|
||||
#define STEPPERS_DISABLE_PIN_X 138
|
||||
#define STEPPERS_DISABLE_PIN_Y 134
|
||||
#define STEPPERS_DISABLE_PIN_Z 131
|
||||
#define STEPPERS_DISABLE_PIN_A 139
|
||||
# define STEPPERS_DISABLE_PIN_X 138
|
||||
# define STEPPERS_DISABLE_PIN_Y 134
|
||||
# define STEPPERS_DISABLE_PIN_Z 131
|
||||
# define STEPPERS_DISABLE_PIN_A 139
|
||||
|
||||
#define FAN1_PIN 13
|
||||
#define FAN2_PIN 142
|
||||
#define FAN3_PIN 143
|
||||
# define FAN1_PIN 13
|
||||
# define FAN2_PIN 142
|
||||
# define FAN3_PIN 143
|
||||
|
||||
#define BED_PIN 4
|
||||
#define NOZZLE_PIN 2
|
||||
# define BED_PIN 4
|
||||
# define NOZZLE_PIN 2
|
||||
|
||||
void machine_init()
|
||||
{
|
||||
// Enable steppers
|
||||
digitalWrite(STEPPERS_DISABLE_PIN_X, LOW); // enable
|
||||
digitalWrite(STEPPERS_DISABLE_PIN_Y, LOW); // enable
|
||||
digitalWrite(STEPPERS_DISABLE_PIN_Z, LOW); // enable
|
||||
digitalWrite(STEPPERS_DISABLE_PIN_A, LOW); // enable
|
||||
void machine_init() {
|
||||
// Enable steppers
|
||||
digitalWrite(STEPPERS_DISABLE_PIN_X, LOW); // enable
|
||||
digitalWrite(STEPPERS_DISABLE_PIN_Y, LOW); // enable
|
||||
digitalWrite(STEPPERS_DISABLE_PIN_Z, LOW); // enable
|
||||
digitalWrite(STEPPERS_DISABLE_PIN_A, LOW); // enable
|
||||
|
||||
// digitalWrite(FAN1_PIN, LOW); // comment out for JTAG debugging
|
||||
// digitalWrite(FAN1_PIN, LOW); // comment out for JTAG debugging
|
||||
|
||||
digitalWrite(FAN2_PIN, LOW); // disable
|
||||
digitalWrite(FAN3_PIN, LOW); // disable
|
||||
digitalWrite(FAN2_PIN, LOW); // disable
|
||||
digitalWrite(FAN3_PIN, LOW); // disable
|
||||
|
||||
digitalWrite(BED_PIN, LOW); // disable
|
||||
digitalWrite(NOZZLE_PIN, LOW); // disable
|
||||
digitalWrite(BED_PIN, LOW); // disable
|
||||
digitalWrite(NOZZLE_PIN, LOW); // disable
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -89,10 +88,9 @@ void machine_init()
|
||||
example, if you need to manually prep the machine for homing, you could implement
|
||||
user_defined_homing() to wait for some button to be pressed, then return true.
|
||||
*/
|
||||
bool user_defined_homing()
|
||||
{
|
||||
// True = done with homing, false = continue with normal Grbl_ESP32 homing
|
||||
return true;
|
||||
bool user_defined_homing() {
|
||||
// True = done with homing, false = continue with normal Grbl_ESP32 homing
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -114,10 +112,9 @@ bool user_defined_homing()
|
||||
pl_data = planner data (see the definition of this type to see what it is)
|
||||
position = an N_AXIS array of where the machine is starting from for this move
|
||||
*/
|
||||
void inverse_kinematics(float *target, plan_line_data_t *pl_data, float *position)
|
||||
{
|
||||
// this simply moves to the target. Replace with your kinematics.
|
||||
mc_line(target, pl_data);
|
||||
void inverse_kinematics(float* target, plan_line_data_t* pl_data, float* position) {
|
||||
// this simply moves to the target. Replace with your kinematics.
|
||||
mc_line(target, pl_data);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -128,15 +125,13 @@ void inverse_kinematics(float *target, plan_line_data_t *pl_data, float *positio
|
||||
*/
|
||||
bool kinematics_pre_homing(uint8_t cycle_mask))
|
||||
{
|
||||
return false; // finish normal homing cycle
|
||||
return false; // finish normal homing cycle
|
||||
}
|
||||
|
||||
/*
|
||||
kinematics_post_homing() is called at the end of normal homing
|
||||
*/
|
||||
void kinematics_post_homing()
|
||||
{
|
||||
}
|
||||
void kinematics_post_homing() {}
|
||||
#endif
|
||||
|
||||
#ifdef USE_FWD_KINEMATIC
|
||||
@@ -146,10 +141,9 @@ void kinematics_post_homing()
|
||||
|
||||
Convert the N_AXIS array of motor positions to cartesian in your code.
|
||||
*/
|
||||
void forward_kinematics(float *position)
|
||||
{
|
||||
// position[X_AXIS] =
|
||||
// position[Y_AXIS] =
|
||||
void forward_kinematics(float* position) {
|
||||
// position[X_AXIS] =
|
||||
// position[Y_AXIS] =
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -158,9 +152,7 @@ void forward_kinematics(float *position)
|
||||
user_tool_change() is called when tool change gcode is received,
|
||||
to perform appropriate actions for your machine.
|
||||
*/
|
||||
void user_tool_change(uint8_t new_tool)
|
||||
{
|
||||
}
|
||||
void user_tool_change(uint8_t new_tool) {}
|
||||
#endif
|
||||
|
||||
#if defined(MACRO_BUTTON_0_PIN) || defined(MACRO_BUTTON_1_PIN) || defined(MACRO_BUTTON_2_PIN)
|
||||
@@ -168,18 +160,14 @@ void user_tool_change(uint8_t new_tool)
|
||||
options. user_defined_macro() is called with the button number to
|
||||
perform whatever actions you choose.
|
||||
*/
|
||||
void user_defined_macro(uint8_t index)
|
||||
{
|
||||
}
|
||||
void user_defined_macro(uint8_t index) {}
|
||||
#endif
|
||||
|
||||
#ifdef USE_M30
|
||||
/*
|
||||
user_m30() is called when an M30 gcode signals the end of a gcode file.
|
||||
*/
|
||||
void user_m30()
|
||||
{
|
||||
}
|
||||
void user_m30() {}
|
||||
#endif
|
||||
|
||||
#ifdef USE_MACHINE_TRINAMIC_INIT
|
||||
@@ -187,9 +175,7 @@ void user_m30()
|
||||
machine_triaminic_setup() replaces the normal setup of trinamic
|
||||
drivers with your own code. For example, you could setup StallGuard
|
||||
*/
|
||||
void machine_trinamic_setup()
|
||||
{
|
||||
}
|
||||
void machine_trinamic_setup() {}
|
||||
#endif
|
||||
|
||||
// If you add any additional functions specific to your machine that
|
||||
|
@@ -54,18 +54,17 @@
|
||||
// in Machines/polar_coaster.h, thus causing this file to be included
|
||||
// from ../custom_code.cpp
|
||||
|
||||
|
||||
void calc_polar(float *target_xyz, float *polar, float last_angle);
|
||||
void calc_polar(float* target_xyz, float* polar, float last_angle);
|
||||
float abs_angle(float ang);
|
||||
|
||||
static float last_angle = 0;
|
||||
static float last_angle = 0;
|
||||
static float last_radius = 0;
|
||||
|
||||
// this get called before homing
|
||||
// return false to complete normal home
|
||||
// return true to exit normal homing
|
||||
bool kinematics_pre_homing(uint8_t cycle_mask) {
|
||||
return false; // finish normal homing cycle
|
||||
return false; // finish normal homing cycle
|
||||
}
|
||||
|
||||
void kinematics_post_homing() {
|
||||
@@ -86,17 +85,17 @@ void kinematics_post_homing() {
|
||||
|
||||
|
||||
*/
|
||||
void inverse_kinematics(float *target, plan_line_data_t *pl_data, float *position) {
|
||||
void inverse_kinematics(float* target, plan_line_data_t* pl_data, float* position) {
|
||||
//static float last_angle = 0;
|
||||
//static float last_radius = 0;
|
||||
float dx, dy, dz; // distances in each cartesian axis
|
||||
float p_dx, p_dy, p_dz; // distances in each polar axis
|
||||
float dist, polar_dist; // the distances in both systems...used to determine feed rate
|
||||
uint32_t segment_count; // number of segments the move will be broken in to.
|
||||
float seg_target[N_AXIS]; // The target of the current segment
|
||||
float polar[N_AXIS]; // target location in polar coordinates
|
||||
float x_offset = gc_state.coord_system[X_AXIS] + gc_state.coord_offset[X_AXIS]; // offset from machine coordinate system
|
||||
float z_offset = gc_state.coord_system[Z_AXIS] + gc_state.coord_offset[Z_AXIS]; // offset from machine coordinate system
|
||||
float dx, dy, dz; // distances in each cartesian axis
|
||||
float p_dx, p_dy, p_dz; // distances in each polar axis
|
||||
float dist, polar_dist; // the distances in both systems...used to determine feed rate
|
||||
uint32_t segment_count; // number of segments the move will be broken in to.
|
||||
float seg_target[N_AXIS]; // The target of the current segment
|
||||
float polar[N_AXIS]; // target location in polar coordinates
|
||||
float x_offset = gc_state.coord_system[X_AXIS] + gc_state.coord_offset[X_AXIS]; // offset from machine coordinate system
|
||||
float z_offset = gc_state.coord_system[Z_AXIS] + gc_state.coord_offset[Z_AXIS]; // offset from machine coordinate system
|
||||
//grbl_sendf(CLIENT_SERIAL, "Position: %4.2f %4.2f %4.2f \r\n", position[X_AXIS] - x_offset, position[Y_AXIS], position[Z_AXIS]);
|
||||
//grbl_sendf(CLIENT_SERIAL, "Target: %4.2f %4.2f %4.2f \r\n", target[X_AXIS] - x_offset, target[Y_AXIS], target[Z_AXIS]);
|
||||
// calculate cartesian move distance for each axis
|
||||
@@ -120,11 +119,11 @@ void inverse_kinematics(float *target, plan_line_data_t *pl_data, float *positio
|
||||
calc_polar(seg_target, polar, last_angle);
|
||||
// begin determining new feed rate
|
||||
// calculate move distance for each axis
|
||||
p_dx = polar[RADIUS_AXIS] - last_radius;
|
||||
p_dy = polar[POLAR_AXIS] - last_angle;
|
||||
p_dz = dz;
|
||||
polar_dist = sqrt((p_dx * p_dx) + (p_dy * p_dy) + (p_dz * p_dz)); // calculate the total move distance
|
||||
float polar_rate_multiply = 1.0; // fail safe rate
|
||||
p_dx = polar[RADIUS_AXIS] - last_radius;
|
||||
p_dy = polar[POLAR_AXIS] - last_angle;
|
||||
p_dz = dz;
|
||||
polar_dist = sqrt((p_dx * p_dx) + (p_dy * p_dy) + (p_dz * p_dz)); // calculate the total move distance
|
||||
float polar_rate_multiply = 1.0; // fail safe rate
|
||||
if (polar_dist == 0 || dist == 0) {
|
||||
// prevent 0 feed rate and division by 0
|
||||
polar_rate_multiply = 1.0; // default to same feed rate
|
||||
@@ -141,7 +140,7 @@ void inverse_kinematics(float *target, plan_line_data_t *pl_data, float *positio
|
||||
polar[RADIUS_AXIS] += x_offset;
|
||||
polar[Z_AXIS] += z_offset;
|
||||
last_radius = polar[RADIUS_AXIS];
|
||||
last_angle = polar[POLAR_AXIS];
|
||||
last_angle = polar[POLAR_AXIS];
|
||||
mc_line(polar, pl_data);
|
||||
}
|
||||
// TO DO don't need a feedrate for rapids
|
||||
@@ -160,18 +159,18 @@ position = the current machine position
|
||||
converted = position with forward kinematics applied.
|
||||
|
||||
*/
|
||||
void forward_kinematics(float *position) {
|
||||
float original_position[N_AXIS]; // temporary storage of original
|
||||
float print_position[N_AXIS];
|
||||
void forward_kinematics(float* position) {
|
||||
float original_position[N_AXIS]; // temporary storage of original
|
||||
float print_position[N_AXIS];
|
||||
int32_t current_position[N_AXIS]; // Copy current state of the system position variable
|
||||
memcpy(current_position, sys_position, sizeof(sys_position));
|
||||
system_convert_array_steps_to_mpos(print_position, current_position);
|
||||
original_position[X_AXIS] = print_position[X_AXIS] - gc_state.coord_system[X_AXIS] + gc_state.coord_offset[X_AXIS];
|
||||
original_position[Y_AXIS] = print_position[Y_AXIS] - gc_state.coord_system[Y_AXIS] + gc_state.coord_offset[Y_AXIS];
|
||||
original_position[Z_AXIS] = print_position[Z_AXIS] - gc_state.coord_system[Z_AXIS] + gc_state.coord_offset[Z_AXIS];
|
||||
position[X_AXIS] = cos(radians(original_position[Y_AXIS])) * original_position[X_AXIS] * -1;
|
||||
position[Y_AXIS] = sin(radians(original_position[Y_AXIS])) * original_position[X_AXIS];
|
||||
position[Z_AXIS] = original_position[Z_AXIS]; // unchanged
|
||||
position[X_AXIS] = cos(radians(original_position[Y_AXIS])) * original_position[X_AXIS] * -1;
|
||||
position[Y_AXIS] = sin(radians(original_position[Y_AXIS])) * original_position[X_AXIS];
|
||||
position[Z_AXIS] = original_position[Z_AXIS]; // unchanged
|
||||
}
|
||||
|
||||
// helper functions
|
||||
@@ -189,7 +188,7 @@ void forward_kinematics(float *position) {
|
||||
* a long job.
|
||||
*
|
||||
*/
|
||||
void calc_polar(float *target_xyz, float *polar, float last_angle) {
|
||||
void calc_polar(float* target_xyz, float* polar, float last_angle) {
|
||||
float delta_ang; // the difference from the last and next angle
|
||||
polar[RADIUS_AXIS] = hypot_f(target_xyz[X_AXIS], target_xyz[Y_AXIS]);
|
||||
if (polar[RADIUS_AXIS] == 0) {
|
||||
@@ -200,7 +199,7 @@ void calc_polar(float *target_xyz, float *polar, float last_angle) {
|
||||
polar[POLAR_AXIS] = abs_angle(polar[POLAR_AXIS]);
|
||||
}
|
||||
polar[Z_AXIS] = target_xyz[Z_AXIS]; // Z is unchanged
|
||||
delta_ang = polar[POLAR_AXIS] - abs_angle(last_angle);
|
||||
delta_ang = polar[POLAR_AXIS] - abs_angle(last_angle);
|
||||
// if the delta is above 180 degrees it means we are crossing the 0 degree line
|
||||
if (fabs(delta_ang) <= 180.0)
|
||||
polar[POLAR_AXIS] = last_angle + delta_ang;
|
||||
@@ -225,26 +224,24 @@ float abs_angle(float ang) {
|
||||
void user_defined_macro(uint8_t index) {
|
||||
switch (index) {
|
||||
#ifdef MACRO_BUTTON_0_PIN
|
||||
case CONTROL_PIN_INDEX_MACRO_0:
|
||||
inputBuffer.push("$H\r"); // home machine
|
||||
break;
|
||||
case CONTROL_PIN_INDEX_MACRO_0:
|
||||
inputBuffer.push("$H\r"); // home machine
|
||||
break;
|
||||
#endif
|
||||
#ifdef MACRO_BUTTON_1_PIN
|
||||
case CONTROL_PIN_INDEX_MACRO_1:
|
||||
inputBuffer.push("[ESP220]/1.nc\r"); // run SD card file 1.nc
|
||||
break;
|
||||
case CONTROL_PIN_INDEX_MACRO_1:
|
||||
inputBuffer.push("[ESP220]/1.nc\r"); // run SD card file 1.nc
|
||||
break;
|
||||
#endif
|
||||
#ifdef MACRO_BUTTON_2_PIN
|
||||
case CONTROL_PIN_INDEX_MACRO_2:
|
||||
inputBuffer.push("[ESP220]/2.nc\r"); // run SD card file 2.nc
|
||||
break;
|
||||
case CONTROL_PIN_INDEX_MACRO_2:
|
||||
inputBuffer.push("[ESP220]/2.nc\r"); // run SD card file 2.nc
|
||||
break;
|
||||
#endif
|
||||
#ifdef MACRO_BUTTON_3_PIN
|
||||
case CONTROL_PIN_INDEX_MACRO_3:
|
||||
break;
|
||||
case CONTROL_PIN_INDEX_MACRO_3: break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -18,55 +18,45 @@
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "grbl.h"
|
||||
#include "WiFi.h"
|
||||
|
||||
#include "Spindles/SpindleClass.cpp"
|
||||
#include "Motors/MotorClass.cpp"
|
||||
#include "src/Grbl.h"
|
||||
#include <WiFi.h>
|
||||
|
||||
// Declare system global variable structure
|
||||
system_t sys;
|
||||
int32_t sys_position[N_AXIS]; // Real-time machine (aka home) position vector in steps.
|
||||
int32_t sys_probe_position[N_AXIS]; // Last probe position in machine coordinates and steps.
|
||||
volatile uint8_t sys_probe_state; // Probing state value. Used to coordinate the probing cycle with stepper ISR.
|
||||
volatile uint8_t sys_rt_exec_state; // Global realtime executor bitflag variable for state management. See EXEC bitmasks.
|
||||
volatile uint8_t sys_rt_exec_alarm; // Global realtime executor bitflag variable for setting various alarms.
|
||||
volatile uint8_t sys_rt_exec_motion_override; // Global realtime executor bitflag variable for motion-based overrides.
|
||||
volatile uint8_t sys_rt_exec_accessory_override; // Global realtime executor bitflag variable for spindle/coolant overrides.
|
||||
system_t sys;
|
||||
int32_t sys_position[N_AXIS]; // Real-time machine (aka home) position vector in steps.
|
||||
int32_t sys_probe_position[N_AXIS]; // Last probe position in machine coordinates and steps.
|
||||
volatile uint8_t sys_probe_state; // Probing state value. Used to coordinate the probing cycle with stepper ISR.
|
||||
volatile uint8_t sys_rt_exec_state; // Global realtime executor bitflag variable for state management. See EXEC bitmasks.
|
||||
volatile uint8_t sys_rt_exec_alarm; // Global realtime executor bitflag variable for setting various alarms.
|
||||
volatile uint8_t sys_rt_exec_motion_override; // Global realtime executor bitflag variable for motion-based overrides.
|
||||
volatile uint8_t sys_rt_exec_accessory_override; // Global realtime executor bitflag variable for spindle/coolant overrides.
|
||||
#ifdef DEBUG
|
||||
volatile uint8_t sys_rt_exec_debug;
|
||||
volatile uint8_t sys_rt_exec_debug;
|
||||
#endif
|
||||
|
||||
Spindle *spindle;
|
||||
|
||||
|
||||
Spindles::Spindle* spindle;
|
||||
|
||||
void setup() {
|
||||
#ifdef USE_I2S_OUT
|
||||
i2s_out_init(); // The I2S out must be initialized before it can access the expanded GPIO port
|
||||
i2s_out_init(); // The I2S out must be initialized before it can access the expanded GPIO port
|
||||
#endif
|
||||
WiFi.persistent(false);
|
||||
WiFi.disconnect(true);
|
||||
WiFi.enableSTA(false);
|
||||
WiFi.enableAP(false);
|
||||
WiFi.mode(WIFI_OFF);
|
||||
serial_init(); // Setup serial baud rate and interrupts
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Grbl_ESP32 Ver %s Date %s", GRBL_VERSION, GRBL_VERSION_BUILD); // print grbl_esp32 verion info
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Compiled with ESP32 SDK:%s", ESP.getSdkVersion()); // print the SDK version
|
||||
serial_init(); // Setup serial baud rate and interrupts
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Grbl_ESP32 Ver %s Date %s", GRBL_VERSION, GRBL_VERSION_BUILD); // print grbl_esp32 verion info
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Compiled with ESP32 SDK:%s", ESP.getSdkVersion()); // print the SDK version
|
||||
// show the map name at startup
|
||||
#ifdef MACHINE_NAME
|
||||
#ifdef MACHINE_EXTRA
|
||||
#define MACHINE_STRING MACHINE_NAME MACHINE_EXTRA
|
||||
#else
|
||||
#define MACHINE_STRING MACHINE_NAME
|
||||
#endif
|
||||
report_machine_type(CLIENT_SERIAL);
|
||||
#endif
|
||||
settings_init(); // Load Grbl settings from EEPROM
|
||||
stepper_init(); // Configure stepper pins and interrupt timers
|
||||
settings_init(); // Load Grbl settings from EEPROM
|
||||
stepper_init(); // Configure stepper pins and interrupt timers
|
||||
init_motors();
|
||||
system_ini(); // Configure pinout pins and pin-change interrupt (Renamed due to conflict with esp32 files)
|
||||
memset(sys_position, 0, sizeof(sys_position)); // Clear machine position.
|
||||
system_ini(); // Configure pinout pins and pin-change interrupt (Renamed due to conflict with esp32 files)
|
||||
memset(sys_position, 0, sizeof(sys_position)); // Clear machine position.
|
||||
#ifdef USE_PEN_SERVO
|
||||
servo_init();
|
||||
#endif
|
||||
@@ -77,7 +67,7 @@ void setup() {
|
||||
solenoid_init();
|
||||
#endif
|
||||
#ifdef USE_MACHINE_INIT
|
||||
machine_init(); // user supplied function for special initialization
|
||||
machine_init(); // user supplied function for special initialization
|
||||
#endif
|
||||
// Initialize system state.
|
||||
#ifdef FORCE_INITIALIZATION_ALARM
|
||||
@@ -94,9 +84,10 @@ void setup() {
|
||||
// not after disabling the alarm locks. Prevents motion startup blocks from crashing into
|
||||
// things uncontrollably. Very bad.
|
||||
#ifdef HOMING_INIT_LOCK
|
||||
if (homing_enable->get()) sys.state = STATE_ALARM;
|
||||
if (homing_enable->get())
|
||||
sys.state = STATE_ALARM;
|
||||
#endif
|
||||
spindle_select();
|
||||
Spindles::Spindle::select();
|
||||
#ifdef ENABLE_WIFI
|
||||
wifi_config.begin();
|
||||
#endif
|
||||
@@ -109,26 +100,26 @@ void setup() {
|
||||
void loop() {
|
||||
// Reset system variables.
|
||||
uint8_t prior_state = sys.state;
|
||||
memset(&sys, 0, sizeof(system_t)); // Clear system struct variable.
|
||||
sys.state = prior_state;
|
||||
sys.f_override = DEFAULT_FEED_OVERRIDE; // Set to 100%
|
||||
sys.r_override = DEFAULT_RAPID_OVERRIDE; // Set to 100%
|
||||
sys.spindle_speed_ovr = DEFAULT_SPINDLE_SPEED_OVERRIDE; // Set to 100%
|
||||
memset(sys_probe_position, 0, sizeof(sys_probe_position)); // Clear probe position.
|
||||
sys_probe_state = 0;
|
||||
sys_rt_exec_state = 0;
|
||||
sys_rt_exec_alarm = 0;
|
||||
sys_rt_exec_motion_override = 0;
|
||||
memset(&sys, 0, sizeof(system_t)); // Clear system struct variable.
|
||||
sys.state = prior_state;
|
||||
sys.f_override = DEFAULT_FEED_OVERRIDE; // Set to 100%
|
||||
sys.r_override = DEFAULT_RAPID_OVERRIDE; // Set to 100%
|
||||
sys.spindle_speed_ovr = DEFAULT_SPINDLE_SPEED_OVERRIDE; // Set to 100%
|
||||
memset(sys_probe_position, 0, sizeof(sys_probe_position)); // Clear probe position.
|
||||
sys_probe_state = 0;
|
||||
sys_rt_exec_state = 0;
|
||||
sys_rt_exec_alarm = 0;
|
||||
sys_rt_exec_motion_override = 0;
|
||||
sys_rt_exec_accessory_override = 0;
|
||||
// Reset Grbl primary systems.
|
||||
serial_reset_read_buffer(CLIENT_ALL); // Clear serial read buffer
|
||||
gc_init(); // Set g-code parser to default state
|
||||
serial_reset_read_buffer(CLIENT_ALL); // Clear serial read buffer
|
||||
gc_init(); // Set g-code parser to default state
|
||||
spindle->stop();
|
||||
coolant_init();
|
||||
limits_init();
|
||||
probe_init();
|
||||
plan_reset(); // Clear block buffer and planner variables
|
||||
st_reset(); // Clear stepper subsystem variables
|
||||
plan_reset(); // Clear block buffer and planner variables
|
||||
st_reset(); // Clear stepper subsystem variables
|
||||
// Sync cleared gcode and planner positions to current system position.
|
||||
plan_sync_position();
|
||||
gc_sync_position();
|
||||
|
@@ -1,218 +0,0 @@
|
||||
/*
|
||||
MotorClass.h
|
||||
Header file for Motor Classes
|
||||
Here is the hierarchy
|
||||
Motor
|
||||
Nullmotor
|
||||
StandardStepper
|
||||
TrinamicDriver
|
||||
Unipolar
|
||||
RC Servo
|
||||
|
||||
These are for motors coordinated by Grbl_ESP32
|
||||
See motorClass.cpp for more details
|
||||
|
||||
Part of Grbl_ESP32
|
||||
2020 - Bart Dring
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef MOTORCLASS_H
|
||||
#define MOTORCLASS_H
|
||||
|
||||
#include "../grbl.h"
|
||||
#include <TMCStepper.h> // https://github.com/teemuatlut/TMCStepper
|
||||
#include "TrinamicDriverClass.h"
|
||||
#include "RcServoClass.h"
|
||||
//#include "SolenoidClass.h"
|
||||
|
||||
extern uint8_t rmt_chan_num[MAX_AXES][2];
|
||||
extern rmt_item32_t rmtItem[2];
|
||||
extern rmt_config_t rmtConfig;
|
||||
|
||||
typedef enum {
|
||||
MOTOR,
|
||||
NULL_MOTOR,
|
||||
STANDARD_MOTOR,
|
||||
TRINAMIC_SPI_MOTOR,
|
||||
UNIPOLAR_MOTOR,
|
||||
RC_SERVO_MOTOR,
|
||||
SOLENOID
|
||||
} motor_class_id_t;
|
||||
|
||||
// These are used for setup and to talk to the motors as a group.
|
||||
void init_motors();
|
||||
uint8_t get_next_trinamic_driver_index();
|
||||
bool motors_have_type_id(motor_class_id_t id);
|
||||
void readSgTask(void* pvParameters);
|
||||
void motors_read_settings();
|
||||
void motors_set_homing_mode(uint8_t homing_mask, bool isHoming);
|
||||
void motors_set_disable(bool disable);
|
||||
void motors_set_direction_pins(uint8_t onMask);
|
||||
void motors_step(uint8_t step_mask, uint8_t dir_mask);
|
||||
void servoUpdateTask(void* pvParameters);
|
||||
|
||||
extern bool motor_class_steps; // true if at least one motor class is handling steps
|
||||
|
||||
// ==================== Motor Classes ====================
|
||||
|
||||
class Motor {
|
||||
public:
|
||||
Motor();
|
||||
|
||||
virtual void init(); // not in constructor because this also gets called when $$ settings change
|
||||
virtual void config_message();
|
||||
virtual void debug_message();
|
||||
virtual void read_settings();
|
||||
virtual void set_homing_mode(uint8_t homing_mask, bool isHoming);
|
||||
virtual void set_disable(bool disable);
|
||||
virtual void set_direction_pins(uint8_t onMask);
|
||||
virtual void step(uint8_t step_mask, uint8_t dir_mask); // only used on Unipolar right now
|
||||
virtual bool test();
|
||||
virtual void set_axis_name();
|
||||
virtual void update();
|
||||
|
||||
motor_class_id_t type_id;
|
||||
uint8_t is_active = false;
|
||||
|
||||
protected:
|
||||
uint8_t axis_index; // X_AXIS, etc
|
||||
uint8_t dual_axis_index; // 0 = primary 1=ganged
|
||||
|
||||
bool _showError;
|
||||
bool _use_mpos = true;
|
||||
uint8_t _homing_mask;
|
||||
char _axis_name[10];// this the name to use when reporting like "X" or "X2"
|
||||
};
|
||||
|
||||
class Nullmotor : public Motor {
|
||||
|
||||
};
|
||||
|
||||
class StandardStepper : public Motor {
|
||||
public:
|
||||
StandardStepper();
|
||||
StandardStepper(uint8_t axis_index, uint8_t step_pin, uint8_t dir_pin, uint8_t disable_pin);
|
||||
|
||||
virtual void config_message();
|
||||
virtual void init();
|
||||
virtual void set_direction_pins(uint8_t onMask);
|
||||
void init_step_dir_pins();
|
||||
virtual void set_disable(bool disable);
|
||||
uint8_t step_pin;
|
||||
|
||||
protected:
|
||||
bool _invert_step_pin;
|
||||
uint8_t dir_pin;
|
||||
uint8_t disable_pin;
|
||||
};
|
||||
|
||||
class TrinamicDriver : public StandardStepper {
|
||||
public:
|
||||
TrinamicDriver(uint8_t axis_index,
|
||||
uint8_t step_pin,
|
||||
uint8_t dir_pin,
|
||||
uint8_t disable_pin,
|
||||
uint8_t cs_pin,
|
||||
uint16_t driver_part_number,
|
||||
float r_sense,
|
||||
int8_t spi_index);
|
||||
|
||||
void config_message();
|
||||
void init();
|
||||
void set_mode(bool isHoming);
|
||||
void read_settings();
|
||||
void trinamic_test_response();
|
||||
void trinamic_stepper_enable(bool enable);
|
||||
void debug_message();
|
||||
void set_homing_mode(uint8_t homing_mask, bool ishoming);
|
||||
void set_disable(bool disable);
|
||||
bool test();
|
||||
|
||||
private:
|
||||
uint32_t calc_tstep(float speed, float percent);
|
||||
|
||||
TMC2130Stepper* tmcstepper; // all other driver types are subclasses of this one
|
||||
uint8_t _homing_mode;
|
||||
uint8_t cs_pin = UNDEFINED_PIN; // The chip select pin (can be the same for daisy chain)
|
||||
uint16_t _driver_part_number; // example: use 2130 for TMC2130
|
||||
float _r_sense;
|
||||
int8_t spi_index;
|
||||
protected:
|
||||
uint8_t _mode;
|
||||
uint8_t _lastMode = 255;
|
||||
};
|
||||
|
||||
|
||||
class UnipolarMotor : public Motor {
|
||||
public:
|
||||
UnipolarMotor();
|
||||
UnipolarMotor(uint8_t axis_index, uint8_t pin_phase0, uint8_t pin_phase1, uint8_t pin_phase2, uint8_t pin_phase3);
|
||||
void init();
|
||||
void config_message();
|
||||
void set_disable(bool disable);
|
||||
void step(uint8_t step_mask, uint8_t dir_mask); // only used on Unipolar right now
|
||||
|
||||
private:
|
||||
uint8_t _pin_phase0;
|
||||
uint8_t _pin_phase1;
|
||||
uint8_t _pin_phase2;
|
||||
uint8_t _pin_phase3;
|
||||
uint8_t _current_phase;
|
||||
bool _half_step;
|
||||
bool _enabled;
|
||||
};
|
||||
|
||||
class RcServo : public Motor {
|
||||
public:
|
||||
RcServo();
|
||||
RcServo(uint8_t axis_index, uint8_t pwm_pin, float min, float max);
|
||||
virtual void config_message();
|
||||
virtual void init();
|
||||
void _write_pwm(uint32_t duty);
|
||||
virtual void set_disable(bool disable);
|
||||
virtual void update();
|
||||
void read_settings();
|
||||
void set_homing_mode(bool is_homing, bool isHoming);
|
||||
|
||||
protected:
|
||||
void set_location();
|
||||
void _get_calibration();
|
||||
|
||||
uint8_t _pwm_pin;
|
||||
uint8_t _channel_num;
|
||||
uint32_t _current_pwm_duty;
|
||||
bool _disabled;
|
||||
|
||||
float _position_min;
|
||||
float _position_max; // position in millimeters
|
||||
float _homing_position;
|
||||
|
||||
float _pwm_pulse_min;
|
||||
float _pwm_pulse_max;
|
||||
};
|
||||
|
||||
class Solenoid : public RcServo {
|
||||
public:
|
||||
Solenoid();
|
||||
Solenoid(uint8_t axis_index, gpio_num_t pwm_pin, float transition_poiont);
|
||||
void config_message();
|
||||
void set_location();
|
||||
void update();
|
||||
void init();
|
||||
void set_disable(bool disable);
|
||||
|
||||
float _transition_poiont;
|
||||
};
|
||||
|
||||
#endif
|
@@ -1,190 +0,0 @@
|
||||
/*
|
||||
RcServoServoClass.cpp
|
||||
|
||||
This allows an RcServo to be used like any other motor. Serrvos
|
||||
do have limitation in travel and speed, so you do need to respect that.
|
||||
|
||||
Part of Grbl_ESP32
|
||||
|
||||
2020 - Bart Dring
|
||||
|
||||
Servos have a limited travel, so they map the travel across a range in
|
||||
the current work coordinatee system. The servo can only travel as far
|
||||
as the range, but the internal axis value can keep going.
|
||||
|
||||
Range: The range is specified in the machine definition file with...
|
||||
#define X_SERVO_RANGE_MIN 0.0
|
||||
#define X_SERVO_RANGE_MAX 5.0
|
||||
|
||||
Direction: The direction can be changed using the $3 setting for the axis
|
||||
|
||||
Homing: During homing, the servo will move to one of the endpoints. The
|
||||
endpoint is determined by the $23 or $HomingDirInvertMask setting for the axis.
|
||||
Do not define a homing cycle for the axis with the servo.
|
||||
You do need at least 1 homing cycle. TODO: Fix this
|
||||
|
||||
Calibration. You can tweak the endpoints using the $10n or nStepsPerMm and
|
||||
$13n or $xMaxTravel setting, where n is the axis.
|
||||
The value is a percent. If you secify a percent outside the
|
||||
the range specified by the values below, it will be reset to 100.0 (100% ... no change)
|
||||
The calibration adjusts in direction of positive momement, so a value above 100% moves
|
||||
towards the higher axis value.
|
||||
|
||||
#define SERVO_CAL_MIN
|
||||
#define SERVO_CAL_MAX
|
||||
|
||||
Grbl_ESP32 is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
RcServo :: RcServo() {
|
||||
|
||||
}
|
||||
|
||||
RcServo :: RcServo(uint8_t axis_index, uint8_t pwm_pin, float min, float max) {
|
||||
type_id = RC_SERVO_MOTOR;
|
||||
this->axis_index = axis_index % MAX_AXES;
|
||||
this->dual_axis_index = axis_index < MAX_AXES ? 0 : 1; // 0 = primary 1 = ganged
|
||||
this->_pwm_pin = pwm_pin;
|
||||
_position_min = min;
|
||||
_position_max = max;
|
||||
init();
|
||||
}
|
||||
|
||||
void RcServo :: init() {
|
||||
read_settings();
|
||||
_channel_num = sys_get_next_PWM_chan_num();
|
||||
ledcSetup(_channel_num, SERVO_PULSE_FREQ, SERVO_PULSE_RES_BITS);
|
||||
ledcAttachPin(_pwm_pin, _channel_num);
|
||||
_current_pwm_duty = 0;
|
||||
is_active = true; // as opposed to NullMotors, this is a real motor
|
||||
set_axis_name();
|
||||
config_message();
|
||||
}
|
||||
|
||||
void RcServo :: config_message() {
|
||||
grbl_msg_sendf(CLIENT_SERIAL,
|
||||
MSG_LEVEL_INFO,
|
||||
"%s Axis RC Servo motor Output:%d Min:%5.3fmm Max:%5.3fmm",
|
||||
_axis_name,
|
||||
_pwm_pin,
|
||||
_position_min,
|
||||
_position_max);
|
||||
}
|
||||
|
||||
void RcServo::_write_pwm(uint32_t duty) {
|
||||
// to prevent excessive calls to ledcWrite, make sure duty hass changed
|
||||
if (duty == _current_pwm_duty)
|
||||
return;
|
||||
|
||||
_current_pwm_duty = duty;
|
||||
|
||||
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "%s Servo Pwm %d", _axis_name, duty);
|
||||
ledcWrite(_channel_num, duty);
|
||||
}
|
||||
|
||||
// sets the PWM to zero. This allows most servos to be manually moved
|
||||
void RcServo::set_disable(bool disable) {
|
||||
return;
|
||||
_disabled = disable;
|
||||
if (_disabled)
|
||||
_write_pwm(0);
|
||||
}
|
||||
|
||||
void RcServo::set_homing_mode(bool is_homing, bool isHoming) {
|
||||
float home_pos = 0.0;
|
||||
|
||||
if (!is_homing)
|
||||
return;
|
||||
|
||||
if (bit_istrue(homing_dir_mask->get(), bit(axis_index)))
|
||||
home_pos = _position_min;
|
||||
else
|
||||
home_pos = _position_max;
|
||||
|
||||
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Servo set home %d %3.2f", is_homing, home_pos);
|
||||
sys_position[axis_index] = home_pos * axis_settings[axis_index]->steps_per_mm->get(); // convert to steps
|
||||
|
||||
}
|
||||
|
||||
void RcServo::update() {
|
||||
set_location();
|
||||
}
|
||||
|
||||
void RcServo::set_location() {
|
||||
uint32_t servo_pulse_len;
|
||||
float servo_pos, mpos, offset;
|
||||
// skip location if we are in alarm mode
|
||||
|
||||
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "locate");
|
||||
_get_calibration();
|
||||
|
||||
if (sys.state == STATE_ALARM) {
|
||||
set_disable(true);
|
||||
return;
|
||||
}
|
||||
|
||||
mpos = system_convert_axis_steps_to_mpos(sys_position, axis_index); // get the axis machine position in mm
|
||||
offset = gc_state.coord_system[axis_index] + gc_state.coord_offset[axis_index]; // get the current axis work offset
|
||||
servo_pos = mpos - offset; // determine the current work position
|
||||
|
||||
// determine the pulse length
|
||||
servo_pulse_len = (uint32_t)mapConstrain(servo_pos, _position_min, _position_max, _pwm_pulse_min, _pwm_pulse_max);
|
||||
|
||||
_write_pwm(servo_pulse_len);
|
||||
|
||||
}
|
||||
|
||||
void RcServo::read_settings() {
|
||||
_get_calibration();
|
||||
}
|
||||
|
||||
// this should change to use its own settings.
|
||||
void RcServo::_get_calibration() {
|
||||
float _cal_min = 1.0;
|
||||
float _cal_max = 1.0;
|
||||
|
||||
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Read settings");
|
||||
|
||||
// make sure the min is in range
|
||||
if ((axis_settings[axis_index]->steps_per_mm->get() < SERVO_CAL_MIN) || (axis_settings[axis_index]->steps_per_mm->get() > SERVO_CAL_MAX)) {
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Servo calibration ($10%d) value error. Reset to 100", axis_index);
|
||||
char reset_val[] = "100";
|
||||
axis_settings[axis_index]->steps_per_mm->setStringValue(reset_val);
|
||||
}
|
||||
|
||||
// make sure the max is in range
|
||||
// Note: Max travel is set positive via $$, but stored as a negative number
|
||||
if ((axis_settings[axis_index]->max_travel->get() < SERVO_CAL_MIN) || (axis_settings[axis_index]->max_travel->get() > SERVO_CAL_MAX)) {
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Servo calibration ($13%d) value error. %3.2f Reset to 100", axis_index, axis_settings[axis_index]->max_travel->get());
|
||||
char reset_val[] = "100";
|
||||
axis_settings[axis_index]->max_travel->setStringValue(reset_val);
|
||||
}
|
||||
|
||||
_pwm_pulse_min = SERVO_MIN_PULSE;
|
||||
_pwm_pulse_max = SERVO_MAX_PULSE;
|
||||
|
||||
|
||||
if (bit_istrue(dir_invert_mask->get(), bit(axis_index))) { // normal direction
|
||||
_cal_min = 2.0 - (axis_settings[axis_index]->steps_per_mm->get() / 100.0);
|
||||
_cal_max = 2.0 - (axis_settings[axis_index]->max_travel->get() / 100.0);
|
||||
swap(_pwm_pulse_min, _pwm_pulse_max);
|
||||
} else { // inverted direction
|
||||
_cal_min = (axis_settings[axis_index]->steps_per_mm->get() / 100.0);
|
||||
_cal_max = (axis_settings[axis_index]->max_travel->get() / 100.0);
|
||||
}
|
||||
|
||||
_pwm_pulse_min *= _cal_min;
|
||||
_pwm_pulse_max *= _cal_max;
|
||||
|
||||
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Servo calibration min:%1.2f max %1.2f", _pwm_pulse_min, _pwm_pulse_max);
|
||||
|
||||
}
|
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
RcServoClass.h
|
||||
|
||||
Part of Grbl_ESP32
|
||||
|
||||
2020 - Bart Dring
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef RCSERVOCLASS_H
|
||||
#define RCSERVOCLASS_H
|
||||
|
||||
// this is the pulse range of a the servo. Typical servos are 0.001 to 0.002 seconds
|
||||
// some servos have a wider range. You can adjust this here or in the calibration feature
|
||||
#define SERVO_MIN_PULSE_SEC 0.001 // min pulse in seconds
|
||||
#define SERVO_MAX_PULSE_SEC 0.002 // max pulse in seconds
|
||||
|
||||
#define SERVO_POSITION_MIN_DEFAULT 0.0 // mm
|
||||
#define SERVO_POSITION_MAX_DEFAULT 20.0 // mm
|
||||
|
||||
#define SERVO_PULSE_FREQ 50 // 50Hz ...This is a standard analog servo value. Digital ones can repeat faster
|
||||
|
||||
#define SERVO_PULSE_RES_BITS 16 // bits of resolution of PWM (16 is max)
|
||||
#define SERVO_PULSE_RES_COUNT 65535 // see above TODO...do the math here 2^SERVO_PULSE_RES_BITS
|
||||
|
||||
#define SERVO_TIME_PER_BIT ((1.0 / (float)SERVO_PULSE_FREQ) / ((float)SERVO_PULSE_RES_COUNT) ) // seconds
|
||||
|
||||
#define SERVO_MIN_PULSE (uint16_t)(SERVO_MIN_PULSE_SEC / SERVO_TIME_PER_BIT) // in timer counts
|
||||
#define SERVO_MAX_PULSE (uint16_t)(SERVO_MAX_PULSE_SEC / SERVO_TIME_PER_BIT) // in timer counts
|
||||
|
||||
#define SERVO_PULSE_RANGE (SERVO_MAX_PULSE-SERVO_MIN_PULSE)
|
||||
|
||||
#define SERVO_CAL_MIN 20.0 // Percent: the minimum allowable calibration value
|
||||
#define SERVO_CAL_MAX 180.0 // Percent: the maximum allowable calibration value
|
||||
|
||||
#define SERVO_TIMER_INT_FREQ 50.0 // Hz This is the task frequency
|
||||
|
||||
#endif
|
@@ -1,107 +0,0 @@
|
||||
/*
|
||||
StandardStepperClass.cpp
|
||||
|
||||
This is used for a stepper motor that just requires step and direction
|
||||
pins.
|
||||
TODO: Add an enable pin
|
||||
|
||||
Part of Grbl_ESP32
|
||||
|
||||
2020 - Bart Dring
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
StandardStepper :: StandardStepper() {
|
||||
|
||||
}
|
||||
|
||||
StandardStepper :: StandardStepper(uint8_t axis_index, uint8_t step_pin, uint8_t dir_pin, uint8_t disable_pin) {
|
||||
type_id = STANDARD_MOTOR;
|
||||
this->axis_index = axis_index % MAX_AXES;
|
||||
this->dual_axis_index = axis_index < MAX_AXES ? 0 : 1; // 0 = primary 1 = ganged
|
||||
this->step_pin = step_pin;
|
||||
this->dir_pin = dir_pin;
|
||||
this->disable_pin = disable_pin;
|
||||
init();
|
||||
}
|
||||
|
||||
void StandardStepper :: init() {
|
||||
_homing_mask = 0;
|
||||
is_active = true; // as opposed to NullMotors, this is a real motor
|
||||
set_axis_name();
|
||||
init_step_dir_pins();
|
||||
config_message();
|
||||
}
|
||||
|
||||
void StandardStepper :: init_step_dir_pins() {
|
||||
// TODO Step pin, but RMT complicates things
|
||||
_invert_step_pin = bit_istrue(step_invert_mask->get(), bit(axis_index));
|
||||
pinMode(dir_pin, OUTPUT);
|
||||
|
||||
#ifdef USE_RMT_STEPS
|
||||
rmtConfig.rmt_mode = RMT_MODE_TX;
|
||||
rmtConfig.clk_div = 20;
|
||||
rmtConfig.mem_block_num = 2;
|
||||
rmtConfig.tx_config.loop_en = false;
|
||||
rmtConfig.tx_config.carrier_en = false;
|
||||
rmtConfig.tx_config.carrier_freq_hz = 0;
|
||||
rmtConfig.tx_config.carrier_duty_percent = 50;
|
||||
rmtConfig.tx_config.carrier_level = RMT_CARRIER_LEVEL_LOW;
|
||||
rmtConfig.tx_config.idle_output_en = true;
|
||||
|
||||
|
||||
#ifdef STEP_PULSE_DELAY
|
||||
rmtItem[0].duration0 = STEP_PULSE_DELAY * 4;
|
||||
#else
|
||||
rmtItem[0].duration0 = 1;
|
||||
#endif
|
||||
|
||||
rmtItem[0].duration1 = 4 * pulse_microseconds->get();
|
||||
rmtItem[1].duration0 = 0;
|
||||
rmtItem[1].duration1 = 0;
|
||||
|
||||
rmt_chan_num[axis_index][dual_axis_index] = sys_get_next_RMT_chan_num();
|
||||
rmt_set_source_clk((rmt_channel_t)rmt_chan_num[axis_index][dual_axis_index], RMT_BASECLK_APB);
|
||||
rmtConfig.channel = (rmt_channel_t)rmt_chan_num[axis_index][dual_axis_index];
|
||||
rmtConfig.tx_config.idle_level = _invert_step_pin ? RMT_IDLE_LEVEL_HIGH : RMT_IDLE_LEVEL_LOW;
|
||||
rmtConfig.gpio_num = gpio_num_t(step_pin); // c is a wacky lang
|
||||
rmtItem[0].level0 = rmtConfig.tx_config.idle_level;
|
||||
rmtItem[0].level1 = !rmtConfig.tx_config.idle_level;
|
||||
rmt_config(&rmtConfig);
|
||||
rmt_fill_tx_items(rmtConfig.channel, &rmtItem[0], rmtConfig.mem_block_num, 0);
|
||||
|
||||
#else
|
||||
pinMode(step_pin, OUTPUT);
|
||||
|
||||
#endif // USE_RMT_STEPS
|
||||
pinMode(disable_pin, OUTPUT);
|
||||
}
|
||||
|
||||
|
||||
void StandardStepper :: config_message() {
|
||||
grbl_msg_sendf(CLIENT_SERIAL,
|
||||
MSG_LEVEL_INFO,
|
||||
"%s Axis standard stepper motor Step:%s Dir:%s Disable:%s",
|
||||
_axis_name,
|
||||
pinName(step_pin).c_str(),
|
||||
pinName(dir_pin).c_str(),
|
||||
pinName(disable_pin).c_str());
|
||||
}
|
||||
|
||||
void StandardStepper :: set_direction_pins(uint8_t onMask) {
|
||||
digitalWrite(dir_pin, (onMask & bit(axis_index)));
|
||||
}
|
||||
|
||||
void StandardStepper :: set_disable(bool disable) {
|
||||
digitalWrite(disable_pin, disable);
|
||||
}
|
@@ -1,242 +0,0 @@
|
||||
/*
|
||||
TrinamicDriverClass.cpp
|
||||
This is used for Trinamic SPI controlled stepper motor drivers.
|
||||
|
||||
Part of Grbl_ESP32
|
||||
2020 - Bart Dring
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
#include <TMCStepper.h>
|
||||
#include "TrinamicDriverClass.h"
|
||||
|
||||
TrinamicDriver :: TrinamicDriver(uint8_t axis_index,
|
||||
uint8_t step_pin,
|
||||
uint8_t dir_pin,
|
||||
uint8_t disable_pin,
|
||||
uint8_t cs_pin,
|
||||
uint16_t driver_part_number,
|
||||
float r_sense,
|
||||
int8_t spi_index) {
|
||||
type_id = TRINAMIC_SPI_MOTOR;
|
||||
this->axis_index = axis_index % MAX_AXES;
|
||||
this->dual_axis_index = axis_index < 6 ? 0 : 1; // 0 = primary 1 = ganged
|
||||
_driver_part_number = driver_part_number;
|
||||
_r_sense = r_sense;
|
||||
this->step_pin = step_pin;
|
||||
this->dir_pin = dir_pin;
|
||||
this->disable_pin = disable_pin;
|
||||
this->cs_pin = cs_pin;
|
||||
this->spi_index = spi_index;
|
||||
|
||||
_homing_mode = TRINAMIC_HOMING_MODE;
|
||||
_homing_mask = 0; // no axes homing
|
||||
|
||||
if (_driver_part_number == 2130)
|
||||
tmcstepper = new TMC2130Stepper(cs_pin, _r_sense, spi_index);
|
||||
else if (_driver_part_number == 5160)
|
||||
tmcstepper = new TMC5160Stepper(cs_pin, _r_sense, spi_index);
|
||||
else {
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Trinamic unsupported p/n:%d", _driver_part_number);
|
||||
return;
|
||||
}
|
||||
|
||||
set_axis_name();
|
||||
|
||||
init_step_dir_pins(); // from StandardStepper
|
||||
|
||||
digitalWrite(cs_pin, HIGH);
|
||||
pinMode(cs_pin, OUTPUT);
|
||||
|
||||
// use slower speed if I2S
|
||||
if (cs_pin >= I2S_OUT_PIN_BASE)
|
||||
tmcstepper->setSPISpeed(TRINAMIC_SPI_FREQ);
|
||||
|
||||
config_message();
|
||||
|
||||
// init() must be called later, after all TMC drivers have CS pins setup.
|
||||
}
|
||||
|
||||
void TrinamicDriver :: init() {
|
||||
|
||||
SPI.begin(); // this will get called for each motor, but does not seem to hurt anything
|
||||
|
||||
tmcstepper->begin();
|
||||
test(); // Try communicating with motor. Prints an error if there is a problem.
|
||||
read_settings(); // pull info from settings
|
||||
set_mode(false);
|
||||
|
||||
_homing_mask = 0;
|
||||
is_active = true; // as opposed to NullMotors, this is a real motor
|
||||
}
|
||||
|
||||
/*
|
||||
This is the startup message showing the basic definition
|
||||
*/
|
||||
void TrinamicDriver :: config_message() {
|
||||
grbl_msg_sendf(CLIENT_SERIAL,
|
||||
MSG_LEVEL_INFO,
|
||||
"%s Axis Trinamic TMC%d Step:%s Dir:%s CS:%s Disable:%s Index:%d",
|
||||
_axis_name,
|
||||
_driver_part_number,
|
||||
pinName(step_pin).c_str(),
|
||||
pinName(dir_pin).c_str(),
|
||||
pinName(cs_pin).c_str(),
|
||||
pinName(disable_pin).c_str(),
|
||||
spi_index);
|
||||
}
|
||||
|
||||
bool TrinamicDriver :: test() {
|
||||
switch (tmcstepper->test_connection()) {
|
||||
case 1:
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "%s Trinamic driver test failed. Check connection", _axis_name);
|
||||
return false;
|
||||
case 2:
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "%s Trinamic driver test failed. Check motor power", _axis_name);
|
||||
return false;
|
||||
default:
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "%s Trinamic driver test passed", _axis_name);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Read setting and send them to the driver. Called at init() and whenever related settings change
|
||||
both are stored as float Amps, but TMCStepper library expects...
|
||||
uint16_t run (mA)
|
||||
float hold (as a percentage of run)
|
||||
*/
|
||||
void TrinamicDriver :: read_settings() {
|
||||
uint16_t run_i_ma = (uint16_t)(axis_settings[axis_index]->run_current->get() * 1000.0);
|
||||
float hold_i_percent;
|
||||
|
||||
if (axis_settings[axis_index]->run_current->get() == 0)
|
||||
hold_i_percent = 0;
|
||||
else {
|
||||
hold_i_percent = axis_settings[axis_index]->hold_current->get() / axis_settings[axis_index]->run_current->get();
|
||||
if (hold_i_percent > 1.0)
|
||||
hold_i_percent = 1.0;
|
||||
}
|
||||
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "%s Current run %d hold %f", _axis_name, run_i_ma, hold_i_percent);
|
||||
|
||||
tmcstepper->microsteps(axis_settings[axis_index]->microsteps->get());
|
||||
tmcstepper->rms_current(run_i_ma, hold_i_percent);
|
||||
|
||||
}
|
||||
|
||||
void TrinamicDriver :: set_homing_mode(uint8_t homing_mask, bool isHoming) {
|
||||
_homing_mask = homing_mask;
|
||||
set_mode(isHoming);
|
||||
}
|
||||
|
||||
/*
|
||||
There are ton of settings. I'll start by grouping then into modes for now.
|
||||
Many people will want quiet and stallgaurd homing. Stallguard only run in
|
||||
Coolstep mode, so it will need to switch to Coolstep when homing
|
||||
*/
|
||||
void TrinamicDriver :: set_mode(bool isHoming) {
|
||||
|
||||
if (isHoming)
|
||||
_mode = TRINAMIC_HOMING_MODE;
|
||||
else
|
||||
_mode = TRINAMIC_RUN_MODE;
|
||||
|
||||
if (_lastMode == _mode)
|
||||
return;
|
||||
_lastMode = _mode;
|
||||
|
||||
switch (_mode) {
|
||||
case TRINAMIC_MODE_STEALTHCHOP:
|
||||
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "TRINAMIC_MODE_STEALTHCHOP");
|
||||
tmcstepper->en_pwm_mode(true);
|
||||
tmcstepper->pwm_autoscale(true);
|
||||
tmcstepper->diag1_stall(false);
|
||||
break;
|
||||
case TRINAMIC_MODE_COOLSTEP:
|
||||
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "TRINAMIC_MODE_COOLSTEP");
|
||||
tmcstepper->en_pwm_mode(false);
|
||||
tmcstepper->pwm_autoscale(false);
|
||||
tmcstepper->TCOOLTHRS(NORMAL_TCOOLTHRS); // when to turn on coolstep
|
||||
tmcstepper->THIGH(NORMAL_THIGH);
|
||||
break;
|
||||
case TRINAMIC_MODE_STALLGUARD:
|
||||
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "TRINAMIC_MODE_STALLGUARD");
|
||||
tmcstepper->en_pwm_mode(false);
|
||||
tmcstepper->pwm_autoscale(false);
|
||||
tmcstepper->TCOOLTHRS(calc_tstep(homing_feed_rate->get(), 150.0));
|
||||
tmcstepper->THIGH(calc_tstep(homing_feed_rate->get(), 60.0));
|
||||
tmcstepper->sfilt(1);
|
||||
tmcstepper->diag1_stall(true); // stallguard i/o is on diag1
|
||||
tmcstepper->sgt(axis_settings[axis_index]->stallguard->get());
|
||||
break;
|
||||
default:
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "TRINAMIC_MODE_UNDEFINED");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
This is the stallguard tuning info. It is call debug, so it could be generic across all classes.
|
||||
*/
|
||||
void TrinamicDriver :: debug_message() {
|
||||
|
||||
uint32_t tstep = tmcstepper->TSTEP();
|
||||
|
||||
if (tstep == 0xFFFFF || tstep < 1) // if axis is not moving return
|
||||
return;
|
||||
float feedrate = st_get_realtime_rate(); //* settings.microsteps[axis_index] / 60.0 ; // convert mm/min to Hz
|
||||
|
||||
grbl_msg_sendf(CLIENT_SERIAL,
|
||||
MSG_LEVEL_INFO,
|
||||
"%s Stallguard %d SG_Val: %04d Rate: %05.0f mm/min SG_Setting:%d",
|
||||
_axis_name,
|
||||
tmcstepper->stallguard(),
|
||||
tmcstepper->sg_result(),
|
||||
feedrate,
|
||||
axis_settings[axis_index]->stallguard->get());
|
||||
}
|
||||
|
||||
// calculate a tstep from a rate
|
||||
// tstep = TRINAMIC_FCLK / (time between 1/256 steps)
|
||||
// This is used to set the stallguard window from the homing speed.
|
||||
// The percent is the offset on the window
|
||||
uint32_t TrinamicDriver :: calc_tstep(float speed, float percent) {
|
||||
float tstep = speed / 60.0 * axis_settings[axis_index]->steps_per_mm->get() * (float)(256 / axis_settings[axis_index]->microsteps->get());
|
||||
tstep = TRINAMIC_FCLK / tstep * percent / 100.0;
|
||||
|
||||
return (uint32_t)tstep;
|
||||
}
|
||||
|
||||
|
||||
// this can use the enable feature over SPI. The dedicated pin must be in the enable mode,
|
||||
// but that can be hardwired that way.
|
||||
void TrinamicDriver :: set_disable(bool disable) {
|
||||
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "%s Axis disable %d", _axis_name, disable);
|
||||
|
||||
digitalWrite(disable_pin, disable);
|
||||
|
||||
#ifdef USE_TRINAMIC_ENABLE
|
||||
if (disable)
|
||||
tmcstepper->toff(TRINAMIC_TOFF_DISABLE);
|
||||
else {
|
||||
if (_mode == TRINAMIC_MODE_STEALTHCHOP)
|
||||
tmcstepper->toff(TRINAMIC_TOFF_STEALTHCHOP);
|
||||
else
|
||||
tmcstepper->toff(TRINAMIC_TOFF_COOLSTEP);
|
||||
}
|
||||
#endif
|
||||
// the pin based enable could be added here.
|
||||
// This would be for individual motors, not the single pin for all motors.
|
||||
}
|
||||
|
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
TrinamicDriverClass.h
|
||||
|
||||
Part of Grbl_ESP32
|
||||
|
||||
2020 - Bart Dring
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define TRINAMIC_MODE_STEALTHCHOP 0 // very quiet
|
||||
#define TRINAMIC_MODE_COOLSTEP 1 // everything runs cooler so higher current possible
|
||||
#define TRINAMIC_MODE_STALLGUARD 2 // coolstep plus generates stall indication
|
||||
|
||||
#define NORMAL_TCOOLTHRS 0xFFFFF // 20 bit is max
|
||||
#define NORMAL_THIGH 0
|
||||
|
||||
#define TMC2130_RSENSE_DEFAULT 0.11f
|
||||
#define TMC5160_RSENSE_DEFAULT 0.075f
|
||||
|
||||
#define TRINAMIC_SPI_FREQ 100000
|
||||
|
||||
#define TRINAMIC_FCLK 12700000.0 // Internal clock Approx (Hz) used to calculate TSTEP from homing rate
|
||||
|
||||
// ==== defaults OK to define them in your machine definition ====
|
||||
#ifndef TRINAMIC_RUN_MODE
|
||||
#define TRINAMIC_RUN_MODE TRINAMIC_MODE_COOLSTEP
|
||||
#endif
|
||||
|
||||
#ifndef TRINAMIC_HOMING_MODE
|
||||
#define TRINAMIC_HOMING_MODE TRINAMIC_RUN_MODE
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef TRINAMIC_TOFF_DISABLE
|
||||
#define TRINAMIC_TOFF_DISABLE 0
|
||||
#endif
|
||||
|
||||
#ifndef TRINAMIC_TOFF_STEALTHCHOP
|
||||
#define TRINAMIC_TOFF_STEALTHCHOP 5
|
||||
#endif
|
||||
|
||||
#ifndef TRINAMIC_TOFF_COOLSTEP
|
||||
#define TRINAMIC_TOFF_COOLSTEP 3
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifndef TRINAMICDRIVERCLASS_H
|
||||
#define TRINAMICDRIVERCLASS_H
|
||||
|
||||
#include "MotorClass.h"
|
||||
#include <TMCStepper.h> // https://github.com/teemuatlut/TMCStepper
|
||||
|
||||
#endif
|
@@ -1,146 +0,0 @@
|
||||
UnipolarMotor :: UnipolarMotor() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
UnipolarMotor :: UnipolarMotor(uint8_t axis_index, uint8_t pin_phase0, uint8_t pin_phase1, uint8_t pin_phase2, uint8_t pin_phase3) {
|
||||
type_id = UNIPOLAR_MOTOR;
|
||||
this->axis_index = axis_index % MAX_AXES;
|
||||
this->dual_axis_index = axis_index < MAX_AXES ? 0 : 1; // 0 = primary 1 = ganged
|
||||
_pin_phase0 = pin_phase0;
|
||||
_pin_phase1 = pin_phase1;
|
||||
_pin_phase2 = pin_phase2;
|
||||
_pin_phase3 = pin_phase3;
|
||||
|
||||
_half_step = true; // TODO read from settings ... microstep > 1 = half step
|
||||
|
||||
set_axis_name();
|
||||
init();
|
||||
config_message();
|
||||
}
|
||||
|
||||
void UnipolarMotor :: init() {
|
||||
pinMode(_pin_phase0, OUTPUT);
|
||||
pinMode(_pin_phase1, OUTPUT);
|
||||
pinMode(_pin_phase2, OUTPUT);
|
||||
pinMode(_pin_phase3, OUTPUT);
|
||||
_current_phase = 0;
|
||||
}
|
||||
|
||||
void UnipolarMotor :: config_message() {
|
||||
grbl_msg_sendf(CLIENT_SERIAL,
|
||||
MSG_LEVEL_INFO,
|
||||
"%s Axis unipolar stepper motor Ph0:%s Ph1:%s Ph2:%s Ph3:%s",
|
||||
_axis_name,
|
||||
pinName(_pin_phase0).c_str(),
|
||||
pinName(_pin_phase1).c_str(),
|
||||
pinName(_pin_phase2).c_str(),
|
||||
pinName(_pin_phase3).c_str());
|
||||
}
|
||||
|
||||
void UnipolarMotor :: set_disable(bool disable) {
|
||||
if (disable) {
|
||||
digitalWrite(_pin_phase0, 0);
|
||||
digitalWrite(_pin_phase1, 0);
|
||||
digitalWrite(_pin_phase2, 0);
|
||||
digitalWrite(_pin_phase3, 0);
|
||||
}
|
||||
_enabled = !disable;
|
||||
}
|
||||
|
||||
void UnipolarMotor::step(uint8_t step_mask, uint8_t dir_mask) {
|
||||
uint8_t _phase[8] = {0, 0, 0, 0, 0, 0, 0, 0}; // temporary phase values...all start as off
|
||||
uint8_t phase_max;
|
||||
|
||||
if (!(step_mask & bit(axis_index)))
|
||||
return; // a step is not required on this interrupt
|
||||
|
||||
if (!_enabled)
|
||||
return; // don't do anything, phase is not changed or lost
|
||||
|
||||
if (_half_step)
|
||||
phase_max = 7;
|
||||
else
|
||||
phase_max = 3;
|
||||
|
||||
if (dir_mask & bit(axis_index)) { // count up
|
||||
if (_current_phase == phase_max)
|
||||
_current_phase = 0;
|
||||
else
|
||||
_current_phase++;
|
||||
} else { // count down
|
||||
if (_current_phase == 0)
|
||||
_current_phase = phase_max;
|
||||
else
|
||||
_current_phase--;
|
||||
}
|
||||
/*
|
||||
8 Step : A – AB – B – BC – C – CD – D – DA
|
||||
4 Step : AB – BC – CD – DA
|
||||
|
||||
Step IN4 IN3 IN2 IN1
|
||||
A 0 0 0 1
|
||||
AB 0 0 1 1
|
||||
B 0 0 1 0
|
||||
BC 0 1 1 0
|
||||
C 0 1 0 0
|
||||
CD 1 1 0 0
|
||||
D 1 0 0 0
|
||||
DA 1 0 0 1
|
||||
*/
|
||||
if (_half_step) {
|
||||
switch (_current_phase) {
|
||||
case 0:
|
||||
_phase[0] = 1;
|
||||
break;
|
||||
case 1:
|
||||
_phase[0] = 1;
|
||||
_phase[1] = 1;
|
||||
break;
|
||||
case 2:
|
||||
_phase[1] = 1;
|
||||
break;
|
||||
case 3:
|
||||
_phase[1] = 1;
|
||||
_phase[2] = 1;
|
||||
break;
|
||||
case 4:
|
||||
_phase[2] = 1;
|
||||
break;
|
||||
case 5:
|
||||
_phase[2] = 1;
|
||||
_phase[3] = 1;
|
||||
break;
|
||||
case 6:
|
||||
_phase[3] = 1;
|
||||
break;
|
||||
case 7:
|
||||
_phase[3] = 1;
|
||||
_phase[0] = 1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (_current_phase) {
|
||||
case 0:
|
||||
_phase[0] = 1;
|
||||
_phase[1] = 1;
|
||||
break;
|
||||
case 1:
|
||||
_phase[1] = 1;
|
||||
_phase[2] = 1;
|
||||
break;
|
||||
case 2:
|
||||
_phase[2] = 1;
|
||||
_phase[3] = 1;
|
||||
break;
|
||||
case 3:
|
||||
_phase[3] = 1;
|
||||
_phase[0] = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
digitalWrite(_pin_phase0, _phase[0]);
|
||||
digitalWrite(_pin_phase1, _phase[1]);
|
||||
digitalWrite(_pin_phase2, _phase[2]);
|
||||
digitalWrite(_pin_phase3, _phase[3]);
|
||||
}
|
@@ -1,351 +0,0 @@
|
||||
#pragma once
|
||||
#include "JSONencoder.h"
|
||||
#include <map>
|
||||
#include <nvs.h>
|
||||
#include "espresponse.h"
|
||||
|
||||
// Command::List is a linked list of all settings,
|
||||
// so common code can enumerate them.
|
||||
class Command;
|
||||
// extern Command *CommandsList;
|
||||
|
||||
// This abstract class defines the generic interface that
|
||||
// is used to set and get values for all settings independent
|
||||
// of their underlying data type. The values are always
|
||||
// represented as human-readable strings. This generic
|
||||
// interface is used for managing settings via the user interface.
|
||||
|
||||
// Derived classes implement these generic functions for different
|
||||
// kinds of data. Code that accesses settings should use only these
|
||||
// generic functions and should not use derived classes directly.
|
||||
|
||||
enum {
|
||||
NO_AXIS = 255,
|
||||
};
|
||||
typedef enum : uint8_t {
|
||||
GRBL = 1, // Classic GRBL settings like $100
|
||||
EXTENDED, // Settings added by early versions of Grbl_Esp32
|
||||
WEBSET, // Settings for ESP3D_WebUI, stored in NVS
|
||||
GRBLCMD, // Non-persistent GRBL commands like $H
|
||||
WEBCMD, // ESP3D_WebUI commands that are not directly settings
|
||||
} type_t;
|
||||
typedef enum : uint8_t {
|
||||
WG, // Readable and writable as guest
|
||||
WU, // Readable and writable as user and admin
|
||||
WA, // Readable as user and admin, writable as admin
|
||||
} permissions_t;
|
||||
typedef uint8_t axis_t;
|
||||
|
||||
class Word {
|
||||
protected:
|
||||
const char* _description;
|
||||
const char* _grblName;
|
||||
const char* _fullName;
|
||||
type_t _type;
|
||||
permissions_t _permissions;
|
||||
public:
|
||||
Word(type_t type, permissions_t permissions, const char *description, const char * grblName, const char* fullName);
|
||||
type_t getType() { return _type; }
|
||||
permissions_t getPermissions() { return _permissions; }
|
||||
const char* getName() { return _fullName; }
|
||||
const char* getGrblName() { return _grblName; }
|
||||
const char* getDescription() { return _description; }
|
||||
};
|
||||
|
||||
class Command : public Word {
|
||||
protected:
|
||||
Command *link; // linked list of setting objects
|
||||
public:
|
||||
static Command* List;
|
||||
Command* next() { return link; }
|
||||
|
||||
~Command() {}
|
||||
Command(const char *description, type_t type, permissions_t permissions, const char * grblName, const char* fullName);
|
||||
|
||||
// The default implementation of addWebui() does nothing.
|
||||
// Derived classes may override it to do something.
|
||||
virtual void addWebui(JSONencoder *) {};
|
||||
|
||||
virtual err_t action(char* value, auth_t auth_level, ESPResponseStream* out) =0;
|
||||
};
|
||||
|
||||
class Setting : public Word {
|
||||
private:
|
||||
protected:
|
||||
static nvs_handle _handle;
|
||||
// group_t _group;
|
||||
axis_t _axis = NO_AXIS;
|
||||
Setting *link; // linked list of setting objects
|
||||
|
||||
bool (*_checker)(char *);
|
||||
const char* _keyName;
|
||||
public:
|
||||
static void init();
|
||||
static Setting* List;
|
||||
Setting* next() { return link; }
|
||||
|
||||
err_t check(char *s);
|
||||
|
||||
static err_t report_nvs_stats(const char* value, auth_t auth_level, ESPResponseStream* out) {
|
||||
nvs_stats_t stats;
|
||||
if (err_t err = nvs_get_stats(NULL, &stats))
|
||||
return err;
|
||||
grbl_sendf(out->client(), "[MSG: NVS Used: %d Free: %d Total: %d]\r\n",
|
||||
stats.used_entries, stats.free_entries, stats.total_entries);
|
||||
#if 0 // The SDK we use does not have this yet
|
||||
nvs_iterator_t it = nvs_entry_find(NULL, NULL, NVS_TYPE_ANY);
|
||||
while (it != NULL) {
|
||||
nvs_entry_info_t info;
|
||||
nvs_entry_info(it, &info);
|
||||
it = nvs_entry_next(it);
|
||||
grbl_sendf(out->client(), "namespace %s key '%s', type '%d' \n", info.namespace_name, info.key, info.type);
|
||||
}
|
||||
#endif
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
static err_t eraseNVS(const char* value, auth_t auth_level, ESPResponseStream* out) {
|
||||
nvs_erase_all(_handle);
|
||||
// return STATUS_OK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
~Setting() {}
|
||||
// Setting(const char *description, group_t group, const char * grblName, const char* fullName, bool (*checker)(char *));
|
||||
Setting(const char *description, type_t type, permissions_t permissions, const char * grblName, const char* fullName, bool (*checker)(char *));
|
||||
axis_t getAxis() { return _axis; }
|
||||
void setAxis(axis_t axis) { _axis = axis; }
|
||||
|
||||
// load() reads the backing store to get the current
|
||||
// value of the setting. This could be slow so it
|
||||
// should be done infrequently, typically once at startup.
|
||||
virtual void load() {};
|
||||
virtual void setDefault() {};
|
||||
|
||||
// The default implementation of addWebui() does nothing.
|
||||
// Derived classes may override it to do something.
|
||||
virtual void addWebui(JSONencoder *) {};
|
||||
|
||||
virtual err_t setStringValue(char* value) =0;
|
||||
err_t setStringValue(String s) { return setStringValue(s.c_str()); }
|
||||
virtual const char* getStringValue() =0;
|
||||
virtual const char* getCompatibleValue() { return getStringValue(); }
|
||||
};
|
||||
|
||||
class IntSetting : public Setting {
|
||||
private:
|
||||
int32_t _defaultValue;
|
||||
int32_t _currentValue;
|
||||
int32_t _storedValue;
|
||||
int32_t _minValue;
|
||||
int32_t _maxValue;
|
||||
|
||||
public:
|
||||
IntSetting(const char *description, type_t type, permissions_t permissions, const char* grblName, const char* name, int32_t defVal, int32_t minVal, int32_t maxVal, bool (*checker)(char *));
|
||||
|
||||
IntSetting(type_t type, permissions_t permissions, const char* grblName, const char* name, int32_t defVal, int32_t minVal, int32_t maxVal, bool (*checker)(char *) = NULL)
|
||||
: IntSetting(NULL, type, permissions, grblName, name, defVal, minVal, maxVal, checker)
|
||||
{ }
|
||||
|
||||
void load();
|
||||
void setDefault();
|
||||
void addWebui(JSONencoder *);
|
||||
err_t setStringValue(char* value);
|
||||
const char* getStringValue();
|
||||
|
||||
int32_t get() { return _currentValue; }
|
||||
};
|
||||
|
||||
class AxisMaskSetting : public Setting {
|
||||
private:
|
||||
int32_t _defaultValue;
|
||||
int32_t _currentValue;
|
||||
int32_t _storedValue;
|
||||
|
||||
public:
|
||||
AxisMaskSetting(const char *description, type_t type, permissions_t permissions, const char* grblName, const char* name, int32_t defVal, bool (*checker)(char *));
|
||||
|
||||
AxisMaskSetting(type_t type, permissions_t permissions, const char* grblName, const char* name, int32_t defVal, bool (*checker)(char *) = NULL)
|
||||
: AxisMaskSetting(NULL, type, permissions, grblName, name, defVal, checker)
|
||||
{ }
|
||||
|
||||
void load();
|
||||
void setDefault();
|
||||
void addWebui(JSONencoder *);
|
||||
err_t setStringValue(char* value);
|
||||
const char* getCompatibleValue();
|
||||
const char* getStringValue();
|
||||
|
||||
int32_t get() { return _currentValue; }
|
||||
};
|
||||
|
||||
class FloatSetting : public Setting {
|
||||
private:
|
||||
float _defaultValue;
|
||||
float _currentValue;
|
||||
float _storedValue;
|
||||
float _minValue;
|
||||
float _maxValue;
|
||||
public:
|
||||
FloatSetting(const char *description, type_t type, permissions_t permissions, const char* grblName, const char* name, float defVal, float minVal, float maxVal, bool (*checker)(char *));
|
||||
|
||||
FloatSetting(type_t type, permissions_t permissions, const char* grblName, const char* name, float defVal, float minVal, float maxVal, bool (*checker)(char *) = NULL)
|
||||
: FloatSetting(NULL, type, permissions, grblName, name, defVal, minVal, maxVal, checker)
|
||||
{ }
|
||||
|
||||
void load();
|
||||
void setDefault();
|
||||
// There are no Float settings in WebUI
|
||||
void addWebui(JSONencoder *) {}
|
||||
err_t setStringValue(char* value);
|
||||
const char* getStringValue();
|
||||
|
||||
float get() { return _currentValue; }
|
||||
};
|
||||
|
||||
#define MAX_SETTING_STRING 256
|
||||
class StringSetting : public Setting {
|
||||
private:
|
||||
String _defaultValue;
|
||||
String _currentValue;
|
||||
String _storedValue;
|
||||
int _minLength;
|
||||
int _maxLength;
|
||||
void _setStoredValue(const char *s);
|
||||
public:
|
||||
StringSetting(const char *description, type_t type, permissions_t permissions, const char* grblName, const char* name, const char* defVal, int min, int max, bool (*checker)(char *));
|
||||
|
||||
StringSetting(type_t type, permissions_t permissions, const char* grblName, const char* name, const char* defVal, bool (*checker)(char *) = NULL)
|
||||
: StringSetting(NULL, type, permissions, grblName, name, defVal, 0, 0, checker)
|
||||
{ };
|
||||
|
||||
void load();
|
||||
void setDefault();
|
||||
void addWebui(JSONencoder *);
|
||||
err_t setStringValue(char* value);
|
||||
const char* getStringValue();
|
||||
|
||||
const char* get() { return _currentValue.c_str(); }
|
||||
};
|
||||
struct cmp_str
|
||||
{
|
||||
bool operator()(char const *a, char const *b) const
|
||||
{
|
||||
return strcasecmp(a, b) < 0;
|
||||
}
|
||||
};
|
||||
typedef std::map<const char *, int8_t, cmp_str> enum_opt_t;
|
||||
|
||||
class EnumSetting : public Setting {
|
||||
private:
|
||||
int8_t _defaultValue;
|
||||
int8_t _storedValue;
|
||||
int8_t _currentValue;
|
||||
std::map<const char *, int8_t, cmp_str>* _options;
|
||||
public:
|
||||
EnumSetting(const char *description, type_t type, permissions_t permissions, const char* grblName, const char* name, int8_t defVal, enum_opt_t* opts);
|
||||
|
||||
EnumSetting(type_t type, permissions_t permissions, const char* grblName, const char* name, int8_t defVal, enum_opt_t* opts) :
|
||||
EnumSetting(NULL, type, permissions, grblName, name, defVal, opts)
|
||||
{ }
|
||||
|
||||
void load();
|
||||
void setDefault();
|
||||
void addWebui(JSONencoder *);
|
||||
err_t setStringValue(char* value);
|
||||
const char* getStringValue();
|
||||
|
||||
int8_t get() { return _currentValue; }
|
||||
};
|
||||
|
||||
class FlagSetting : public Setting {
|
||||
private:
|
||||
bool _defaultValue;
|
||||
int8_t _storedValue;
|
||||
bool _currentValue;
|
||||
public:
|
||||
FlagSetting(const char *description, type_t type, permissions_t permissions, const char* grblName, const char* name, bool defVal, bool (*checker)(char *));
|
||||
FlagSetting(type_t type, permissions_t permissions, const char* grblName, const char* name, bool defVal, bool (*checker)(char *) = NULL)
|
||||
: FlagSetting(NULL, type, permissions, grblName, name, defVal, checker)
|
||||
{ }
|
||||
|
||||
void load();
|
||||
void setDefault();
|
||||
// There are no Flag settings in WebUI
|
||||
// The booleans are expressed as Enums
|
||||
void addWebui(JSONencoder *) {}
|
||||
err_t setStringValue(char* value);
|
||||
const char* getCompatibleValue();
|
||||
const char* getStringValue();
|
||||
|
||||
bool get() { return _currentValue; }
|
||||
};
|
||||
|
||||
class IPaddrSetting : public Setting {
|
||||
private:
|
||||
uint32_t _defaultValue;
|
||||
uint32_t _currentValue;
|
||||
uint32_t _storedValue;
|
||||
|
||||
public:
|
||||
IPaddrSetting(const char *description, type_t type, permissions_t permissions, const char * grblName, const char* name, uint32_t defVal, bool (*checker)(char *));
|
||||
IPaddrSetting(const char *description, type_t type, permissions_t permissions, const char * grblName, const char* name, const char *defVal, bool (*checker)(char *));
|
||||
|
||||
void load();
|
||||
void setDefault();
|
||||
void addWebui(JSONencoder *);
|
||||
err_t setStringValue(char* value);
|
||||
const char* getStringValue();
|
||||
|
||||
uint32_t get() { return _currentValue; }
|
||||
};
|
||||
|
||||
class AxisSettings {
|
||||
public:
|
||||
const char* name;
|
||||
FloatSetting *steps_per_mm;
|
||||
FloatSetting *max_rate;
|
||||
FloatSetting *acceleration;
|
||||
FloatSetting *max_travel;
|
||||
FloatSetting *run_current;
|
||||
FloatSetting *hold_current;
|
||||
IntSetting *microsteps;
|
||||
IntSetting *stallguard;
|
||||
|
||||
AxisSettings(const char *axisName);
|
||||
};
|
||||
class WebCommand : public Command {
|
||||
private:
|
||||
err_t (*_action)(char *, auth_t);
|
||||
const char* password;
|
||||
public:
|
||||
WebCommand(const char* description, type_t type, permissions_t permissions, const char * grblName, const char* name, err_t (*action)(char *, auth_t)) :
|
||||
Command(description, type, permissions, grblName, name),
|
||||
_action(action)
|
||||
{}
|
||||
err_t action(char* value, auth_t auth_level, ESPResponseStream* response);
|
||||
};
|
||||
|
||||
enum : uint8_t {
|
||||
ANY_STATE = 0,
|
||||
IDLE_OR_ALARM = 0xff & ~STATE_ALARM,
|
||||
IDLE_OR_JOG = 0xff & ~STATE_JOG,
|
||||
NOT_CYCLE_OR_HOLD = STATE_CYCLE | STATE_HOLD,
|
||||
};
|
||||
|
||||
class GrblCommand : public Command {
|
||||
private:
|
||||
err_t (*_action)(const char *, auth_t, ESPResponseStream*);
|
||||
uint8_t _disallowedStates;
|
||||
public:
|
||||
GrblCommand(const char * grblName, const char* name, err_t (*action)(const char*, auth_t, ESPResponseStream*), uint8_t disallowedStates, permissions_t auth)
|
||||
: Command(NULL, GRBLCMD, auth, grblName, name)
|
||||
, _action(action)
|
||||
, _disallowedStates(disallowedStates)
|
||||
{}
|
||||
|
||||
GrblCommand(const char * grblName, const char* name, err_t (*action)(const char*, auth_t, ESPResponseStream*), uint8_t disallowedStates)
|
||||
: GrblCommand(grblName, name, action, disallowedStates, WG)
|
||||
{}
|
||||
err_t action(char* value, auth_t auth_level, ESPResponseStream* response);
|
||||
};
|
@@ -1,320 +0,0 @@
|
||||
#include "grbl.h"
|
||||
|
||||
bool motorSettingChanged = false;
|
||||
|
||||
StringSetting* startup_line_0;
|
||||
StringSetting* startup_line_1;
|
||||
StringSetting* build_info;
|
||||
|
||||
IntSetting* pulse_microseconds;
|
||||
IntSetting* stepper_idle_lock_time;
|
||||
|
||||
AxisMaskSetting* step_invert_mask;
|
||||
AxisMaskSetting* dir_invert_mask;
|
||||
// TODO Settings - need to call st_generate_step_invert_masks;
|
||||
AxisMaskSetting* homing_dir_mask;
|
||||
AxisMaskSetting* stallguard_debug_mask;
|
||||
|
||||
FlagSetting* step_enable_invert;
|
||||
FlagSetting* limit_invert;
|
||||
FlagSetting* probe_invert;
|
||||
FlagSetting* report_inches;
|
||||
FlagSetting* soft_limits;
|
||||
// TODO Settings - need to check for HOMING_ENABLE
|
||||
FlagSetting* hard_limits;
|
||||
// TODO Settings - need to call limits_init;
|
||||
FlagSetting* homing_enable;
|
||||
// TODO Settings - also need to clear, but not set, soft_limits
|
||||
FlagSetting* laser_mode;
|
||||
// TODO Settings - also need to call my_spindle->init;
|
||||
|
||||
IntSetting* status_mask;
|
||||
FloatSetting* junction_deviation;
|
||||
FloatSetting* arc_tolerance;
|
||||
|
||||
FloatSetting* homing_feed_rate;
|
||||
FloatSetting* homing_seek_rate;
|
||||
FloatSetting* homing_debounce;
|
||||
FloatSetting* homing_pulloff;
|
||||
FloatSetting* spindle_pwm_freq;
|
||||
FloatSetting* rpm_max;
|
||||
FloatSetting* rpm_min;
|
||||
FloatSetting* spindle_delay_spinup;
|
||||
FloatSetting* spindle_delay_spindown;
|
||||
|
||||
FloatSetting* spindle_pwm_off_value;
|
||||
FloatSetting* spindle_pwm_min_value;
|
||||
FloatSetting* spindle_pwm_max_value;
|
||||
IntSetting* spindle_pwm_bit_precision;
|
||||
|
||||
EnumSetting* spindle_type;
|
||||
|
||||
enum_opt_t spindleTypes = {
|
||||
{ "NONE", SPINDLE_TYPE_NONE, },
|
||||
{ "PWM", SPINDLE_TYPE_PWM, },
|
||||
{ "RELAY", SPINDLE_TYPE_RELAY, },
|
||||
{ "LASER", SPINDLE_TYPE_LASER, },
|
||||
{ "DAC", SPINDLE_TYPE_DAC, },
|
||||
{ "HUANYANG", SPINDLE_TYPE_HUANYANG, },
|
||||
{ "BESC", SPINDLE_TYPE_BESC, },
|
||||
{ "10V", SPINDLE_TYPE_10V, },
|
||||
};
|
||||
|
||||
AxisSettings* x_axis_settings;
|
||||
AxisSettings* y_axis_settings;
|
||||
AxisSettings* z_axis_settings;
|
||||
AxisSettings* a_axis_settings;
|
||||
AxisSettings* b_axis_settings;
|
||||
AxisSettings* c_axis_settings;
|
||||
|
||||
AxisSettings* axis_settings[MAX_N_AXIS];
|
||||
|
||||
typedef struct {
|
||||
const char* name;
|
||||
float steps_per_mm;
|
||||
float max_rate;
|
||||
float acceleration;
|
||||
float max_travel;
|
||||
float run_current;
|
||||
float hold_current;
|
||||
uint16_t microsteps;
|
||||
uint16_t stallguard;
|
||||
} axis_defaults_t;
|
||||
axis_defaults_t axis_defaults[] = {
|
||||
{
|
||||
"X",
|
||||
DEFAULT_X_STEPS_PER_MM,
|
||||
DEFAULT_X_MAX_RATE,
|
||||
DEFAULT_X_ACCELERATION,
|
||||
DEFAULT_X_MAX_TRAVEL,
|
||||
DEFAULT_X_CURRENT,
|
||||
DEFAULT_X_HOLD_CURRENT,
|
||||
DEFAULT_X_MICROSTEPS,
|
||||
DEFAULT_X_STALLGUARD
|
||||
},
|
||||
{
|
||||
"Y",
|
||||
DEFAULT_Y_STEPS_PER_MM,
|
||||
DEFAULT_Y_MAX_RATE,
|
||||
DEFAULT_Y_ACCELERATION,
|
||||
DEFAULT_Y_MAX_TRAVEL,
|
||||
DEFAULT_Y_CURRENT,
|
||||
DEFAULT_Y_HOLD_CURRENT,
|
||||
DEFAULT_Y_MICROSTEPS,
|
||||
DEFAULT_Y_STALLGUARD
|
||||
},
|
||||
{
|
||||
"Z",
|
||||
DEFAULT_Z_STEPS_PER_MM,
|
||||
DEFAULT_Z_MAX_RATE,
|
||||
DEFAULT_Z_ACCELERATION,
|
||||
DEFAULT_Z_MAX_TRAVEL,
|
||||
DEFAULT_Z_CURRENT,
|
||||
DEFAULT_Z_HOLD_CURRENT,
|
||||
DEFAULT_Z_MICROSTEPS,
|
||||
DEFAULT_Z_STALLGUARD
|
||||
},
|
||||
{
|
||||
"A",
|
||||
DEFAULT_A_STEPS_PER_MM,
|
||||
DEFAULT_A_MAX_RATE,
|
||||
DEFAULT_A_ACCELERATION,
|
||||
DEFAULT_A_MAX_TRAVEL,
|
||||
DEFAULT_A_CURRENT,
|
||||
DEFAULT_A_HOLD_CURRENT,
|
||||
DEFAULT_A_MICROSTEPS,
|
||||
DEFAULT_A_STALLGUARD
|
||||
},
|
||||
{
|
||||
"B",
|
||||
DEFAULT_B_STEPS_PER_MM,
|
||||
DEFAULT_B_MAX_RATE,
|
||||
DEFAULT_B_ACCELERATION,
|
||||
DEFAULT_B_MAX_TRAVEL,
|
||||
DEFAULT_B_CURRENT,
|
||||
DEFAULT_B_HOLD_CURRENT,
|
||||
DEFAULT_B_MICROSTEPS,
|
||||
DEFAULT_B_STALLGUARD
|
||||
},
|
||||
{
|
||||
"C",
|
||||
DEFAULT_C_STEPS_PER_MM,
|
||||
DEFAULT_C_MAX_RATE,
|
||||
DEFAULT_C_ACCELERATION,
|
||||
DEFAULT_C_MAX_TRAVEL,
|
||||
DEFAULT_C_CURRENT,
|
||||
DEFAULT_C_HOLD_CURRENT,
|
||||
DEFAULT_C_MICROSTEPS,
|
||||
DEFAULT_C_STALLGUARD
|
||||
}
|
||||
};
|
||||
|
||||
// Construct e.g. X_MAX_RATE from axisName "X" and tail "_MAX_RATE"
|
||||
// in dynamically allocated memory that will not be freed.
|
||||
|
||||
static const char *makename(const char *axisName, const char *tail) {
|
||||
char* retval = (char *)malloc(strlen(axisName) + strlen(tail) + 2);
|
||||
|
||||
strcpy(retval, axisName);
|
||||
strcat(retval, "/");
|
||||
return strcat(retval, tail);
|
||||
}
|
||||
|
||||
static bool checkStartupLine(char* value) {
|
||||
if (sys.state != STATE_IDLE)
|
||||
return STATUS_IDLE_ERROR;
|
||||
return gc_execute_line(value, CLIENT_SERIAL) == 0;
|
||||
}
|
||||
|
||||
static bool checkStallguard(char* value) {
|
||||
motorSettingChanged = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool checkMicrosteps(char* value) {
|
||||
motorSettingChanged = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool checkRunCurrent(char* value) {
|
||||
motorSettingChanged = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool checkHoldcurrent(char* value) {
|
||||
motorSettingChanged = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool checkStallguardDebugMask(char* val) {
|
||||
motorSettingChanged = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Generates a string like "122" from axisNum 2 and base 120
|
||||
static const char* makeGrblName(int axisNum, int base) {
|
||||
// To omit A,B,C axes:
|
||||
// if (axisNum > 2) return NULL;
|
||||
char buf[4];
|
||||
snprintf(buf, 4, "%d", axisNum + base);
|
||||
char* retval = (char*)malloc(strlen(buf));
|
||||
return strcpy(retval, buf);
|
||||
}
|
||||
|
||||
void make_settings() {
|
||||
Setting::init();
|
||||
|
||||
// Create the axis settings in the order that people are
|
||||
// accustomed to seeing.
|
||||
int axis;
|
||||
axis_defaults_t* def;
|
||||
for (axis = 0; axis < N_AXIS; axis++) {
|
||||
def = &axis_defaults[axis];
|
||||
axis_settings[axis] = new AxisSettings(def->name);
|
||||
}
|
||||
x_axis_settings = axis_settings[X_AXIS];
|
||||
y_axis_settings = axis_settings[Y_AXIS];
|
||||
z_axis_settings = axis_settings[Z_AXIS];
|
||||
a_axis_settings = axis_settings[A_AXIS];
|
||||
b_axis_settings = axis_settings[B_AXIS];
|
||||
c_axis_settings = axis_settings[C_AXIS];
|
||||
for (axis = N_AXIS - 1; axis >= 0; axis--) {
|
||||
def = &axis_defaults[axis];
|
||||
auto setting = new IntSetting(EXTENDED, WG, makeGrblName(axis, 170), makename(def->name, "StallGuard"), def->stallguard, -64, 63, checkStallguard);
|
||||
setting->setAxis(axis);
|
||||
axis_settings[axis]->stallguard = setting;
|
||||
}
|
||||
for (axis = N_AXIS - 1; axis >= 0; axis--) {
|
||||
def = &axis_defaults[axis];
|
||||
auto setting = new IntSetting(EXTENDED, WG, makeGrblName(axis, 160), makename(def->name, "Microsteps"), def->microsteps, 0, 256, checkMicrosteps);
|
||||
setting->setAxis(axis);
|
||||
axis_settings[axis]->microsteps = setting;
|
||||
}
|
||||
for (axis = N_AXIS - 1; axis >= 0; axis--) {
|
||||
def = &axis_defaults[axis];
|
||||
auto setting = new FloatSetting(EXTENDED, WG, makeGrblName(axis, 150), makename(def->name, "Current/Hold"), def->hold_current, 0.05, 20.0, checkHoldcurrent); // Amps
|
||||
setting->setAxis(axis);
|
||||
axis_settings[axis]->hold_current = setting;
|
||||
}
|
||||
for (axis = N_AXIS - 1; axis >= 0; axis--) {
|
||||
def = &axis_defaults[axis];
|
||||
auto setting = new FloatSetting(EXTENDED, WG, makeGrblName(axis, 140), makename(def->name, "Current/Run"), def->run_current, 0.0, 20.0, checkRunCurrent); // Amps
|
||||
setting->setAxis(axis);
|
||||
axis_settings[axis]->run_current = setting;
|
||||
}
|
||||
for (axis = N_AXIS - 1; axis >= 0; axis--) {
|
||||
def = &axis_defaults[axis];
|
||||
auto setting = new FloatSetting(GRBL, WG, makeGrblName(axis, 130), makename(def->name, "MaxTravel"), def->max_travel, 1.0, 100000.0);
|
||||
setting->setAxis(axis);
|
||||
axis_settings[axis]->max_travel = setting;
|
||||
}
|
||||
for (axis = N_AXIS - 1; axis >= 0; axis--) {
|
||||
def = &axis_defaults[axis];
|
||||
auto setting = new FloatSetting(GRBL, WG, makeGrblName(axis, 120), makename(def->name, "Acceleration"), def->acceleration, 1.0, 100000.0);
|
||||
setting->setAxis(axis);
|
||||
axis_settings[axis]->acceleration = setting;
|
||||
}
|
||||
for (axis = N_AXIS - 1; axis >= 0; axis--) {
|
||||
def = &axis_defaults[axis];
|
||||
auto setting = new FloatSetting(GRBL, WG, makeGrblName(axis, 110), makename(def->name, "MaxRate"), def->max_rate, 1.0, 100000.0);
|
||||
setting->setAxis(axis);
|
||||
axis_settings[axis]->max_rate = setting;
|
||||
}
|
||||
for (axis = N_AXIS - 1; axis >= 0; axis--) {
|
||||
def = &axis_defaults[axis];
|
||||
auto setting = new FloatSetting(GRBL, WG, makeGrblName(axis, 100), makename(def->name, "StepsPerMm"), def->steps_per_mm, 1.0, 100000.0);
|
||||
setting->setAxis(axis);
|
||||
axis_settings[axis]->steps_per_mm = setting;
|
||||
}
|
||||
|
||||
// Spindle Settings
|
||||
spindle_pwm_max_value = new FloatSetting(EXTENDED, WG, "36", "Spindle/PWM/Max", DEFAULT_SPINDLE_MAX_VALUE, 0.0, 100.0);
|
||||
spindle_pwm_min_value = new FloatSetting(EXTENDED, WG, "35", "Spindle/PWM/Min", DEFAULT_SPINDLE_MIN_VALUE, 0.0, 100.0);
|
||||
spindle_pwm_off_value = new FloatSetting(EXTENDED, WG, "34", "Spindle/PWM/Off", DEFAULT_SPINDLE_OFF_VALUE, 0.0, 100.0); // these are percentages
|
||||
// IntSetting spindle_pwm_bit_precision(EXTENDED, WG, "Spindle/PWM/Precision", DEFAULT_SPINDLE_BIT_PRECISION, 1, 16);
|
||||
spindle_pwm_freq = new FloatSetting(EXTENDED, WG, "33", "Spindle/PWM/Frequency", DEFAULT_SPINDLE_FREQ, 0, 100000);
|
||||
spindle_delay_spinup = new FloatSetting(EXTENDED, WG, NULL, "Spindle/Delay/SpinUp", DEFAULT_SPINDLE_DELAY_SPINUP, 0, 30);
|
||||
spindle_delay_spindown = new FloatSetting(EXTENDED, WG, NULL, "Spindle/Delay/SpinDown", DEFAULT_SPINDLE_DELAY_SPINUP, 0, 30);
|
||||
|
||||
// GRBL Non-numbered settings
|
||||
startup_line_0 = new StringSetting(GRBL, WG, "N0", "GCode/Line0", "", checkStartupLine);
|
||||
startup_line_1 = new StringSetting(GRBL, WG, "N1", "GCode/Line1", "", checkStartupLine);
|
||||
|
||||
// GRBL Numbered Settings
|
||||
laser_mode = new FlagSetting(GRBL, WG, "32", "GCode/LaserMode", DEFAULT_LASER_MODE);
|
||||
// TODO Settings - also need to call my_spindle->init();
|
||||
rpm_min = new FloatSetting(GRBL, WG, "31", "GCode/MinS", DEFAULT_SPINDLE_RPM_MIN, 0, 100000);
|
||||
rpm_max = new FloatSetting(GRBL, WG, "30", "GCode/MaxS", DEFAULT_SPINDLE_RPM_MAX, 0, 100000);
|
||||
|
||||
|
||||
homing_pulloff = new FloatSetting(GRBL, WG, "27", "Homing/Pulloff", DEFAULT_HOMING_PULLOFF, 0, 1000);
|
||||
homing_debounce = new FloatSetting(GRBL, WG, "26", "Homing/Debounce", DEFAULT_HOMING_DEBOUNCE_DELAY, 0, 10000);
|
||||
homing_seek_rate = new FloatSetting(GRBL, WG, "25", "Homing/Seek", DEFAULT_HOMING_SEEK_RATE, 0, 10000);
|
||||
homing_feed_rate = new FloatSetting(GRBL, WG, "24", "Homing/Feed", DEFAULT_HOMING_FEED_RATE, 0, 10000);
|
||||
|
||||
// TODO Settings - need to call st_generate_step_invert_masks()
|
||||
homing_dir_mask = new AxisMaskSetting(GRBL, WG, "23", "Homing/DirInvert", DEFAULT_HOMING_DIR_MASK);
|
||||
|
||||
// TODO Settings - need to call limits_init();
|
||||
homing_enable = new FlagSetting(GRBL, WG, "22", "Homing/Enable", DEFAULT_HOMING_ENABLE);
|
||||
// TODO Settings - need to check for HOMING_ENABLE
|
||||
hard_limits = new FlagSetting(GRBL, WG, "21", "Limits/Hard", DEFAULT_HARD_LIMIT_ENABLE);
|
||||
soft_limits = new FlagSetting(GRBL, WG, "20", "Limits/Soft", DEFAULT_SOFT_LIMIT_ENABLE, NULL);
|
||||
|
||||
report_inches = new FlagSetting(GRBL, WG, "13", "Report/Inches", DEFAULT_REPORT_INCHES);
|
||||
// TODO Settings - also need to clear, but not set, soft_limits
|
||||
arc_tolerance = new FloatSetting(GRBL, WG, "12", "GCode/ArcTolerance", DEFAULT_ARC_TOLERANCE, 0, 1);
|
||||
junction_deviation = new FloatSetting(GRBL, WG, "11", "GCode/JunctionDeviation", DEFAULT_JUNCTION_DEVIATION, 0, 10);
|
||||
status_mask = new IntSetting(GRBL, WG, "10", "Report/Status", DEFAULT_STATUS_REPORT_MASK, 0, 2);
|
||||
|
||||
probe_invert = new FlagSetting(GRBL, WG, "6", "Probe/Invert", DEFAULT_INVERT_PROBE_PIN);
|
||||
limit_invert = new FlagSetting(GRBL, WG, "5", "Limits/Invert", DEFAULT_INVERT_LIMIT_PINS);
|
||||
step_enable_invert = new FlagSetting(GRBL, WG, "4", "Stepper/EnableInvert", DEFAULT_INVERT_ST_ENABLE);
|
||||
dir_invert_mask = new AxisMaskSetting(GRBL, WG, "3", "Stepper/DirInvert", DEFAULT_DIRECTION_INVERT_MASK);
|
||||
step_invert_mask = new AxisMaskSetting(GRBL, WG, "2", "Stepper/StepInvert", DEFAULT_STEPPING_INVERT_MASK);
|
||||
stepper_idle_lock_time = new IntSetting(GRBL, WG, "1", "Stepper/IdleTime", DEFAULT_STEPPER_IDLE_LOCK_TIME, 0, 255);
|
||||
pulse_microseconds = new IntSetting(GRBL, WG, "0", "Stepper/Pulse", DEFAULT_STEP_PULSE_MICROSECONDS, 3, 1000);
|
||||
spindle_type = new EnumSetting(NULL, EXTENDED, WG, NULL, "Spindle/Type", SPINDLE_TYPE, &spindleTypes);
|
||||
stallguard_debug_mask = new AxisMaskSetting(EXTENDED, WG, NULL, "Report/StallGuard", 0, checkStallguardDebugMask);
|
||||
}
|
@@ -1,172 +0,0 @@
|
||||
/*
|
||||
10vSpindle.cpp
|
||||
|
||||
|
||||
This is basically a PWM spindle with some changes, so a separate forward and
|
||||
reverse signal can be sent.
|
||||
|
||||
The direction pins will act as enables for the 2 directions. There is usually
|
||||
a min RPM with VFDs, that speed will remain even if speed is 0. You
|
||||
must turn off both direction pins when enable is off.
|
||||
|
||||
|
||||
Part of Grbl_ESP32
|
||||
2020 - Bart Dring
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
|
||||
*/
|
||||
#include "SpindleClass.h"
|
||||
|
||||
|
||||
|
||||
void _10vSpindle :: init() {
|
||||
|
||||
get_pins_and_settings(); // these gets the standard PWM settings, but many need to be changed for BESC
|
||||
|
||||
// a couple more pins not inherited from PWM Spindle
|
||||
#ifdef SPINDLE_FORWARD_PIN
|
||||
_forward_pin = SPINDLE_FORWARD_PIN;
|
||||
#else
|
||||
_forward_pin = UNDEFINED_PIN;
|
||||
#endif
|
||||
|
||||
#ifdef SPINDLE_REVERSE_PIN
|
||||
_reverse_pin = SPINDLE_REVERSE_PIN;
|
||||
#else
|
||||
_reverse_pin = UNDEFINED_PIN;
|
||||
#endif
|
||||
|
||||
|
||||
if (_output_pin == UNDEFINED_PIN) {
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Warning: BESC output pin not defined");
|
||||
return; // We cannot continue without the output pin
|
||||
}
|
||||
|
||||
ledcSetup(_spindle_pwm_chan_num, (double)_pwm_freq, _pwm_precision); // setup the channel
|
||||
ledcAttachPin(_output_pin, _spindle_pwm_chan_num); // attach the PWM to the pin
|
||||
|
||||
pinMode(_enable_pin, OUTPUT);
|
||||
pinMode(_direction_pin, OUTPUT);
|
||||
pinMode(_forward_pin, OUTPUT);
|
||||
pinMode(_reverse_pin, OUTPUT);
|
||||
|
||||
set_rpm(0);
|
||||
|
||||
config_message();
|
||||
|
||||
is_reversable = true; // these VFDs are always reversable
|
||||
use_delays = true;
|
||||
|
||||
}
|
||||
|
||||
// prints the startup message of the spindle config
|
||||
void _10vSpindle :: config_message() {
|
||||
grbl_msg_sendf(CLIENT_SERIAL,
|
||||
MSG_LEVEL_INFO,
|
||||
"0-10V spindle Out:%s Enbl:%s, Dir:%s, Fwd:%s, Rev:%s, Freq:%dHz Res:%dbits",
|
||||
pinName(_output_pin).c_str(),
|
||||
pinName(_enable_pin).c_str(),
|
||||
pinName(_direction_pin).c_str(),
|
||||
pinName(_forward_pin).c_str(),
|
||||
pinName(_reverse_pin).c_str(),
|
||||
_pwm_freq,
|
||||
_pwm_precision);
|
||||
}
|
||||
|
||||
uint32_t _10vSpindle::set_rpm(uint32_t rpm) {
|
||||
uint32_t pwm_value;
|
||||
|
||||
if (_output_pin == UNDEFINED_PIN)
|
||||
return rpm;
|
||||
|
||||
// apply speed overrides
|
||||
rpm = rpm * sys.spindle_speed_ovr / 100; // Scale by spindle speed override value (percent)
|
||||
|
||||
// apply limits limits
|
||||
if ((_min_rpm >= _max_rpm) || (rpm >= _max_rpm))
|
||||
rpm = _max_rpm;
|
||||
else if (rpm != 0 && rpm <= _min_rpm)
|
||||
rpm = _min_rpm;
|
||||
sys.spindle_speed = rpm;
|
||||
|
||||
// determine the pwm value
|
||||
if (rpm == 0)
|
||||
pwm_value = _pwm_off_value;
|
||||
else
|
||||
pwm_value = map_uint32_t(rpm, _min_rpm, _max_rpm, _pwm_min_value, _pwm_max_value);
|
||||
|
||||
set_output(pwm_value);
|
||||
return rpm;
|
||||
}
|
||||
/*
|
||||
void _10vSpindle::set_state(uint8_t state, uint32_t rpm) {
|
||||
if (sys.abort)
|
||||
return; // Block during abort.
|
||||
|
||||
if (state == SPINDLE_DISABLE) { // Halt or set spindle direction and rpm.
|
||||
sys.spindle_speed = 0;
|
||||
stop();
|
||||
} else {
|
||||
set_spindle_dir_pin(state == SPINDLE_ENABLE_CW);
|
||||
set_rpm(rpm);
|
||||
}
|
||||
|
||||
set_enable_pin(state != SPINDLE_DISABLE);
|
||||
|
||||
sys.report_ovr_counter = 0; // Set to report change immediately
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
|
||||
uint8_t _10vSpindle::get_state() {
|
||||
if (_current_pwm_duty == 0 || _output_pin == UNDEFINED_PIN)
|
||||
return (SPINDLE_STATE_DISABLE);
|
||||
if (_direction_pin != UNDEFINED_PIN)
|
||||
return digitalRead(_direction_pin) ? SPINDLE_STATE_CW : SPINDLE_STATE_CCW;
|
||||
return (SPINDLE_STATE_CW);
|
||||
}
|
||||
|
||||
void _10vSpindle::stop() {
|
||||
// inverts are delt with in methods
|
||||
set_enable_pin(false);
|
||||
set_output(_pwm_off_value);
|
||||
}
|
||||
|
||||
void _10vSpindle::set_enable_pin(bool enable) {
|
||||
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "_10vSpindle::set_enable_pin");
|
||||
if (_off_with_zero_speed && sys.spindle_speed == 0)
|
||||
enable = false;
|
||||
|
||||
#ifdef INVERT_SPINDLE_ENABLE_PIN
|
||||
enable = !enable;
|
||||
#endif
|
||||
digitalWrite(_enable_pin, enable);
|
||||
|
||||
// turn off anything that acts like an enable
|
||||
if (!enable) {
|
||||
digitalWrite(_direction_pin, enable);
|
||||
digitalWrite(_forward_pin, enable);
|
||||
digitalWrite(_reverse_pin, enable);
|
||||
}
|
||||
}
|
||||
|
||||
void _10vSpindle::set_spindle_dir_pin(bool Clockwise) {
|
||||
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "_10vSpindle::set_spindle_dir_pin");
|
||||
digitalWrite(_direction_pin, Clockwise);
|
||||
digitalWrite(_forward_pin, Clockwise);
|
||||
digitalWrite(_reverse_pin, ! Clockwise);
|
||||
}
|
||||
|
@@ -1,122 +0,0 @@
|
||||
/*
|
||||
BESCSpindle.cpp
|
||||
|
||||
This a special type of PWM spindle for RC type Brushless DC Speed
|
||||
controllers. They use a short pulse for off and a longer pulse for
|
||||
full on. The pulse is always a small portion of the full cycle.
|
||||
Some BESCs have a special turn on procedure. This may be a one time
|
||||
procedure or must be done every time. The user must do that via gcode.
|
||||
|
||||
Part of Grbl_ESP32
|
||||
2020 - Bart Dring
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Important ESC Settings
|
||||
50 Hz this is a typical frequency for an ESC
|
||||
Some ESCs can handle higher frequencies, but there is no advantage to changing it.
|
||||
|
||||
Determine the typical min and max pulse length of your ESC
|
||||
BESC_MIN_PULSE_SECS is typically 1ms (0.001 sec) or less
|
||||
BESC_MAX_PULSE_SECS is typically 2ms (0.002 sec) or more
|
||||
|
||||
*/
|
||||
#include "SpindleClass.h"
|
||||
|
||||
|
||||
// don't change these
|
||||
#define BESC_PWM_FREQ 50.0f // Hz
|
||||
#define BESC_PWM_BIT_PRECISION 16 // bits
|
||||
#define BESC_PULSE_PERIOD (1.0 / BESC_PWM_FREQ)
|
||||
|
||||
// Ok to tweak. These are the pulse lengths in seconds
|
||||
// #define them in your machine definition file if you want different values
|
||||
#ifndef BESC_MIN_PULSE_SECS
|
||||
#define BESC_MIN_PULSE_SECS 0.0009f // in seconds
|
||||
#endif
|
||||
|
||||
#ifndef BESC_MAX_PULSE_SECS
|
||||
#define BESC_MAX_PULSE_SECS 0.0022f // in seconds
|
||||
#endif
|
||||
|
||||
//calculations...don't change
|
||||
#define BESC_MIN_PULSE_CNT (uint16_t)(BESC_MIN_PULSE_SECS / BESC_PULSE_PERIOD * 65535.0)
|
||||
#define BESC_MAX_PULSE_CNT (uint16_t)(BESC_MAX_PULSE_SECS / BESC_PULSE_PERIOD * 65535.0)
|
||||
|
||||
void BESCSpindle :: init() {
|
||||
|
||||
get_pins_and_settings(); // these gets the standard PWM settings, but many need to be changed for BESC
|
||||
|
||||
if (_output_pin == UNDEFINED_PIN) {
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Warning: BESC output pin not defined");
|
||||
return; // We cannot continue without the output pin
|
||||
}
|
||||
|
||||
// override some settings to what is required for a BESC
|
||||
_pwm_freq = (uint32_t)BESC_PWM_FREQ;
|
||||
_pwm_precision = 16;
|
||||
|
||||
// override these settings
|
||||
_pwm_off_value = BESC_MIN_PULSE_CNT;
|
||||
_pwm_min_value = _pwm_off_value;
|
||||
_pwm_max_value = BESC_MAX_PULSE_CNT;
|
||||
|
||||
ledcSetup(_spindle_pwm_chan_num, (double)_pwm_freq, _pwm_precision); // setup the channel
|
||||
ledcAttachPin(_output_pin, _spindle_pwm_chan_num); // attach the PWM to the pin
|
||||
|
||||
pinMode(_enable_pin, OUTPUT);
|
||||
|
||||
set_rpm(0);
|
||||
|
||||
use_delays = true;
|
||||
|
||||
config_message();
|
||||
}
|
||||
|
||||
// prints the startup message of the spindle config
|
||||
void BESCSpindle :: config_message() {
|
||||
grbl_msg_sendf(CLIENT_SERIAL,
|
||||
MSG_LEVEL_INFO,
|
||||
"BESC spindle on Pin:%s Min:%0.2fms Max:%0.2fms Freq:%dHz Res:%dbits",
|
||||
pinName(_output_pin).c_str(),
|
||||
BESC_MIN_PULSE_SECS * 1000.0, // convert to milliseconds
|
||||
BESC_MAX_PULSE_SECS * 1000.0, // convert to milliseconds
|
||||
_pwm_freq,
|
||||
_pwm_precision);
|
||||
}
|
||||
|
||||
uint32_t BESCSpindle::set_rpm(uint32_t rpm) {
|
||||
uint32_t pwm_value;
|
||||
|
||||
if (_output_pin == UNDEFINED_PIN)
|
||||
return rpm;
|
||||
|
||||
// apply speed overrides
|
||||
rpm = rpm * sys.spindle_speed_ovr / 100; // Scale by spindle speed override value (percent)
|
||||
|
||||
// apply limits limits
|
||||
if ((_min_rpm >= _max_rpm) || (rpm >= _max_rpm))
|
||||
rpm = _max_rpm;
|
||||
else if (rpm != 0 && rpm <= _min_rpm)
|
||||
rpm = _min_rpm;
|
||||
sys.spindle_speed = rpm;
|
||||
|
||||
// determine the pwm value
|
||||
if (rpm == 0) {
|
||||
pwm_value = _pwm_off_value;
|
||||
} else {
|
||||
pwm_value = map_uint32_t(rpm, _min_rpm, _max_rpm, _pwm_min_value, _pwm_max_value);
|
||||
}
|
||||
|
||||
set_output(pwm_value);
|
||||
return rpm;
|
||||
}
|
@@ -1,104 +0,0 @@
|
||||
/*
|
||||
DacSpindle.cpp
|
||||
|
||||
This uses the Analog DAC in the ESP32 to generate a voltage
|
||||
proportional to the GCode S value desired. Some spindle uses
|
||||
a 0-5V or 0-10V value to control the spindle. You would use
|
||||
an Op Amp type circuit to get from the 0.3.3V of the ESP32 to that voltage.
|
||||
|
||||
Part of Grbl_ESP32
|
||||
2020 - Bart Dring
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
#include "SpindleClass.h"
|
||||
|
||||
// ======================================== DacSpindle ======================================
|
||||
void DacSpindle :: init() {
|
||||
get_pins_and_settings();
|
||||
|
||||
if (_output_pin == UNDEFINED_PIN)
|
||||
return;
|
||||
|
||||
_min_rpm = rpm_min->get();
|
||||
_max_rpm = rpm_max->get();
|
||||
_pwm_min_value = 0; // not actually PWM...DAC counts
|
||||
_pwm_max_value = 255; // not actually PWM...DAC counts
|
||||
_gpio_ok = true;
|
||||
|
||||
if (_output_pin != GPIO_NUM_25 && _output_pin != GPIO_NUM_26) { // DAC can only be used on these pins
|
||||
_gpio_ok = false;
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "DAC spindle pin invalid GPIO_NUM_%d (pin 25 or 26 only)", _output_pin);
|
||||
return;
|
||||
}
|
||||
|
||||
pinMode(_enable_pin, OUTPUT);
|
||||
pinMode(_direction_pin, OUTPUT);
|
||||
|
||||
is_reversable = (_direction_pin != UNDEFINED_PIN);
|
||||
use_delays = true;
|
||||
|
||||
config_message();
|
||||
}
|
||||
|
||||
void DacSpindle :: config_message() {
|
||||
grbl_msg_sendf(CLIENT_SERIAL,
|
||||
MSG_LEVEL_INFO,
|
||||
"DAC spindle Output:%s, Enbl:%s, Dir:%s, Res:8bits",
|
||||
pinName(_output_pin).c_str(),
|
||||
pinName(_enable_pin).c_str(),
|
||||
pinName(_direction_pin).c_str());
|
||||
}
|
||||
|
||||
uint32_t DacSpindle::set_rpm(uint32_t rpm) {
|
||||
if (_output_pin == UNDEFINED_PIN)
|
||||
return rpm;
|
||||
|
||||
uint32_t pwm_value;
|
||||
|
||||
// apply overrides and limits
|
||||
rpm = rpm * sys.spindle_speed_ovr / 100; // Scale by spindle speed override value (percent)
|
||||
|
||||
// Calculate PWM register value based on rpm max/min settings and programmed rpm.
|
||||
if ((_min_rpm >= _max_rpm) || (rpm >= _max_rpm)) {
|
||||
// No PWM range possible. Set simple on/off spindle control pin state.
|
||||
sys.spindle_speed = _max_rpm;
|
||||
pwm_value = _pwm_max_value;
|
||||
} else if (rpm <= _min_rpm) {
|
||||
if (rpm == 0) { // S0 disables spindle
|
||||
sys.spindle_speed = 0;
|
||||
pwm_value = 0;
|
||||
} else { // Set minimum PWM output
|
||||
rpm = _min_rpm;
|
||||
sys.spindle_speed = rpm;
|
||||
pwm_value = 0;
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Spindle RPM less than min RPM:%5.2f %d", rpm, pwm_value);
|
||||
}
|
||||
} else {
|
||||
// Compute intermediate PWM value with linear spindle speed model.
|
||||
// NOTE: A nonlinear model could be installed here, if required, but keep it VERY light-weight.
|
||||
sys.spindle_speed = rpm;
|
||||
|
||||
pwm_value = map_uint32_t(rpm, _min_rpm, _max_rpm, _pwm_min_value, _pwm_max_value);
|
||||
}
|
||||
|
||||
set_output(pwm_value);
|
||||
|
||||
return rpm;
|
||||
}
|
||||
|
||||
void DacSpindle :: set_output(uint32_t duty) {
|
||||
if (_gpio_ok) {
|
||||
dacWrite(_output_pin, (uint8_t)duty);
|
||||
}
|
||||
}
|
@@ -1,483 +0,0 @@
|
||||
/*
|
||||
HuanyangSpindle.cpp
|
||||
|
||||
This is for a Huanyang VFD based spindle via RS485 Modbus.
|
||||
Sorry for the lengthy comments, but finding the details on this
|
||||
VFD was a PITA. I am just trying to help the next person.
|
||||
|
||||
Part of Grbl_ESP32
|
||||
2020 - Bart Dring
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
WARNING!!!!
|
||||
VFDs are very dangerous. They have high voltages and are very powerful
|
||||
Remove power before changing bits.
|
||||
|
||||
==============================================================================
|
||||
|
||||
If a user changes state or RPM level, the command to do that is sent. If
|
||||
the command is not responded to a message is sent to serial that there was
|
||||
a timeout. If the Grbl is in a critical state, an alarm will be generated and
|
||||
the machine stopped.
|
||||
|
||||
If there are no commands to execute, various status items will be polled. If there
|
||||
is no response, it will behave as described above. It will stop any running jobs with
|
||||
an alarm.
|
||||
|
||||
===============================================================================
|
||||
|
||||
Protocol Details
|
||||
|
||||
VFD frequencies are in Hz. Multiply by 60 for RPM
|
||||
|
||||
before using spindle, VFD must be setup for RS485 and match your spindle
|
||||
PD001 2 RS485 Control of run commands
|
||||
PD002 2 RS485 Control of operating frequency
|
||||
PD005 400 Maximum frequency Hz (Typical for spindles)
|
||||
PD011 120 Min Speed (Recommend Aircooled=120 Water=100)
|
||||
PD014 10 Acceleration time (Test to optimize)
|
||||
PD015 10 Deceleration time (Test to optimize)
|
||||
PD023 1 Reverse run enabled
|
||||
PD142 3.7 Max current Amps (0.8kw=3.7 1.5kw=7.0, 2.2kw=??)
|
||||
PD143 2 Poles most are 2 (I think this is only used for RPM calc from Hz)
|
||||
PD163 1 RS485 Address: 1 (Typical. OK to change...see below)
|
||||
PD164 1 RS485 Baud rate: 9600 (Typical. OK to change...see below)
|
||||
PD165 3 RS485 Mode: RTU, 8N1
|
||||
|
||||
The official documentation of the RS485 is horrible. I had to piece it together from
|
||||
a lot of different sources
|
||||
|
||||
Manuals: https://github.com/RobertOlechowski/Huanyang_VFD/tree/master/Documentations/pdf
|
||||
Reference: https://github.com/Smoothieware/Smoothieware/blob/edge/src/modules/tools/spindle/HuanyangSpindleControl.cpp
|
||||
Refernece: https://gist.github.com/Bouni/803492ed0aab3f944066
|
||||
VFD settings: https://www.hobbytronics.co.za/Content/external/1159/Spindle_Settings.pdf
|
||||
Spindle Talker 2 https://github.com/GilchristT/SpindleTalker2/releases
|
||||
Python https://github.com/RobertOlechowski/Huanyang_VFD
|
||||
|
||||
=========================================================================
|
||||
|
||||
Commands
|
||||
ADDR CMD LEN DATA CRC
|
||||
0x01 0x03 0x01 0x01 0x31 0x88 Start spindle clockwise
|
||||
0x01 0x03 0x01 0x08 0xF1 0x8E Stop spindle
|
||||
0x01 0x03 0x01 0x11 0x30 0x44 Start spindle counter-clockwise
|
||||
|
||||
Return values are
|
||||
0 = run
|
||||
1 = jog
|
||||
2 = r/f
|
||||
3 = running
|
||||
4 = jogging
|
||||
5 = r/f
|
||||
6 = Braking
|
||||
7 = Track start
|
||||
|
||||
==========================================================================
|
||||
|
||||
Setting RPM
|
||||
ADDR CMD LEN DATA CRC
|
||||
0x01 0x05 0x02 0x09 0xC4 0xBF 0x0F Write Frequency (0x9C4 = 2500 = 25.00HZ)
|
||||
|
||||
Response is same as data sent
|
||||
|
||||
==========================================================================
|
||||
|
||||
Status registers
|
||||
Addr Read Len Reg DataH DataL CRC CRC
|
||||
0x01 0x04 0x03 0x00 0x00 0x00 CRC CRC // Set Frequency * 100 (25Hz = 2500)
|
||||
0x01 0x04 0x03 0x01 0x00 0x00 CRC CRC // Ouput Frequency * 100
|
||||
0x01 0x04 0x03 0x02 0x00 0x00 CRC CRC // Ouput Amps * 10
|
||||
0x01 0x04 0x03 0x03 0x00 0x00 0xF0 0x4E // Read RPM (example CRC shown)
|
||||
0x01 0x04 0x03 0x0 0x00 0x00 CRC CRC // DC voltage
|
||||
0x01 0x04 0x03 0x05 0x00 0x00 CRC CRC // AC voltage
|
||||
0x01 0x04 0x03 0x06 0x00 0x00 CRC CRC // Cont
|
||||
0x01 0x04 0x03 0x07 0x00 0x00 CRC CRC // VFD Temp
|
||||
Message is returned with requested value = (DataH * 16) + DataL (see decimal offset above)
|
||||
|
||||
TODO:
|
||||
Move CRC Calc to task to free up main task
|
||||
|
||||
|
||||
*/
|
||||
#include "SpindleClass.h"
|
||||
|
||||
#include "driver/uart.h"
|
||||
|
||||
#define HUANYANG_UART_PORT UART_NUM_2 // hard coded for this port right now
|
||||
#define ECHO_TEST_CTS UART_PIN_NO_CHANGE // CTS pin is not used
|
||||
#define HUANYANG_BUF_SIZE 127
|
||||
#define HUANYANG_QUEUE_SIZE 10 // numv\ber of commands that can be queued up.
|
||||
#define RESPONSE_WAIT_TICKS 50 // how long to wait for a response
|
||||
#define HUANYANG_MAX_MSG_SIZE 16 // more than enough for a modbus message
|
||||
#define HUANYANG_POLL_RATE 200 // in milliseconds betwwen commands
|
||||
|
||||
// OK to change these
|
||||
// #define them in your machine definition file if you want different values
|
||||
#ifndef HUANYANG_ADDR
|
||||
#define HUANYANG_ADDR 0x01
|
||||
#endif
|
||||
|
||||
#ifndef HUANYANG_BAUD_RATE
|
||||
#define HUANYANG_BAUD_RATE 9600 // PD164 setting
|
||||
#endif
|
||||
|
||||
// communication task and queue stuff
|
||||
typedef struct {
|
||||
uint8_t tx_length;
|
||||
uint8_t rx_length;
|
||||
bool critical;
|
||||
char msg[HUANYANG_MAX_MSG_SIZE];
|
||||
} hy_command_t;
|
||||
|
||||
typedef enum : uint8_t {
|
||||
READ_SET_FREQ = 0, // The set frequency
|
||||
READ_OUTPUT_FREQ = 1, // The current operating frequency
|
||||
READ_OUTPUT_AMPS = 2, //
|
||||
READ_SET_RPM = 3, // This is the last requested freq even in off mode
|
||||
READ_DC_VOLTAGE = 4, //
|
||||
READ_AC_VOLTAGE = 5, //
|
||||
READ_CONT = 6, // counting value???
|
||||
READ_TEMP = 7, //
|
||||
} read_register_t;
|
||||
|
||||
QueueHandle_t hy_cmd_queue;
|
||||
|
||||
static TaskHandle_t vfd_cmdTaskHandle = 0;
|
||||
|
||||
bool hy_spindle_ok = true;
|
||||
|
||||
// The communications task
|
||||
void vfd_cmd_task(void* pvParameters) {
|
||||
static bool unresponsive = false; // to pop off a message once each time it becomes unresponsive
|
||||
uint8_t reg_item = 0x00;
|
||||
hy_command_t next_cmd;
|
||||
uint8_t rx_message[HUANYANG_MAX_MSG_SIZE];
|
||||
|
||||
while (true) {
|
||||
if (xQueueReceive(hy_cmd_queue, &next_cmd, 0) == pdTRUE) {
|
||||
|
||||
uart_flush(HUANYANG_UART_PORT);
|
||||
//report_hex_msg(next_cmd.msg, "Tx: ", next_cmd.tx_length);
|
||||
uart_write_bytes(HUANYANG_UART_PORT, next_cmd.msg, next_cmd.tx_length);
|
||||
|
||||
uint16_t read_length = uart_read_bytes(HUANYANG_UART_PORT, rx_message, next_cmd.rx_length, RESPONSE_WAIT_TICKS);
|
||||
|
||||
if (read_length < next_cmd.rx_length) {
|
||||
if (!unresponsive) {
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Spindle RS485 Unresponsive %d", read_length);
|
||||
if (next_cmd.critical) {
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Critical Spindle RS485 Unresponsive");
|
||||
system_set_exec_alarm(EXEC_ALARM_SPINDLE_CONTROL);
|
||||
}
|
||||
unresponsive = true;
|
||||
}
|
||||
} else {
|
||||
// success
|
||||
unresponsive = false;
|
||||
//report_hex_msg(rx_message, "Rx: ", read_length);
|
||||
uint32_t ret_value = ((uint32_t)rx_message[4] << 8) + rx_message[5];
|
||||
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Item:%d value:%05d ", rx_message[3], ret_value);
|
||||
}
|
||||
|
||||
} else {
|
||||
HuanyangSpindle :: read_value(reg_item); // only this appears to work all the time. Other registers are flakey.
|
||||
if (reg_item < 0x03)
|
||||
reg_item++;
|
||||
else
|
||||
{
|
||||
reg_item = 0x00;
|
||||
}
|
||||
|
||||
}
|
||||
vTaskDelay(HUANYANG_POLL_RATE); // TODO: What is the best value here?
|
||||
}
|
||||
}
|
||||
|
||||
// ================== Class methods ==================================
|
||||
|
||||
void HuanyangSpindle :: init() {
|
||||
hy_spindle_ok = true; // initialize
|
||||
|
||||
// fail if required items are not defined
|
||||
if (!get_pins_and_settings()) {
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Huanyang spindle errors");
|
||||
return;
|
||||
}
|
||||
|
||||
if (! _task_running) { // init can happen many times, we only want to start one task
|
||||
hy_cmd_queue = xQueueCreate(HUANYANG_QUEUE_SIZE, sizeof(hy_command_t));
|
||||
xTaskCreatePinnedToCore(vfd_cmd_task, // task
|
||||
"vfd_cmdTaskHandle", // name for task
|
||||
2048, // size of task stack
|
||||
NULL, // parameters
|
||||
1, // priority
|
||||
&vfd_cmdTaskHandle,
|
||||
0 // core
|
||||
);
|
||||
_task_running = true;
|
||||
}
|
||||
|
||||
// this allows us to init() again later.
|
||||
// If you change certain settings, init() gets called agian
|
||||
uart_driver_delete(HUANYANG_UART_PORT);
|
||||
|
||||
uart_config_t uart_config = {
|
||||
.baud_rate = HUANYANG_BAUD_RATE,
|
||||
.data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_DISABLE,
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||
.rx_flow_ctrl_thresh = 122,
|
||||
};
|
||||
|
||||
uart_param_config(HUANYANG_UART_PORT, &uart_config);
|
||||
|
||||
uart_set_pin(HUANYANG_UART_PORT,
|
||||
_txd_pin,
|
||||
_rxd_pin,
|
||||
_rts_pin,
|
||||
UART_PIN_NO_CHANGE);
|
||||
|
||||
uart_driver_install(HUANYANG_UART_PORT,
|
||||
HUANYANG_BUF_SIZE * 2,
|
||||
0,
|
||||
0,
|
||||
NULL,
|
||||
0);
|
||||
|
||||
uart_set_mode(HUANYANG_UART_PORT, UART_MODE_RS485_HALF_DUPLEX);
|
||||
|
||||
is_reversable = true; // these VFDs are always reversable
|
||||
use_delays = true;
|
||||
|
||||
//
|
||||
_current_rpm = 0;
|
||||
_state = SPINDLE_DISABLE;
|
||||
|
||||
config_message();
|
||||
}
|
||||
|
||||
// Checks for all the required pin definitions
|
||||
// It returns a message for each missing pin
|
||||
// Returns true if all pins are defined.
|
||||
bool HuanyangSpindle :: get_pins_and_settings() {
|
||||
|
||||
|
||||
#ifdef HUANYANG_TXD_PIN
|
||||
_txd_pin = HUANYANG_TXD_PIN;
|
||||
#else
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Undefined HUANYANG_TXD_PIN");
|
||||
hy_spindle_ok = false;
|
||||
#endif
|
||||
|
||||
#ifdef HUANYANG_RXD_PIN
|
||||
_rxd_pin = HUANYANG_RXD_PIN;
|
||||
#else
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Undefined HUANYANG_RXD_PIN");
|
||||
hy_spindle_ok = false;
|
||||
#endif
|
||||
|
||||
#ifdef HUANYANG_RTS_PIN
|
||||
_rts_pin = HUANYANG_RTS_PIN;
|
||||
#else
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Undefined HUANYANG_RTS_PIN");
|
||||
hy_spindle_ok = false;
|
||||
#endif
|
||||
|
||||
if (laser_mode->get()) {
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Huanyang spindle disabled in laser mode. Set $GCode/LaserMode=Off and restart");
|
||||
hy_spindle_ok = false;
|
||||
}
|
||||
|
||||
_min_rpm = rpm_min->get();
|
||||
_max_rpm = rpm_max->get();
|
||||
|
||||
return hy_spindle_ok;
|
||||
}
|
||||
|
||||
void HuanyangSpindle :: config_message() {
|
||||
grbl_msg_sendf(CLIENT_SERIAL,
|
||||
MSG_LEVEL_INFO,
|
||||
"Huanyang Spindle Tx:%s Rx:%s RTS:%s",
|
||||
pinName(_txd_pin).c_str(),
|
||||
pinName(_rxd_pin).c_str(),
|
||||
pinName(_rts_pin).c_str());
|
||||
}
|
||||
|
||||
|
||||
void HuanyangSpindle :: set_state(uint8_t state, uint32_t rpm) {
|
||||
if (sys.abort)
|
||||
return; // Block during abort.
|
||||
|
||||
bool critical = (sys.state == STATE_CYCLE || state != SPINDLE_DISABLE);
|
||||
|
||||
if (_current_state != state) { // already at the desired state. This function gets called a lot.
|
||||
set_mode(state, critical); // critical if we are in a job
|
||||
set_rpm(rpm);
|
||||
if (state == SPINDLE_DISABLE) {
|
||||
sys.spindle_speed = 0;
|
||||
if (_current_state != state)
|
||||
mc_dwell(spindle_delay_spindown->get());
|
||||
} else {
|
||||
if (_current_state != state)
|
||||
mc_dwell(spindle_delay_spinup->get());
|
||||
}
|
||||
} else {
|
||||
if (_current_rpm != rpm)
|
||||
set_rpm(rpm);
|
||||
}
|
||||
|
||||
_current_state = state; // store locally for faster get_state()
|
||||
|
||||
sys.report_ovr_counter = 0; // Set to report change immediately
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bool HuanyangSpindle :: set_mode(uint8_t mode, bool critical) {
|
||||
|
||||
if (!hy_spindle_ok) return false;
|
||||
|
||||
hy_command_t mode_cmd;
|
||||
|
||||
mode_cmd.tx_length = 6;
|
||||
mode_cmd.rx_length = 6;
|
||||
|
||||
mode_cmd.msg[0] = HUANYANG_ADDR;
|
||||
mode_cmd.msg[1] = 0x03;
|
||||
mode_cmd.msg[2] = 0x01;
|
||||
|
||||
if (mode == SPINDLE_ENABLE_CW)
|
||||
mode_cmd.msg[3] = 0x01;
|
||||
else if (mode == SPINDLE_ENABLE_CCW)
|
||||
mode_cmd.msg[3] = 0x11;
|
||||
else { //SPINDLE_DISABLE
|
||||
mode_cmd.msg[3] = 0x08;
|
||||
|
||||
if (! xQueueReset(hy_cmd_queue)) {
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "VFD spindle off, queue could not be reset");
|
||||
}
|
||||
}
|
||||
|
||||
add_ModRTU_CRC(mode_cmd.msg, mode_cmd.rx_length);
|
||||
|
||||
mode_cmd.critical = critical;
|
||||
|
||||
if (xQueueSend(hy_cmd_queue, &mode_cmd, 0) != pdTRUE)
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "VFD Queue Full");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
uint32_t HuanyangSpindle :: set_rpm(uint32_t rpm) {
|
||||
if (!hy_spindle_ok) return 0;
|
||||
|
||||
hy_command_t rpm_cmd;
|
||||
|
||||
// apply override
|
||||
rpm = rpm * sys.spindle_speed_ovr / 100; // Scale by spindle speed override value (uint8_t percent)
|
||||
|
||||
// apply limits
|
||||
if ((_min_rpm >= _max_rpm) || (rpm >= _max_rpm))
|
||||
rpm = _max_rpm;
|
||||
else if (rpm != 0 && rpm <= _min_rpm)
|
||||
rpm = _min_rpm;
|
||||
|
||||
sys.spindle_speed = rpm;
|
||||
|
||||
if (rpm == _current_rpm) // prevent setting same RPM twice
|
||||
return rpm;
|
||||
|
||||
_current_rpm = rpm;
|
||||
|
||||
// TODO add the speed modifiers override, linearization, etc.
|
||||
|
||||
rpm_cmd.tx_length = 7;
|
||||
rpm_cmd.rx_length = 6;
|
||||
|
||||
rpm_cmd.msg[0] = HUANYANG_ADDR;
|
||||
rpm_cmd.msg[1] = 0x05;
|
||||
rpm_cmd.msg[2] = 0x02;
|
||||
|
||||
uint16_t data = (uint16_t)(rpm * 100 / 60); // send Hz * 10 (Ex:1500 RPM = 25Hz .... Send 2500)
|
||||
|
||||
rpm_cmd.msg[3] = (data & 0xFF00) >> 8;
|
||||
rpm_cmd.msg[4] = (data & 0xFF);
|
||||
|
||||
add_ModRTU_CRC(rpm_cmd.msg, rpm_cmd.tx_length);
|
||||
|
||||
rpm_cmd.critical = false;
|
||||
|
||||
if (xQueueSend(hy_cmd_queue, &rpm_cmd, 0) != pdTRUE)
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "VFD Queue Full");
|
||||
|
||||
return rpm;
|
||||
}
|
||||
|
||||
|
||||
// This appears to read the control register and will return an RPM running or not.
|
||||
void HuanyangSpindle :: read_value(uint8_t reg) {
|
||||
uint16_t ret_value = 0;
|
||||
hy_command_t read_cmd;
|
||||
uint8_t rx_message[HUANYANG_MAX_MSG_SIZE];
|
||||
|
||||
read_cmd.tx_length = 8;
|
||||
read_cmd.rx_length = 8;
|
||||
|
||||
read_cmd.msg[0] = HUANYANG_ADDR;
|
||||
read_cmd.msg[1] = 0x04;
|
||||
read_cmd.msg[2] = 0x03;
|
||||
|
||||
read_cmd.msg[3] = reg;
|
||||
|
||||
read_cmd.msg[4] = 0x00;
|
||||
read_cmd.msg[5] = 0x00;
|
||||
|
||||
read_cmd.critical = (sys.state == STATE_CYCLE); // only critical if running a job TBD.... maybe spindle on?
|
||||
|
||||
add_ModRTU_CRC(read_cmd.msg, read_cmd.tx_length);
|
||||
|
||||
if (xQueueSend(hy_cmd_queue, &read_cmd, 0) != pdTRUE)
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "VFD Queue Full");
|
||||
}
|
||||
|
||||
void HuanyangSpindle ::stop() {
|
||||
set_mode(SPINDLE_DISABLE, false);
|
||||
}
|
||||
|
||||
// state is cached rather than read right now to prevent delays
|
||||
uint8_t HuanyangSpindle :: get_state() {
|
||||
return _state;
|
||||
}
|
||||
|
||||
// Calculate the CRC on all of the byte except the last 2
|
||||
// It then added the CRC to those last 2 bytes
|
||||
// full_msg_len This is the length of the message including the 2 crc bytes
|
||||
// Source: https://ctlsys.com/support/how_to_compute_the_modbus_rtu_message_crc/
|
||||
void HuanyangSpindle :: add_ModRTU_CRC(char* buf, int full_msg_len) {
|
||||
uint16_t crc = 0xFFFF;
|
||||
for (int pos = 0; pos < full_msg_len - 2; pos++) {
|
||||
crc ^= (uint16_t)buf[pos]; // XOR byte into least sig. byte of crc
|
||||
for (int i = 8; i != 0; i--) { // Loop over each bit
|
||||
if ((crc & 0x0001) != 0) { // If the LSB is set
|
||||
crc >>= 1; // Shift right and XOR 0xA001
|
||||
crc ^= 0xA001;
|
||||
} else // Else LSB is not set
|
||||
crc >>= 1; // Just shift right
|
||||
}
|
||||
}
|
||||
// add the calculated Crc to the message
|
||||
buf[full_msg_len - 1] = (crc & 0xFF00) >> 8;
|
||||
buf[full_msg_len - 2] = (crc & 0xFF);
|
||||
}
|
@@ -1,268 +0,0 @@
|
||||
/*
|
||||
PWMSpindle.cpp
|
||||
|
||||
This is a full featured TTL PWM spindle This does not include speed/power
|
||||
compensation. Use the Laser class for that.
|
||||
|
||||
Part of Grbl_ESP32
|
||||
2020 - Bart Dring
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
#include "SpindleClass.h"
|
||||
|
||||
// ======================= PWMSpindle ==============================
|
||||
/*
|
||||
This gets called at startup or whenever a spindle setting changes
|
||||
If the spindle is running it will stop and need to be restarted with M3Snnnn
|
||||
*/
|
||||
|
||||
//#include "grbl.h"
|
||||
|
||||
void PWMSpindle :: init() {
|
||||
|
||||
get_pins_and_settings();
|
||||
|
||||
if (_output_pin == UNDEFINED_PIN) {
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Warning: Spindle output pin not defined");
|
||||
return; // We cannot continue without the output pin
|
||||
}
|
||||
|
||||
if (_output_pin >= I2S_OUT_PIN_BASE) {
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Warning: Spindle output pin %s cannot do PWM", pinName(_output_pin).c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
ledcSetup(_spindle_pwm_chan_num, (double)_pwm_freq, _pwm_precision); // setup the channel
|
||||
ledcAttachPin(_output_pin, _spindle_pwm_chan_num); // attach the PWM to the pin
|
||||
|
||||
pinMode(_enable_pin, OUTPUT);
|
||||
pinMode(_direction_pin, OUTPUT);
|
||||
|
||||
use_delays = true;
|
||||
|
||||
config_message();
|
||||
}
|
||||
|
||||
// Get the GPIO from the machine definition
|
||||
void PWMSpindle :: get_pins_and_settings() {
|
||||
// setup all the pins
|
||||
|
||||
#ifdef SPINDLE_OUTPUT_PIN
|
||||
_output_pin = SPINDLE_OUTPUT_PIN;
|
||||
#else
|
||||
_output_pin = UNDEFINED_PIN;
|
||||
#endif
|
||||
|
||||
#ifdef INVERT_SPINDLE_OUTPUT_PIN
|
||||
_invert_pwm = true;
|
||||
#else
|
||||
_invert_pwm = false;
|
||||
#endif
|
||||
|
||||
#ifdef SPINDLE_ENABLE_PIN
|
||||
_enable_pin = SPINDLE_ENABLE_PIN;
|
||||
#ifdef SPINDLE_ENABLE_OFF_WITH_ZERO_SPEED
|
||||
_off_with_zero_speed = true;
|
||||
#endif
|
||||
#else
|
||||
_enable_pin = UNDEFINED_PIN;
|
||||
_off_with_zero_speed = false;
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef SPINDLE_DIR_PIN
|
||||
_direction_pin = SPINDLE_DIR_PIN;
|
||||
#else
|
||||
_direction_pin = UNDEFINED_PIN;
|
||||
#endif
|
||||
|
||||
is_reversable = (_direction_pin != UNDEFINED_PIN);
|
||||
|
||||
_pwm_freq = spindle_pwm_freq->get();
|
||||
_pwm_precision = calc_pwm_precision(_pwm_freq); // detewrmine the best precision
|
||||
_pwm_period = (1 << _pwm_precision);
|
||||
|
||||
if (spindle_pwm_min_value->get() > spindle_pwm_min_value->get())
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Warning: Spindle min pwm is greater than max. Check $35 and $36");
|
||||
|
||||
// pre-caculate some PWM count values
|
||||
_pwm_off_value = (_pwm_period * spindle_pwm_off_value->get() / 100.0);
|
||||
_pwm_min_value = (_pwm_period * spindle_pwm_min_value->get() / 100.0);
|
||||
_pwm_max_value = (_pwm_period * spindle_pwm_max_value->get() / 100.0);
|
||||
|
||||
#ifdef ENABLE_PIECEWISE_LINEAR_SPINDLE
|
||||
_min_rpm = RPM_MIN;
|
||||
_max_rpm = RPM_MAX;
|
||||
_piecewide_linear = true;
|
||||
#else
|
||||
_min_rpm = rpm_min->get();
|
||||
_max_rpm = rpm_max->get();
|
||||
_piecewide_linear = false;
|
||||
#endif
|
||||
// The pwm_gradient is the pwm duty cycle units per rpm
|
||||
// _pwm_gradient = (_pwm_max_value - _pwm_min_value) / (_max_rpm - _min_rpm);
|
||||
|
||||
_spindle_pwm_chan_num = 0; // Channel 0 is reserved for spindle use
|
||||
|
||||
|
||||
}
|
||||
|
||||
uint32_t PWMSpindle::set_rpm(uint32_t rpm) {
|
||||
uint32_t pwm_value;
|
||||
|
||||
if (_output_pin == UNDEFINED_PIN)
|
||||
return rpm;
|
||||
|
||||
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "set_rpm(%d)", rpm);
|
||||
|
||||
// apply override
|
||||
rpm = rpm * sys.spindle_speed_ovr / 100; // Scale by spindle speed override value (uint8_t percent)
|
||||
|
||||
// apply limits
|
||||
if ((_min_rpm >= _max_rpm) || (rpm >= _max_rpm))
|
||||
rpm = _max_rpm;
|
||||
else if (rpm != 0 && rpm <= _min_rpm)
|
||||
rpm = _min_rpm;
|
||||
|
||||
sys.spindle_speed = rpm;
|
||||
|
||||
if (_piecewide_linear) {
|
||||
//pwm_value = piecewise_linear_fit(rpm); TODO
|
||||
pwm_value = 0;
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Warning: Linear fit not implemented yet.");
|
||||
|
||||
} else {
|
||||
if (rpm == 0)
|
||||
pwm_value = _pwm_off_value;
|
||||
else
|
||||
pwm_value = map_uint32_t(rpm, _min_rpm, _max_rpm, _pwm_min_value, _pwm_max_value);
|
||||
}
|
||||
|
||||
set_output(pwm_value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PWMSpindle::set_state(uint8_t state, uint32_t rpm) {
|
||||
if (sys.abort)
|
||||
return; // Block during abort.
|
||||
|
||||
if (state == SPINDLE_DISABLE) { // Halt or set spindle direction and rpm.
|
||||
sys.spindle_speed = 0;
|
||||
stop();
|
||||
if (use_delays && (_current_state != state)) {
|
||||
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "SpinDown Start ");
|
||||
mc_dwell(spindle_delay_spindown->get());
|
||||
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "SpinDown Done");
|
||||
}
|
||||
} else {
|
||||
set_spindle_dir_pin(state == SPINDLE_ENABLE_CW);
|
||||
set_rpm(rpm);
|
||||
set_enable_pin(state != SPINDLE_DISABLE); // must be done after setting rpm for enable features to work
|
||||
if (use_delays && (_current_state != state)) {
|
||||
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "SpinUp Start %d", rpm);
|
||||
mc_dwell(spindle_delay_spinup->get());
|
||||
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "SpinUp Done");
|
||||
}
|
||||
}
|
||||
|
||||
_current_state = state;
|
||||
|
||||
sys.report_ovr_counter = 0; // Set to report change immediately
|
||||
}
|
||||
|
||||
uint8_t PWMSpindle::get_state() {
|
||||
if (_current_pwm_duty == 0 || _output_pin == UNDEFINED_PIN)
|
||||
return (SPINDLE_STATE_DISABLE);
|
||||
if (_direction_pin != UNDEFINED_PIN)
|
||||
return digitalRead(_direction_pin) ? SPINDLE_STATE_CW : SPINDLE_STATE_CCW;
|
||||
return (SPINDLE_STATE_CW);
|
||||
}
|
||||
|
||||
void PWMSpindle::stop() {
|
||||
// inverts are delt with in methods
|
||||
set_enable_pin(false);
|
||||
set_output(_pwm_off_value);
|
||||
|
||||
}
|
||||
|
||||
// prints the startup message of the spindle config
|
||||
void PWMSpindle :: config_message() {
|
||||
grbl_msg_sendf(CLIENT_SERIAL,
|
||||
MSG_LEVEL_INFO,
|
||||
"PWM spindle Output:%s, Enbl:%s, Dir:%s, Freq:%dHz, Res:%dbits",
|
||||
pinName(_output_pin).c_str(),
|
||||
pinName(_enable_pin).c_str(),
|
||||
pinName(_direction_pin).c_str(),
|
||||
_pwm_freq,
|
||||
_pwm_precision);
|
||||
}
|
||||
|
||||
|
||||
void PWMSpindle::set_output(uint32_t duty) {
|
||||
|
||||
|
||||
if (_output_pin == UNDEFINED_PIN)
|
||||
return;
|
||||
|
||||
// to prevent excessive calls to ledcWrite, make sure duty hass changed
|
||||
if (duty == _current_pwm_duty)
|
||||
return;
|
||||
|
||||
_current_pwm_duty = duty;
|
||||
|
||||
if (_invert_pwm)
|
||||
duty = (1 << _pwm_precision) - duty;
|
||||
|
||||
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "set_output(%d)", duty);
|
||||
|
||||
ledcWrite(_spindle_pwm_chan_num, duty);
|
||||
}
|
||||
|
||||
void PWMSpindle::set_enable_pin(bool enable) {
|
||||
|
||||
if (_enable_pin == UNDEFINED_PIN)
|
||||
return;
|
||||
|
||||
if (_off_with_zero_speed && sys.spindle_speed == 0)
|
||||
enable = false;
|
||||
|
||||
#ifndef INVERT_SPINDLE_ENABLE_PIN
|
||||
digitalWrite(_enable_pin, enable);
|
||||
#else
|
||||
digitalWrite(_enable_pin, !enable);
|
||||
#endif
|
||||
digitalWrite(_enable_pin, enable);
|
||||
}
|
||||
|
||||
void PWMSpindle::set_spindle_dir_pin(bool Clockwise) {
|
||||
digitalWrite(_direction_pin, Clockwise);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Calculate the highest precision of a PWM based on the frequency in bits
|
||||
|
||||
80,000,000 / freq = period
|
||||
determine the highest precision where (1 << precision) < period
|
||||
*/
|
||||
uint8_t PWMSpindle :: calc_pwm_precision(uint32_t freq) {
|
||||
uint8_t precision = 0;
|
||||
|
||||
// increase the precision (bits) until it exceeds allow by frequency the max or is 16
|
||||
while ((1 << precision) < (uint32_t)(80000000 / freq) && precision <= 16)
|
||||
precision++;
|
||||
|
||||
return precision - 1;
|
||||
}
|
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
RelaySpindle.cpp
|
||||
|
||||
This is used for a basic on/off spindle All S Values above 0
|
||||
will turn the spindle on.
|
||||
|
||||
Part of Grbl_ESP32
|
||||
2020 - Bart Dring
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
#include "SpindleClass.h"
|
||||
|
||||
// ========================= RelaySpindle ==================================
|
||||
/*
|
||||
This is a sub class of PWMSpindle but is a digital rather than PWM output
|
||||
*/
|
||||
void RelaySpindle::init() {
|
||||
get_pins_and_settings();
|
||||
|
||||
if (_output_pin == UNDEFINED_PIN)
|
||||
return;
|
||||
|
||||
pinMode(_output_pin, OUTPUT);
|
||||
pinMode(_enable_pin, OUTPUT);
|
||||
pinMode(_direction_pin, OUTPUT);
|
||||
|
||||
is_reversable = (_direction_pin != UNDEFINED_PIN);
|
||||
use_delays = true;
|
||||
|
||||
config_message();
|
||||
}
|
||||
|
||||
// prints the startup message of the spindle config
|
||||
void RelaySpindle :: config_message() {
|
||||
grbl_msg_sendf(CLIENT_SERIAL,
|
||||
MSG_LEVEL_INFO,
|
||||
"Relay spindle Output:%s, Enbl:%s, Dir:%s",
|
||||
pinName(_output_pin).c_str(),
|
||||
pinName(_enable_pin).c_str(),
|
||||
pinName(_direction_pin).c_str());
|
||||
}
|
||||
|
||||
uint32_t RelaySpindle::set_rpm(uint32_t rpm) {
|
||||
if (_output_pin == UNDEFINED_PIN)
|
||||
return rpm;
|
||||
|
||||
sys.spindle_speed = rpm;
|
||||
set_output(rpm != 0);
|
||||
|
||||
|
||||
return rpm;
|
||||
}
|
||||
|
||||
void RelaySpindle::set_output(uint32_t duty) {
|
||||
#ifdef INVERT_SPINDLE_PWM
|
||||
duty = (duty == 0); // flip duty
|
||||
#endif
|
||||
digitalWrite(_output_pin, duty > 0); // anything greater
|
||||
}
|
@@ -1,96 +0,0 @@
|
||||
/*
|
||||
SpindleClass.cpp
|
||||
|
||||
A Base class for spindles and spinsle like things such as lasers
|
||||
|
||||
Part of Grbl_ESP32
|
||||
|
||||
2020 - Bart Dring
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
TODO
|
||||
Add Spindle spin up/down delays
|
||||
|
||||
Get rid of dependance on machine definition #defines
|
||||
SPINDLE_OUTPUT_PIN
|
||||
SPINDLE_ENABLE_PIN
|
||||
SPINDLE_DIR_PIN
|
||||
|
||||
*/
|
||||
#include "NullSpindle.cpp"
|
||||
#include "PWMSpindle.cpp"
|
||||
#include "DacSpindle.cpp"
|
||||
#include "RelaySpindle.cpp"
|
||||
#include "Laser.cpp"
|
||||
#include "HuanyangSpindle.cpp"
|
||||
#include "BESCSpindle.cpp"
|
||||
#include "10vSpindle.cpp"
|
||||
|
||||
|
||||
// An instance of each type of spindle is created here.
|
||||
// This allows the spindle to be dynamicly switched
|
||||
NullSpindle null_spindle;
|
||||
PWMSpindle pwm_spindle;
|
||||
RelaySpindle relay_spindle;
|
||||
Laser laser;
|
||||
DacSpindle dac_spindle;
|
||||
HuanyangSpindle huanyang_spindle;
|
||||
BESCSpindle besc_spindle;
|
||||
_10vSpindle _10v_spindle;
|
||||
|
||||
|
||||
void spindle_select() {
|
||||
|
||||
switch (spindle_type->get()) {
|
||||
case SPINDLE_TYPE_PWM:
|
||||
spindle = &pwm_spindle;
|
||||
break;
|
||||
case SPINDLE_TYPE_RELAY:
|
||||
spindle = &relay_spindle;
|
||||
break;
|
||||
case SPINDLE_TYPE_LASER:
|
||||
spindle = &laser;
|
||||
break;
|
||||
case SPINDLE_TYPE_DAC:
|
||||
spindle = &dac_spindle;
|
||||
break;
|
||||
case SPINDLE_TYPE_HUANYANG:
|
||||
spindle = &huanyang_spindle;
|
||||
break;
|
||||
case SPINDLE_TYPE_BESC:
|
||||
spindle = &besc_spindle;
|
||||
break;
|
||||
case SPINDLE_TYPE_10V:
|
||||
spindle = &_10v_spindle;
|
||||
break;
|
||||
case SPINDLE_TYPE_NONE:
|
||||
default:
|
||||
spindle = &null_spindle;
|
||||
break;
|
||||
}
|
||||
|
||||
spindle->init();
|
||||
}
|
||||
|
||||
// ========================= Spindle ==================================
|
||||
|
||||
bool Spindle::isRateAdjusted() {
|
||||
return false; // default for basic spindle is false
|
||||
}
|
||||
|
||||
void Spindle :: spindle_sync(uint8_t state, uint32_t rpm) {
|
||||
if (sys.state == STATE_CHECK_MODE)
|
||||
return;
|
||||
protocol_buffer_synchronize(); // Empty planner buffer to ensure spindle is set when programmed.
|
||||
set_state(state, rpm);
|
||||
}
|
@@ -1,229 +0,0 @@
|
||||
/*
|
||||
SpindleClass.h
|
||||
|
||||
Header file for a Spindle Class
|
||||
See SpindleClass.cpp for more details
|
||||
|
||||
Part of Grbl_ESP32
|
||||
|
||||
2020 - Bart Dring This file was modified for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
See SpindleClass.cpp for more info and references
|
||||
|
||||
*/
|
||||
|
||||
#define SPINDLE_STATE_DISABLE 0 // Must be zero.
|
||||
#define SPINDLE_STATE_CW bit(0)
|
||||
#define SPINDLE_STATE_CCW bit(1)
|
||||
|
||||
|
||||
#define SPINDLE_TYPE_NONE 0
|
||||
#define SPINDLE_TYPE_PWM 1
|
||||
#define SPINDLE_TYPE_RELAY 2
|
||||
#define SPINDLE_TYPE_LASER 3
|
||||
#define SPINDLE_TYPE_DAC 4
|
||||
#define SPINDLE_TYPE_HUANYANG 5
|
||||
#define SPINDLE_TYPE_BESC 6
|
||||
#define SPINDLE_TYPE_10V 7
|
||||
|
||||
#ifndef SPINDLE_CLASS_H
|
||||
#define SPINDLE_CLASS_H
|
||||
|
||||
#include "../grbl.h"
|
||||
#include <driver/dac.h>
|
||||
#include "driver/uart.h"
|
||||
|
||||
|
||||
// =============== No floats! ===========================
|
||||
// ================ NO FLOATS! ==========================
|
||||
|
||||
// This is the base class. Do not use this as your spindle
|
||||
class Spindle {
|
||||
public:
|
||||
virtual void init(); // not in constructor because this also gets called when $$ settings change
|
||||
virtual uint32_t set_rpm(uint32_t rpm);
|
||||
virtual void set_state(uint8_t state, uint32_t rpm);
|
||||
virtual uint8_t get_state();
|
||||
virtual void stop();
|
||||
virtual void config_message();
|
||||
virtual bool isRateAdjusted();
|
||||
virtual void spindle_sync(uint8_t state, uint32_t rpm);
|
||||
|
||||
bool is_reversable;
|
||||
bool use_delays; // will SpinUp and SpinDown delays be used.
|
||||
uint8_t _current_state;
|
||||
};
|
||||
|
||||
// This is a dummy spindle that has no I/O.
|
||||
// It is used to ignore spindle commands when no spinde is desired
|
||||
class NullSpindle : public Spindle {
|
||||
public:
|
||||
void init();
|
||||
uint32_t set_rpm(uint32_t rpm);
|
||||
void set_state(uint8_t state, uint32_t rpm);
|
||||
uint8_t get_state();
|
||||
void stop();
|
||||
void config_message();
|
||||
};
|
||||
|
||||
// This adds support for PWM
|
||||
class PWMSpindle : public Spindle {
|
||||
public:
|
||||
void init();
|
||||
virtual uint32_t set_rpm(uint32_t rpm);
|
||||
void set_state(uint8_t state, uint32_t rpm);
|
||||
uint8_t get_state();
|
||||
void stop();
|
||||
void config_message();
|
||||
|
||||
private:
|
||||
void set_spindle_dir_pin(bool Clockwise);
|
||||
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
int32_t _current_pwm_duty;
|
||||
uint32_t _min_rpm;
|
||||
uint32_t _max_rpm;
|
||||
uint32_t _pwm_off_value;
|
||||
uint32_t _pwm_min_value;
|
||||
uint32_t _pwm_max_value;
|
||||
uint8_t _output_pin;
|
||||
uint8_t _enable_pin;
|
||||
uint8_t _direction_pin;
|
||||
uint8_t _spindle_pwm_chan_num;
|
||||
uint32_t _pwm_freq;
|
||||
uint32_t _pwm_period; // how many counts in 1 period
|
||||
uint8_t _pwm_precision;
|
||||
bool _piecewide_linear;
|
||||
bool _off_with_zero_speed;
|
||||
bool _invert_pwm;
|
||||
//uint32_t _pwm_gradient; // Precalulated value to speed up rpm to PWM conversions.
|
||||
|
||||
virtual void set_output(uint32_t duty);
|
||||
void set_enable_pin(bool enable_pin);
|
||||
void get_pins_and_settings();
|
||||
uint8_t calc_pwm_precision(uint32_t freq);
|
||||
};
|
||||
|
||||
// This is for an on/off spindle all RPMs above 0 are on
|
||||
class RelaySpindle : public PWMSpindle {
|
||||
public:
|
||||
void init();
|
||||
void config_message();
|
||||
uint32_t set_rpm(uint32_t rpm);
|
||||
protected:
|
||||
void set_output(uint32_t duty);
|
||||
};
|
||||
|
||||
// this is the same as a PWM spindle but the M4 compensation is supported.
|
||||
class Laser : public PWMSpindle {
|
||||
public:
|
||||
bool isRateAdjusted();
|
||||
void config_message();
|
||||
};
|
||||
|
||||
// This uses one of the (2) DAC pins on ESP32 to output a voltage
|
||||
class DacSpindle : public PWMSpindle {
|
||||
public:
|
||||
void init();
|
||||
void config_message();
|
||||
uint32_t set_rpm(uint32_t rpm);
|
||||
private:
|
||||
bool _gpio_ok; // DAC is on a valid pin
|
||||
protected:
|
||||
void set_output(uint32_t duty); // sets DAC instead of PWM
|
||||
};
|
||||
|
||||
class HuanyangSpindle : public Spindle {
|
||||
private:
|
||||
uint16_t ModRTU_CRC(char* buf, int len);
|
||||
|
||||
bool set_mode(uint8_t mode, bool critical);
|
||||
|
||||
bool get_pins_and_settings();
|
||||
|
||||
uint32_t _current_rpm;
|
||||
uint8_t _txd_pin;
|
||||
uint8_t _rxd_pin;
|
||||
uint8_t _rts_pin;
|
||||
uint8_t _state;
|
||||
bool _task_running;
|
||||
|
||||
public:
|
||||
HuanyangSpindle() {
|
||||
_task_running = false;
|
||||
}
|
||||
void init();
|
||||
void config_message();
|
||||
void set_state(uint8_t state, uint32_t rpm);
|
||||
uint8_t get_state();
|
||||
uint32_t set_rpm(uint32_t rpm);
|
||||
void stop();
|
||||
static void read_value(uint8_t reg);
|
||||
static void add_ModRTU_CRC(char* buf, int full_msg_len);
|
||||
|
||||
protected:
|
||||
uint32_t _min_rpm;
|
||||
uint32_t _max_rpm;
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
class BESCSpindle : public PWMSpindle {
|
||||
public:
|
||||
void init();
|
||||
void config_message();
|
||||
uint32_t set_rpm(uint32_t rpm);
|
||||
};
|
||||
|
||||
class _10vSpindle : public PWMSpindle {
|
||||
public:
|
||||
void init();
|
||||
void config_message();
|
||||
uint32_t set_rpm(uint32_t rpm);
|
||||
uint8_t _forward_pin;
|
||||
uint8_t _reverse_pin;
|
||||
|
||||
//void set_state(uint8_t state, uint32_t rpm);
|
||||
|
||||
uint8_t get_state();
|
||||
void stop();
|
||||
protected:
|
||||
void set_enable_pin(bool enable_pin);
|
||||
void set_spindle_dir_pin(bool Clockwise);
|
||||
|
||||
};
|
||||
|
||||
extern Spindle* spindle;
|
||||
|
||||
|
||||
extern NullSpindle null_spindle;
|
||||
extern PWMSpindle pwm_spindle;
|
||||
extern RelaySpindle relay_spindle;
|
||||
extern Laser laser;
|
||||
extern DacSpindle dac_spindle;
|
||||
extern HuanyangSpindle huanyang_spindle;
|
||||
extern BESCSpindle besc_spindle;
|
||||
extern _10vSpindle _10v_spindle;
|
||||
|
||||
void spindle_select();
|
||||
|
||||
// in HuanyangSpindle.cpp
|
||||
void vfd_cmd_task(void* pvParameters);
|
||||
|
||||
#endif
|
@@ -1,13 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
//Authentication level
|
||||
typedef enum {
|
||||
LEVEL_GUEST = 0,
|
||||
LEVEL_USER = 1,
|
||||
LEVEL_ADMIN = 2
|
||||
} auth_t;
|
||||
|
||||
#define MIN_LOCAL_PASSWORD_LENGTH 1
|
||||
#define MAX_LOCAL_PASSWORD_LENGTH 16
|
||||
|
||||
void remove_password(char *str, auth_t& auth_level);
|
@@ -1,437 +0,0 @@
|
||||
/*
|
||||
defaults.h - defaults settings configuration file
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2012-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
|
||||
2018 - Bart Dring This file was modifed for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* The defaults.h file serves as a central default settings selector for different machine
|
||||
types, from DIY CNC mills to CNC conversions of off-the-shelf machines. The settings
|
||||
files listed here are supplied by users, so your results may vary. However, this should
|
||||
give you a good starting point as you get to know your machine and tweak the settings for
|
||||
your nefarious needs.
|
||||
NOTE: Ensure one and only one of these DEFAULTS_XXX values is defined in config.h */
|
||||
|
||||
#ifndef defaults_h
|
||||
|
||||
/*
|
||||
All of these settings check to see if they have been defined already
|
||||
before defining them. This allows to to easily set them eslewhere.
|
||||
You only need to set ones that are important or unique to your
|
||||
machine. The rest will be pulled from here.
|
||||
*/
|
||||
|
||||
// Grbl generic default settings. Should work across different machines.
|
||||
#ifndef DEFAULT_STEP_PULSE_MICROSECONDS
|
||||
#define DEFAULT_STEP_PULSE_MICROSECONDS 3 // $0
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_STEPPER_IDLE_LOCK_TIME
|
||||
#define DEFAULT_STEPPER_IDLE_LOCK_TIME 250 // $1 msec (0-254, 255 keeps steppers enabled)
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_STEPPING_INVERT_MASK
|
||||
#define DEFAULT_STEPPING_INVERT_MASK 0 // $2 uint8_t
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_DIRECTION_INVERT_MASK
|
||||
#define DEFAULT_DIRECTION_INVERT_MASK 0 // $3 uint8_
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_INVERT_ST_ENABLE
|
||||
#define DEFAULT_INVERT_ST_ENABLE 0 // $4 boolean
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_INVERT_LIMIT_PINS
|
||||
#define DEFAULT_INVERT_LIMIT_PINS 1 // $5 boolean
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_INVERT_PROBE_PIN
|
||||
#define DEFAULT_INVERT_PROBE_PIN 0 // $6 boolean
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_STATUS_REPORT_MASK
|
||||
#define DEFAULT_STATUS_REPORT_MASK 1 // $10
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_JUNCTION_DEVIATION
|
||||
#define DEFAULT_JUNCTION_DEVIATION 0.01 // $11 mm
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_ARC_TOLERANCE
|
||||
#define DEFAULT_ARC_TOLERANCE 0.002 // $12 mm
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_REPORT_INCHES
|
||||
#define DEFAULT_REPORT_INCHES 0 // $13 false
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_SOFT_LIMIT_ENABLE
|
||||
#define DEFAULT_SOFT_LIMIT_ENABLE 0 // $20 false
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_HARD_LIMIT_ENABLE
|
||||
#define DEFAULT_HARD_LIMIT_ENABLE 0 // $21 false
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_HOMING_ENABLE
|
||||
#define DEFAULT_HOMING_ENABLE 0 // $22 false
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_HOMING_DIR_MASK
|
||||
#define DEFAULT_HOMING_DIR_MASK 3 // $23 move positive dir Z, negative X,Y
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_HOMING_FEED_RATE
|
||||
#define DEFAULT_HOMING_FEED_RATE 200.0 // $24 mm/min
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_HOMING_SEEK_RATE
|
||||
#define DEFAULT_HOMING_SEEK_RATE 2000.0 // $25 mm/min
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_HOMING_DEBOUNCE_DELAY
|
||||
#define DEFAULT_HOMING_DEBOUNCE_DELAY 250 // $26 msec (0-65k)
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_HOMING_PULLOFF
|
||||
#define DEFAULT_HOMING_PULLOFF 1.0 // $27 mm
|
||||
#endif
|
||||
|
||||
// ======== SPINDLE STUFF ====================
|
||||
#ifndef SPINDLE_TYPE
|
||||
#define SPINDLE_TYPE SPINDLE_TYPE_NONE
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_SPINDLE_RPM_MIN // $31
|
||||
#define DEFAULT_SPINDLE_RPM_MIN 0.0 // rpm
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_LASER_MODE // $32
|
||||
#define DEFAULT_LASER_MODE 0 // false
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_SPINDLE_RPM_MAX // $30
|
||||
#define DEFAULT_SPINDLE_RPM_MAX 1000.0 // rpm
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_SPINDLE_FREQ
|
||||
#define DEFAULT_SPINDLE_FREQ 5000.0 // $33 Hz (extended set)
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_SPINDLE_OFF_VALUE
|
||||
#define DEFAULT_SPINDLE_OFF_VALUE 0.0 // $34 Percent of full period(extended set)
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_SPINDLE_MIN_VALUE
|
||||
#define DEFAULT_SPINDLE_MIN_VALUE 0.0 // $35 Percent of full period (extended set)
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_SPINDLE_MAX_VALUE
|
||||
#define DEFAULT_SPINDLE_MAX_VALUE 100.0 // $36 Percent of full period (extended set)
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_SPINDLE_DELAY_SPINUP
|
||||
#define DEFAULT_SPINDLE_DELAY_SPINUP 0
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_SPINDLE_DELAY_SPINDOWN
|
||||
#define DEFAULT_SPINDLE_DELAY_SPINDOWN 0
|
||||
#endif
|
||||
|
||||
// ================ user settings =====================
|
||||
#ifndef DEFAULT_USER_INT_80
|
||||
#define DEFAULT_USER_INT_80 0 // $80 User integer setting
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_USER_INT_81
|
||||
#define DEFAULT_USER_INT_81 0 // $81 User integer setting
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_USER_INT_82
|
||||
#define DEFAULT_USER_INT_82 0 // $82 User integer setting
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_USER_INT_83
|
||||
#define DEFAULT_USER_INT_83 0 // $83 User integer setting
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_USER_INT_84
|
||||
#define DEFAULT_USER_INT_84 0 // $84 User integer setting
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_USER_FLOAT_90
|
||||
#define DEFAULT_USER_FLOAT_90 0.0 // $90 User integer setting
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_USER_FLOAT_91
|
||||
#define DEFAULT_USER_FLOAT_91 0.0 // $92 User integer setting
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_USER_FLOAT_92
|
||||
#define DEFAULT_USER_FLOAT_92 0.0 // $92 User integer setting
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_USER_FLOAT_93
|
||||
#define DEFAULT_USER_FLOAT_93 0.0 // $93 User integer setting
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_USER_FLOAT_94
|
||||
#define DEFAULT_USER_FLOAT_94 0.0 // $94 User integer setting
|
||||
#endif
|
||||
|
||||
|
||||
// =========== AXIS RESOLUTION ======
|
||||
|
||||
#ifndef DEFAULT_X_STEPS_PER_MM
|
||||
#define DEFAULT_X_STEPS_PER_MM 100.0
|
||||
#endif
|
||||
#ifndef DEFAULT_Y_STEPS_PER_MM
|
||||
#define DEFAULT_Y_STEPS_PER_MM 100.0
|
||||
#endif
|
||||
#ifndef DEFAULT_Z_STEPS_PER_MM
|
||||
#define DEFAULT_Z_STEPS_PER_MM 100.0
|
||||
#endif
|
||||
#ifndef DEFAULT_A_STEPS_PER_MM
|
||||
#define DEFAULT_A_STEPS_PER_MM 100.0
|
||||
#endif
|
||||
#ifndef DEFAULT_B_STEPS_PER_MM
|
||||
#define DEFAULT_B_STEPS_PER_MM 100.0
|
||||
#endif
|
||||
#ifndef DEFAULT_C_STEPS_PER_MM
|
||||
#define DEFAULT_C_STEPS_PER_MM 100.0
|
||||
#endif
|
||||
|
||||
// ============ AXIS MAX SPPED =========
|
||||
|
||||
#ifndef DEFAULT_X_MAX_RATE
|
||||
#define DEFAULT_X_MAX_RATE 1000.0 // mm/min
|
||||
#endif
|
||||
#ifndef DEFAULT_Y_MAX_RATE
|
||||
#define DEFAULT_Y_MAX_RATE 1000.0 // mm/min
|
||||
#endif
|
||||
#ifndef DEFAULT_Z_MAX_RATE
|
||||
#define DEFAULT_Z_MAX_RATE 1000.0 // mm/min
|
||||
#endif
|
||||
#ifndef DEFAULT_A_MAX_RATE
|
||||
#define DEFAULT_A_MAX_RATE 1000.0 // mm/min
|
||||
#endif
|
||||
#ifndef DEFAULT_B_MAX_RATE
|
||||
#define DEFAULT_B_MAX_RATE 1000.0 // mm/min
|
||||
#endif
|
||||
#ifndef DEFAULT_C_MAX_RATE
|
||||
#define DEFAULT_C_MAX_RATE 1000.0 // mm/min
|
||||
#endif
|
||||
|
||||
// ============== Axis Acceleration =========
|
||||
#define SEC_PER_MIN_SQ (60.0*60.0) // Seconds Per Minute Squared, for acceleration conversion
|
||||
// Default accelerations are expressed in mm/sec^2
|
||||
#ifndef DEFAULT_X_ACCELERATION
|
||||
#define DEFAULT_X_ACCELERATION 200.0
|
||||
#endif
|
||||
#ifndef DEFAULT_Y_ACCELERATION
|
||||
#define DEFAULT_Y_ACCELERATION 200.0
|
||||
#endif
|
||||
#ifndef DEFAULT_Z_ACCELERATION
|
||||
#define DEFAULT_Z_ACCELERATION 200.0
|
||||
#endif
|
||||
#ifndef DEFAULT_A_ACCELERATION
|
||||
#define DEFAULT_A_ACCELERATION 200.0
|
||||
#endif
|
||||
#ifndef DEFAULT_B_ACCELERATION
|
||||
#define DEFAULT_B_ACCELERATION 200.0
|
||||
#endif
|
||||
#ifndef DEFAULT_C_ACCELERATION
|
||||
#define DEFAULT_C_ACCELERATION 200.0
|
||||
#endif
|
||||
|
||||
// ========= AXIS MAX TRAVEL ============
|
||||
|
||||
#ifndef DEFAULT_X_MAX_TRAVEL
|
||||
#define DEFAULT_X_MAX_TRAVEL 300.0 // $130 mm NOTE: Must be a positive value.
|
||||
#endif
|
||||
#ifndef DEFAULT_Y_MAX_TRAVEL
|
||||
#define DEFAULT_Y_MAX_TRAVEL 300.0 // mm NOTE: Must be a positive value.
|
||||
#endif
|
||||
#ifndef DEFAULT_Z_MAX_TRAVEL
|
||||
#define DEFAULT_Z_MAX_TRAVEL 300.0 // mm NOTE: Must be a positive value.
|
||||
#endif
|
||||
#ifndef DEFAULT_A_MAX_TRAVEL
|
||||
#define DEFAULT_A_MAX_TRAVEL 300.0 // mm NOTE: Must be a positive value.
|
||||
#endif
|
||||
#ifndef DEFAULT_B_MAX_TRAVEL
|
||||
#define DEFAULT_B_MAX_TRAVEL 300.0 // mm NOTE: Must be a positive value.
|
||||
#endif
|
||||
#ifndef DEFAULT_C_MAX_TRAVEL
|
||||
#define DEFAULT_C_MAX_TRAVEL 300.0 // mm NOTE: Must be a positive value.
|
||||
#endif
|
||||
|
||||
// ========== Motor current (SPI Drivers ) =============
|
||||
#ifndef DEFAULT_X_CURRENT
|
||||
#define DEFAULT_X_CURRENT 0.25 // $140 current in amps (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_Y_CURRENT
|
||||
#define DEFAULT_Y_CURRENT 0.25 // $141 current in amps (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_Z_CURRENT
|
||||
#define DEFAULT_Z_CURRENT 0.25 // $142 current in amps (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_A_CURRENT
|
||||
#define DEFAULT_A_CURRENT 0.25 // $143 current in amps (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_B_CURRENT
|
||||
#define DEFAULT_B_CURRENT 0.25 // $144 current in amps (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_C_CURRENT
|
||||
#define DEFAULT_C_CURRENT 0.25 // $145 current in amps (extended set)
|
||||
#endif
|
||||
|
||||
// ========== Motor hold current (SPI Drivers ) =============
|
||||
|
||||
#ifndef DEFAULT_X_HOLD_CURRENT
|
||||
#define DEFAULT_X_HOLD_CURRENT 0.125 // $150 current in amps (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_Y_HOLD_CURRENT
|
||||
#define DEFAULT_Y_HOLD_CURRENT 0.125 // $151 current in amps (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_Z_HOLD_CURRENT
|
||||
#define DEFAULT_Z_HOLD_CURRENT 0.125 // $152 current in amps (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_A_HOLD_CURRENT
|
||||
#define DEFAULT_A_HOLD_CURRENT 0.125 // $153 current in amps (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_B_HOLD_CURRENT
|
||||
#define DEFAULT_B_HOLD_CURRENT 0.125 // $154 current in amps (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_C_HOLD_CURRENT
|
||||
#define DEFAULT_C_HOLD_CURRENT 0.125 // $154 current in amps (extended set)
|
||||
#endif
|
||||
|
||||
// ========== Microsteps (SPI Drivers ) ================
|
||||
|
||||
#ifndef DEFAULT_X_MICROSTEPS
|
||||
#define DEFAULT_X_MICROSTEPS 16 // $160 micro steps (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_Y_MICROSTEPS
|
||||
#define DEFAULT_Y_MICROSTEPS 16 // $161 micro steps (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_Z_MICROSTEPS
|
||||
#define DEFAULT_Z_MICROSTEPS 16 // $162 micro steps (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_A_MICROSTEPS
|
||||
#define DEFAULT_A_MICROSTEPS 16 // $163 micro steps (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_B_MICROSTEPS
|
||||
#define DEFAULT_B_MICROSTEPS 16 // $164 micro steps (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_C_MICROSTEPS
|
||||
#define DEFAULT_C_MICROSTEPS 16 // $165 micro steps (extended set)
|
||||
#endif
|
||||
|
||||
// ========== Stallguard (SPI Drivers ) ================
|
||||
|
||||
#ifndef DEFAULT_X_STALLGUARD
|
||||
#define DEFAULT_X_STALLGUARD 16 // $170 stallguard (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_Y_STALLGUARD
|
||||
#define DEFAULT_Y_STALLGUARD 16 // $171 stallguard (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_Z_STALLGUARD
|
||||
#define DEFAULT_Z_STALLGUARD 16 // $172 stallguard (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_A_STALLGUARD
|
||||
#define DEFAULT_A_STALLGUARD 16 // $173 stallguard (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_B_STALLGUARD
|
||||
#define DEFAULT_B_STALLGUARD 16 // $174 stallguard (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_C_STALLGUARD
|
||||
#define DEFAULT_C_STALLGUARD 16 // $175 stallguard (extended set)
|
||||
#endif
|
||||
|
||||
|
||||
// ================== pin defaults ========================
|
||||
|
||||
|
||||
// Here is a place to default pins to UNDEFINED_PIN.
|
||||
// This can eliminate checking to see if the pin is defined because
|
||||
// the overridden pinMode and digitalWrite functions will deal with it.
|
||||
|
||||
#ifndef STEPPERS_DISABLE_PIN
|
||||
#define STEPPERS_DISABLE_PIN UNDEFINED_PIN
|
||||
#endif
|
||||
|
||||
#ifndef X_DISABLE_PIN
|
||||
#define X_DISABLE_PIN UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef Y_DISABLE_PIN
|
||||
#define Y_DISABLE_PIN UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef Z_DISABLE_PIN
|
||||
#define Z_DISABLE_PIN UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef A_DISABLE_PIN
|
||||
#define A_DISABLE_PIN UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef B_DISABLE_PIN
|
||||
#define B_DISABLE_PIN UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef C_DISABLE_PIN
|
||||
#define C_DISABLE_PIN UNDEFINED_PIN
|
||||
#endif
|
||||
|
||||
#ifndef X2_DISABLE_PIN
|
||||
#define X2_DISABLE_PIN UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef Y2_DISABLE_PIN
|
||||
#define Y2_DISABLE_PIN UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef Z2_DISABLE_PIN
|
||||
#define Z2_DISABLE_PIN UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef A2_DISABLE_PIN
|
||||
#define A2_DISABLE_PIN UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef B2_DISABLE_PIN
|
||||
#define B2_DISABLE_PIN UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef C2_DISABLE_PIN
|
||||
#define C2_DISABLE_PIN UNDEFINED_PIN
|
||||
#endif
|
||||
|
||||
#ifndef X_LIMIT_PIN
|
||||
#define X_LIMIT_PIN UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef Y_LIMIT_PIN
|
||||
#define Y_LIMIT_PIN UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef Z_LIMIT_PIN
|
||||
#define Z_LIMIT_PIN UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef A_LIMIT_PIN
|
||||
#define A_LIMIT_PIN UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef B_LIMIT_PIN
|
||||
#define B_LIMIT_PIN UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef C_LIMIT_PIN
|
||||
#define C_LIMIT_PIN UNDEFINED_PIN
|
||||
#endif
|
||||
|
||||
#endif
|
1390
Grbl_Esp32/gcode.cpp
1390
Grbl_Esp32/gcode.cpp
File diff suppressed because it is too large
Load Diff
@@ -1,268 +0,0 @@
|
||||
/*
|
||||
gcode.h - rs274/ngc parser.
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2011-2015 Sungeun K. Jeon
|
||||
Copyright (c) 2009-2011 Simen Svale Skogsrud
|
||||
|
||||
2018 - Bart Dring This file was modifed for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef gcode_h
|
||||
#define gcode_h
|
||||
|
||||
|
||||
// Define modal group internal numbers for checking multiple command violations and tracking the
|
||||
// type of command that is called in the block. A modal group is a group of g-code commands that are
|
||||
// mutually exclusive, or cannot exist on the same line, because they each toggle a state or execute
|
||||
// a unique motion. These are defined in the NIST RS274-NGC v3 g-code standard, available online,
|
||||
// and are similar/identical to other g-code interpreters by manufacturers (Haas,Fanuc,Mazak,etc).
|
||||
// NOTE: Modal group define values must be sequential and starting from zero.
|
||||
#define MODAL_GROUP_G0 0 // [G4,G10,G28,G28.1,G30,G30.1,G53,G92,G92.1] Non-modal
|
||||
#define MODAL_GROUP_G1 1 // [G0,G1,G2,G3,G38.2,G38.3,G38.4,G38.5,G80] Motion
|
||||
#define MODAL_GROUP_G2 2 // [G17,G18,G19] Plane selection
|
||||
#define MODAL_GROUP_G3 3 // [G90,G91] Distance mode
|
||||
#define MODAL_GROUP_G4 4 // [G91.1] Arc IJK distance mode
|
||||
#define MODAL_GROUP_G5 5 // [G93,G94] Feed rate mode
|
||||
#define MODAL_GROUP_G6 6 // [G20,G21] Units
|
||||
#define MODAL_GROUP_G7 7 // [G40] Cutter radius compensation mode. G41/42 NOT SUPPORTED.
|
||||
#define MODAL_GROUP_G8 8 // [G43.1,G49] Tool length offset
|
||||
#define MODAL_GROUP_G12 9 // [G54,G55,G56,G57,G58,G59] Coordinate system selection
|
||||
#define MODAL_GROUP_G13 10 // [G61] Control mode
|
||||
|
||||
#define MODAL_GROUP_M4 11 // [M0,M1,M2,M30] Stopping
|
||||
#define MODAL_GROUP_M6 14 // [M6] Tool change
|
||||
#define MODAL_GROUP_M7 12 // [M3,M4,M5] Spindle turning
|
||||
#define MODAL_GROUP_M8 13 // [M7,M8,M9] Coolant control
|
||||
#define MODAL_GROUP_M9 14 // [M56] Override control
|
||||
#define MODAL_GROUP_M10 15 // [M62, M63] User Defined http://linuxcnc.org/docs/html/gcode/overview.html#_modal_groups
|
||||
|
||||
// #define OTHER_INPUT_F 14
|
||||
// #define OTHER_INPUT_S 15
|
||||
// #define OTHER_INPUT_T 16
|
||||
|
||||
// Define command actions for within execution-type modal groups (motion, stopping, non-modal). Used
|
||||
// internally by the parser to know which command to execute.
|
||||
// NOTE: Some macro values are assigned specific values to make g-code state reporting and parsing
|
||||
// compile a litte smaller. Necessary due to being completely out of flash on the 328p. Although not
|
||||
// ideal, just be careful with values that state 'do not alter' and check both report.c and gcode.c
|
||||
// to see how they are used, if you need to alter them.
|
||||
|
||||
// Modal Group G0: Non-modal actions
|
||||
#define NON_MODAL_NO_ACTION 0 // (Default: Must be zero)
|
||||
#define NON_MODAL_DWELL 4 // G4 (Do not alter value)
|
||||
#define NON_MODAL_SET_COORDINATE_DATA 10 // G10 (Do not alter value)
|
||||
#define NON_MODAL_GO_HOME_0 28 // G28 (Do not alter value)
|
||||
#define NON_MODAL_SET_HOME_0 38 // G28.1 (Do not alter value)
|
||||
#define NON_MODAL_GO_HOME_1 30 // G30 (Do not alter value)
|
||||
#define NON_MODAL_SET_HOME_1 40 // G30.1 (Do not alter value)
|
||||
#define NON_MODAL_ABSOLUTE_OVERRIDE 53 // G53 (Do not alter value)
|
||||
#define NON_MODAL_SET_COORDINATE_OFFSET 92 // G92 (Do not alter value)
|
||||
#define NON_MODAL_RESET_COORDINATE_OFFSET 102 //G92.1 (Do not alter value)
|
||||
|
||||
// Modal Group G1: Motion modes
|
||||
#define MOTION_MODE_SEEK 0 // G0 (Default: Must be zero)
|
||||
#define MOTION_MODE_LINEAR 1 // G1 (Do not alter value)
|
||||
#define MOTION_MODE_CW_ARC 2 // G2 (Do not alter value)
|
||||
#define MOTION_MODE_CCW_ARC 3 // G3 (Do not alter value)
|
||||
#define MOTION_MODE_PROBE_TOWARD 140 // G38.2 (Do not alter value)
|
||||
#define MOTION_MODE_PROBE_TOWARD_NO_ERROR 141 // G38.3 (Do not alter value)
|
||||
#define MOTION_MODE_PROBE_AWAY 142 // G38.4 (Do not alter value)
|
||||
#define MOTION_MODE_PROBE_AWAY_NO_ERROR 143 // G38.5 (Do not alter value)
|
||||
#define MOTION_MODE_NONE 80 // G80 (Do not alter value)
|
||||
|
||||
// Modal Group G2: Plane select
|
||||
#define PLANE_SELECT_XY 0 // G17 (Default: Must be zero)
|
||||
#define PLANE_SELECT_ZX 1 // G18 (Do not alter value)
|
||||
#define PLANE_SELECT_YZ 2 // G19 (Do not alter value)
|
||||
|
||||
// Modal Group G3: Distance mode
|
||||
#define DISTANCE_MODE_ABSOLUTE 0 // G90 (Default: Must be zero)
|
||||
#define DISTANCE_MODE_INCREMENTAL 1 // G91 (Do not alter value)
|
||||
|
||||
// Modal Group G4: Arc IJK distance mode
|
||||
#define DISTANCE_ARC_MODE_INCREMENTAL 0 // G91.1 (Default: Must be zero)
|
||||
|
||||
// Modal Group M4: Program flow
|
||||
#define PROGRAM_FLOW_RUNNING 0 // (Default: Must be zero)
|
||||
#define PROGRAM_FLOW_PAUSED 3 // M0
|
||||
#define PROGRAM_FLOW_OPTIONAL_STOP 1 // M1 NOTE: Not supported, but valid and ignored.
|
||||
#define PROGRAM_FLOW_COMPLETED_M2 2 // M2 (Do not alter value)
|
||||
#define PROGRAM_FLOW_COMPLETED_M30 30 // M30 (Do not alter value)
|
||||
|
||||
// Modal Group G5: Feed rate mode
|
||||
#define FEED_RATE_MODE_UNITS_PER_MIN 0 // G94 (Default: Must be zero)
|
||||
#define FEED_RATE_MODE_INVERSE_TIME 1 // G93 (Do not alter value)
|
||||
|
||||
// Modal Group G6: Units mode
|
||||
#define UNITS_MODE_MM 0 // G21 (Default: Must be zero)
|
||||
#define UNITS_MODE_INCHES 1 // G20 (Do not alter value)
|
||||
|
||||
// Modal Group G7: Cutter radius compensation mode
|
||||
#define CUTTER_COMP_DISABLE 0 // G40 (Default: Must be zero)
|
||||
|
||||
// Modal Group G13: Control mode
|
||||
#define CONTROL_MODE_EXACT_PATH 0 // G61 (Default: Must be zero)
|
||||
|
||||
// Modal Group M7: Spindle control
|
||||
#define SPINDLE_DISABLE 0 // M5 (Default: Must be zero)
|
||||
#define SPINDLE_ENABLE_CW PL_COND_FLAG_SPINDLE_CW // M3 (NOTE: Uses planner condition bit flag)
|
||||
#define SPINDLE_ENABLE_CCW PL_COND_FLAG_SPINDLE_CCW // M4 (NOTE: Uses planner condition bit flag)
|
||||
|
||||
// Modal Group M8: Coolant control
|
||||
#define COOLANT_DISABLE 0 // M9 (Default: Must be zero)
|
||||
#define COOLANT_FLOOD_ENABLE PL_COND_FLAG_COOLANT_FLOOD // M8 (NOTE: Uses planner condition bit flag)
|
||||
#define COOLANT_MIST_ENABLE PL_COND_FLAG_COOLANT_MIST // M7 (NOTE: Uses planner condition bit flag)
|
||||
|
||||
// Modal Group M9: Override control
|
||||
#ifdef DEACTIVATE_PARKING_UPON_INIT
|
||||
#define OVERRIDE_DISABLED 0 // (Default: Must be zero)
|
||||
#define OVERRIDE_PARKING_MOTION 1 // M56
|
||||
#else
|
||||
#define OVERRIDE_PARKING_MOTION 0 // M56 (Default: Must be zero)
|
||||
#define OVERRIDE_DISABLED 1 // Parking disabled.
|
||||
#endif
|
||||
|
||||
// modal Group M10: User I/O control
|
||||
#define NON_MODAL_IO_ENABLE 1
|
||||
#define NON_MODAL_IO_DISABLE 2
|
||||
#define MAX_USER_DIGITAL_PIN 4
|
||||
|
||||
// Modal Group G8: Tool length offset
|
||||
#define TOOL_LENGTH_OFFSET_CANCEL 0 // G49 (Default: Must be zero)
|
||||
#define TOOL_LENGTH_OFFSET_ENABLE_DYNAMIC 1 // G43.1
|
||||
|
||||
#define TOOL_CHANGE 1
|
||||
|
||||
// Modal Group G12: Active work coordinate system
|
||||
// N/A: Stores coordinate system value (54-59) to change to.
|
||||
|
||||
// Define parameter word mapping.
|
||||
#define WORD_F 0
|
||||
#define WORD_I 1
|
||||
#define WORD_J 2
|
||||
#define WORD_K 3
|
||||
#define WORD_L 4
|
||||
#define WORD_N 5
|
||||
#define WORD_P 6
|
||||
#define WORD_R 7
|
||||
#define WORD_S 8
|
||||
#define WORD_T 9
|
||||
#define WORD_X 10
|
||||
#define WORD_Y 11
|
||||
#define WORD_Z 12
|
||||
#define WORD_A 13
|
||||
#define WORD_B 14
|
||||
#define WORD_C 15
|
||||
|
||||
// Define g-code parser position updating flags
|
||||
#define GC_UPDATE_POS_TARGET 0 // Must be zero
|
||||
#define GC_UPDATE_POS_SYSTEM 1
|
||||
#define GC_UPDATE_POS_NONE 2
|
||||
|
||||
// Define probe cycle exit states and assign proper position updating.
|
||||
#define GC_PROBE_FOUND GC_UPDATE_POS_SYSTEM
|
||||
#define GC_PROBE_ABORT GC_UPDATE_POS_NONE
|
||||
#define GC_PROBE_FAIL_INIT GC_UPDATE_POS_NONE
|
||||
#define GC_PROBE_FAIL_END GC_UPDATE_POS_TARGET
|
||||
#ifdef SET_CHECK_MODE_PROBE_TO_START
|
||||
#define GC_PROBE_CHECK_MODE GC_UPDATE_POS_NONE
|
||||
#else
|
||||
#define GC_PROBE_CHECK_MODE GC_UPDATE_POS_TARGET
|
||||
#endif
|
||||
|
||||
// Define gcode parser flags for handling special cases.
|
||||
#define GC_PARSER_NONE 0 // Must be zero.
|
||||
#define GC_PARSER_JOG_MOTION bit(0)
|
||||
#define GC_PARSER_CHECK_MANTISSA bit(1)
|
||||
#define GC_PARSER_ARC_IS_CLOCKWISE bit(2)
|
||||
#define GC_PARSER_PROBE_IS_AWAY bit(3)
|
||||
#define GC_PARSER_PROBE_IS_NO_ERROR bit(4)
|
||||
#define GC_PARSER_LASER_FORCE_SYNC bit(5)
|
||||
#define GC_PARSER_LASER_DISABLE bit(6)
|
||||
#define GC_PARSER_LASER_ISMOTION bit(7)
|
||||
|
||||
|
||||
// NOTE: When this struct is zeroed, the above defines set the defaults for the system.
|
||||
typedef struct {
|
||||
uint8_t motion; // {G0,G1,G2,G3,G38.2,G80}
|
||||
uint8_t feed_rate; // {G93,G94}
|
||||
uint8_t units; // {G20,G21}
|
||||
uint8_t distance; // {G90,G91}
|
||||
// uint8_t distance_arc; // {G91.1} NOTE: Don't track. Only default supported.
|
||||
uint8_t plane_select; // {G17,G18,G19}
|
||||
// uint8_t cutter_comp; // {G40} NOTE: Don't track. Only default supported.
|
||||
uint8_t tool_length; // {G43.1,G49}
|
||||
uint8_t coord_select; // {G54,G55,G56,G57,G58,G59}
|
||||
// uint8_t control; // {G61} NOTE: Don't track. Only default supported.
|
||||
uint8_t program_flow; // {M0,M1,M2,M30}
|
||||
uint8_t coolant; // {M7,M8,M9}
|
||||
uint8_t spindle; // {M3,M4,M5}
|
||||
uint8_t tool_change; // {M6}
|
||||
uint8_t io_control; // {M62, M63}
|
||||
uint8_t override; // {M56}
|
||||
} gc_modal_t;
|
||||
|
||||
typedef struct {
|
||||
float f; // Feed
|
||||
float ijk[N_AXIS]; // I,J,K Axis arc offsets
|
||||
uint8_t l; // G10 or canned cycles parameters
|
||||
int32_t n; // Line number
|
||||
float p; // G10 or dwell parameters
|
||||
// float q; // G82 peck drilling
|
||||
float r; // Arc radius
|
||||
float s; // Spindle speed
|
||||
uint8_t t; // Tool selection
|
||||
float xyz[N_AXIS]; // X,Y,Z Translational axes
|
||||
} gc_values_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
gc_modal_t modal;
|
||||
|
||||
float spindle_speed; // RPM
|
||||
float feed_rate; // Millimeters/min
|
||||
uint8_t tool; // Tracks tool number. NOT USED.
|
||||
int32_t line_number; // Last line number sent
|
||||
|
||||
float position[N_AXIS]; // Where the interpreter considers the tool to be at this point in the code
|
||||
|
||||
float coord_system[N_AXIS]; // Current work coordinate system (G54+). Stores offset from absolute machine
|
||||
// position in mm. Loaded from EEPROM when called.
|
||||
float coord_offset[N_AXIS]; // Retains the G92 coordinate offset (work coordinates) relative to
|
||||
// machine zero in mm. Non-persistent. Cleared upon reset and boot.
|
||||
float tool_length_offset; // Tracks tool length offset value when enabled.
|
||||
} parser_state_t;
|
||||
extern parser_state_t gc_state;
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint8_t non_modal_command;
|
||||
gc_modal_t modal;
|
||||
gc_values_t values;
|
||||
} parser_block_t;
|
||||
|
||||
|
||||
// Initialize the parser
|
||||
void gc_init();
|
||||
|
||||
// Execute one block of rs275/ngc/g-code
|
||||
uint8_t gc_execute_line(char* line, uint8_t client);
|
||||
|
||||
// Set g-code parser position. Input in steps.
|
||||
void gc_sync_position();
|
||||
|
||||
#endif
|
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* Connect the SD card to the following pins:
|
||||
*
|
||||
* SD Card | ESP32
|
||||
* D2 -
|
||||
* D3 SS
|
||||
* CMD MOSI
|
||||
* VSS GND
|
||||
* VDD 3.3V
|
||||
* CLK SCK
|
||||
* VSS GND
|
||||
* D0 MISO
|
||||
* D1 -
|
||||
*/
|
||||
|
||||
#ifndef grbl_sd_h
|
||||
#define grbl_sd_h
|
||||
|
||||
|
||||
#include "grbl.h"
|
||||
#include "FS.h"
|
||||
#include "SD.h"
|
||||
#include "SPI.h"
|
||||
|
||||
#define FILE_TYPE_COUNT 5 // number of acceptable gcode file types in array
|
||||
|
||||
#define SDCARD_DET_PIN -1
|
||||
#define SDCARD_DET_VAL 0
|
||||
|
||||
#define SDCARD_IDLE 0
|
||||
#define SDCARD_NOT_PRESENT 1
|
||||
#define SDCARD_BUSY_PRINTING 2
|
||||
#define SDCARD_BUSY_UPLOADING 4
|
||||
#define SDCARD_BUSY_PARSING 8
|
||||
|
||||
|
||||
|
||||
extern bool SD_ready_next; // Grbl has processed a line and is waiting for another
|
||||
extern uint8_t SD_client;
|
||||
|
||||
//bool sd_mount();
|
||||
uint8_t get_sd_state(bool refresh);
|
||||
uint8_t set_sd_state(uint8_t flag);
|
||||
void listDir(fs::FS& fs, const char* dirname, uint8_t levels, uint8_t client);
|
||||
boolean openFile(fs::FS& fs, const char* path);
|
||||
boolean closeFile();
|
||||
boolean readFileLine(char* line, int len);
|
||||
void readFile(fs::FS& fs, const char* path);
|
||||
float sd_report_perc_complete();
|
||||
uint32_t sd_get_current_line_number();
|
||||
void sd_get_current_filename(char* name);
|
||||
|
||||
#endif
|
@@ -1,907 +0,0 @@
|
||||
/*
|
||||
i2s_out.cpp
|
||||
Part of Grbl_ESP32
|
||||
|
||||
Basic GPIO expander using the ESP32 I2S peripheral (output)
|
||||
|
||||
2020 - Michiyasu Odaki
|
||||
|
||||
Grbl_ESP32 is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl_ESP32. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#include "config.h"
|
||||
|
||||
#ifdef USE_I2S_OUT
|
||||
|
||||
#include <FreeRTOS.h>
|
||||
#include <driver/periph_ctrl.h>
|
||||
#include <rom/lldesc.h>
|
||||
#include <soc/i2s_struct.h>
|
||||
#include <freertos/queue.h>
|
||||
|
||||
#include <stdatomic.h>
|
||||
|
||||
#include "Pins.h"
|
||||
#include "i2s_out.h"
|
||||
|
||||
//
|
||||
// Configrations for DMA connected I2S
|
||||
//
|
||||
// One DMA buffer transfer takes about 2 ms
|
||||
// I2S_OUT_DMABUF_LEN / I2S_SAMPLE_SIZE x I2S_OUT_USEC_PER_PULSE
|
||||
// = 2000 / 4 x 4
|
||||
// = 2000us = 2ms
|
||||
// If I2S_OUT_DMABUF_COUNT is 5, it will take about 10 ms for all the DMA buffer transfers to finish.
|
||||
//
|
||||
// Increasing I2S_OUT_DMABUF_COUNT has the effect of preventing buffer underflow,
|
||||
// but on the other hand, it leads to a delay with pulse and/or non-pulse-generated I/Os.
|
||||
// The number of I2S_OUT_DMABUF_COUNT should be chosen carefully.
|
||||
//
|
||||
// Reference information:
|
||||
// FreeRTOS task time slice = portTICK_PERIOD_MS = 1 ms (ESP32 FreeRTOS port)
|
||||
//
|
||||
#define I2S_SAMPLE_SIZE 4 /* 4 bytes, 32 bits per sample */
|
||||
#define DMA_SAMPLE_COUNT I2S_OUT_DMABUF_LEN / I2S_SAMPLE_SIZE /* number of samples per buffer */
|
||||
#define SAMPLE_SAFE_COUNT (20/I2S_OUT_USEC_PER_PULSE) /* prevent buffer overrun (GRBL's $0 should be less than or equal 20) */
|
||||
|
||||
#ifdef USE_I2S_OUT_STREAM
|
||||
typedef struct {
|
||||
uint32_t **buffers;
|
||||
uint32_t *current;
|
||||
uint32_t rw_pos;
|
||||
lldesc_t **desc;
|
||||
xQueueHandle queue;
|
||||
} i2s_out_dma_t;
|
||||
|
||||
static i2s_out_dma_t o_dma;
|
||||
static intr_handle_t i2s_out_isr_handle;
|
||||
#endif
|
||||
|
||||
// output value
|
||||
static atomic_uint_least32_t i2s_out_port_data = ATOMIC_VAR_INIT(0);
|
||||
|
||||
// inner lock
|
||||
static portMUX_TYPE i2s_out_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||
#define I2S_OUT_ENTER_CRITICAL() portENTER_CRITICAL(&i2s_out_spinlock)
|
||||
#define I2S_OUT_EXIT_CRITICAL() portEXIT_CRITICAL(&i2s_out_spinlock)
|
||||
#define I2S_OUT_ENTER_CRITICAL_ISR() portENTER_CRITICAL_ISR(&i2s_out_spinlock)
|
||||
#define I2S_OUT_EXIT_CRITICAL_ISR() portEXIT_CRITICAL_ISR(&i2s_out_spinlock)
|
||||
|
||||
static int i2s_out_initialized = 0;
|
||||
|
||||
#ifdef USE_I2S_OUT_STREAM
|
||||
static volatile uint32_t i2s_out_pulse_period;
|
||||
static uint32_t i2s_out_remain_time_until_next_pulse; // Time remaining until the next pulse (μsec)
|
||||
static volatile i2s_out_pulse_func_t i2s_out_pulse_func;
|
||||
#endif
|
||||
|
||||
static uint8_t i2s_out_ws_pin = 255;
|
||||
static uint8_t i2s_out_bck_pin = 255;
|
||||
static uint8_t i2s_out_data_pin = 255;
|
||||
|
||||
enum i2s_out_pulser_status_t {
|
||||
PASSTHROUGH = 0, // Static I2S mode.The i2s_out_write() reflected with very little delay
|
||||
STEPPING, // Streaming step data.
|
||||
WAITING, // Waiting for the step DMA completion
|
||||
};
|
||||
static volatile i2s_out_pulser_status_t i2s_out_pulser_status = PASSTHROUGH;
|
||||
|
||||
// outer lock
|
||||
static portMUX_TYPE i2s_out_pulser_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||
#define I2S_OUT_PULSER_ENTER_CRITICAL() portENTER_CRITICAL(&i2s_out_pulser_spinlock)
|
||||
#define I2S_OUT_PULSER_EXIT_CRITICAL() portEXIT_CRITICAL(&i2s_out_pulser_spinlock)
|
||||
#define I2S_OUT_PULSER_ENTER_CRITICAL_ISR() portENTER_CRITICAL_ISR(&i2s_out_pulser_spinlock)
|
||||
#define I2S_OUT_PULSER_EXIT_CRITICAL_ISR() portEXIT_CRITICAL_ISR(&i2s_out_pulser_spinlock)
|
||||
|
||||
//
|
||||
// Internal functions
|
||||
//
|
||||
static inline void gpio_matrix_out_check(uint8_t gpio, uint32_t signal_idx, bool out_inv, bool oen_inv) {
|
||||
//if pin == 255, do not need to configure
|
||||
if (gpio != 255) {
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[gpio], PIN_FUNC_GPIO);
|
||||
gpio_set_direction((gpio_num_t)gpio, (gpio_mode_t)GPIO_MODE_DEF_OUTPUT);
|
||||
gpio_matrix_out(gpio, signal_idx, out_inv, oen_inv);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void i2s_out_single_data() {
|
||||
#if I2S_OUT_NUM_BITS == 16
|
||||
uint32_t port_data = atomic_load(&i2s_out_port_data);
|
||||
port_data <<= 16; // Shift needed. This specification is not spelled out in the manual.
|
||||
I2S0.conf_single_data = port_data; // Apply port data in real-time (static I2S)
|
||||
#else
|
||||
I2S0.conf_single_data = atomic_load(&i2s_out_port_data); // Apply port data in real-time (static I2S)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void i2s_out_reset_fifo_without_lock() {
|
||||
I2S0.conf.rx_fifo_reset = 1;
|
||||
I2S0.conf.rx_fifo_reset = 0;
|
||||
I2S0.conf.tx_fifo_reset = 1;
|
||||
I2S0.conf.tx_fifo_reset = 0;
|
||||
}
|
||||
|
||||
static void IRAM_ATTR i2s_out_reset_fifo() {
|
||||
I2S_OUT_ENTER_CRITICAL();
|
||||
i2s_out_reset_fifo_without_lock();
|
||||
I2S_OUT_EXIT_CRITICAL();
|
||||
}
|
||||
|
||||
#ifdef USE_I2S_OUT_STREAM
|
||||
static int IRAM_ATTR i2s_clear_dma_buffer(lldesc_t *dma_desc, uint32_t port_data) {
|
||||
|
||||
uint32_t *buf = (uint32_t*)dma_desc->buf;
|
||||
for (int i = 0; i < DMA_SAMPLE_COUNT; i++) {
|
||||
buf[i] = port_data;
|
||||
}
|
||||
// Restore the buffer length.
|
||||
// The length may have been changed short when the data was filled in to prevent buffer overrun.
|
||||
dma_desc->length = I2S_OUT_DMABUF_LEN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int IRAM_ATTR i2s_clear_o_dma_buffers(uint32_t port_data) {
|
||||
for (int buf_idx = 0; buf_idx < I2S_OUT_DMABUF_COUNT; buf_idx++) {
|
||||
// Initialize DMA descriptor
|
||||
o_dma.desc[buf_idx]->owner = 1;
|
||||
o_dma.desc[buf_idx]->eof = 1; // set to 1 will trigger the interrupt
|
||||
o_dma.desc[buf_idx]->sosf = 0;
|
||||
o_dma.desc[buf_idx]->length = I2S_OUT_DMABUF_LEN;
|
||||
o_dma.desc[buf_idx]->size = I2S_OUT_DMABUF_LEN;
|
||||
o_dma.desc[buf_idx]->buf = (uint8_t *) o_dma.buffers[buf_idx];
|
||||
o_dma.desc[buf_idx]->offset = 0;
|
||||
o_dma.desc[buf_idx]->qe.stqe_next = (lldesc_t *)((buf_idx < (I2S_OUT_DMABUF_COUNT - 1)) ? (o_dma.desc[buf_idx + 1]) : o_dma.desc[0]);
|
||||
i2s_clear_dma_buffer(o_dma.desc[buf_idx], port_data);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int IRAM_ATTR i2s_out_gpio_attach(uint8_t ws, uint8_t bck, uint8_t data) {
|
||||
// Route the i2s pins to the appropriate GPIO
|
||||
gpio_matrix_out_check(data, I2S0O_DATA_OUT23_IDX, 0, 0);
|
||||
gpio_matrix_out_check(bck, I2S0O_BCK_OUT_IDX, 0, 0);
|
||||
gpio_matrix_out_check(ws, I2S0O_WS_OUT_IDX, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define I2S_OUT_DETACH_PORT_IDX 0x100
|
||||
|
||||
static int IRAM_ATTR i2s_out_gpio_detach(uint8_t ws, uint8_t bck, uint8_t data) {
|
||||
// Route the i2s pins to the appropriate GPIO
|
||||
gpio_matrix_out_check(ws, I2S_OUT_DETACH_PORT_IDX, 0, 0);
|
||||
gpio_matrix_out_check(bck, I2S_OUT_DETACH_PORT_IDX, 0, 0);
|
||||
gpio_matrix_out_check(data, I2S_OUT_DETACH_PORT_IDX, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int IRAM_ATTR i2s_out_gpio_shiftout(uint32_t port_data) {
|
||||
__digitalWrite(i2s_out_ws_pin, LOW);
|
||||
for (int i = 0; i <I2S_OUT_NUM_BITS; i++) {
|
||||
__digitalWrite(i2s_out_data_pin, !!(port_data & bit(I2S_OUT_NUM_BITS-1 - i)));
|
||||
__digitalWrite(i2s_out_bck_pin, HIGH);
|
||||
__digitalWrite(i2s_out_bck_pin, LOW);
|
||||
}
|
||||
__digitalWrite(i2s_out_ws_pin, HIGH); // Latch
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int IRAM_ATTR i2s_out_stop() {
|
||||
I2S_OUT_ENTER_CRITICAL();
|
||||
#ifdef USE_I2S_OUT_STREAM
|
||||
// Stop FIFO DMA
|
||||
I2S0.out_link.stop = 1;
|
||||
|
||||
// Disconnect DMA from FIFO
|
||||
I2S0.fifo_conf.dscr_en = 0; //Unset this bit to disable I2S DMA mode. (R/W)
|
||||
#endif
|
||||
// stop TX module
|
||||
I2S0.conf.tx_start = 0;
|
||||
|
||||
// Force WS to LOW before detach
|
||||
// This operation prevents unintended WS edge trigger when detach
|
||||
__digitalWrite(i2s_out_ws_pin, LOW);
|
||||
|
||||
// Now, detach GPIO pin from I2S
|
||||
i2s_out_gpio_detach(i2s_out_ws_pin, i2s_out_bck_pin, i2s_out_data_pin);
|
||||
|
||||
// Force BCK to LOW
|
||||
// After the TX module is stopped, BCK always seems to be in LOW.
|
||||
// However, I'm going to do it manually to ensure the BCK's LOW.
|
||||
__digitalWrite(i2s_out_bck_pin, LOW);
|
||||
|
||||
// Transmit recovery data to 74HC595
|
||||
uint32_t port_data = atomic_load(&i2s_out_port_data); // current expanded port value
|
||||
i2s_out_gpio_shiftout(port_data);
|
||||
|
||||
#ifdef USE_I2S_OUT_STREAM
|
||||
//clear pending interrupt
|
||||
I2S0.int_clr.val = I2S0.int_st.val;
|
||||
#endif
|
||||
I2S_OUT_EXIT_CRITICAL();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int IRAM_ATTR i2s_out_start() {
|
||||
if (!i2s_out_initialized) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
I2S_OUT_ENTER_CRITICAL();
|
||||
// Transmit recovery data to 74HC595
|
||||
uint32_t port_data = atomic_load(&i2s_out_port_data); // current expanded port value
|
||||
i2s_out_gpio_shiftout(port_data);
|
||||
|
||||
// Attach I2S to specified GPIO pin
|
||||
i2s_out_gpio_attach(i2s_out_ws_pin, i2s_out_bck_pin, i2s_out_data_pin);
|
||||
//start DMA link
|
||||
i2s_out_reset_fifo_without_lock();
|
||||
|
||||
#ifdef USE_I2S_OUT_STREAM
|
||||
if (i2s_out_pulser_status == PASSTHROUGH) {
|
||||
I2S0.conf_chan.tx_chan_mod = 3; // 3:right+constant 4:left+constant (when tx_msb_right = 1)
|
||||
I2S0.conf_single_data = port_data;
|
||||
} else {
|
||||
I2S0.conf_chan.tx_chan_mod = 4; // 3:right+constant 4:left+constant (when tx_msb_right = 1)
|
||||
I2S0.conf_single_data = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_I2S_OUT_STREAM
|
||||
//reset DMA
|
||||
I2S0.lc_conf.in_rst = 1;
|
||||
I2S0.lc_conf.in_rst = 0;
|
||||
I2S0.lc_conf.out_rst = 1;
|
||||
I2S0.lc_conf.out_rst = 0;
|
||||
|
||||
I2S0.out_link.addr = (uint32_t)o_dma.desc[0];
|
||||
#endif
|
||||
|
||||
I2S0.conf.tx_reset = 1;
|
||||
I2S0.conf.tx_reset = 0;
|
||||
I2S0.conf.rx_reset = 1;
|
||||
I2S0.conf.rx_reset = 0;
|
||||
|
||||
I2S0.conf1.tx_stop_en = 1; // BCK and WCK are suppressed while FIFO is empty
|
||||
|
||||
#ifdef USE_I2S_OUT_STREAM
|
||||
// Connect DMA to FIFO
|
||||
I2S0.fifo_conf.dscr_en = 1; // Set this bit to enable I2S DMA mode. (R/W)
|
||||
|
||||
I2S0.int_clr.val = 0xFFFFFFFF;
|
||||
I2S0.out_link.start = 1;
|
||||
#endif
|
||||
I2S0.conf.tx_start = 1;
|
||||
// Wait for the first FIFO data to prevent the unintentional generation of 0 data
|
||||
ets_delay_us(20);
|
||||
I2S0.conf1.tx_stop_en = 0; // BCK and WCK are generated regardless of the FIFO status
|
||||
|
||||
I2S_OUT_EXIT_CRITICAL();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef USE_I2S_OUT_STREAM
|
||||
|
||||
static int IRAM_ATTR i2s_fillout_dma_buffer(lldesc_t *dma_desc) {
|
||||
uint32_t *buf = (uint32_t*)dma_desc->buf;
|
||||
o_dma.rw_pos = 0;
|
||||
// It reuses the oldest (just transferred) buffer with the name "current"
|
||||
// and fills the buffer for later DMA.
|
||||
I2S_OUT_PULSER_ENTER_CRITICAL(); // Lock pulser status
|
||||
if (i2s_out_pulser_status == STEPPING) {
|
||||
//
|
||||
// Fillout the buffer for pulse
|
||||
//
|
||||
// To avoid buffer overflow, all of the maximum pulse width (normaly about 10us)
|
||||
// is adjusted to be in a single buffer.
|
||||
// DMA_SAMPLE_SAFE_COUNT is referred to as the margin value.
|
||||
// Therefore, if a buffer is close to full and it is time to generate a pulse,
|
||||
// the generation of the buffer is interrupted (the buffer length is shortened slightly)
|
||||
// and the pulse generation is postponed until the next buffer is filled.
|
||||
//
|
||||
o_dma.rw_pos = 0;
|
||||
while (o_dma.rw_pos < (DMA_SAMPLE_COUNT - SAMPLE_SAFE_COUNT)) {
|
||||
// no data to read (buffer empty)
|
||||
if (i2s_out_remain_time_until_next_pulse < I2S_OUT_USEC_PER_PULSE) {
|
||||
// pulser status may change in pulse phase func, so I need to check it every time.
|
||||
if (i2s_out_pulser_status == STEPPING) {
|
||||
// fillout future DMA buffer (tail of the DMA buffer chains)
|
||||
if (i2s_out_pulse_func != NULL) {
|
||||
I2S_OUT_PULSER_EXIT_CRITICAL(); // Temporarily unlocked status lock as it may be locked in pulse callback.
|
||||
(*i2s_out_pulse_func)(); // should be pushed into buffer max DMA_SAMPLE_SAFE_COUNT
|
||||
I2S_OUT_PULSER_ENTER_CRITICAL(); // Lock again.
|
||||
i2s_out_remain_time_until_next_pulse = i2s_out_pulse_period;
|
||||
if (i2s_out_pulser_status == WAITING) {
|
||||
// i2s_out_set_passthrough() has called from the pulse function.
|
||||
// It needs to go into pass-through mode.
|
||||
// This DMA descriptor must be a tail of the chain.
|
||||
dma_desc->qe.stqe_next = NULL; // Cut the DMA descriptor ring. This allow us to identify the tail of the buffer.
|
||||
} else if (i2s_out_pulser_status == PASSTHROUGH) {
|
||||
// i2s_out_reset() has called during the execution of the pulse function.
|
||||
// I2S has already in static mode, and buffers has cleared to zero.
|
||||
// To prevent the pulse function from being called back,
|
||||
// we assume that the buffer is already full.
|
||||
i2s_out_remain_time_until_next_pulse = 0; // There is no need to fill the current buffer.
|
||||
o_dma.rw_pos = DMA_SAMPLE_COUNT; // The buffer is full.
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
// no pulse data in push buffer (pulse off or idle or callback is not defined)
|
||||
buf[o_dma.rw_pos++] = atomic_load(&i2s_out_port_data);
|
||||
if (i2s_out_remain_time_until_next_pulse >= I2S_OUT_USEC_PER_PULSE) {
|
||||
i2s_out_remain_time_until_next_pulse -= I2S_OUT_USEC_PER_PULSE;
|
||||
} else {
|
||||
i2s_out_remain_time_until_next_pulse = 0;
|
||||
}
|
||||
}
|
||||
// set filled length to the DMA descriptor
|
||||
dma_desc->length = o_dma.rw_pos * I2S_SAMPLE_SIZE;
|
||||
} else if (i2s_out_pulser_status == WAITING) {
|
||||
i2s_clear_dma_buffer(dma_desc, 0); // Essentially, no clearing is required. I'll make sure I know when I've written something.
|
||||
o_dma.rw_pos = 0; // If someone calls i2s_out_push_sample, make sure there is no buffer overflow
|
||||
dma_desc->qe.stqe_next = NULL; // Cut the DMA descriptor ring. This allow us to identify the tail of the buffer.
|
||||
} else {
|
||||
// Stepper paused (passthrough state, static I2S control mode)
|
||||
// In the passthrough mode, there is no need to fill the buffer with port_data.
|
||||
i2s_clear_dma_buffer(dma_desc, 0); // Essentially, no clearing is required. I'll make sure I know when I've written something.
|
||||
o_dma.rw_pos = 0; // If someone calls i2s_out_push_sample, make sure there is no buffer overflow
|
||||
}
|
||||
I2S_OUT_PULSER_EXIT_CRITICAL(); // Unlock pulser status
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// I2S out DMA Interrupts handler
|
||||
//
|
||||
static void IRAM_ATTR i2s_out_intr_handler(void *arg) {
|
||||
lldesc_t *finish_desc;
|
||||
portBASE_TYPE high_priority_task_awoken = pdFALSE;
|
||||
|
||||
if (I2S0.int_st.out_eof || I2S0.int_st.out_total_eof) {
|
||||
if (I2S0.int_st.out_total_eof) {
|
||||
// This is tail of the DMA descriptors
|
||||
I2S_OUT_ENTER_CRITICAL_ISR();
|
||||
// Stop FIFO DMA
|
||||
I2S0.out_link.stop = 1;
|
||||
// Disconnect DMA from FIFO
|
||||
I2S0.fifo_conf.dscr_en = 0; //Unset this bit to disable I2S DMA mode. (R/W)
|
||||
// Stop TX module
|
||||
I2S0.conf.tx_start = 0;
|
||||
I2S_OUT_EXIT_CRITICAL_ISR();
|
||||
}
|
||||
// Get the descriptor of the last item in the linkedlist
|
||||
finish_desc = (lldesc_t*) I2S0.out_eof_des_addr;
|
||||
|
||||
// If the queue is full it's because we have an underflow,
|
||||
// more than buf_count isr without new data, remove the front buffer
|
||||
if (xQueueIsQueueFullFromISR(o_dma.queue)) {
|
||||
lldesc_t *front_desc;
|
||||
// Remove a descriptor from the DMA complete event queue
|
||||
xQueueReceiveFromISR(o_dma.queue, &front_desc, &high_priority_task_awoken);
|
||||
I2S_OUT_PULSER_ENTER_CRITICAL_ISR();
|
||||
uint32_t port_data = 0;
|
||||
if (i2s_out_pulser_status == STEPPING) {
|
||||
port_data = atomic_load(&i2s_out_port_data);
|
||||
}
|
||||
I2S_OUT_PULSER_EXIT_CRITICAL_ISR();
|
||||
for (int i = 0; i < DMA_SAMPLE_COUNT; i++) {
|
||||
front_desc->buf[i] = port_data;
|
||||
}
|
||||
front_desc->length = I2S_OUT_DMABUF_LEN;
|
||||
}
|
||||
|
||||
// Send a DMA complete event to the I2S bitstreamer task with finished buffer
|
||||
xQueueSendFromISR(o_dma.queue, &finish_desc, &high_priority_task_awoken);
|
||||
}
|
||||
|
||||
if (high_priority_task_awoken == pdTRUE) portYIELD_FROM_ISR();
|
||||
|
||||
// clear interrupt
|
||||
I2S0.int_clr.val = I2S0.int_st.val; //clear pending interrupt
|
||||
}
|
||||
|
||||
//
|
||||
// I2S bitstream generator task
|
||||
//
|
||||
static void IRAM_ATTR i2sOutTask(void* parameter) {
|
||||
lldesc_t *dma_desc;
|
||||
while (1) {
|
||||
// Wait a DMA complete event from I2S isr
|
||||
// (Block until a DMA transfer has complete)
|
||||
xQueueReceive(o_dma.queue, &dma_desc, portMAX_DELAY);
|
||||
o_dma.current = (uint32_t*)(dma_desc->buf);
|
||||
// It reuses the oldest (just transferred) buffer with the name "current"
|
||||
// and fills the buffer for later DMA.
|
||||
I2S_OUT_PULSER_ENTER_CRITICAL(); // Lock pulser status
|
||||
if (i2s_out_pulser_status == STEPPING) {
|
||||
//
|
||||
// Fillout the buffer for pulse
|
||||
//
|
||||
// To avoid buffer overflow, all of the maximum pulse width (normaly about 10us)
|
||||
// is adjusted to be in a single buffer.
|
||||
// DMA_SAMPLE_SAFE_COUNT is referred to as the margin value.
|
||||
// Therefore, if a buffer is close to full and it is time to generate a pulse,
|
||||
// the generation of the buffer is interrupted (the buffer length is shortened slightly)
|
||||
// and the pulse generation is postponed until the next buffer is filled.
|
||||
//
|
||||
i2s_fillout_dma_buffer(dma_desc);
|
||||
dma_desc->length = o_dma.rw_pos * I2S_SAMPLE_SIZE;
|
||||
} else if (i2s_out_pulser_status == WAITING) {
|
||||
if (dma_desc->qe.stqe_next == NULL) {
|
||||
// Tail of the DMA descriptor found
|
||||
// I2S TX module has alrewdy stopped by ISR
|
||||
i2s_out_stop();
|
||||
i2s_clear_o_dma_buffers(0); // 0 for static I2S control mode (right ch. data is always 0)
|
||||
// You need to set the status before calling i2s_out_start()
|
||||
// because the process in i2s_out_start() is different depending on the status.
|
||||
i2s_out_pulser_status = PASSTHROUGH;
|
||||
i2s_out_start();
|
||||
} else {
|
||||
// Processing a buffer slightly ahead of the tail buffer.
|
||||
// We don't need to fill up the buffer by port_data any more.
|
||||
i2s_clear_dma_buffer(dma_desc, 0); // Essentially, no clearing is required. I'll make sure I know when I've written something.
|
||||
o_dma.rw_pos = 0; // If someone calls i2s_out_push_sample, make sure there is no buffer overflow
|
||||
dma_desc->qe.stqe_next = NULL; // Cut the DMA descriptor ring. This allow us to identify the tail of the buffer.
|
||||
}
|
||||
} else {
|
||||
// Stepper paused (passthrough state, static I2S control mode)
|
||||
// In the passthrough mode, there is no need to fill the buffer with port_data.
|
||||
i2s_clear_dma_buffer(dma_desc, 0); // Essentially, no clearing is required. I'll make sure I know when I've written something.
|
||||
o_dma.rw_pos = 0; // If someone calls i2s_out_push_sample, make sure there is no buffer overflow
|
||||
}
|
||||
I2S_OUT_PULSER_EXIT_CRITICAL(); // Unlock pulser status
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
// External funtions
|
||||
//
|
||||
void IRAM_ATTR i2s_out_delay() {
|
||||
#ifdef USE_I2S_OUT_STREAM
|
||||
I2S_OUT_PULSER_ENTER_CRITICAL();
|
||||
if (i2s_out_pulser_status == PASSTHROUGH) {
|
||||
// Depending on the timing, it may not be reflected immediately,
|
||||
// so wait twice as long just in case.
|
||||
ets_delay_us(I2S_OUT_USEC_PER_PULSE * 2);
|
||||
} else {
|
||||
// Just wait until the data now registered in the DMA descripter
|
||||
// is reflected in the I2S TX module via FIFO.
|
||||
delay(I2S_OUT_DELAY_MS);
|
||||
}
|
||||
I2S_OUT_PULSER_EXIT_CRITICAL();
|
||||
#else
|
||||
ets_delay_us(I2S_OUT_USEC_PER_PULSE * 2);
|
||||
#endif
|
||||
}
|
||||
|
||||
void IRAM_ATTR i2s_out_write(uint8_t pin, uint8_t val) {
|
||||
uint32_t bit = bit(pin);
|
||||
if (val) {
|
||||
atomic_fetch_or(&i2s_out_port_data, bit);
|
||||
} else {
|
||||
atomic_fetch_and(&i2s_out_port_data, ~bit);
|
||||
}
|
||||
#ifdef USE_I2S_OUT_STREAM
|
||||
// It needs a lock for access, but I've given up because I need speed.
|
||||
// This is not a problem as long as there is no overlap between the status change and digitalWrite().
|
||||
if (i2s_out_pulser_status == PASSTHROUGH) {
|
||||
i2s_out_single_data();
|
||||
}
|
||||
#else
|
||||
i2s_out_single_data();
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t IRAM_ATTR i2s_out_state(uint8_t pin) {
|
||||
uint32_t port_data = atomic_load(&i2s_out_port_data);
|
||||
return (!!(port_data & bit(pin)));
|
||||
}
|
||||
|
||||
uint32_t IRAM_ATTR i2s_out_push_sample(uint32_t num) {
|
||||
#ifdef USE_I2S_OUT_STREAM
|
||||
if (num > SAMPLE_SAFE_COUNT) {
|
||||
return 0;
|
||||
}
|
||||
// push at least one sample (even if num is zero)
|
||||
uint32_t port_data = atomic_load(&i2s_out_port_data);
|
||||
uint32_t n = 0;
|
||||
do {
|
||||
o_dma.current[o_dma.rw_pos++] = port_data;
|
||||
n++;
|
||||
} while(n < num);
|
||||
return n;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int IRAM_ATTR i2s_out_set_passthrough() {
|
||||
I2S_OUT_PULSER_ENTER_CRITICAL();
|
||||
#ifdef USE_I2S_OUT_STREAM
|
||||
if (i2s_out_pulser_status == STEPPING) {
|
||||
i2s_out_pulser_status = WAITING; // Start stopping the pulser
|
||||
}
|
||||
#else
|
||||
i2s_out_pulser_status = PASSTHROUGH;
|
||||
#endif
|
||||
I2S_OUT_PULSER_EXIT_CRITICAL();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int IRAM_ATTR i2s_out_set_stepping() {
|
||||
I2S_OUT_PULSER_ENTER_CRITICAL();
|
||||
#ifdef USE_I2S_OUT_STREAM
|
||||
if (i2s_out_pulser_status == STEPPING) {
|
||||
// Re-entered (fail safe)
|
||||
I2S_OUT_PULSER_EXIT_CRITICAL();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (i2s_out_pulser_status == WAITING) {
|
||||
// Wait for complete DMAs
|
||||
for(;;) {
|
||||
I2S_OUT_PULSER_EXIT_CRITICAL();
|
||||
delay(I2S_OUT_DELAY_DMABUF_MS);
|
||||
I2S_OUT_PULSER_ENTER_CRITICAL();
|
||||
if (i2s_out_pulser_status == WAITING) {
|
||||
continue;
|
||||
}
|
||||
if (i2s_out_pulser_status == PASSTHROUGH) {
|
||||
// DMA completed
|
||||
break;
|
||||
}
|
||||
// Another function change the I2S state to STEPPING
|
||||
I2S_OUT_PULSER_EXIT_CRITICAL();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Change I2S state from PASSTHROUGH to STEPPING
|
||||
i2s_out_stop();
|
||||
uint32_t port_data = atomic_load(&i2s_out_port_data);
|
||||
i2s_clear_o_dma_buffers(port_data);
|
||||
|
||||
// You need to set the status before calling i2s_out_start()
|
||||
// because the process in i2s_out_start() is different depending on the status.
|
||||
i2s_out_pulser_status = STEPPING;
|
||||
i2s_out_start();
|
||||
#else
|
||||
i2s_out_pulser_status = STEPPING;
|
||||
#endif
|
||||
I2S_OUT_PULSER_EXIT_CRITICAL();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int IRAM_ATTR i2s_out_set_pulse_period(uint32_t period) {
|
||||
#ifdef USE_I2S_OUT_STREAM
|
||||
i2s_out_pulse_period = period;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int IRAM_ATTR i2s_out_set_pulse_callback(i2s_out_pulse_func_t func) {
|
||||
#ifdef USE_I2S_OUT_STREAM
|
||||
i2s_out_pulse_func = func;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int IRAM_ATTR i2s_out_reset() {
|
||||
I2S_OUT_PULSER_ENTER_CRITICAL();
|
||||
i2s_out_stop();
|
||||
#ifdef USE_I2S_OUT_STREAM
|
||||
if (i2s_out_pulser_status == STEPPING) {
|
||||
uint32_t port_data = atomic_load(&i2s_out_port_data);
|
||||
i2s_clear_o_dma_buffers(port_data);
|
||||
} else if (i2s_out_pulser_status == WAITING) {
|
||||
i2s_clear_o_dma_buffers(0);
|
||||
i2s_out_pulser_status = PASSTHROUGH;
|
||||
}
|
||||
#endif
|
||||
// You need to set the status before calling i2s_out_start()
|
||||
// because the process in i2s_out_start() is different depending on the status.
|
||||
i2s_out_start();
|
||||
I2S_OUT_PULSER_EXIT_CRITICAL();
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Initialize funtion (external function)
|
||||
//
|
||||
int IRAM_ATTR i2s_out_init(i2s_out_init_t &init_param) {
|
||||
if (i2s_out_initialized) {
|
||||
// already initialized
|
||||
return -1;
|
||||
}
|
||||
|
||||
atomic_store(&i2s_out_port_data, init_param.init_val);
|
||||
|
||||
// To make sure hardware is enabled before any hardware register operations.
|
||||
periph_module_reset(PERIPH_I2S0_MODULE);
|
||||
periph_module_enable(PERIPH_I2S0_MODULE);
|
||||
|
||||
// Route the i2s pins to the appropriate GPIO
|
||||
i2s_out_gpio_attach(init_param.ws_pin, init_param.bck_pin, init_param.data_pin);
|
||||
|
||||
/**
|
||||
* Each i2s transfer will take
|
||||
* fpll = PLL_D2_CLK -- clka_en = 0
|
||||
*
|
||||
* fi2s = fpll / N + b/a -- N + b/a = clkm_div_num
|
||||
* fi2s = 160MHz / 2
|
||||
* fi2s = 80MHz
|
||||
*
|
||||
* fbclk = fi2s / M -- M = tx_bck_div_num
|
||||
* fbclk = 80MHz / 2
|
||||
* fbclk = 40MHz
|
||||
*
|
||||
* fwclk = fbclk / 32
|
||||
*
|
||||
* for fwclk = 250kHz(16-bit: 4µS pulse time), 125kHz(32-bit: 8μS pulse time)
|
||||
* N = 10, b/a = 0
|
||||
* M = 2
|
||||
* for fwclk = 500kHz(16-bit: 2µS pulse time), 250kHz(32-bit: 4μS pulse time)
|
||||
* N = 5, b/a = 0
|
||||
* M = 2
|
||||
* for fwclk = 1000kHz(16-bit: 1µS pulse time), 500kHz(32-bit: 2μS pulse time)
|
||||
* N = 2, b/a = 2/1 (N + b/a = 2.5)
|
||||
* M = 2
|
||||
*/
|
||||
|
||||
#ifdef USE_I2S_OUT_STREAM
|
||||
// Allocate the array of pointers to the buffers
|
||||
o_dma.buffers = (uint32_t **)malloc(sizeof(uint32_t*) * I2S_OUT_DMABUF_COUNT);
|
||||
if (o_dma.buffers == nullptr) return -1;
|
||||
|
||||
// Allocate each buffer that can be used by the DMA controller
|
||||
for (int buf_idx = 0; buf_idx < I2S_OUT_DMABUF_COUNT; buf_idx++) {
|
||||
o_dma.buffers[buf_idx] = (uint32_t*) heap_caps_calloc(1, I2S_OUT_DMABUF_LEN, MALLOC_CAP_DMA);
|
||||
if (o_dma.buffers[buf_idx] == nullptr) return -1;
|
||||
}
|
||||
|
||||
// Allocate the array of DMA descriptors
|
||||
o_dma.desc = (lldesc_t**) malloc(sizeof(lldesc_t*) * I2S_OUT_DMABUF_COUNT);
|
||||
if (o_dma.desc == nullptr) return -1;
|
||||
|
||||
// Allocate each DMA descriptor that will be used by the DMA controller
|
||||
for (int buf_idx = 0; buf_idx < I2S_OUT_DMABUF_COUNT; buf_idx++) {
|
||||
o_dma.desc[buf_idx] = (lldesc_t*) heap_caps_malloc(sizeof(lldesc_t), MALLOC_CAP_DMA);
|
||||
if (o_dma.desc[buf_idx] == nullptr) return -1;
|
||||
}
|
||||
|
||||
// Initialize
|
||||
i2s_clear_o_dma_buffers(init_param.init_val);
|
||||
o_dma.rw_pos = 0;
|
||||
o_dma.current = NULL;
|
||||
o_dma.queue = xQueueCreate(I2S_OUT_DMABUF_COUNT, sizeof(uint32_t *));
|
||||
|
||||
// Set the first DMA descriptor
|
||||
I2S0.out_link.addr = (uint32_t)o_dma.desc[0];
|
||||
#endif
|
||||
|
||||
// stop i2s
|
||||
I2S0.out_link.stop = 1;
|
||||
I2S0.conf.tx_start = 0;
|
||||
|
||||
I2S0.int_clr.val = I2S0.int_st.val; //clear pending interrupt
|
||||
|
||||
//
|
||||
// i2s_param_config
|
||||
//
|
||||
|
||||
// configure I2S data port interface.
|
||||
i2s_out_reset_fifo();
|
||||
|
||||
//reset i2s
|
||||
I2S0.conf.tx_reset = 1;
|
||||
I2S0.conf.tx_reset = 0;
|
||||
I2S0.conf.rx_reset = 1;
|
||||
I2S0.conf.rx_reset = 0;
|
||||
|
||||
//reset dma
|
||||
I2S0.lc_conf.in_rst = 1; // Set this bit to reset in DMA FSM. (R/W)
|
||||
I2S0.lc_conf.in_rst = 0;
|
||||
I2S0.lc_conf.out_rst = 1; // Set this bit to reset out DMA FSM. (R/W)
|
||||
I2S0.lc_conf.out_rst = 0;
|
||||
|
||||
//Enable and configure DMA
|
||||
I2S0.lc_conf.check_owner = 0;
|
||||
I2S0.lc_conf.out_loop_test = 0;
|
||||
I2S0.lc_conf.out_auto_wrback = 0; // Disable auto outlink-writeback when all the data has been transmitted
|
||||
I2S0.lc_conf.out_data_burst_en = 0;
|
||||
I2S0.lc_conf.outdscr_burst_en = 0;
|
||||
I2S0.lc_conf.out_no_restart_clr = 0;
|
||||
I2S0.lc_conf.indscr_burst_en = 0;
|
||||
#ifdef USE_I2S_OUT_STREAM
|
||||
I2S0.lc_conf.out_eof_mode = 1; // I2S_OUT_EOF_INT generated when DMA has popped all data from the FIFO;
|
||||
#endif
|
||||
I2S0.conf2.lcd_en = 0;
|
||||
I2S0.conf2.camera_en = 0;
|
||||
I2S0.pdm_conf.pcm2pdm_conv_en = 0;
|
||||
I2S0.pdm_conf.pdm2pcm_conv_en = 0;
|
||||
|
||||
I2S0.fifo_conf.dscr_en = 0;
|
||||
|
||||
#ifdef USE_I2S_OUT_STREAM
|
||||
if (i2s_out_pulser_status == STEPPING) {
|
||||
// Stream output mode
|
||||
I2S0.conf_chan.tx_chan_mod = 4; // 3:right+constant 4:left+constant (when tx_msb_right = 1)
|
||||
I2S0.conf_single_data = 0;
|
||||
} else {
|
||||
// Static output mode
|
||||
I2S0.conf_chan.tx_chan_mod = 3; // 3:right+constant 4:left+constant (when tx_msb_right = 1)
|
||||
I2S0.conf_single_data = init_param.init_val;
|
||||
}
|
||||
#else
|
||||
// For the static output mode
|
||||
I2S0.conf_chan.tx_chan_mod = 3; // 3:right+constant 4:left+constant (when tx_msb_right = 1)
|
||||
I2S0.conf_single_data = init_param.init_val; // initial constant value
|
||||
#endif
|
||||
#if I2S_OUT_NUM_BITS == 16
|
||||
I2S0.fifo_conf.tx_fifo_mod = 0; // 0: 16-bit dual channel data, 3: 32-bit single channel data
|
||||
I2S0.fifo_conf.rx_fifo_mod = 0; // 0: 16-bit dual channel data, 3: 32-bit single channel data
|
||||
I2S0.sample_rate_conf.tx_bits_mod = 16; // default is 16-bits
|
||||
I2S0.sample_rate_conf.rx_bits_mod = 16; // default is 16-bits
|
||||
#else
|
||||
I2S0.fifo_conf.tx_fifo_mod = 3; // 0: 16-bit dual channel data, 3: 32-bit single channel data
|
||||
I2S0.fifo_conf.rx_fifo_mod = 3; // 0: 16-bit dual channel data, 3: 32-bit single channel data
|
||||
// Data width is 32-bit. Forgetting this setting will result in a 16-bit transfer.
|
||||
I2S0.sample_rate_conf.tx_bits_mod = 32;
|
||||
I2S0.sample_rate_conf.rx_bits_mod = 32;
|
||||
#endif
|
||||
I2S0.conf.tx_mono = 0; // Set this bit to enable transmitter’s mono mode in PCM standard mode.
|
||||
|
||||
I2S0.conf_chan.rx_chan_mod = 1; // 1: right+right
|
||||
I2S0.conf.rx_mono = 0;
|
||||
|
||||
#ifdef USE_I2S_OUT_STREAM
|
||||
I2S0.fifo_conf.dscr_en = 1; //connect DMA to fifo
|
||||
#endif
|
||||
I2S0.conf.tx_start = 0;
|
||||
I2S0.conf.rx_start = 0;
|
||||
|
||||
I2S0.conf.tx_msb_right = 1; // Set this bit to place right-channel data at the MSB in the transmit FIFO.
|
||||
I2S0.conf.tx_right_first = 0; // Setting this bit allows the right-channel data to be sent first.
|
||||
|
||||
I2S0.conf.tx_slave_mod = 0; // Master
|
||||
#ifdef USE_I2S_OUT_STREAM
|
||||
I2S0.fifo_conf.tx_fifo_mod_force_en = 1; //The bit should always be set to 1.
|
||||
#endif
|
||||
I2S0.pdm_conf.rx_pdm_en = 0; // Set this bit to enable receiver’s PDM mode.
|
||||
I2S0.pdm_conf.tx_pdm_en = 0; // Set this bit to enable transmitter’s PDM mode.
|
||||
|
||||
// I2S_COMM_FORMAT_I2S_LSB
|
||||
I2S0.conf.tx_short_sync = 0; // Set this bit to enable transmitter in PCM standard mode.
|
||||
I2S0.conf.rx_short_sync = 0; // Set this bit to enable receiver in PCM standard mode.
|
||||
I2S0.conf.tx_msb_shift = 0; // Do not use the Philips standard to avoid bit-shifting
|
||||
I2S0.conf.rx_msb_shift = 0; // Do not use the Philips standard to avoid bit-shifting
|
||||
|
||||
//
|
||||
// i2s_set_clk
|
||||
//
|
||||
|
||||
// set clock (fi2s) 160MHz / 5
|
||||
I2S0.clkm_conf.clka_en = 0; // Use 160 MHz PLL_D2_CLK as reference
|
||||
// N + b/a = 0
|
||||
#if I2S_OUT_NUM_BITS == 16
|
||||
// N = 10
|
||||
I2S0.clkm_conf.clkm_div_num = 10; // minimum value of 2, reset value of 4, max 256 (I²S clock divider’s integral value)
|
||||
#else
|
||||
// N = 5
|
||||
I2S0.clkm_conf.clkm_div_num = 5; // minimum value of 2, reset value of 4, max 256 (I²S clock divider’s integral value)
|
||||
#endif
|
||||
// b/a = 0
|
||||
I2S0.clkm_conf.clkm_div_b = 0; // 0 at reset
|
||||
I2S0.clkm_conf.clkm_div_a = 0; // 0 at reset, what about divide by 0? (not an issue)
|
||||
|
||||
// Bit clock configuration bit in transmitter mode.
|
||||
// fbck = fi2s / tx_bck_div_num = (160 MHz / 5) / 2 = 16 MHz
|
||||
I2S0.sample_rate_conf.tx_bck_div_num = 2; // minimum value of 2 defaults to 6
|
||||
I2S0.sample_rate_conf.rx_bck_div_num = 2;
|
||||
|
||||
#ifdef USE_I2S_OUT_STREAM
|
||||
// Enable TX interrupts (DMA Interrupts)
|
||||
I2S0.int_ena.out_eof = 1; // Triggered when rxlink has finished sending a packet.
|
||||
I2S0.int_ena.out_dscr_err = 0; // Triggered when invalid rxlink descriptors are encountered.
|
||||
I2S0.int_ena.out_total_eof = 1; // Triggered when all transmitting linked lists are used up.
|
||||
I2S0.int_ena.out_done = 0; // Triggered when all transmitted and buffered data have been read.
|
||||
|
||||
// default pulse callback period (μsec)
|
||||
i2s_out_pulse_period = init_param.pulse_period;
|
||||
i2s_out_pulse_func = init_param.pulse_func;
|
||||
|
||||
// Create the task that will feed the buffer
|
||||
xTaskCreatePinnedToCore(i2sOutTask,
|
||||
"I2SOutTask",
|
||||
1024 * 10,
|
||||
NULL,
|
||||
1,
|
||||
nullptr,
|
||||
CONFIG_ARDUINO_RUNNING_CORE // must run the task on same core
|
||||
);
|
||||
|
||||
// Allocate and Enable the I2S interrupt
|
||||
esp_intr_alloc(ETS_I2S0_INTR_SOURCE, 0, i2s_out_intr_handler, nullptr, &i2s_out_isr_handle);
|
||||
esp_intr_enable(i2s_out_isr_handle);
|
||||
#endif
|
||||
|
||||
// Remember GPIO pin numbers
|
||||
i2s_out_ws_pin = init_param.ws_pin;
|
||||
i2s_out_bck_pin = init_param.bck_pin;
|
||||
i2s_out_data_pin = init_param.data_pin;
|
||||
i2s_out_initialized = 1;
|
||||
|
||||
// Start the I2S peripheral
|
||||
i2s_out_start();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef I2S_OUT_WS
|
||||
#define I2S_OUT_WS GPIO_NUM_17
|
||||
#endif
|
||||
#ifndef I2S_OUT_BCK
|
||||
#define I2S_OUT_BCK GPIO_NUM_22
|
||||
#endif
|
||||
#ifndef I2S_OUT_DATA
|
||||
#define I2S_OUT_DATA GPIO_NUM_21
|
||||
#endif
|
||||
#ifndef I2S_OUT_INIT_VAL
|
||||
#define I2S_OUT_INIT_VAL 0
|
||||
#endif
|
||||
/*
|
||||
Initialize I2S out by default parameters.
|
||||
|
||||
return -1 ... already initialized
|
||||
*/
|
||||
int IRAM_ATTR i2s_out_init() {
|
||||
i2s_out_init_t default_param = {
|
||||
.ws_pin = I2S_OUT_WS,
|
||||
.bck_pin = I2S_OUT_BCK,
|
||||
.data_pin = I2S_OUT_DATA,
|
||||
.pulse_func = NULL,
|
||||
.pulse_period = I2S_OUT_USEC_PER_PULSE,
|
||||
.init_val = I2S_OUT_INIT_VAL,
|
||||
};
|
||||
return i2s_out_init(default_param);
|
||||
}
|
||||
|
||||
#endif
|
@@ -1,38 +0,0 @@
|
||||
#ifndef _machine_common_h
|
||||
#define _machine_common_h
|
||||
|
||||
#ifndef SPINDLE_TYPE
|
||||
#define SPINDLE_TYPE SPINDLE_TYPE_PWM
|
||||
#endif
|
||||
|
||||
// Grbl setting that are common to all machines
|
||||
// It should not be necessary to change anything herein
|
||||
|
||||
#ifndef GRBL_SPI_FREQ
|
||||
// You can override these by defining them in a board file.
|
||||
// To override, you must set all of them
|
||||
//-1 means use the default board pin
|
||||
#define GRBL_SPI_SS -1
|
||||
#define GRBL_SPI_MOSI -1
|
||||
#define GRBL_SPI_MISO -1
|
||||
#define GRBL_SPI_SCK -1
|
||||
#define GRBL_SPI_FREQ 4000000
|
||||
#endif
|
||||
|
||||
// ESP32 CPU Settings
|
||||
#define F_TIMERS 80000000 // a reference to the speed of ESP32 timers
|
||||
#define F_STEPPER_TIMER 20000000 // frequency of step pulse timer
|
||||
#define STEPPER_OFF_TIMER_PRESCALE 8 // gives a frequency of 10MHz
|
||||
#define STEPPER_OFF_PERIOD_uSEC 3 // each tick is
|
||||
|
||||
#define STEP_PULSE_MIN 2 // uSeconds
|
||||
#define STEP_PULSE_MAX 10 // uSeconds
|
||||
|
||||
// =============== Don't change or comment these out ======================
|
||||
// They are for legacy purposes and will not affect your I/O
|
||||
|
||||
#define STEP_MASK B111111
|
||||
|
||||
#define PROBE_MASK 1
|
||||
|
||||
#endif // _machine_common_h
|
@@ -1,138 +0,0 @@
|
||||
/*
|
||||
print.c - Functions for formatting output strings
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
Copyright (c) 2009-2011 Simen Svale Skogsrud
|
||||
|
||||
2018 - Bart Dring This file was modifed for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "grbl.h"
|
||||
|
||||
|
||||
|
||||
|
||||
// void printIntegerInBase(unsigned long n, unsigned long base)
|
||||
// {
|
||||
// unsigned char buf[8 * sizeof(long)]; // Assumes 8-bit chars.
|
||||
// unsigned long i = 0;
|
||||
//
|
||||
// if (n == 0) {
|
||||
// serial_write('0');
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// while (n > 0) {
|
||||
// buf[i++] = n % base;
|
||||
// n /= base;
|
||||
// }
|
||||
//
|
||||
// for (; i > 0; i--)
|
||||
// serial_write(buf[i - 1] < 10 ?
|
||||
// '0' + buf[i - 1] :
|
||||
// 'A' + buf[i - 1] - 10);
|
||||
// }
|
||||
|
||||
|
||||
// Prints an uint8 variable in base 10.
|
||||
void print_uint8_base10(uint8_t n) {
|
||||
uint8_t digit_a = 0;
|
||||
uint8_t digit_b = 0;
|
||||
if (n >= 100) { // 100-255
|
||||
digit_a = '0' + n % 10;
|
||||
n /= 10;
|
||||
}
|
||||
if (n >= 10) { // 10-99
|
||||
digit_b = '0' + n % 10;
|
||||
n /= 10;
|
||||
}
|
||||
serial_write('0' + n);
|
||||
if (digit_b) serial_write(digit_b);
|
||||
if (digit_a) serial_write(digit_a);
|
||||
}
|
||||
|
||||
|
||||
// Prints an uint8 variable in base 2 with desired number of desired digits.
|
||||
void print_uint8_base2_ndigit(uint8_t n, uint8_t digits) {
|
||||
unsigned char buf[digits];
|
||||
uint8_t i = 0;
|
||||
for (; i < digits; i++) {
|
||||
buf[i] = n % 2 ;
|
||||
n /= 2;
|
||||
}
|
||||
for (; i > 0; i--)
|
||||
Serial.print('0' + buf[i - 1]);
|
||||
}
|
||||
|
||||
|
||||
void print_uint32_base10(uint32_t n) {
|
||||
if (n == 0) {
|
||||
Serial.print('0');
|
||||
return;
|
||||
}
|
||||
unsigned char buf[10];
|
||||
uint8_t i = 0;
|
||||
while (n > 0) {
|
||||
buf[i++] = n % 10;
|
||||
n /= 10;
|
||||
}
|
||||
for (; i > 0; i--)
|
||||
Serial.print('0' + buf[i - 1]);
|
||||
}
|
||||
|
||||
|
||||
void printInteger(long n) {
|
||||
if (n < 0) {
|
||||
Serial.print('-');
|
||||
print_uint32_base10(-n);
|
||||
} else
|
||||
print_uint32_base10(n);
|
||||
}
|
||||
|
||||
|
||||
// Convert float to string by immediately converting to a long integer, which contains
|
||||
// more digits than a float. Number of decimal places, which are tracked by a counter,
|
||||
// may be set by the user. The integer is then efficiently converted to a string.
|
||||
// NOTE: AVR '%' and '/' integer operations are very efficient. Bitshifting speed-up
|
||||
// techniques are actually just slightly slower. Found this out the hard way.
|
||||
void printFloat(float n, uint8_t decimal_places) {
|
||||
Serial.print(n, decimal_places);
|
||||
}
|
||||
|
||||
|
||||
// Floating value printing handlers for special variables types used in Grbl and are defined
|
||||
// in the config.h.
|
||||
// - CoordValue: Handles all position or coordinate values in inches or mm reporting.
|
||||
// - RateValue: Handles feed rate and current velocity in inches or mm reporting.
|
||||
void printFloat_CoordValue(float n) {
|
||||
if (report_inches->get())
|
||||
printFloat(n * INCH_PER_MM, N_DECIMAL_COORDVALUE_INCH);
|
||||
else
|
||||
printFloat(n, N_DECIMAL_COORDVALUE_MM);
|
||||
}
|
||||
|
||||
// Debug tool to print free memory in bytes at the called point.
|
||||
// NOTE: Keep commented unless using. Part of this function always gets compiled in.
|
||||
// void printFreeMemory()
|
||||
// {
|
||||
// extern int __heap_start, *__brkval;
|
||||
// uint16_t free; // Up to 64k values.
|
||||
// free = (int) &free - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
|
||||
// printInteger((int32_t)free);
|
||||
// printString(" ");
|
||||
// }
|
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
print.h - Functions for formatting output strings
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
Copyright (c) 2009-2011 Simen Svale Skogsrud
|
||||
|
||||
2018 - Bart Dring This file was modifed for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef print_h
|
||||
#define print_h
|
||||
|
||||
|
||||
void printString(const char* s);
|
||||
|
||||
void printPgmString(const char* s);
|
||||
|
||||
void printInteger(long n);
|
||||
|
||||
void print_uint32_base10(uint32_t n);
|
||||
|
||||
// Prints an uint8 variable in base 10.
|
||||
void print_uint8_base10(uint8_t n);
|
||||
|
||||
// Prints an uint8 variable in base 2 with desired number of desired digits.
|
||||
void print_uint8_base2_ndigit(uint8_t n, uint8_t digits);
|
||||
|
||||
void printFloat(float n, uint8_t decimal_places);
|
||||
|
||||
// Floating value printing handlers for special variables types used in Grbl.
|
||||
// - CoordValue: Handles all position or coordinate values in inches or mm reporting.
|
||||
// - RateValue: Handles feed rate and current velocity in inches or mm reporting.
|
||||
void printFloat_CoordValue(float n);
|
||||
void printFloat_RateValue(float n);
|
||||
|
||||
// Debug tool to print free memory in bytes at the called point. Not used otherwise.
|
||||
void printFreeMemory();
|
||||
|
||||
#endif
|
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
config.h - compile time configuration
|
||||
Config.h - compile time configuration
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2012-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
@@ -35,8 +37,6 @@ Some features should not be changed. See notes below.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef config_h
|
||||
#define config_h
|
||||
#include <Arduino.h>
|
||||
|
||||
// It is no longer necessary to edit this file to choose
|
||||
@@ -62,7 +62,7 @@ Some features should not be changed. See notes below.
|
||||
// NOTE: Defaults are set for a traditional 3-axis CNC machine. Z-axis first to clear, followed by X & Y.
|
||||
// These homing cycle definitions precede the machine.h file so that the machine
|
||||
// definition can undefine them if necessary.
|
||||
#define HOMING_CYCLE_0 bit(Z_AXIS) // TYPICALLY REQUIRED: First move Z to clear workspace.
|
||||
#define HOMING_CYCLE_0 bit(Z_AXIS) // TYPICALLY REQUIRED: First move Z to clear workspace.
|
||||
#define HOMING_CYCLE_1 bit(X_AXIS)
|
||||
#define HOMING_CYCLE_2 bit(Y_AXIS)
|
||||
|
||||
@@ -74,34 +74,34 @@ Some features should not be changed. See notes below.
|
||||
// normally-closed switches on the specified pins, rather than the default normally-open switches.
|
||||
// The mask order is Cycle Start | Feed Hold | Reset | Safety Door
|
||||
// For example B1101 will invert the function of the Reset pin.
|
||||
#define INVERT_CONTROL_PIN_MASK B1111
|
||||
#define INVERT_CONTROL_PIN_MASK B1111
|
||||
|
||||
#define ENABLE_CONTROL_SW_DEBOUNCE // Default disabled. Uncomment to enable.
|
||||
#define CONTROL_SW_DEBOUNCE_PERIOD 32 // in milliseconds default 32 microseconds
|
||||
#define ENABLE_CONTROL_SW_DEBOUNCE // Default disabled. Uncomment to enable.
|
||||
#define CONTROL_SW_DEBOUNCE_PERIOD 32 // in milliseconds default 32 microseconds
|
||||
|
||||
#define USE_RMT_STEPS
|
||||
|
||||
// Include the file that loads the machine-specific config file.
|
||||
// machine.h must be edited to choose the desired file.
|
||||
#include "machine.h"
|
||||
#include "Machine.h"
|
||||
|
||||
// machine_common.h contains settings that do not change
|
||||
#include "machine_common.h"
|
||||
#include "MachineCommon.h"
|
||||
|
||||
#define MAX_N_AXIS 6
|
||||
|
||||
// Number of axes defined (steppers, servos, etc) (valid range: 3 to 6)
|
||||
// Even if your machine only uses less than the minimum of 3, you should select 3
|
||||
#ifndef N_AXIS
|
||||
#define N_AXIS 3
|
||||
# define N_AXIS 3
|
||||
#endif
|
||||
|
||||
#ifndef LIMIT_MASK
|
||||
#define LIMIT_MASK B0
|
||||
# define LIMIT_MASK B0
|
||||
#endif
|
||||
|
||||
#define VERBOSE_HELP // Currently this doesn't do anything
|
||||
#define GRBL_MSG_LEVEL MSG_LEVEL_INFO // what level of [MSG:....] do you want to see 0=all off
|
||||
#define VERBOSE_HELP // Currently this doesn't do anything
|
||||
#define GRBL_MSG_LEVEL MSG_LEVEL_INFO // what level of [MSG:....] do you want to see 0=all off
|
||||
|
||||
// Serial baud rate
|
||||
// OK to change, but the ESP32 boot text is 115200, so you will not see that is your
|
||||
@@ -112,24 +112,23 @@ Some features should not be changed. See notes below.
|
||||
//#define CONNECT_TO_SSID "your SSID"
|
||||
//#define SSID_PASSWORD "your SSID password"
|
||||
//CONFIGURE_EYECATCH_BEGIN (DO NOT MODIFY THIS LINE)
|
||||
#define ENABLE_BLUETOOTH // enable bluetooth
|
||||
#define ENABLE_BLUETOOTH // enable bluetooth
|
||||
|
||||
#define ENABLE_SD_CARD // enable use of SD Card to run jobs
|
||||
#define ENABLE_SD_CARD // enable use of SD Card to run jobs
|
||||
|
||||
#define ENABLE_WIFI //enable wifi
|
||||
#define ENABLE_WIFI //enable wifi
|
||||
|
||||
#if defined(ENABLE_WIFI) || defined(ENABLE_BLUETOOTH)
|
||||
#define WIFI_OR_BLUETOOTH
|
||||
# define WIFI_OR_BLUETOOTH
|
||||
#endif
|
||||
|
||||
|
||||
#define ENABLE_HTTP //enable HTTP and all related services
|
||||
#define ENABLE_OTA //enable OTA
|
||||
#define ENABLE_TELNET //enable telnet
|
||||
#define ENABLE_TELNET_WELCOME_MSG //display welcome string when connect to telnet
|
||||
#define ENABLE_MDNS //enable mDNS discovery
|
||||
#define ENABLE_SSDP //enable UPNP discovery
|
||||
#define ENABLE_NOTIFICATIONS //enable notifications
|
||||
#define ENABLE_HTTP //enable HTTP and all related services
|
||||
#define ENABLE_OTA //enable OTA
|
||||
#define ENABLE_TELNET //enable telnet
|
||||
#define ENABLE_TELNET_WELCOME_MSG //display welcome string when connect to telnet
|
||||
#define ENABLE_MDNS //enable mDNS discovery
|
||||
#define ENABLE_SSDP //enable UPNP discovery
|
||||
#define ENABLE_NOTIFICATIONS //enable notifications
|
||||
|
||||
#define ENABLE_SERIAL2SOCKET_IN
|
||||
#define ENABLE_SERIAL2SOCKET_OUT
|
||||
@@ -150,32 +149,32 @@ Some features should not be changed. See notes below.
|
||||
#define NAMESPACE "GRBL"
|
||||
|
||||
#ifdef ENABLE_AUTHENTICATION
|
||||
#define DEFAULT_ADMIN_PWD "admin"
|
||||
#define DEFAULT_USER_PWD "user"
|
||||
#define DEFAULT_ADMIN_LOGIN "admin"
|
||||
#define DEFAULT_USER_LOGIN "user"
|
||||
# define DEFAULT_ADMIN_PWD "admin"
|
||||
# define DEFAULT_USER_PWD "user"
|
||||
# define DEFAULT_ADMIN_LOGIN "admin"
|
||||
# define DEFAULT_USER_LOGIN "user"
|
||||
#endif
|
||||
|
||||
//Radio Mode
|
||||
#define ESP_RADIO_OFF 0
|
||||
#define ESP_WIFI_STA 1
|
||||
#define ESP_WIFI_AP 2
|
||||
#define ESP_BT 3
|
||||
#define ESP_WIFI_AP 2
|
||||
#define ESP_BT 3
|
||||
|
||||
//Default mode
|
||||
#ifdef ENABLE_WIFI
|
||||
#ifdef CONNECT_TO_SSID
|
||||
#define DEFAULT_RADIO_MODE ESP_WIFI_STA
|
||||
#else
|
||||
#define DEFAULT_RADIO_MODE ESP_WIFI_AP
|
||||
#endif //CONNECT_TO_SSID
|
||||
# ifdef CONNECT_TO_SSID
|
||||
# define DEFAULT_RADIO_MODE ESP_WIFI_STA
|
||||
# else
|
||||
# define DEFAULT_RADIO_MODE ESP_WIFI_AP
|
||||
# endif //CONNECT_TO_SSID
|
||||
#else
|
||||
#undef ENABLE_NOTIFICATIONS
|
||||
#ifdef ENABLE_BLUETOOTH
|
||||
#define DEFAULT_RADIO_MODE ESP_BT
|
||||
#else
|
||||
#define DEFAULT_RADIO_MODE ESP_RADIO_OFF
|
||||
#endif
|
||||
# undef ENABLE_NOTIFICATIONS
|
||||
# ifdef ENABLE_BLUETOOTH
|
||||
# define DEFAULT_RADIO_MODE ESP_BT
|
||||
# else
|
||||
# define DEFAULT_RADIO_MODE ESP_RADIO_OFF
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// Define realtime command special characters. These characters are 'picked-off' directly from the
|
||||
@@ -185,7 +184,7 @@ Some features should not be changed. See notes below.
|
||||
// g-code programs, maybe selected for interface programs.
|
||||
// NOTE: If changed, manually update help message in report.c.
|
||||
|
||||
#define CMD_RESET 0x18 // ctrl-x.
|
||||
#define CMD_RESET 0x18 // ctrl-x.
|
||||
#define CMD_STATUS_REPORT '?'
|
||||
#define CMD_CYCLE_START '~'
|
||||
#define CMD_FEED_HOLD '!'
|
||||
@@ -199,19 +198,19 @@ Some features should not be changed. See notes below.
|
||||
// #define CMD_CYCLE_START 0x82
|
||||
// #define CMD_FEED_HOLD 0x83
|
||||
#define CMD_SAFETY_DOOR 0x84
|
||||
#define CMD_JOG_CANCEL 0x85
|
||||
#define CMD_DEBUG_REPORT 0x86 // Only when DEBUG enabled, sends debug report in '{}' braces.
|
||||
#define CMD_FEED_OVR_RESET 0x90 // Restores feed override value to 100%.
|
||||
#define CMD_JOG_CANCEL 0x85
|
||||
#define CMD_DEBUG_REPORT 0x86 // Only when DEBUG enabled, sends debug report in '{}' braces.
|
||||
#define CMD_FEED_OVR_RESET 0x90 // Restores feed override value to 100%.
|
||||
#define CMD_FEED_OVR_COARSE_PLUS 0x91
|
||||
#define CMD_FEED_OVR_COARSE_MINUS 0x92
|
||||
#define CMD_FEED_OVR_FINE_PLUS 0x93
|
||||
#define CMD_FEED_OVR_FINE_MINUS 0x94
|
||||
#define CMD_RAPID_OVR_RESET 0x95 // Restores rapid override value to 100%.
|
||||
#define CMD_FEED_OVR_FINE_PLUS 0x93
|
||||
#define CMD_FEED_OVR_FINE_MINUS 0x94
|
||||
#define CMD_RAPID_OVR_RESET 0x95 // Restores rapid override value to 100%.
|
||||
#define CMD_RAPID_OVR_MEDIUM 0x96
|
||||
#define CMD_RAPID_OVR_LOW 0x97
|
||||
// #define CMD_RAPID_OVR_EXTRA_LOW 0x98 // *NOT SUPPORTED*
|
||||
#define CMD_SPINDLE_OVR_RESET 0x99 // Restores spindle override value to 100%.
|
||||
#define CMD_SPINDLE_OVR_COARSE_PLUS 0x9A // 154
|
||||
#define CMD_SPINDLE_OVR_RESET 0x99 // Restores spindle override value to 100%.
|
||||
#define CMD_SPINDLE_OVR_COARSE_PLUS 0x9A // 154
|
||||
#define CMD_SPINDLE_OVR_COARSE_MINUS 0x9B
|
||||
#define CMD_SPINDLE_OVR_FINE_PLUS 0x9C
|
||||
#define CMD_SPINDLE_OVR_FINE_MINUS 0x9D
|
||||
@@ -222,18 +221,18 @@ Some features should not be changed. See notes below.
|
||||
// If homing is enabled, homing init lock sets Grbl into an alarm state upon power up. This forces
|
||||
// the user to perform the homing cycle (or override the locks) before doing anything else. This is
|
||||
// mainly a safety feature to remind the user to home, since position is unknown to Grbl.
|
||||
#define HOMING_INIT_LOCK // Comment to disable
|
||||
#define HOMING_INIT_LOCK // Comment to disable
|
||||
|
||||
// Number of homing cycles performed after when the machine initially jogs to limit switches.
|
||||
// This help in preventing overshoot and should improve repeatability. This value should be one or
|
||||
// greater.
|
||||
#define N_HOMING_LOCATE_CYCLE 1 // Integer (1-128)
|
||||
#define N_HOMING_LOCATE_CYCLE 1 // Integer (1-128)
|
||||
|
||||
// Enables single axis homing commands. $HX, $HY, and $HZ for X, Y, and Z-axis homing. The full homing
|
||||
// cycle is still invoked by the $H command. This is disabled by default. It's here only to address
|
||||
// users that need to switch between a two-axis and three-axis machine. This is actually very rare.
|
||||
// If you have a two-axis machine, DON'T USE THIS. Instead, just alter the homing cycle for two-axes.
|
||||
#define HOMING_SINGLE_AXIS_COMMANDS // Default disabled. Uncomment to enable.
|
||||
#define HOMING_SINGLE_AXIS_COMMANDS // Default disabled. Uncomment to enable.
|
||||
|
||||
// After homing, Grbl will set by default the entire machine space into negative space, as is typical
|
||||
// for professional CNC machines, regardless of where the limit switches are located. Uncomment this
|
||||
@@ -250,7 +249,7 @@ Some features should not be changed. See notes below.
|
||||
// and addresses are defined in settings.h. With the current settings, up to 2 startup blocks may
|
||||
// be stored and executed in order. These startup blocks would typically be used to set the g-code
|
||||
// parser state depending on user preferences.
|
||||
#define N_STARTUP_LINE 2 // Integer (1-2)
|
||||
#define N_STARTUP_LINE 2 // Integer (1-2)
|
||||
|
||||
// Number of floating decimal points printed by Grbl for certain value types. These settings are
|
||||
// determined by realistic and commonly observed values in CNC machines. For example, position
|
||||
@@ -258,12 +257,12 @@ Some features should not be changed. See notes below.
|
||||
// precise this. So, there is likely no need to change these, but you can if you need to here.
|
||||
// NOTE: Must be an integer value from 0 to ~4. More than 4 may exhibit round-off errors.
|
||||
// ESP32 Note: These are mostly hard coded, so these values will not change anything
|
||||
#define N_DECIMAL_COORDVALUE_INCH 4 // Coordinate or position value in inches
|
||||
#define N_DECIMAL_COORDVALUE_MM 3 // Coordinate or position value in mm
|
||||
#define N_DECIMAL_RATEVALUE_INCH 1 // Rate or velocity value in in/min
|
||||
#define N_DECIMAL_RATEVALUE_MM 0 // Rate or velocity value in mm/min
|
||||
#define N_DECIMAL_SETTINGVALUE 3 // Decimals for floating point setting values
|
||||
#define N_DECIMAL_RPMVALUE 0 // RPM value in rotations per min.
|
||||
#define N_DECIMAL_COORDVALUE_INCH 4 // Coordinate or position value in inches
|
||||
#define N_DECIMAL_COORDVALUE_MM 3 // Coordinate or position value in mm
|
||||
#define N_DECIMAL_RATEVALUE_INCH 1 // Rate or velocity value in in/min
|
||||
#define N_DECIMAL_RATEVALUE_MM 0 // Rate or velocity value in mm/min
|
||||
#define N_DECIMAL_SETTINGVALUE 3 // Decimals for floating point setting values
|
||||
#define N_DECIMAL_RPMVALUE 0 // RPM value in rotations per min.
|
||||
|
||||
// If your machine has two limits switches wired in parallel to one axis, you will need to enable
|
||||
// this feature. Since the two switches are sharing a single pin, there is no way for Grbl to tell
|
||||
@@ -280,7 +279,7 @@ Some features should not be changed. See notes below.
|
||||
// Upon a successful probe cycle, this option provides immediately feedback of the probe coordinates
|
||||
// through an automatically generated message. If disabled, users can still access the last probe
|
||||
// coordinates through Grbl '$#' print parameters.
|
||||
#define MESSAGE_PROBE_COORDINATES // Enabled by default. Comment to disable.
|
||||
#define MESSAGE_PROBE_COORDINATES // Enabled by default. Comment to disable.
|
||||
|
||||
// Enables a second coolant control pin via the mist coolant g-code command M7 on the Arduino Uno
|
||||
// analog pin 4. Only use this option if you require a second coolant control pin.
|
||||
@@ -293,12 +292,12 @@ Some features should not be changed. See notes below.
|
||||
// immediately forces a feed hold and then safely de-energizes the machine. Resuming is blocked until
|
||||
// the safety door is re-engaged. When it is, Grbl will re-energize the machine and then resume on the
|
||||
// previous tool path, as if nothing happened.
|
||||
#define ENABLE_SAFETY_DOOR_INPUT_PIN // ESP32 Leave this enabled for now .. code for undefined not ready
|
||||
#define ENABLE_SAFETY_DOOR_INPUT_PIN // ESP32 Leave this enabled for now .. code for undefined not ready
|
||||
|
||||
// After the safety door switch has been toggled and restored, this setting sets the power-up delay
|
||||
// between restoring the spindle and coolant and resuming the cycle.
|
||||
#define SAFETY_DOOR_SPINDLE_DELAY 4.0 // Float (seconds)
|
||||
#define SAFETY_DOOR_COOLANT_DELAY 1.0 // Float (seconds)
|
||||
#define SAFETY_DOOR_SPINDLE_DELAY 4.0 // Float (seconds)
|
||||
#define SAFETY_DOOR_COOLANT_DELAY 1.0 // Float (seconds)
|
||||
|
||||
// Enable CoreXY kinematics. Use ONLY with CoreXY machines.
|
||||
// IMPORTANT: If homing is enabled, you must reconfigure the homing cycle #defines above to
|
||||
@@ -317,13 +316,6 @@ Some features should not be changed. See notes below.
|
||||
// NOTE: PLEASE DO NOT USE THIS, unless you have a situation that needs it.
|
||||
// #define INVERT_LIMIT_PIN_MASK (bit(X_AXIS)|bit(Y_AXIS)) // Default disabled. Uncomment to enable.
|
||||
|
||||
// Inverts the spindle enable pin from low-disabled/high-enabled to low-enabled/high-disabled. Useful
|
||||
// for some pre-built electronic boards.
|
||||
// #define INVERT_SPINDLE_ENABLE_PIN // Default disabled. Uncomment to enable.
|
||||
|
||||
// Inverts the spindle PWM output pin from low-disabled/high-enabled to low-enabled/high-disabled.
|
||||
// #define INVERT_SPINDLE_OUTPUT_PIN // Default disabled. Uncomment to enable.
|
||||
|
||||
// Inverts the selected coolant pin from low-disabled/high-enabled to low-enabled/high-disabled. Useful
|
||||
// for some pre-built electronic boards.
|
||||
// #define INVERT_COOLANT_FLOOD_PIN // Default disabled. Uncomment to enable.
|
||||
@@ -352,27 +344,27 @@ Some features should not be changed. See notes below.
|
||||
// Configure rapid, feed, and spindle override settings. These values define the max and min
|
||||
// allowable override values and the coarse and fine increments per command received. Please
|
||||
// note the allowable values in the descriptions following each define.
|
||||
#define DEFAULT_FEED_OVERRIDE 100 // 100%. Don't change this value.
|
||||
#define MAX_FEED_RATE_OVERRIDE 200 // Percent of programmed feed rate (100-255). Usually 120% or 200%
|
||||
#define MIN_FEED_RATE_OVERRIDE 10 // Percent of programmed feed rate (1-100). Usually 50% or 1%
|
||||
#define FEED_OVERRIDE_COARSE_INCREMENT 10 // (1-99). Usually 10%.
|
||||
#define FEED_OVERRIDE_FINE_INCREMENT 1 // (1-99). Usually 1%.
|
||||
#define DEFAULT_FEED_OVERRIDE 100 // 100%. Don't change this value.
|
||||
#define MAX_FEED_RATE_OVERRIDE 200 // Percent of programmed feed rate (100-255). Usually 120% or 200%
|
||||
#define MIN_FEED_RATE_OVERRIDE 10 // Percent of programmed feed rate (1-100). Usually 50% or 1%
|
||||
#define FEED_OVERRIDE_COARSE_INCREMENT 10 // (1-99). Usually 10%.
|
||||
#define FEED_OVERRIDE_FINE_INCREMENT 1 // (1-99). Usually 1%.
|
||||
|
||||
#define DEFAULT_RAPID_OVERRIDE 100 // 100%. Don't change this value.
|
||||
#define RAPID_OVERRIDE_MEDIUM 50 // Percent of rapid (1-99). Usually 50%.
|
||||
#define RAPID_OVERRIDE_LOW 25 // Percent of rapid (1-99). Usually 25%.
|
||||
#define DEFAULT_RAPID_OVERRIDE 100 // 100%. Don't change this value.
|
||||
#define RAPID_OVERRIDE_MEDIUM 50 // Percent of rapid (1-99). Usually 50%.
|
||||
#define RAPID_OVERRIDE_LOW 25 // Percent of rapid (1-99). Usually 25%.
|
||||
// #define RAPID_OVERRIDE_EXTRA_LOW 5 // *NOT SUPPORTED* Percent of rapid (1-99). Usually 5%.
|
||||
|
||||
#define DEFAULT_SPINDLE_SPEED_OVERRIDE 100 // 100%. Don't change this value.
|
||||
#define MAX_SPINDLE_SPEED_OVERRIDE 200 // Percent of programmed spindle speed (100-255). Usually 200%.
|
||||
#define MIN_SPINDLE_SPEED_OVERRIDE 10 // Percent of programmed spindle speed (1-100). Usually 10%.
|
||||
#define SPINDLE_OVERRIDE_COARSE_INCREMENT 10 // (1-99). Usually 10%.
|
||||
#define SPINDLE_OVERRIDE_FINE_INCREMENT 1 // (1-99). Usually 1%.
|
||||
#define DEFAULT_SPINDLE_SPEED_OVERRIDE 100 // 100%. Don't change this value.
|
||||
#define MAX_SPINDLE_SPEED_OVERRIDE 200 // Percent of programmed spindle speed (100-255). Usually 200%.
|
||||
#define MIN_SPINDLE_SPEED_OVERRIDE 10 // Percent of programmed spindle speed (1-100). Usually 10%.
|
||||
#define SPINDLE_OVERRIDE_COARSE_INCREMENT 10 // (1-99). Usually 10%.
|
||||
#define SPINDLE_OVERRIDE_FINE_INCREMENT 1 // (1-99). Usually 1%.
|
||||
|
||||
// When a M2 or M30 program end command is executed, most g-code states are restored to their defaults.
|
||||
// This compile-time option includes the restoring of the feed, rapid, and spindle speed override values
|
||||
// to their default values at program end.
|
||||
#define RESTORE_OVERRIDES_AFTER_PROGRAM_END // Default enabled. Comment to disable.
|
||||
#define RESTORE_OVERRIDES_AFTER_PROGRAM_END // Default enabled. Comment to disable.
|
||||
|
||||
// The status report change for Grbl v1.1 and after also removed the ability to disable/enable most data
|
||||
// fields from the report. This caused issues for GUI developers, who've had to manage several scenarios
|
||||
@@ -380,12 +372,12 @@ Some features should not be changed. See notes below.
|
||||
// be sent without potential performance issues.
|
||||
// NOTE: The options below are here only provide a way to disable certain data fields if a unique
|
||||
// situation demands it, but be aware GUIs may depend on this data. If disabled, it may not be compatible.
|
||||
#define REPORT_FIELD_BUFFER_STATE // Default enabled. Comment to disable.
|
||||
#define REPORT_FIELD_PIN_STATE // Default enabled. Comment to disable.
|
||||
#define REPORT_FIELD_CURRENT_FEED_SPEED // Default enabled. Comment to disable.
|
||||
#define REPORT_FIELD_WORK_COORD_OFFSET // Default enabled. Comment to disable.
|
||||
#define REPORT_FIELD_OVERRIDES // Default enabled. Comment to disable.
|
||||
#define REPORT_FIELD_LINE_NUMBERS // Default enabled. Comment to disable.
|
||||
#define REPORT_FIELD_BUFFER_STATE // Default enabled. Comment to disable.
|
||||
#define REPORT_FIELD_PIN_STATE // Default enabled. Comment to disable.
|
||||
#define REPORT_FIELD_CURRENT_FEED_SPEED // Default enabled. Comment to disable.
|
||||
#define REPORT_FIELD_WORK_COORD_OFFSET // Default enabled. Comment to disable.
|
||||
#define REPORT_FIELD_OVERRIDES // Default enabled. Comment to disable.
|
||||
#define REPORT_FIELD_LINE_NUMBERS // Default enabled. Comment to disable.
|
||||
|
||||
// Some status report data isn't necessary for realtime, only intermittently, because the values don't
|
||||
// change often. The following macros configures how many times a status report needs to be called before
|
||||
@@ -414,7 +406,7 @@ Some features should not be changed. See notes below.
|
||||
// smoothing the stepping of multi-axis motions. This feature smooths motion particularly at low step
|
||||
// frequencies below 10kHz, where the aliasing between axes of multi-axis motions can cause audible
|
||||
// noise and shake your machine. At even lower step frequencies, AMASS adapts and provides even better
|
||||
// step smoothing. See stepper.c for more details on the AMASS system works.
|
||||
// step smoothing. See Stepper.c for more details on the AMASS system works.
|
||||
#define ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING // Default enabled. Comment to disable.
|
||||
|
||||
// Sets the maximum step rate allowed to be written as a Grbl setting. This option enables an error
|
||||
@@ -444,14 +436,7 @@ Some features should not be changed. See notes below.
|
||||
// Sets which axis the tool length offset is applied. Assumes the spindle is always parallel with
|
||||
// the selected axis with the tool oriented toward the negative direction. In other words, a positive
|
||||
// tool length offset value is subtracted from the current location.
|
||||
#define TOOL_LENGTH_OFFSET_AXIS Z_AXIS // Default z-axis. Valid values are X_AXIS, Y_AXIS, or Z_AXIS.
|
||||
|
||||
// Alters the behavior of the spindle enable pin. By default Grbl will not disable the enable pin if
|
||||
// spindle speed is zero and M3/4 is active, but still sets the PWM output to zero. This allows the users
|
||||
// to know if the spindle is active and use it as an additional control input.
|
||||
// However, in some use cases, user may want the enable pin to disable with a zero spindle speed and
|
||||
// re-enable when spindle speed is greater than zero. This option does that.
|
||||
#define SPINDLE_ENABLE_OFF_WITH_ZERO_SPEED // Default enabled. Comment to disable.
|
||||
#define TOOL_LENGTH_OFFSET_AXIS Z_AXIS // Default z-axis. Valid values are X_AXIS, Y_AXIS, or Z_AXIS.
|
||||
|
||||
// With this enabled, Grbl sends back an echo of the line it has received, which has been pre-parsed (spaces
|
||||
// removed, capitalized letters, no comments) and is to be immediately executed by Grbl. Echoes will not be
|
||||
@@ -474,19 +459,19 @@ Some features should not be changed. See notes below.
|
||||
// limits or angle between neighboring block line move directions. This is useful for machines that can't
|
||||
// tolerate the tool dwelling for a split second, i.e. 3d printers or laser cutters. If used, this value
|
||||
// should not be much greater than zero or to the minimum value necessary for the machine to work.
|
||||
#define MINIMUM_JUNCTION_SPEED 0.0 // (mm/min)
|
||||
#define MINIMUM_JUNCTION_SPEED 0.0 // (mm/min)
|
||||
|
||||
// Sets the minimum feed rate the planner will allow. Any value below it will be set to this minimum
|
||||
// value. This also ensures that a planned motion always completes and accounts for any floating-point
|
||||
// round-off errors. Although not recommended, a lower value than 1.0 mm/min will likely work in smaller
|
||||
// machines, perhaps to 0.1mm/min, but your success may vary based on multiple factors.
|
||||
#define MINIMUM_FEED_RATE 1.0 // (mm/min)
|
||||
#define MINIMUM_FEED_RATE 1.0 // (mm/min)
|
||||
|
||||
// Number of arc generation iterations by small angle approximation before exact arc trajectory
|
||||
// correction with expensive sin() and cos() calcualtions. This parameter maybe decreased if there
|
||||
// are issues with the accuracy of the arc generations, or increased if arc execution is getting
|
||||
// bogged down by too many trig calculations.
|
||||
#define N_ARC_CORRECTION 12 // Integer (1-255)
|
||||
#define N_ARC_CORRECTION 12 // Integer (1-255)
|
||||
|
||||
// The arc G2/3 g-code standard is problematic by definition. Radius-based arcs have horrible numerical
|
||||
// errors when arc at semi-circles(pi) or full-circles(2*pi). Offset-based arcs are much more accurate
|
||||
@@ -496,15 +481,14 @@ Some features should not be changed. See notes below.
|
||||
// This define value sets the machine epsilon cutoff to determine if the arc is a full-circle or not.
|
||||
// NOTE: Be very careful when adjusting this value. It should always be greater than 1.2e-7 but not too
|
||||
// much greater than this. The default setting should capture most, if not all, full arc error situations.
|
||||
#define ARC_ANGULAR_TRAVEL_EPSILON 5E-7 // Float (radians)
|
||||
#define ARC_ANGULAR_TRAVEL_EPSILON 5E-7 // Float (radians)
|
||||
|
||||
// Time delay increments performed during a dwell. The default value is set at 50ms, which provides
|
||||
// a maximum time delay of roughly 55 minutes, more than enough for most any application. Increasing
|
||||
// this delay will increase the maximum dwell time linearly, but also reduces the responsiveness of
|
||||
// run-time command executions, like status reports, since these are performed between each dwell
|
||||
// time step. Also, keep in mind that the Arduino delay timer is not very accurate for long delays.
|
||||
#define DWELL_TIME_STEP 50 // Integer (1-255) (milliseconds)
|
||||
|
||||
#define DWELL_TIME_STEP 50 // Integer (1-255) (milliseconds)
|
||||
|
||||
// For test use only. This uses the ESP32's RMT peripheral to generate step pulses
|
||||
// It allows the use of the STEP_PULSE_DELAY (see below) and it automatically ends the
|
||||
@@ -568,7 +552,7 @@ Some features should not be changed. See notes below.
|
||||
// switch interrupt unblock a waiting task which will recheck the limit switch pins after
|
||||
// a short delay. Default disabled
|
||||
//#define ENABLE_SOFTWARE_DEBOUNCE // Default disabled. Uncomment to enable.
|
||||
#define DEBOUNCE_PERIOD 32 // in milliseconds default 32 microseconds
|
||||
#define DEBOUNCE_PERIOD 32 // in milliseconds default 32 microseconds
|
||||
|
||||
// Configures the position after a probing cycle during Grbl's check mode. Disabled sets
|
||||
// the position to the probe target, when enabled sets the position to the start position.
|
||||
@@ -597,9 +581,9 @@ Some features should not be changed. See notes below.
|
||||
// Enable the '$RST=*', '$RST=$', and '$RST=#' eeprom restore commands. There are cases where
|
||||
// these commands may be undesirable. Simply comment the desired macro to disable it.
|
||||
// NOTE: See SETTINGS_RESTORE_ALL macro for customizing the `$RST=*` command.
|
||||
#define ENABLE_RESTORE_EEPROM_WIPE_ALL // '$RST=*' Default enabled. Comment to disable.
|
||||
#define ENABLE_RESTORE_EEPROM_DEFAULT_SETTINGS // '$RST=$' Default enabled. Comment to disable.
|
||||
#define ENABLE_RESTORE_EEPROM_CLEAR_PARAMETERS // '$RST=#' Default enabled. Comment to disable.
|
||||
#define ENABLE_RESTORE_EEPROM_WIPE_ALL // '$RST=*' Default enabled. Comment to disable.
|
||||
#define ENABLE_RESTORE_EEPROM_DEFAULT_SETTINGS // '$RST=$' Default enabled. Comment to disable.
|
||||
#define ENABLE_RESTORE_EEPROM_CLEAR_PARAMETERS // '$RST=#' Default enabled. Comment to disable.
|
||||
|
||||
// Defines the EEPROM data restored upon a settings version change and `$RST=*` command. Whenever the
|
||||
// the settings or other EEPROM data structure changes between Grbl versions, Grbl will automatically
|
||||
@@ -622,7 +606,7 @@ Some features should not be changed. See notes below.
|
||||
// NOTE: If disabled and to ensure Grbl can never alter the build info line, you'll also need to enable
|
||||
// the SETTING_RESTORE_ALL macro above and remove SETTINGS_RESTORE_BUILD_INFO from the mask.
|
||||
// NOTE: See the included grblWrite_BuildInfo.ino example file to write this string seperately.
|
||||
#define ENABLE_BUILD_INFO_WRITE_COMMAND // '$I=' Default enabled. Comment to disable.
|
||||
#define ENABLE_BUILD_INFO_WRITE_COMMAND // '$I=' Default enabled. Comment to disable.
|
||||
|
||||
// AVR processors require all interrupts to be disabled during an EEPROM write. This includes both
|
||||
// the stepper ISRs and serial comm ISRs. In the event of a long EEPROM write, this ISR pause can
|
||||
@@ -636,7 +620,7 @@ Some features should not be changed. See notes below.
|
||||
// NOTE: Most EEPROM write commands are implicitly blocked during a job (all '$' commands). However,
|
||||
// coordinate set g-code commands (G10,G28/30.1) are not, since they are part of an active streaming
|
||||
// job. At this time, this option only forces a planner buffer sync with these g-code commands.
|
||||
#define FORCE_BUFFER_SYNC_DURING_EEPROM_WRITE // Default enabled. Comment to disable.
|
||||
#define FORCE_BUFFER_SYNC_DURING_EEPROM_WRITE // Default enabled. Comment to disable.
|
||||
|
||||
// In Grbl v0.9 and prior, there is an old outstanding bug where the `WPos:` work position reported
|
||||
// may not correlate to what is executing, because `WPos:` is based on the g-code parser state, which
|
||||
@@ -644,7 +628,7 @@ Some features should not be changed. See notes below.
|
||||
// motion whenever there is a command that alters the work coordinate offsets `G10,G43.1,G92,G54-59`.
|
||||
// This is the simplest way to ensure `WPos:` is always correct. Fortunately, it's exceedingly rare
|
||||
// that any of these commands are used need continuous motions through them.
|
||||
#define FORCE_BUFFER_SYNC_DURING_WCO_CHANGE // Default enabled. Comment to disable.
|
||||
#define FORCE_BUFFER_SYNC_DURING_WCO_CHANGE // Default enabled. Comment to disable.
|
||||
|
||||
// By default, Grbl disables feed rate overrides for all G38.x probe cycle commands. Although this
|
||||
// may be different than some pro-class machine control, it's arguable that it should be this way.
|
||||
@@ -669,11 +653,11 @@ Some features should not be changed. See notes below.
|
||||
//#define PARKING_ENABLE // Default disabled. Uncomment to enable
|
||||
|
||||
// Configure options for the parking motion, if enabled.
|
||||
#define PARKING_AXIS Z_AXIS // Define which axis that performs the parking motion
|
||||
#define PARKING_TARGET -5.0 // Parking axis target. In mm, as machine coordinate [-max_travel,0].
|
||||
#define PARKING_RATE 500.0 // Parking fast rate after pull-out in mm/min.
|
||||
#define PARKING_PULLOUT_RATE 100.0 // Pull-out/plunge slow feed rate in mm/min.
|
||||
#define PARKING_PULLOUT_INCREMENT 5.0 // Spindle pull-out and plunge distance in mm. Incremental distance.
|
||||
#define PARKING_AXIS Z_AXIS // Define which axis that performs the parking motion
|
||||
#define PARKING_TARGET -5.0 // Parking axis target. In mm, as machine coordinate [-max_travel,0].
|
||||
#define PARKING_RATE 500.0 // Parking fast rate after pull-out in mm/min.
|
||||
#define PARKING_PULLOUT_RATE 100.0 // Pull-out/plunge slow feed rate in mm/min.
|
||||
#define PARKING_PULLOUT_INCREMENT 5.0 // Spindle pull-out and plunge distance in mm. Incremental distance.
|
||||
// Must be positive value or equal to zero.
|
||||
|
||||
// Enables a special set of M-code commands that enables and disables the parking motion.
|
||||
@@ -689,7 +673,7 @@ Some features should not be changed. See notes below.
|
||||
// override immediately after coming to a stop. However, this also means that the laser still may
|
||||
// be reenabled by disabling the spindle stop override, if needed. This is purely a safety feature
|
||||
// to ensure the laser doesn't inadvertently remain powered while at a stop and cause a fire.
|
||||
#define DISABLE_LASER_DURING_HOLD // Default enabled. Comment to disable.
|
||||
#define DISABLE_LASER_DURING_HOLD // Default enabled. Comment to disable.
|
||||
|
||||
// Enables a piecewise linear model of the spindle PWM/speed output. Requires a solution by the
|
||||
// 'fit_nonlinear_spindle.py' script in the /doc/script folder of the repo. See file comments
|
||||
@@ -728,5 +712,3 @@ Some features should not be changed. See notes below.
|
||||
#define RPM_LINE_B2 4.754411e+01
|
||||
#define RPM_LINE_A3 9.528342e-03
|
||||
#define RPM_LINE_B3 3.306286e+01
|
||||
|
||||
#endif
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
coolant_control.c - coolant control methods
|
||||
CoolantControl.cpp - coolant control methods
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2012-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
@@ -21,8 +21,7 @@
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "grbl.h"
|
||||
|
||||
#include "Grbl.h"
|
||||
|
||||
void coolant_init() {
|
||||
#ifdef COOLANT_FLOOD_PIN
|
||||
@@ -34,88 +33,86 @@ void coolant_init() {
|
||||
coolant_stop();
|
||||
}
|
||||
|
||||
|
||||
// Returns current coolant output state. Overrides may alter it from programmed state.
|
||||
uint8_t coolant_get_state() {
|
||||
uint8_t cl_state = COOLANT_STATE_DISABLE;
|
||||
#ifdef COOLANT_FLOOD_PIN
|
||||
#ifdef INVERT_COOLANT_FLOOD_PIN
|
||||
if (! digitalRead(COOLANT_FLOOD_PIN)) {
|
||||
#else
|
||||
# ifdef INVERT_COOLANT_FLOOD_PIN
|
||||
if (!digitalRead(COOLANT_FLOOD_PIN)) {
|
||||
# else
|
||||
if (digitalRead(COOLANT_FLOOD_PIN)) {
|
||||
#endif
|
||||
# endif
|
||||
cl_state |= COOLANT_STATE_FLOOD;
|
||||
}
|
||||
#endif
|
||||
#ifdef COOLANT_MIST_PIN
|
||||
#ifdef INVERT_COOLANT_MIST_PIN
|
||||
if (! digitalRead(COOLANT_MIST_PIN)) {
|
||||
#else
|
||||
# ifdef INVERT_COOLANT_MIST_PIN
|
||||
if (!digitalRead(COOLANT_MIST_PIN)) {
|
||||
# else
|
||||
if (digitalRead(COOLANT_MIST_PIN)) {
|
||||
#endif
|
||||
# endif
|
||||
cl_state |= COOLANT_STATE_MIST;
|
||||
}
|
||||
#endif
|
||||
return (cl_state);
|
||||
}
|
||||
|
||||
|
||||
// Directly called by coolant_init(), coolant_set_state(), and mc_reset(), which can be at
|
||||
// an interrupt-level. No report flag set, but only called by routines that don't need it.
|
||||
void coolant_stop() {
|
||||
#ifdef COOLANT_FLOOD_PIN
|
||||
#ifdef INVERT_COOLANT_FLOOD_PIN
|
||||
# ifdef INVERT_COOLANT_FLOOD_PIN
|
||||
digitalWrite(COOLANT_FLOOD_PIN, 1);
|
||||
#else
|
||||
# else
|
||||
digitalWrite(COOLANT_FLOOD_PIN, 0);
|
||||
#endif
|
||||
# endif
|
||||
#endif
|
||||
#ifdef COOLANT_MIST_PIN
|
||||
#ifdef INVERT_COOLANT_MIST_PIN
|
||||
# ifdef INVERT_COOLANT_MIST_PIN
|
||||
digitalWrite(COOLANT_MIST_PIN, 1);
|
||||
#else
|
||||
# else
|
||||
digitalWrite(COOLANT_MIST_PIN, 0);
|
||||
#endif
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// Main program only. Immediately sets flood coolant running state and also mist coolant,
|
||||
// if enabled. Also sets a flag to report an update to a coolant state.
|
||||
// Called by coolant toggle override, parking restore, parking retract, sleep mode, g-code
|
||||
// parser program end, and g-code parser coolant_sync().
|
||||
void coolant_set_state(uint8_t mode) {
|
||||
if (sys.abort) return; // Block during abort.
|
||||
if (sys.abort)
|
||||
return; // Block during abort.
|
||||
if (mode == COOLANT_DISABLE)
|
||||
coolant_stop();
|
||||
else {
|
||||
#ifdef COOLANT_FLOOD_PIN
|
||||
if (mode & COOLANT_FLOOD_ENABLE) {
|
||||
#ifdef INVERT_COOLANT_FLOOD_PIN
|
||||
# ifdef INVERT_COOLANT_FLOOD_PIN
|
||||
digitalWrite(COOLANT_FLOOD_PIN, 0);
|
||||
#else
|
||||
# else
|
||||
digitalWrite(COOLANT_FLOOD_PIN, 1);
|
||||
#endif
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
#ifdef COOLANT_MIST_PIN
|
||||
if (mode & COOLANT_MIST_ENABLE) {
|
||||
#ifdef INVERT_COOLANT_MIST_PIN
|
||||
# ifdef INVERT_COOLANT_MIST_PIN
|
||||
digitalWrite(COOLANT_MIST_PIN, 0);
|
||||
#else
|
||||
# else
|
||||
digitalWrite(COOLANT_MIST_PIN, 1);
|
||||
#endif
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
sys.report_ovr_counter = 0; // Set to report change immediately
|
||||
sys.report_ovr_counter = 0; // Set to report change immediately
|
||||
}
|
||||
|
||||
|
||||
// G-code parser entry-point for setting coolant state. Forces a planner buffer sync and bails
|
||||
// if an abort or check-mode is active.
|
||||
void coolant_sync(uint8_t mode) {
|
||||
if (sys.state == STATE_CHECK_MODE) return;
|
||||
protocol_buffer_synchronize(); // Ensure coolant turns on when specified in program.
|
||||
if (sys.state == STATE_CHECK_MODE)
|
||||
return;
|
||||
protocol_buffer_synchronize(); // Ensure coolant turns on when specified in program.
|
||||
coolant_set_state(mode);
|
||||
}
|
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
coolant_control.h - spindle control methods
|
||||
CoolantControl.h - spindle control methods
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2012-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
@@ -21,16 +23,12 @@
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef coolant_control_h
|
||||
#define coolant_control_h
|
||||
|
||||
#define COOLANT_NO_SYNC false
|
||||
#define COOLANT_FORCE_SYNC true
|
||||
|
||||
#define COOLANT_STATE_DISABLE 0 // Must be zero
|
||||
#define COOLANT_STATE_FLOOD bit(0)
|
||||
#define COOLANT_STATE_MIST bit(1)
|
||||
#define COOLANT_NO_SYNC false
|
||||
#define COOLANT_FORCE_SYNC true
|
||||
|
||||
#define COOLANT_STATE_DISABLE 0 // Must be zero
|
||||
#define COOLANT_STATE_FLOOD bit(0)
|
||||
#define COOLANT_STATE_MIST bit(1)
|
||||
|
||||
// Initializes coolant control pins.
|
||||
void coolant_init();
|
||||
@@ -46,5 +44,3 @@ void coolant_set_state(uint8_t mode);
|
||||
|
||||
// G-code parser entry-point for setting coolant states. Checks for and executes additional conditions.
|
||||
void coolant_sync(uint8_t mode);
|
||||
|
||||
#endif
|
@@ -1,8 +1,8 @@
|
||||
// This file loads custom code from the Custom/ subdirectory if
|
||||
// CUSTOM_CODE_FILENAME is defined.
|
||||
|
||||
#include "grbl.h"
|
||||
#include "Grbl.h"
|
||||
|
||||
#ifdef CUSTOM_CODE_FILENAME
|
||||
#include CUSTOM_CODE_FILENAME
|
||||
# include CUSTOM_CODE_FILENAME
|
||||
#endif
|
501
Grbl_Esp32/src/Defaults.h
Normal file
501
Grbl_Esp32/src/Defaults.h
Normal file
@@ -0,0 +1,501 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
Defaults.h - defaults settings configuration file
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2012-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
|
||||
2018 - Bart Dring This file was modifed for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* The defaults.h file serves as a central default settings selector for different machine
|
||||
types, from DIY CNC mills to CNC conversions of off-the-shelf machines. The settings
|
||||
files listed here are supplied by users, so your results may vary. However, this should
|
||||
give you a good starting point as you get to know your machine and tweak the settings for
|
||||
your nefarious needs.
|
||||
NOTE: Ensure one and only one of these DEFAULTS_XXX values is defined in config.h */
|
||||
|
||||
/*
|
||||
All of these settings check to see if they have been defined already
|
||||
before defining them. This allows to to easily set them eslewhere.
|
||||
You only need to set ones that are important or unique to your
|
||||
machine. The rest will be pulled from here.
|
||||
*/
|
||||
|
||||
// Grbl generic default settings. Should work across different machines.
|
||||
#ifndef DEFAULT_STEP_PULSE_MICROSECONDS
|
||||
# define DEFAULT_STEP_PULSE_MICROSECONDS 3 // $0
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_STEPPER_IDLE_LOCK_TIME
|
||||
# define DEFAULT_STEPPER_IDLE_LOCK_TIME 250 // $1 msec (0-254, 255 keeps steppers enabled)
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_STEPPING_INVERT_MASK
|
||||
# define DEFAULT_STEPPING_INVERT_MASK 0 // $2 uint8_t
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_DIRECTION_INVERT_MASK
|
||||
# define DEFAULT_DIRECTION_INVERT_MASK 0 // $3 uint8_
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_INVERT_ST_ENABLE
|
||||
# define DEFAULT_INVERT_ST_ENABLE 0 // $4 boolean
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_INVERT_LIMIT_PINS
|
||||
# define DEFAULT_INVERT_LIMIT_PINS 1 // $5 boolean
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_INVERT_PROBE_PIN
|
||||
# define DEFAULT_INVERT_PROBE_PIN 0 // $6 boolean
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_STATUS_REPORT_MASK
|
||||
# define DEFAULT_STATUS_REPORT_MASK 1 // $10
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_JUNCTION_DEVIATION
|
||||
# define DEFAULT_JUNCTION_DEVIATION 0.01 // $11 mm
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_ARC_TOLERANCE
|
||||
# define DEFAULT_ARC_TOLERANCE 0.002 // $12 mm
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_REPORT_INCHES
|
||||
# define DEFAULT_REPORT_INCHES 0 // $13 false
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_SOFT_LIMIT_ENABLE
|
||||
# define DEFAULT_SOFT_LIMIT_ENABLE 0 // $20 false
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_HARD_LIMIT_ENABLE
|
||||
# define DEFAULT_HARD_LIMIT_ENABLE 0 // $21 false
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_HOMING_ENABLE
|
||||
# define DEFAULT_HOMING_ENABLE 0 // $22 false
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_HOMING_DIR_MASK
|
||||
# define DEFAULT_HOMING_DIR_MASK 3 // $23 move positive dir Z, negative X,Y
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_HOMING_FEED_RATE
|
||||
# define DEFAULT_HOMING_FEED_RATE 200.0 // $24 mm/min
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_HOMING_SEEK_RATE
|
||||
# define DEFAULT_HOMING_SEEK_RATE 2000.0 // $25 mm/min
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_HOMING_DEBOUNCE_DELAY
|
||||
# define DEFAULT_HOMING_DEBOUNCE_DELAY 250 // $26 msec (0-65k)
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_HOMING_PULLOFF
|
||||
# define DEFAULT_HOMING_PULLOFF 1.0 // $27 mm
|
||||
#endif
|
||||
|
||||
// ======== SPINDLE STUFF ====================
|
||||
#ifndef SPINDLE_TYPE
|
||||
# define SPINDLE_TYPE SPINDLE_TYPE_NONE
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_SPINDLE_RPM_MIN // $31
|
||||
# define DEFAULT_SPINDLE_RPM_MIN 0.0 // rpm
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_LASER_MODE // $32
|
||||
# define DEFAULT_LASER_MODE 0 // false
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_SPINDLE_RPM_MAX // $30
|
||||
# define DEFAULT_SPINDLE_RPM_MAX 1000.0 // rpm
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_SPINDLE_FREQ
|
||||
# define DEFAULT_SPINDLE_FREQ 5000.0 // $33 Hz (extended set)
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_SPINDLE_OFF_VALUE
|
||||
# define DEFAULT_SPINDLE_OFF_VALUE 0.0 // $34 Percent of full period(extended set)
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_SPINDLE_MIN_VALUE
|
||||
# define DEFAULT_SPINDLE_MIN_VALUE 0.0 // $35 Percent of full period (extended set)
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_SPINDLE_MAX_VALUE
|
||||
# define DEFAULT_SPINDLE_MAX_VALUE 100.0 // $36 Percent of full period (extended set)
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_SPINDLE_DELAY_SPINUP
|
||||
# define DEFAULT_SPINDLE_DELAY_SPINUP 0
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_SPINDLE_DELAY_SPINDOWN
|
||||
# define DEFAULT_SPINDLE_DELAY_SPINDOWN 0
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_INVERT_SPINDLE_OUTPUT_PIN
|
||||
# define DEFAULT_INVERT_SPINDLE_OUTPUT_PIN 0
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_INVERT_SPINDLE_ENABLE_PIN
|
||||
# define DEFAULT_INVERT_SPINDLE_ENABLE_PIN 0
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_SPINDLE_ENABLE_OFF_WITH_ZERO_SPEED
|
||||
# define DEFAULT_SPINDLE_ENABLE_OFF_WITH_ZERO_SPEED 0
|
||||
#endif
|
||||
|
||||
// ================ user settings =====================
|
||||
#ifndef DEFAULT_USER_INT_80
|
||||
# define DEFAULT_USER_INT_80 0 // $80 User integer setting
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_USER_INT_81
|
||||
# define DEFAULT_USER_INT_81 0 // $81 User integer setting
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_USER_INT_82
|
||||
# define DEFAULT_USER_INT_82 0 // $82 User integer setting
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_USER_INT_83
|
||||
# define DEFAULT_USER_INT_83 0 // $83 User integer setting
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_USER_INT_84
|
||||
# define DEFAULT_USER_INT_84 0 // $84 User integer setting
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_USER_FLOAT_90
|
||||
# define DEFAULT_USER_FLOAT_90 0.0 // $90 User integer setting
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_USER_FLOAT_91
|
||||
# define DEFAULT_USER_FLOAT_91 0.0 // $92 User integer setting
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_USER_FLOAT_92
|
||||
# define DEFAULT_USER_FLOAT_92 0.0 // $92 User integer setting
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_USER_FLOAT_93
|
||||
# define DEFAULT_USER_FLOAT_93 0.0 // $93 User integer setting
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_USER_FLOAT_94
|
||||
# define DEFAULT_USER_FLOAT_94 0.0 // $94 User integer setting
|
||||
#endif
|
||||
|
||||
// =========== AXIS RESOLUTION ======
|
||||
|
||||
#ifndef DEFAULT_X_STEPS_PER_MM
|
||||
# define DEFAULT_X_STEPS_PER_MM 100.0
|
||||
#endif
|
||||
#ifndef DEFAULT_Y_STEPS_PER_MM
|
||||
# define DEFAULT_Y_STEPS_PER_MM 100.0
|
||||
#endif
|
||||
#ifndef DEFAULT_Z_STEPS_PER_MM
|
||||
# define DEFAULT_Z_STEPS_PER_MM 100.0
|
||||
#endif
|
||||
#ifndef DEFAULT_A_STEPS_PER_MM
|
||||
# define DEFAULT_A_STEPS_PER_MM 100.0
|
||||
#endif
|
||||
#ifndef DEFAULT_B_STEPS_PER_MM
|
||||
# define DEFAULT_B_STEPS_PER_MM 100.0
|
||||
#endif
|
||||
#ifndef DEFAULT_C_STEPS_PER_MM
|
||||
# define DEFAULT_C_STEPS_PER_MM 100.0
|
||||
#endif
|
||||
|
||||
// ============ AXIS MAX SPPED =========
|
||||
|
||||
#ifndef DEFAULT_X_MAX_RATE
|
||||
# define DEFAULT_X_MAX_RATE 1000.0 // mm/min
|
||||
#endif
|
||||
#ifndef DEFAULT_Y_MAX_RATE
|
||||
# define DEFAULT_Y_MAX_RATE 1000.0 // mm/min
|
||||
#endif
|
||||
#ifndef DEFAULT_Z_MAX_RATE
|
||||
# define DEFAULT_Z_MAX_RATE 1000.0 // mm/min
|
||||
#endif
|
||||
#ifndef DEFAULT_A_MAX_RATE
|
||||
# define DEFAULT_A_MAX_RATE 1000.0 // mm/min
|
||||
#endif
|
||||
#ifndef DEFAULT_B_MAX_RATE
|
||||
# define DEFAULT_B_MAX_RATE 1000.0 // mm/min
|
||||
#endif
|
||||
#ifndef DEFAULT_C_MAX_RATE
|
||||
# define DEFAULT_C_MAX_RATE 1000.0 // mm/min
|
||||
#endif
|
||||
|
||||
// ============== Axis Acceleration =========
|
||||
#define SEC_PER_MIN_SQ (60.0 * 60.0) // Seconds Per Minute Squared, for acceleration conversion
|
||||
// Default accelerations are expressed in mm/sec^2
|
||||
#ifndef DEFAULT_X_ACCELERATION
|
||||
# define DEFAULT_X_ACCELERATION 200.0
|
||||
#endif
|
||||
#ifndef DEFAULT_Y_ACCELERATION
|
||||
# define DEFAULT_Y_ACCELERATION 200.0
|
||||
#endif
|
||||
#ifndef DEFAULT_Z_ACCELERATION
|
||||
# define DEFAULT_Z_ACCELERATION 200.0
|
||||
#endif
|
||||
#ifndef DEFAULT_A_ACCELERATION
|
||||
# define DEFAULT_A_ACCELERATION 200.0
|
||||
#endif
|
||||
#ifndef DEFAULT_B_ACCELERATION
|
||||
# define DEFAULT_B_ACCELERATION 200.0
|
||||
#endif
|
||||
#ifndef DEFAULT_C_ACCELERATION
|
||||
# define DEFAULT_C_ACCELERATION 200.0
|
||||
#endif
|
||||
|
||||
// ========= AXIS MAX TRAVEL ============
|
||||
|
||||
#ifndef DEFAULT_X_MAX_TRAVEL
|
||||
# define DEFAULT_X_MAX_TRAVEL 300.0 // $130 mm NOTE: Must be a positive value.
|
||||
#endif
|
||||
#ifndef DEFAULT_Y_MAX_TRAVEL
|
||||
# define DEFAULT_Y_MAX_TRAVEL 300.0 // mm NOTE: Must be a positive value.
|
||||
#endif
|
||||
#ifndef DEFAULT_Z_MAX_TRAVEL
|
||||
# define DEFAULT_Z_MAX_TRAVEL 300.0 // mm NOTE: Must be a positive value.
|
||||
#endif
|
||||
#ifndef DEFAULT_A_MAX_TRAVEL
|
||||
# define DEFAULT_A_MAX_TRAVEL 300.0 // mm NOTE: Must be a positive value.
|
||||
#endif
|
||||
#ifndef DEFAULT_B_MAX_TRAVEL
|
||||
# define DEFAULT_B_MAX_TRAVEL 300.0 // mm NOTE: Must be a positive value.
|
||||
#endif
|
||||
#ifndef DEFAULT_C_MAX_TRAVEL
|
||||
# define DEFAULT_C_MAX_TRAVEL 300.0 // mm NOTE: Must be a positive value.
|
||||
#endif
|
||||
|
||||
// ========== Motor current (SPI Drivers ) =============
|
||||
#ifndef DEFAULT_X_CURRENT
|
||||
# define DEFAULT_X_CURRENT 0.25 // $140 current in amps (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_Y_CURRENT
|
||||
# define DEFAULT_Y_CURRENT 0.25 // $141 current in amps (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_Z_CURRENT
|
||||
# define DEFAULT_Z_CURRENT 0.25 // $142 current in amps (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_A_CURRENT
|
||||
# define DEFAULT_A_CURRENT 0.25 // $143 current in amps (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_B_CURRENT
|
||||
# define DEFAULT_B_CURRENT 0.25 // $144 current in amps (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_C_CURRENT
|
||||
# define DEFAULT_C_CURRENT 0.25 // $145 current in amps (extended set)
|
||||
#endif
|
||||
|
||||
// ========== Motor hold current (SPI Drivers ) =============
|
||||
|
||||
#ifndef DEFAULT_X_HOLD_CURRENT
|
||||
# define DEFAULT_X_HOLD_CURRENT 0.125 // $150 current in amps (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_Y_HOLD_CURRENT
|
||||
# define DEFAULT_Y_HOLD_CURRENT 0.125 // $151 current in amps (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_Z_HOLD_CURRENT
|
||||
# define DEFAULT_Z_HOLD_CURRENT 0.125 // $152 current in amps (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_A_HOLD_CURRENT
|
||||
# define DEFAULT_A_HOLD_CURRENT 0.125 // $153 current in amps (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_B_HOLD_CURRENT
|
||||
# define DEFAULT_B_HOLD_CURRENT 0.125 // $154 current in amps (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_C_HOLD_CURRENT
|
||||
# define DEFAULT_C_HOLD_CURRENT 0.125 // $154 current in amps (extended set)
|
||||
#endif
|
||||
|
||||
// ========== Microsteps (SPI Drivers ) ================
|
||||
|
||||
#ifndef DEFAULT_X_MICROSTEPS
|
||||
# define DEFAULT_X_MICROSTEPS 16 // $160 micro steps (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_Y_MICROSTEPS
|
||||
# define DEFAULT_Y_MICROSTEPS 16 // $161 micro steps (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_Z_MICROSTEPS
|
||||
# define DEFAULT_Z_MICROSTEPS 16 // $162 micro steps (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_A_MICROSTEPS
|
||||
# define DEFAULT_A_MICROSTEPS 16 // $163 micro steps (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_B_MICROSTEPS
|
||||
# define DEFAULT_B_MICROSTEPS 16 // $164 micro steps (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_C_MICROSTEPS
|
||||
# define DEFAULT_C_MICROSTEPS 16 // $165 micro steps (extended set)
|
||||
#endif
|
||||
|
||||
// ========== Stallguard (SPI Drivers ) ================
|
||||
|
||||
#ifndef DEFAULT_X_STALLGUARD
|
||||
# define DEFAULT_X_STALLGUARD 16 // $170 stallguard (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_Y_STALLGUARD
|
||||
# define DEFAULT_Y_STALLGUARD 16 // $171 stallguard (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_Z_STALLGUARD
|
||||
# define DEFAULT_Z_STALLGUARD 16 // $172 stallguard (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_A_STALLGUARD
|
||||
# define DEFAULT_A_STALLGUARD 16 // $173 stallguard (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_B_STALLGUARD
|
||||
# define DEFAULT_B_STALLGUARD 16 // $174 stallguard (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_C_STALLGUARD
|
||||
# define DEFAULT_C_STALLGUARD 16 // $175 stallguard (extended set)
|
||||
#endif
|
||||
|
||||
// ================== pin defaults ========================
|
||||
|
||||
// Here is a place to default pins to UNDEFINED_PIN.
|
||||
// This can eliminate checking to see if the pin is defined because
|
||||
// the overridden pinMode and digitalWrite functions will deal with it.
|
||||
|
||||
#ifndef STEPPERS_DISABLE_PIN
|
||||
# define STEPPERS_DISABLE_PIN UNDEFINED_PIN
|
||||
#endif
|
||||
|
||||
#ifndef X_DISABLE_PIN
|
||||
# define X_DISABLE_PIN UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef Y_DISABLE_PIN
|
||||
# define Y_DISABLE_PIN UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef Z_DISABLE_PIN
|
||||
# define Z_DISABLE_PIN UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef A_DISABLE_PIN
|
||||
# define A_DISABLE_PIN UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef B_DISABLE_PIN
|
||||
# define B_DISABLE_PIN UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef C_DISABLE_PIN
|
||||
# define C_DISABLE_PIN UNDEFINED_PIN
|
||||
#endif
|
||||
|
||||
#ifndef X2_DISABLE_PIN
|
||||
# define X2_DISABLE_PIN UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef Y2_DISABLE_PIN
|
||||
# define Y2_DISABLE_PIN UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef Z2_DISABLE_PIN
|
||||
# define Z2_DISABLE_PIN UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef A2_DISABLE_PIN
|
||||
# define A2_DISABLE_PIN UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef B2_DISABLE_PIN
|
||||
# define B2_DISABLE_PIN UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef C2_DISABLE_PIN
|
||||
# define C2_DISABLE_PIN UNDEFINED_PIN
|
||||
#endif
|
||||
|
||||
#ifndef X_LIMIT_PIN
|
||||
# define X_LIMIT_PIN UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef Y_LIMIT_PIN
|
||||
# define Y_LIMIT_PIN UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef Z_LIMIT_PIN
|
||||
# define Z_LIMIT_PIN UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef A_LIMIT_PIN
|
||||
# define A_LIMIT_PIN UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef B_LIMIT_PIN
|
||||
# define B_LIMIT_PIN UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef C_LIMIT_PIN
|
||||
# define C_LIMIT_PIN UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef X2_LIMIT_PIN
|
||||
# define X2_LIMIT_PIN UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef Y2_LIMIT_PIN
|
||||
# define Y2_LIMIT_PIN UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef Z2_LIMIT_PIN
|
||||
# define Z2_LIMIT_PIN UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef A2_LIMIT_PIN
|
||||
# define A2_LIMIT_PIN UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef B2_LIMIT_PIN
|
||||
# define B2_LIMIT_PIN UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef C2_LIMIT_PIN
|
||||
# define C2_LIMIT_PIN UNDEFINED_PIN
|
||||
#endif
|
||||
|
||||
// assigned all MS3 (microstep pin 3) to UNDEFINED_PIN
|
||||
|
||||
#ifndef X_STEPPER_MS3
|
||||
# define X_STEPPER_MS3 UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef Y_STEPPER_MS3
|
||||
# define Y_STEPPER_MS3 UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef Z_STEPPER_MS3
|
||||
# define Z_STEPPER_MS3 UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef A_STEPPER_MS3
|
||||
# define A_STEPPER_MS3 UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef B_STEPPER_MS3
|
||||
# define B_STEPPER_MS3 UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef C_STEPPER_MS3
|
||||
# define C_STEPPER_MS3 UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef X2_STEPPER_MS3
|
||||
# define X2_STEPPER_MS3 UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef Y2_STEPPER_MS3
|
||||
# define Y2_STEPPER_MS3 UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef Z2_STEPPER_MS3
|
||||
# define Z2_STEPPER_MS3 UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef A2_STEPPER_MS3
|
||||
# define A2_STEPPER_MS3 UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef B2_STEPPER_MS3
|
||||
# define B2_STEPPER_MS3 UNDEFINED_PIN
|
||||
#endif
|
||||
#ifndef C2_STEPPER_MS3
|
||||
# define C2_STEPPER_MS3 UNDEFINED_PIN
|
||||
#endif
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
eeprom.cpp - Header for system level commands and real-time processes
|
||||
Eeprom.cpp - Header for system level commands and real-time processes
|
||||
Part of Grbl
|
||||
Copyright (c) 2014-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "grbl.h"
|
||||
#include "Grbl.h"
|
||||
|
||||
void memcpy_to_eeprom_with_checksum(unsigned int destination, const char* source, unsigned int size) {
|
||||
unsigned char checksum = 0;
|
||||
@@ -34,7 +34,7 @@ void memcpy_to_eeprom_with_checksum(unsigned int destination, const char* source
|
||||
int memcpy_from_eeprom_with_checksum(char* destination, unsigned int source, unsigned int size) {
|
||||
unsigned char data, checksum = 0;
|
||||
for (; size > 0; size--) {
|
||||
data = EEPROM.read(source++);
|
||||
data = EEPROM.read(source++);
|
||||
checksum = (checksum << 1) || (checksum >> 7);
|
||||
checksum += data;
|
||||
*(destination++) = data;
|
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
eeprom.h - Header for system level commands and real-time processes
|
||||
Eeprom.h - Header for system level commands and real-time processes
|
||||
Part of Grbl
|
||||
Copyright (c) 2014-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
|
||||
@@ -18,14 +20,9 @@
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef eeprom_memcpy_h
|
||||
#define eeprom_memcpy_h
|
||||
|
||||
#include "grbl.h"
|
||||
#include "Grbl.h"
|
||||
|
||||
//unsigned char eeprom_get_char(unsigned int addr);
|
||||
//void eeprom_put_char(unsigned int addr, unsigned char new_value);
|
||||
void memcpy_to_eeprom_with_checksum(unsigned int destination, const char* source, unsigned int size);
|
||||
int memcpy_from_eeprom_with_checksum(char* destination, unsigned int source, unsigned int size);
|
||||
|
||||
#endif
|
||||
int memcpy_from_eeprom_with_checksum(char* destination, unsigned int source, unsigned int size);
|
1365
Grbl_Esp32/src/GCode.cpp
Normal file
1365
Grbl_Esp32/src/GCode.cpp
Normal file
File diff suppressed because it is too large
Load Diff
261
Grbl_Esp32/src/GCode.h
Normal file
261
Grbl_Esp32/src/GCode.h
Normal file
@@ -0,0 +1,261 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
GCode.h - rs274/ngc parser.
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2011-2015 Sungeun K. Jeon
|
||||
Copyright (c) 2009-2011 Simen Svale Skogsrud
|
||||
|
||||
2018 - Bart Dring This file was modifed for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Define modal group internal numbers for checking multiple command violations and tracking the
|
||||
// type of command that is called in the block. A modal group is a group of g-code commands that are
|
||||
// mutually exclusive, or cannot exist on the same line, because they each toggle a state or execute
|
||||
// a unique motion. These are defined in the NIST RS274-NGC v3 g-code standard, available online,
|
||||
// and are similar/identical to other g-code interpreters by manufacturers (Haas,Fanuc,Mazak,etc).
|
||||
// NOTE: Modal group define values must be sequential and starting from zero.
|
||||
#define MODAL_GROUP_G0 0 // [G4,G10,G28,G28.1,G30,G30.1,G53,G92,G92.1] Non-modal
|
||||
#define MODAL_GROUP_G1 1 // [G0,G1,G2,G3,G38.2,G38.3,G38.4,G38.5,G80] Motion
|
||||
#define MODAL_GROUP_G2 2 // [G17,G18,G19] Plane selection
|
||||
#define MODAL_GROUP_G3 3 // [G90,G91] Distance mode
|
||||
#define MODAL_GROUP_G4 4 // [G91.1] Arc IJK distance mode
|
||||
#define MODAL_GROUP_G5 5 // [G93,G94] Feed rate mode
|
||||
#define MODAL_GROUP_G6 6 // [G20,G21] Units
|
||||
#define MODAL_GROUP_G7 7 // [G40] Cutter radius compensation mode. G41/42 NOT SUPPORTED.
|
||||
#define MODAL_GROUP_G8 8 // [G43.1,G49] Tool length offset
|
||||
#define MODAL_GROUP_G12 9 // [G54,G55,G56,G57,G58,G59] Coordinate system selection
|
||||
#define MODAL_GROUP_G13 10 // [G61] Control mode
|
||||
|
||||
#define MODAL_GROUP_M4 11 // [M0,M1,M2,M30] Stopping
|
||||
#define MODAL_GROUP_M6 14 // [M6] Tool change
|
||||
#define MODAL_GROUP_M7 12 // [M3,M4,M5] Spindle turning
|
||||
#define MODAL_GROUP_M8 13 // [M7,M8,M9] Coolant control
|
||||
#define MODAL_GROUP_M9 14 // [M56] Override control
|
||||
#define MODAL_GROUP_M10 15 // [M62, M63] User Defined http://linuxcnc.org/docs/html/gcode/overview.html#_modal_groups
|
||||
|
||||
// #define OTHER_INPUT_F 14
|
||||
// #define OTHER_INPUT_S 15
|
||||
// #define OTHER_INPUT_T 16
|
||||
|
||||
// Define command actions for within execution-type modal groups (motion, stopping, non-modal). Used
|
||||
// internally by the parser to know which command to execute.
|
||||
// NOTE: Some macro values are assigned specific values to make g-code state reporting and parsing
|
||||
// compile a litte smaller. Necessary due to being completely out of flash on the 328p. Although not
|
||||
// ideal, just be careful with values that state 'do not alter' and check both report.c and gcode.c
|
||||
// to see how they are used, if you need to alter them.
|
||||
|
||||
// Modal Group G0: Non-modal actions
|
||||
#define NON_MODAL_NO_ACTION 0 // (Default: Must be zero)
|
||||
#define NON_MODAL_DWELL 4 // G4 (Do not alter value)
|
||||
#define NON_MODAL_SET_COORDINATE_DATA 10 // G10 (Do not alter value)
|
||||
#define NON_MODAL_GO_HOME_0 28 // G28 (Do not alter value)
|
||||
#define NON_MODAL_SET_HOME_0 38 // G28.1 (Do not alter value)
|
||||
#define NON_MODAL_GO_HOME_1 30 // G30 (Do not alter value)
|
||||
#define NON_MODAL_SET_HOME_1 40 // G30.1 (Do not alter value)
|
||||
#define NON_MODAL_ABSOLUTE_OVERRIDE 53 // G53 (Do not alter value)
|
||||
#define NON_MODAL_SET_COORDINATE_OFFSET 92 // G92 (Do not alter value)
|
||||
#define NON_MODAL_RESET_COORDINATE_OFFSET 102 //G92.1 (Do not alter value)
|
||||
|
||||
// Modal Group G1: Motion modes
|
||||
#define MOTION_MODE_SEEK 0 // G0 (Default: Must be zero)
|
||||
#define MOTION_MODE_LINEAR 1 // G1 (Do not alter value)
|
||||
#define MOTION_MODE_CW_ARC 2 // G2 (Do not alter value)
|
||||
#define MOTION_MODE_CCW_ARC 3 // G3 (Do not alter value)
|
||||
#define MOTION_MODE_PROBE_TOWARD 140 // G38.2 (Do not alter value)
|
||||
#define MOTION_MODE_PROBE_TOWARD_NO_ERROR 141 // G38.3 (Do not alter value)
|
||||
#define MOTION_MODE_PROBE_AWAY 142 // G38.4 (Do not alter value)
|
||||
#define MOTION_MODE_PROBE_AWAY_NO_ERROR 143 // G38.5 (Do not alter value)
|
||||
#define MOTION_MODE_NONE 80 // G80 (Do not alter value)
|
||||
|
||||
// Modal Group G2: Plane select
|
||||
#define PLANE_SELECT_XY 0 // G17 (Default: Must be zero)
|
||||
#define PLANE_SELECT_ZX 1 // G18 (Do not alter value)
|
||||
#define PLANE_SELECT_YZ 2 // G19 (Do not alter value)
|
||||
|
||||
// Modal Group G3: Distance mode
|
||||
#define DISTANCE_MODE_ABSOLUTE 0 // G90 (Default: Must be zero)
|
||||
#define DISTANCE_MODE_INCREMENTAL 1 // G91 (Do not alter value)
|
||||
|
||||
// Modal Group G4: Arc IJK distance mode
|
||||
#define DISTANCE_ARC_MODE_INCREMENTAL 0 // G91.1 (Default: Must be zero)
|
||||
|
||||
// Modal Group M4: Program flow
|
||||
#define PROGRAM_FLOW_RUNNING 0 // (Default: Must be zero)
|
||||
#define PROGRAM_FLOW_PAUSED 3 // M0
|
||||
#define PROGRAM_FLOW_OPTIONAL_STOP 1 // M1 NOTE: Not supported, but valid and ignored.
|
||||
#define PROGRAM_FLOW_COMPLETED_M2 2 // M2 (Do not alter value)
|
||||
#define PROGRAM_FLOW_COMPLETED_M30 30 // M30 (Do not alter value)
|
||||
|
||||
// Modal Group G5: Feed rate mode
|
||||
#define FEED_RATE_MODE_UNITS_PER_MIN 0 // G94 (Default: Must be zero)
|
||||
#define FEED_RATE_MODE_INVERSE_TIME 1 // G93 (Do not alter value)
|
||||
|
||||
// Modal Group G6: Units mode
|
||||
#define UNITS_MODE_MM 0 // G21 (Default: Must be zero)
|
||||
#define UNITS_MODE_INCHES 1 // G20 (Do not alter value)
|
||||
|
||||
// Modal Group G7: Cutter radius compensation mode
|
||||
#define CUTTER_COMP_DISABLE 0 // G40 (Default: Must be zero)
|
||||
|
||||
// Modal Group G13: Control mode
|
||||
#define CONTROL_MODE_EXACT_PATH 0 // G61 (Default: Must be zero)
|
||||
|
||||
// Modal Group M7: Spindle control
|
||||
#define SPINDLE_DISABLE 0 // M5 (Default: Must be zero)
|
||||
#define SPINDLE_ENABLE_CW PL_COND_FLAG_SPINDLE_CW // M3 (NOTE: Uses planner condition bit flag)
|
||||
#define SPINDLE_ENABLE_CCW PL_COND_FLAG_SPINDLE_CCW // M4 (NOTE: Uses planner condition bit flag)
|
||||
|
||||
// Modal Group M8: Coolant control
|
||||
#define COOLANT_DISABLE 0 // M9 (Default: Must be zero)
|
||||
#define COOLANT_FLOOD_ENABLE PL_COND_FLAG_COOLANT_FLOOD // M8 (NOTE: Uses planner condition bit flag)
|
||||
#define COOLANT_MIST_ENABLE PL_COND_FLAG_COOLANT_MIST // M7 (NOTE: Uses planner condition bit flag)
|
||||
|
||||
// Modal Group M9: Override control
|
||||
#ifdef DEACTIVATE_PARKING_UPON_INIT
|
||||
# define OVERRIDE_DISABLED 0 // (Default: Must be zero)
|
||||
# define OVERRIDE_PARKING_MOTION 1 // M56
|
||||
#else
|
||||
# define OVERRIDE_PARKING_MOTION 0 // M56 (Default: Must be zero)
|
||||
# define OVERRIDE_DISABLED 1 // Parking disabled.
|
||||
#endif
|
||||
|
||||
// modal Group M10: User I/O control
|
||||
#define NON_MODAL_IO_ENABLE 1
|
||||
#define NON_MODAL_IO_DISABLE 2
|
||||
#define MAX_USER_DIGITAL_PIN 4
|
||||
|
||||
// Modal Group G8: Tool length offset
|
||||
#define TOOL_LENGTH_OFFSET_CANCEL 0 // G49 (Default: Must be zero)
|
||||
#define TOOL_LENGTH_OFFSET_ENABLE_DYNAMIC 1 // G43.1
|
||||
|
||||
#define TOOL_CHANGE 1
|
||||
|
||||
// Modal Group G12: Active work coordinate system
|
||||
// N/A: Stores coordinate system value (54-59) to change to.
|
||||
|
||||
// Define parameter word mapping.
|
||||
#define WORD_F 0
|
||||
#define WORD_I 1
|
||||
#define WORD_J 2
|
||||
#define WORD_K 3
|
||||
#define WORD_L 4
|
||||
#define WORD_N 5
|
||||
#define WORD_P 6
|
||||
#define WORD_R 7
|
||||
#define WORD_S 8
|
||||
#define WORD_T 9
|
||||
#define WORD_X 10
|
||||
#define WORD_Y 11
|
||||
#define WORD_Z 12
|
||||
#define WORD_A 13
|
||||
#define WORD_B 14
|
||||
#define WORD_C 15
|
||||
|
||||
// Define g-code parser position updating flags
|
||||
#define GC_UPDATE_POS_TARGET 0 // Must be zero
|
||||
#define GC_UPDATE_POS_SYSTEM 1
|
||||
#define GC_UPDATE_POS_NONE 2
|
||||
|
||||
// Define probe cycle exit states and assign proper position updating.
|
||||
#define GC_PROBE_FOUND GC_UPDATE_POS_SYSTEM
|
||||
#define GC_PROBE_ABORT GC_UPDATE_POS_NONE
|
||||
#define GC_PROBE_FAIL_INIT GC_UPDATE_POS_NONE
|
||||
#define GC_PROBE_FAIL_END GC_UPDATE_POS_TARGET
|
||||
#ifdef SET_CHECK_MODE_PROBE_TO_START
|
||||
# define GC_PROBE_CHECK_MODE GC_UPDATE_POS_NONE
|
||||
#else
|
||||
# define GC_PROBE_CHECK_MODE GC_UPDATE_POS_TARGET
|
||||
#endif
|
||||
|
||||
// Define gcode parser flags for handling special cases.
|
||||
#define GC_PARSER_NONE 0 // Must be zero.
|
||||
#define GC_PARSER_JOG_MOTION bit(0)
|
||||
#define GC_PARSER_CHECK_MANTISSA bit(1)
|
||||
#define GC_PARSER_ARC_IS_CLOCKWISE bit(2)
|
||||
#define GC_PARSER_PROBE_IS_AWAY bit(3)
|
||||
#define GC_PARSER_PROBE_IS_NO_ERROR bit(4)
|
||||
#define GC_PARSER_LASER_FORCE_SYNC bit(5)
|
||||
#define GC_PARSER_LASER_DISABLE bit(6)
|
||||
#define GC_PARSER_LASER_ISMOTION bit(7)
|
||||
|
||||
// NOTE: When this struct is zeroed, the above defines set the defaults for the system.
|
||||
typedef struct {
|
||||
uint8_t motion; // {G0,G1,G2,G3,G38.2,G80}
|
||||
uint8_t feed_rate; // {G93,G94}
|
||||
uint8_t units; // {G20,G21}
|
||||
uint8_t distance; // {G90,G91}
|
||||
// uint8_t distance_arc; // {G91.1} NOTE: Don't track. Only default supported.
|
||||
uint8_t plane_select; // {G17,G18,G19}
|
||||
// uint8_t cutter_comp; // {G40} NOTE: Don't track. Only default supported.
|
||||
uint8_t tool_length; // {G43.1,G49}
|
||||
uint8_t coord_select; // {G54,G55,G56,G57,G58,G59}
|
||||
// uint8_t control; // {G61} NOTE: Don't track. Only default supported.
|
||||
uint8_t program_flow; // {M0,M1,M2,M30}
|
||||
uint8_t coolant; // {M7,M8,M9}
|
||||
uint8_t spindle; // {M3,M4,M5}
|
||||
uint8_t tool_change; // {M6}
|
||||
uint8_t io_control; // {M62, M63}
|
||||
uint8_t override; // {M56}
|
||||
} gc_modal_t;
|
||||
|
||||
typedef struct {
|
||||
float f; // Feed
|
||||
float ijk[N_AXIS]; // I,J,K Axis arc offsets
|
||||
uint8_t l; // G10 or canned cycles parameters
|
||||
int32_t n; // Line number
|
||||
float p; // G10 or dwell parameters
|
||||
// float q; // G82 peck drilling
|
||||
float r; // Arc radius
|
||||
float s; // Spindle speed
|
||||
uint8_t t; // Tool selection
|
||||
float xyz[N_AXIS]; // X,Y,Z Translational axes
|
||||
} gc_values_t;
|
||||
|
||||
typedef struct {
|
||||
gc_modal_t modal;
|
||||
|
||||
float spindle_speed; // RPM
|
||||
float feed_rate; // Millimeters/min
|
||||
uint8_t tool; // Tracks tool number. NOT USED.
|
||||
int32_t line_number; // Last line number sent
|
||||
|
||||
float position[N_AXIS]; // Where the interpreter considers the tool to be at this point in the code
|
||||
|
||||
float coord_system[N_AXIS]; // Current work coordinate system (G54+). Stores offset from absolute machine
|
||||
// position in mm. Loaded from EEPROM when called.
|
||||
float coord_offset[N_AXIS]; // Retains the G92 coordinate offset (work coordinates) relative to
|
||||
// machine zero in mm. Non-persistent. Cleared upon reset and boot.
|
||||
float tool_length_offset; // Tracks tool length offset value when enabled.
|
||||
} parser_state_t;
|
||||
extern parser_state_t gc_state;
|
||||
|
||||
typedef struct {
|
||||
uint8_t non_modal_command;
|
||||
gc_modal_t modal;
|
||||
gc_values_t values;
|
||||
} parser_block_t;
|
||||
|
||||
// Initialize the parser
|
||||
void gc_init();
|
||||
|
||||
// Execute one block of rs275/ngc/g-code
|
||||
uint8_t gc_execute_line(char* line, uint8_t client);
|
||||
|
||||
// Set g-code parser position. Input in steps.
|
||||
void gc_sync_position();
|
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
grbl.h - Header for system level commands and real-time processes
|
||||
Grbl.h - Header for system level commands and real-time processes
|
||||
Part of Grbl
|
||||
Copyright (c) 2014-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
|
||||
@@ -18,12 +20,10 @@
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
// Grbl versioning system
|
||||
|
||||
#define GRBL_VERSION "1.3a"
|
||||
#define GRBL_VERSION_BUILD "20200727"
|
||||
|
||||
#define GRBL_VERSION_BUILD "20200812"
|
||||
|
||||
//#include <sdkconfig.h>
|
||||
#include <Arduino.h>
|
||||
@@ -33,72 +33,66 @@
|
||||
#include <freertos/task.h>
|
||||
#include <Preferences.h>
|
||||
|
||||
#include "driver/timer.h"
|
||||
#include <driver/timer.h>
|
||||
|
||||
// Define the Grbl system include files. NOTE: Do not alter organization.
|
||||
#include "config.h"
|
||||
#include "nuts_bolts.h"
|
||||
#include "tdef.h"
|
||||
#include "Config.h"
|
||||
#include "NutsBolts.h"
|
||||
|
||||
#include "defaults.h"
|
||||
#include "settings.h"
|
||||
#include "authentication.h"
|
||||
#include "system.h"
|
||||
#include "Defaults.h"
|
||||
#include "SettingsStorage.h"
|
||||
#include "WebUI/Authentication.h"
|
||||
#include "WebUI/Commands.h"
|
||||
#include "System.h"
|
||||
|
||||
#include "planner.h"
|
||||
#include "coolant_control.h"
|
||||
#include "grbl_eeprom.h"
|
||||
#include "gcode.h"
|
||||
#include "grbl_limits.h"
|
||||
#include "motion_control.h"
|
||||
#include "print.h"
|
||||
#include "probe.h"
|
||||
#include "protocol.h"
|
||||
#include "report.h"
|
||||
#include "serial.h"
|
||||
#include "Planner.h"
|
||||
#include "CoolantControl.h"
|
||||
#include "Eeprom.h"
|
||||
#include "GCode.h"
|
||||
#include "Limits.h"
|
||||
#include "MotionControl.h"
|
||||
#include "Probe.h"
|
||||
#include "Protocol.h"
|
||||
#include "Report.h"
|
||||
#include "Serial.h"
|
||||
#include "Pins.h"
|
||||
#include "Spindles/SpindleClass.h"
|
||||
#include "Motors/MotorClass.h"
|
||||
#include "stepper.h"
|
||||
#include "jog.h"
|
||||
#include "inputbuffer.h"
|
||||
#include "commands.h"
|
||||
#include "SettingsClass.h"
|
||||
#include "Spindles/Spindle.h"
|
||||
#include "Motors/Motors.h"
|
||||
#include "Stepper.h"
|
||||
#include "Jog.h"
|
||||
#include "WebUI/InputBuffer.h"
|
||||
#include "Settings.h"
|
||||
#include "SettingsDefinitions.h"
|
||||
#include "WebSettings.h"
|
||||
#include "WebUI/WebSettings.h"
|
||||
|
||||
// Do not guard this because it is needed for local files too
|
||||
#include "grbl_sd.h"
|
||||
#include "SDCard.h"
|
||||
|
||||
#ifdef ENABLE_BLUETOOTH
|
||||
#include "BTconfig.h"
|
||||
# include "WebUI/BTConfig.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_WIFI
|
||||
#include "wificonfig.h"
|
||||
#ifdef ENABLE_HTTP
|
||||
#include "serial2socket.h"
|
||||
#endif
|
||||
#ifdef ENABLE_TELNET
|
||||
#include "telnet_server.h"
|
||||
#endif
|
||||
#ifdef ENABLE_NOTIFICATIONS
|
||||
#include "notifications_service.h"
|
||||
#endif
|
||||
# include "WebUI/WifiConfig.h"
|
||||
# ifdef ENABLE_HTTP
|
||||
# include "WebUI/Serial2Socket.h"
|
||||
# endif
|
||||
# ifdef ENABLE_TELNET
|
||||
# include "WebUI/TelnetServer.h"
|
||||
# endif
|
||||
# ifdef ENABLE_NOTIFICATIONS
|
||||
# include "WebUI/NotificationsService.h"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "solenoid_pen.h"
|
||||
#include "SolenoidPen.h"
|
||||
|
||||
#ifdef USE_SERVO_AXES
|
||||
#include "servo_axis.h"
|
||||
#endif
|
||||
|
||||
#ifdef USE_UNIPOLAR
|
||||
#include "grbl_unipolar.h"
|
||||
# include "ServoAxis.h"
|
||||
#endif
|
||||
|
||||
#ifdef USE_I2S_OUT
|
||||
#include "i2s_out.h"
|
||||
# include "I2SOut.h"
|
||||
#endif
|
||||
|
||||
// Called if USE_MACHINE_INIT is defined
|
914
Grbl_Esp32/src/I2SOut.cpp
Normal file
914
Grbl_Esp32/src/I2SOut.cpp
Normal file
@@ -0,0 +1,914 @@
|
||||
/*
|
||||
I2SOut.cpp
|
||||
Part of Grbl_ESP32
|
||||
|
||||
Basic GPIO expander using the ESP32 I2S peripheral (output)
|
||||
|
||||
2020 - Michiyasu Odaki
|
||||
|
||||
Grbl_ESP32 is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl_ESP32. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#include "Config.h"
|
||||
|
||||
#ifdef USE_I2S_OUT
|
||||
|
||||
# include <FreeRTOS.h>
|
||||
# include <driver/periph_ctrl.h>
|
||||
# include <rom/lldesc.h>
|
||||
# include <soc/i2s_struct.h>
|
||||
# include <freertos/queue.h>
|
||||
|
||||
# include <stdatomic.h>
|
||||
|
||||
# include "Pins.h"
|
||||
# include "I2SOut.h"
|
||||
|
||||
//
|
||||
// Configrations for DMA connected I2S
|
||||
//
|
||||
// One DMA buffer transfer takes about 2 ms
|
||||
// I2S_OUT_DMABUF_LEN / I2S_SAMPLE_SIZE x I2S_OUT_USEC_PER_PULSE
|
||||
// = 2000 / 4 x 4
|
||||
// = 2000us = 2ms
|
||||
// If I2S_OUT_DMABUF_COUNT is 5, it will take about 10 ms for all the DMA buffer transfers to finish.
|
||||
//
|
||||
// Increasing I2S_OUT_DMABUF_COUNT has the effect of preventing buffer underflow,
|
||||
// but on the other hand, it leads to a delay with pulse and/or non-pulse-generated I/Os.
|
||||
// The number of I2S_OUT_DMABUF_COUNT should be chosen carefully.
|
||||
//
|
||||
// Reference information:
|
||||
// FreeRTOS task time slice = portTICK_PERIOD_MS = 1 ms (ESP32 FreeRTOS port)
|
||||
//
|
||||
# define I2S_SAMPLE_SIZE 4 /* 4 bytes, 32 bits per sample */
|
||||
# define DMA_SAMPLE_COUNT I2S_OUT_DMABUF_LEN / I2S_SAMPLE_SIZE /* number of samples per buffer */
|
||||
# define SAMPLE_SAFE_COUNT (20 / I2S_OUT_USEC_PER_PULSE) /* prevent buffer overrun (GRBL's $0 should be less than or equal 20) */
|
||||
|
||||
# ifdef USE_I2S_OUT_STREAM
|
||||
typedef struct {
|
||||
uint32_t** buffers;
|
||||
uint32_t* current;
|
||||
uint32_t rw_pos;
|
||||
lldesc_t** desc;
|
||||
xQueueHandle queue;
|
||||
} i2s_out_dma_t;
|
||||
|
||||
static i2s_out_dma_t o_dma;
|
||||
static intr_handle_t i2s_out_isr_handle;
|
||||
# endif
|
||||
|
||||
// output value
|
||||
static atomic_uint_least32_t i2s_out_port_data = ATOMIC_VAR_INIT(0);
|
||||
|
||||
// inner lock
|
||||
static portMUX_TYPE i2s_out_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||
# define I2S_OUT_ENTER_CRITICAL() portENTER_CRITICAL(&i2s_out_spinlock)
|
||||
# define I2S_OUT_EXIT_CRITICAL() portEXIT_CRITICAL(&i2s_out_spinlock)
|
||||
# define I2S_OUT_ENTER_CRITICAL_ISR() portENTER_CRITICAL_ISR(&i2s_out_spinlock)
|
||||
# define I2S_OUT_EXIT_CRITICAL_ISR() portEXIT_CRITICAL_ISR(&i2s_out_spinlock)
|
||||
|
||||
static int i2s_out_initialized = 0;
|
||||
|
||||
# ifdef USE_I2S_OUT_STREAM
|
||||
static volatile uint64_t i2s_out_pulse_period;
|
||||
static uint64_t i2s_out_remain_time_until_next_pulse; // Time remaining until the next pulse (μsec)
|
||||
static volatile i2s_out_pulse_func_t i2s_out_pulse_func;
|
||||
# endif
|
||||
|
||||
static uint8_t i2s_out_ws_pin = 255;
|
||||
static uint8_t i2s_out_bck_pin = 255;
|
||||
static uint8_t i2s_out_data_pin = 255;
|
||||
|
||||
enum i2s_out_pulser_status_t {
|
||||
PASSTHROUGH = 0, // Static I2S mode.The i2s_out_write() reflected with very little delay
|
||||
STEPPING, // Streaming step data.
|
||||
WAITING, // Waiting for the step DMA completion
|
||||
};
|
||||
static volatile i2s_out_pulser_status_t i2s_out_pulser_status = PASSTHROUGH;
|
||||
|
||||
// outer lock
|
||||
static portMUX_TYPE i2s_out_pulser_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||
# define I2S_OUT_PULSER_ENTER_CRITICAL() portENTER_CRITICAL(&i2s_out_pulser_spinlock)
|
||||
# define I2S_OUT_PULSER_EXIT_CRITICAL() portEXIT_CRITICAL(&i2s_out_pulser_spinlock)
|
||||
# define I2S_OUT_PULSER_ENTER_CRITICAL_ISR() portENTER_CRITICAL_ISR(&i2s_out_pulser_spinlock)
|
||||
# define I2S_OUT_PULSER_EXIT_CRITICAL_ISR() portEXIT_CRITICAL_ISR(&i2s_out_pulser_spinlock)
|
||||
|
||||
//
|
||||
// Internal functions
|
||||
//
|
||||
static inline void gpio_matrix_out_check(uint8_t gpio, uint32_t signal_idx, bool out_inv, bool oen_inv) {
|
||||
//if pin == 255, do not need to configure
|
||||
if (gpio != 255) {
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[gpio], PIN_FUNC_GPIO);
|
||||
gpio_set_direction((gpio_num_t)gpio, (gpio_mode_t)GPIO_MODE_DEF_OUTPUT);
|
||||
gpio_matrix_out(gpio, signal_idx, out_inv, oen_inv);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void i2s_out_single_data() {
|
||||
# if I2S_OUT_NUM_BITS == 16
|
||||
uint32_t port_data = atomic_load(&i2s_out_port_data);
|
||||
port_data <<= 16; // Shift needed. This specification is not spelled out in the manual.
|
||||
I2S0.conf_single_data = port_data; // Apply port data in real-time (static I2S)
|
||||
# else
|
||||
I2S0.conf_single_data = atomic_load(&i2s_out_port_data); // Apply port data in real-time (static I2S)
|
||||
# endif
|
||||
}
|
||||
|
||||
static inline void i2s_out_reset_fifo_without_lock() {
|
||||
I2S0.conf.rx_fifo_reset = 1;
|
||||
I2S0.conf.rx_fifo_reset = 0;
|
||||
I2S0.conf.tx_fifo_reset = 1;
|
||||
I2S0.conf.tx_fifo_reset = 0;
|
||||
}
|
||||
|
||||
static void IRAM_ATTR i2s_out_reset_fifo() {
|
||||
I2S_OUT_ENTER_CRITICAL();
|
||||
i2s_out_reset_fifo_without_lock();
|
||||
I2S_OUT_EXIT_CRITICAL();
|
||||
}
|
||||
|
||||
# ifdef USE_I2S_OUT_STREAM
|
||||
static int IRAM_ATTR i2s_clear_dma_buffer(lldesc_t* dma_desc, uint32_t port_data) {
|
||||
uint32_t* buf = (uint32_t*)dma_desc->buf;
|
||||
for (int i = 0; i < DMA_SAMPLE_COUNT; i++) {
|
||||
buf[i] = port_data;
|
||||
}
|
||||
// Restore the buffer length.
|
||||
// The length may have been changed short when the data was filled in to prevent buffer overrun.
|
||||
dma_desc->length = I2S_OUT_DMABUF_LEN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int IRAM_ATTR i2s_clear_o_dma_buffers(uint32_t port_data) {
|
||||
for (int buf_idx = 0; buf_idx < I2S_OUT_DMABUF_COUNT; buf_idx++) {
|
||||
// Initialize DMA descriptor
|
||||
o_dma.desc[buf_idx]->owner = 1;
|
||||
o_dma.desc[buf_idx]->eof = 1; // set to 1 will trigger the interrupt
|
||||
o_dma.desc[buf_idx]->sosf = 0;
|
||||
o_dma.desc[buf_idx]->length = I2S_OUT_DMABUF_LEN;
|
||||
o_dma.desc[buf_idx]->size = I2S_OUT_DMABUF_LEN;
|
||||
o_dma.desc[buf_idx]->buf = (uint8_t*)o_dma.buffers[buf_idx];
|
||||
o_dma.desc[buf_idx]->offset = 0;
|
||||
o_dma.desc[buf_idx]->qe.stqe_next = (lldesc_t*)((buf_idx < (I2S_OUT_DMABUF_COUNT - 1)) ? (o_dma.desc[buf_idx + 1]) : o_dma.desc[0]);
|
||||
i2s_clear_dma_buffer(o_dma.desc[buf_idx], port_data);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
# endif
|
||||
|
||||
static int IRAM_ATTR i2s_out_gpio_attach(uint8_t ws, uint8_t bck, uint8_t data) {
|
||||
// Route the i2s pins to the appropriate GPIO
|
||||
gpio_matrix_out_check(data, I2S0O_DATA_OUT23_IDX, 0, 0);
|
||||
gpio_matrix_out_check(bck, I2S0O_BCK_OUT_IDX, 0, 0);
|
||||
gpio_matrix_out_check(ws, I2S0O_WS_OUT_IDX, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
# define I2S_OUT_DETACH_PORT_IDX 0x100
|
||||
|
||||
static int IRAM_ATTR i2s_out_gpio_detach(uint8_t ws, uint8_t bck, uint8_t data) {
|
||||
// Route the i2s pins to the appropriate GPIO
|
||||
gpio_matrix_out_check(ws, I2S_OUT_DETACH_PORT_IDX, 0, 0);
|
||||
gpio_matrix_out_check(bck, I2S_OUT_DETACH_PORT_IDX, 0, 0);
|
||||
gpio_matrix_out_check(data, I2S_OUT_DETACH_PORT_IDX, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int IRAM_ATTR i2s_out_gpio_shiftout(uint32_t port_data) {
|
||||
__digitalWrite(i2s_out_ws_pin, LOW);
|
||||
for (int i = 0; i < I2S_OUT_NUM_BITS; i++) {
|
||||
__digitalWrite(i2s_out_data_pin, !!(port_data & bit(I2S_OUT_NUM_BITS - 1 - i)));
|
||||
__digitalWrite(i2s_out_bck_pin, HIGH);
|
||||
__digitalWrite(i2s_out_bck_pin, LOW);
|
||||
}
|
||||
__digitalWrite(i2s_out_ws_pin, HIGH); // Latch
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int IRAM_ATTR i2s_out_stop() {
|
||||
I2S_OUT_ENTER_CRITICAL();
|
||||
# ifdef USE_I2S_OUT_STREAM
|
||||
// Stop FIFO DMA
|
||||
I2S0.out_link.stop = 1;
|
||||
|
||||
// Disconnect DMA from FIFO
|
||||
I2S0.fifo_conf.dscr_en = 0; //Unset this bit to disable I2S DMA mode. (R/W)
|
||||
# endif
|
||||
// stop TX module
|
||||
I2S0.conf.tx_start = 0;
|
||||
|
||||
// Force WS to LOW before detach
|
||||
// This operation prevents unintended WS edge trigger when detach
|
||||
__digitalWrite(i2s_out_ws_pin, LOW);
|
||||
|
||||
// Now, detach GPIO pin from I2S
|
||||
i2s_out_gpio_detach(i2s_out_ws_pin, i2s_out_bck_pin, i2s_out_data_pin);
|
||||
|
||||
// Force BCK to LOW
|
||||
// After the TX module is stopped, BCK always seems to be in LOW.
|
||||
// However, I'm going to do it manually to ensure the BCK's LOW.
|
||||
__digitalWrite(i2s_out_bck_pin, LOW);
|
||||
|
||||
// Transmit recovery data to 74HC595
|
||||
uint32_t port_data = atomic_load(&i2s_out_port_data); // current expanded port value
|
||||
i2s_out_gpio_shiftout(port_data);
|
||||
|
||||
# ifdef USE_I2S_OUT_STREAM
|
||||
//clear pending interrupt
|
||||
I2S0.int_clr.val = I2S0.int_st.val;
|
||||
# endif
|
||||
I2S_OUT_EXIT_CRITICAL();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int IRAM_ATTR i2s_out_start() {
|
||||
if (!i2s_out_initialized) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
I2S_OUT_ENTER_CRITICAL();
|
||||
// Transmit recovery data to 74HC595
|
||||
uint32_t port_data = atomic_load(&i2s_out_port_data); // current expanded port value
|
||||
i2s_out_gpio_shiftout(port_data);
|
||||
|
||||
// Attach I2S to specified GPIO pin
|
||||
i2s_out_gpio_attach(i2s_out_ws_pin, i2s_out_bck_pin, i2s_out_data_pin);
|
||||
//start DMA link
|
||||
i2s_out_reset_fifo_without_lock();
|
||||
|
||||
# ifdef USE_I2S_OUT_STREAM
|
||||
if (i2s_out_pulser_status == PASSTHROUGH) {
|
||||
I2S0.conf_chan.tx_chan_mod = 3; // 3:right+constant 4:left+constant (when tx_msb_right = 1)
|
||||
I2S0.conf_single_data = port_data;
|
||||
} else {
|
||||
I2S0.conf_chan.tx_chan_mod = 4; // 3:right+constant 4:left+constant (when tx_msb_right = 1)
|
||||
I2S0.conf_single_data = 0;
|
||||
}
|
||||
# endif
|
||||
|
||||
# ifdef USE_I2S_OUT_STREAM
|
||||
//reset DMA
|
||||
I2S0.lc_conf.in_rst = 1;
|
||||
I2S0.lc_conf.in_rst = 0;
|
||||
I2S0.lc_conf.out_rst = 1;
|
||||
I2S0.lc_conf.out_rst = 0;
|
||||
|
||||
I2S0.out_link.addr = (uint32_t)o_dma.desc[0];
|
||||
# endif
|
||||
|
||||
I2S0.conf.tx_reset = 1;
|
||||
I2S0.conf.tx_reset = 0;
|
||||
I2S0.conf.rx_reset = 1;
|
||||
I2S0.conf.rx_reset = 0;
|
||||
|
||||
I2S0.conf1.tx_stop_en = 1; // BCK and WCK are suppressed while FIFO is empty
|
||||
|
||||
# ifdef USE_I2S_OUT_STREAM
|
||||
// Connect DMA to FIFO
|
||||
I2S0.fifo_conf.dscr_en = 1; // Set this bit to enable I2S DMA mode. (R/W)
|
||||
|
||||
I2S0.int_clr.val = 0xFFFFFFFF;
|
||||
I2S0.out_link.start = 1;
|
||||
# endif
|
||||
I2S0.conf.tx_start = 1;
|
||||
// Wait for the first FIFO data to prevent the unintentional generation of 0 data
|
||||
ets_delay_us(20);
|
||||
I2S0.conf1.tx_stop_en = 0; // BCK and WCK are generated regardless of the FIFO status
|
||||
|
||||
I2S_OUT_EXIT_CRITICAL();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
# ifdef USE_I2S_OUT_STREAM
|
||||
|
||||
static int IRAM_ATTR i2s_fillout_dma_buffer(lldesc_t* dma_desc) {
|
||||
uint32_t* buf = (uint32_t*)dma_desc->buf;
|
||||
o_dma.rw_pos = 0;
|
||||
// It reuses the oldest (just transferred) buffer with the name "current"
|
||||
// and fills the buffer for later DMA.
|
||||
I2S_OUT_PULSER_ENTER_CRITICAL(); // Lock pulser status
|
||||
if (i2s_out_pulser_status == STEPPING) {
|
||||
//
|
||||
// Fillout the buffer for pulse
|
||||
//
|
||||
// To avoid buffer overflow, all of the maximum pulse width (normaly about 10us)
|
||||
// is adjusted to be in a single buffer.
|
||||
// DMA_SAMPLE_SAFE_COUNT is referred to as the margin value.
|
||||
// Therefore, if a buffer is close to full and it is time to generate a pulse,
|
||||
// the generation of the buffer is interrupted (the buffer length is shortened slightly)
|
||||
// and the pulse generation is postponed until the next buffer is filled.
|
||||
//
|
||||
o_dma.rw_pos = 0;
|
||||
while (o_dma.rw_pos < (DMA_SAMPLE_COUNT - SAMPLE_SAFE_COUNT)) {
|
||||
// no data to read (buffer empty)
|
||||
if (i2s_out_remain_time_until_next_pulse < I2S_OUT_USEC_PER_PULSE) {
|
||||
// pulser status may change in pulse phase func, so I need to check it every time.
|
||||
if (i2s_out_pulser_status == STEPPING) {
|
||||
// fillout future DMA buffer (tail of the DMA buffer chains)
|
||||
if (i2s_out_pulse_func != NULL) {
|
||||
uint32_t old_rw_pos = o_dma.rw_pos;
|
||||
I2S_OUT_PULSER_EXIT_CRITICAL(); // Temporarily unlocked status lock as it may be locked in pulse callback.
|
||||
(*i2s_out_pulse_func)(); // should be pushed into buffer max DMA_SAMPLE_SAFE_COUNT
|
||||
I2S_OUT_PULSER_ENTER_CRITICAL(); // Lock again.
|
||||
// Calculate pulse period. About magic number 2, refer to the st_wake_up(). (Ad hoc delay value)
|
||||
i2s_out_remain_time_until_next_pulse = i2s_out_pulse_period - I2S_OUT_USEC_PER_PULSE * (o_dma.rw_pos - old_rw_pos) + 2;
|
||||
if (i2s_out_pulser_status == WAITING) {
|
||||
// i2s_out_set_passthrough() has called from the pulse function.
|
||||
// It needs to go into pass-through mode.
|
||||
// This DMA descriptor must be a tail of the chain.
|
||||
dma_desc->qe.stqe_next = NULL; // Cut the DMA descriptor ring. This allow us to identify the tail of the buffer.
|
||||
} else if (i2s_out_pulser_status == PASSTHROUGH) {
|
||||
// i2s_out_reset() has called during the execution of the pulse function.
|
||||
// I2S has already in static mode, and buffers has cleared to zero.
|
||||
// To prevent the pulse function from being called back,
|
||||
// we assume that the buffer is already full.
|
||||
i2s_out_remain_time_until_next_pulse = 0; // There is no need to fill the current buffer.
|
||||
o_dma.rw_pos = DMA_SAMPLE_COUNT; // The buffer is full.
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
// no pulse data in push buffer (pulse off or idle or callback is not defined)
|
||||
buf[o_dma.rw_pos++] = atomic_load(&i2s_out_port_data);
|
||||
if (i2s_out_remain_time_until_next_pulse >= I2S_OUT_USEC_PER_PULSE) {
|
||||
i2s_out_remain_time_until_next_pulse -= I2S_OUT_USEC_PER_PULSE;
|
||||
} else {
|
||||
i2s_out_remain_time_until_next_pulse = 0;
|
||||
}
|
||||
}
|
||||
// set filled length to the DMA descriptor
|
||||
dma_desc->length = o_dma.rw_pos * I2S_SAMPLE_SIZE;
|
||||
} else if (i2s_out_pulser_status == WAITING) {
|
||||
i2s_clear_dma_buffer(dma_desc, 0); // Essentially, no clearing is required. I'll make sure I know when I've written something.
|
||||
o_dma.rw_pos = 0; // If someone calls i2s_out_push_sample, make sure there is no buffer overflow
|
||||
dma_desc->qe.stqe_next = NULL; // Cut the DMA descriptor ring. This allow us to identify the tail of the buffer.
|
||||
} else {
|
||||
// Stepper paused (passthrough state, static I2S control mode)
|
||||
// In the passthrough mode, there is no need to fill the buffer with port_data.
|
||||
i2s_clear_dma_buffer(dma_desc, 0); // Essentially, no clearing is required. I'll make sure I know when I've written something.
|
||||
o_dma.rw_pos = 0; // If someone calls i2s_out_push_sample, make sure there is no buffer overflow
|
||||
}
|
||||
I2S_OUT_PULSER_EXIT_CRITICAL(); // Unlock pulser status
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// I2S out DMA Interrupts handler
|
||||
//
|
||||
static void IRAM_ATTR i2s_out_intr_handler(void* arg) {
|
||||
lldesc_t* finish_desc;
|
||||
portBASE_TYPE high_priority_task_awoken = pdFALSE;
|
||||
|
||||
if (I2S0.int_st.out_eof || I2S0.int_st.out_total_eof) {
|
||||
if (I2S0.int_st.out_total_eof) {
|
||||
// This is tail of the DMA descriptors
|
||||
I2S_OUT_ENTER_CRITICAL_ISR();
|
||||
// Stop FIFO DMA
|
||||
I2S0.out_link.stop = 1;
|
||||
// Disconnect DMA from FIFO
|
||||
I2S0.fifo_conf.dscr_en = 0; //Unset this bit to disable I2S DMA mode. (R/W)
|
||||
// Stop TX module
|
||||
I2S0.conf.tx_start = 0;
|
||||
I2S_OUT_EXIT_CRITICAL_ISR();
|
||||
}
|
||||
// Get the descriptor of the last item in the linkedlist
|
||||
finish_desc = (lldesc_t*)I2S0.out_eof_des_addr;
|
||||
|
||||
// If the queue is full it's because we have an underflow,
|
||||
// more than buf_count isr without new data, remove the front buffer
|
||||
if (xQueueIsQueueFullFromISR(o_dma.queue)) {
|
||||
lldesc_t* front_desc;
|
||||
// Remove a descriptor from the DMA complete event queue
|
||||
xQueueReceiveFromISR(o_dma.queue, &front_desc, &high_priority_task_awoken);
|
||||
I2S_OUT_PULSER_ENTER_CRITICAL_ISR();
|
||||
uint32_t port_data = 0;
|
||||
if (i2s_out_pulser_status == STEPPING) {
|
||||
port_data = atomic_load(&i2s_out_port_data);
|
||||
}
|
||||
I2S_OUT_PULSER_EXIT_CRITICAL_ISR();
|
||||
for (int i = 0; i < DMA_SAMPLE_COUNT; i++) {
|
||||
front_desc->buf[i] = port_data;
|
||||
}
|
||||
front_desc->length = I2S_OUT_DMABUF_LEN;
|
||||
}
|
||||
|
||||
// Send a DMA complete event to the I2S bitstreamer task with finished buffer
|
||||
xQueueSendFromISR(o_dma.queue, &finish_desc, &high_priority_task_awoken);
|
||||
}
|
||||
|
||||
if (high_priority_task_awoken == pdTRUE)
|
||||
portYIELD_FROM_ISR();
|
||||
|
||||
// clear interrupt
|
||||
I2S0.int_clr.val = I2S0.int_st.val; //clear pending interrupt
|
||||
}
|
||||
|
||||
//
|
||||
// I2S bitstream generator task
|
||||
//
|
||||
static void IRAM_ATTR i2sOutTask(void* parameter) {
|
||||
lldesc_t* dma_desc;
|
||||
while (1) {
|
||||
// Wait a DMA complete event from I2S isr
|
||||
// (Block until a DMA transfer has complete)
|
||||
xQueueReceive(o_dma.queue, &dma_desc, portMAX_DELAY);
|
||||
o_dma.current = (uint32_t*)(dma_desc->buf);
|
||||
// It reuses the oldest (just transferred) buffer with the name "current"
|
||||
// and fills the buffer for later DMA.
|
||||
I2S_OUT_PULSER_ENTER_CRITICAL(); // Lock pulser status
|
||||
if (i2s_out_pulser_status == STEPPING) {
|
||||
//
|
||||
// Fillout the buffer for pulse
|
||||
//
|
||||
// To avoid buffer overflow, all of the maximum pulse width (normaly about 10us)
|
||||
// is adjusted to be in a single buffer.
|
||||
// DMA_SAMPLE_SAFE_COUNT is referred to as the margin value.
|
||||
// Therefore, if a buffer is close to full and it is time to generate a pulse,
|
||||
// the generation of the buffer is interrupted (the buffer length is shortened slightly)
|
||||
// and the pulse generation is postponed until the next buffer is filled.
|
||||
//
|
||||
i2s_fillout_dma_buffer(dma_desc);
|
||||
dma_desc->length = o_dma.rw_pos * I2S_SAMPLE_SIZE;
|
||||
} else if (i2s_out_pulser_status == WAITING) {
|
||||
if (dma_desc->qe.stqe_next == NULL) {
|
||||
// Tail of the DMA descriptor found
|
||||
// I2S TX module has alrewdy stopped by ISR
|
||||
i2s_out_stop();
|
||||
i2s_clear_o_dma_buffers(0); // 0 for static I2S control mode (right ch. data is always 0)
|
||||
// You need to set the status before calling i2s_out_start()
|
||||
// because the process in i2s_out_start() is different depending on the status.
|
||||
i2s_out_pulser_status = PASSTHROUGH;
|
||||
i2s_out_start();
|
||||
} else {
|
||||
// Processing a buffer slightly ahead of the tail buffer.
|
||||
// We don't need to fill up the buffer by port_data any more.
|
||||
i2s_clear_dma_buffer(dma_desc, 0); // Essentially, no clearing is required. I'll make sure I know when I've written something.
|
||||
o_dma.rw_pos = 0; // If someone calls i2s_out_push_sample, make sure there is no buffer overflow
|
||||
dma_desc->qe.stqe_next = NULL; // Cut the DMA descriptor ring. This allow us to identify the tail of the buffer.
|
||||
}
|
||||
} else {
|
||||
// Stepper paused (passthrough state, static I2S control mode)
|
||||
// In the passthrough mode, there is no need to fill the buffer with port_data.
|
||||
i2s_clear_dma_buffer(dma_desc, 0); // Essentially, no clearing is required. I'll make sure I know when I've written something.
|
||||
o_dma.rw_pos = 0; // If someone calls i2s_out_push_sample, make sure there is no buffer overflow
|
||||
}
|
||||
I2S_OUT_PULSER_EXIT_CRITICAL(); // Unlock pulser status
|
||||
}
|
||||
}
|
||||
# endif
|
||||
|
||||
//
|
||||
// External funtions
|
||||
//
|
||||
void IRAM_ATTR i2s_out_delay() {
|
||||
# ifdef USE_I2S_OUT_STREAM
|
||||
I2S_OUT_PULSER_ENTER_CRITICAL();
|
||||
if (i2s_out_pulser_status == PASSTHROUGH) {
|
||||
// Depending on the timing, it may not be reflected immediately,
|
||||
// so wait twice as long just in case.
|
||||
ets_delay_us(I2S_OUT_USEC_PER_PULSE * 2);
|
||||
} else {
|
||||
// Just wait until the data now registered in the DMA descripter
|
||||
// is reflected in the I2S TX module via FIFO.
|
||||
delay(I2S_OUT_DELAY_MS);
|
||||
}
|
||||
I2S_OUT_PULSER_EXIT_CRITICAL();
|
||||
# else
|
||||
ets_delay_us(I2S_OUT_USEC_PER_PULSE * 2);
|
||||
# endif
|
||||
}
|
||||
|
||||
void IRAM_ATTR i2s_out_write(uint8_t pin, uint8_t val) {
|
||||
uint32_t bit = bit(pin);
|
||||
if (val) {
|
||||
atomic_fetch_or(&i2s_out_port_data, bit);
|
||||
} else {
|
||||
atomic_fetch_and(&i2s_out_port_data, ~bit);
|
||||
}
|
||||
# ifdef USE_I2S_OUT_STREAM
|
||||
// It needs a lock for access, but I've given up because I need speed.
|
||||
// This is not a problem as long as there is no overlap between the status change and digitalWrite().
|
||||
if (i2s_out_pulser_status == PASSTHROUGH) {
|
||||
i2s_out_single_data();
|
||||
}
|
||||
# else
|
||||
i2s_out_single_data();
|
||||
# endif
|
||||
}
|
||||
|
||||
uint8_t IRAM_ATTR i2s_out_state(uint8_t pin) {
|
||||
uint32_t port_data = atomic_load(&i2s_out_port_data);
|
||||
return (!!(port_data & bit(pin)));
|
||||
}
|
||||
|
||||
uint32_t IRAM_ATTR i2s_out_push_sample(uint32_t num) {
|
||||
# ifdef USE_I2S_OUT_STREAM
|
||||
if (num > SAMPLE_SAFE_COUNT) {
|
||||
return 0;
|
||||
}
|
||||
// push at least one sample (even if num is zero)
|
||||
uint32_t port_data = atomic_load(&i2s_out_port_data);
|
||||
uint32_t n = 0;
|
||||
do {
|
||||
o_dma.current[o_dma.rw_pos++] = port_data;
|
||||
n++;
|
||||
} while (n < num);
|
||||
return n;
|
||||
# else
|
||||
return 0;
|
||||
# endif
|
||||
}
|
||||
|
||||
int IRAM_ATTR i2s_out_set_passthrough() {
|
||||
I2S_OUT_PULSER_ENTER_CRITICAL();
|
||||
# ifdef USE_I2S_OUT_STREAM
|
||||
if (i2s_out_pulser_status == STEPPING) {
|
||||
i2s_out_pulser_status = WAITING; // Start stopping the pulser
|
||||
}
|
||||
# else
|
||||
i2s_out_pulser_status = PASSTHROUGH;
|
||||
# endif
|
||||
I2S_OUT_PULSER_EXIT_CRITICAL();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int IRAM_ATTR i2s_out_set_stepping() {
|
||||
I2S_OUT_PULSER_ENTER_CRITICAL();
|
||||
# ifdef USE_I2S_OUT_STREAM
|
||||
if (i2s_out_pulser_status == STEPPING) {
|
||||
// Re-entered (fail safe)
|
||||
I2S_OUT_PULSER_EXIT_CRITICAL();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (i2s_out_pulser_status == WAITING) {
|
||||
// Wait for complete DMAs
|
||||
for (;;) {
|
||||
I2S_OUT_PULSER_EXIT_CRITICAL();
|
||||
delay(I2S_OUT_DELAY_DMABUF_MS);
|
||||
I2S_OUT_PULSER_ENTER_CRITICAL();
|
||||
if (i2s_out_pulser_status == WAITING) {
|
||||
continue;
|
||||
}
|
||||
if (i2s_out_pulser_status == PASSTHROUGH) {
|
||||
// DMA completed
|
||||
break;
|
||||
}
|
||||
// Another function change the I2S state to STEPPING
|
||||
I2S_OUT_PULSER_EXIT_CRITICAL();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Change I2S state from PASSTHROUGH to STEPPING
|
||||
i2s_out_stop();
|
||||
uint32_t port_data = atomic_load(&i2s_out_port_data);
|
||||
i2s_clear_o_dma_buffers(port_data);
|
||||
|
||||
// You need to set the status before calling i2s_out_start()
|
||||
// because the process in i2s_out_start() is different depending on the status.
|
||||
i2s_out_pulser_status = STEPPING;
|
||||
i2s_out_start();
|
||||
# else
|
||||
i2s_out_pulser_status = STEPPING;
|
||||
# endif
|
||||
I2S_OUT_PULSER_EXIT_CRITICAL();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int IRAM_ATTR i2s_out_set_pulse_period(uint64_t period) {
|
||||
# ifdef USE_I2S_OUT_STREAM
|
||||
// Use 64-bit values to avoid overflowing during the calculation.
|
||||
i2s_out_pulse_period = period * 1000000 / F_STEPPER_TIMER;
|
||||
# endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int IRAM_ATTR i2s_out_set_pulse_callback(i2s_out_pulse_func_t func) {
|
||||
# ifdef USE_I2S_OUT_STREAM
|
||||
i2s_out_pulse_func = func;
|
||||
# endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int IRAM_ATTR i2s_out_reset() {
|
||||
I2S_OUT_PULSER_ENTER_CRITICAL();
|
||||
i2s_out_stop();
|
||||
# ifdef USE_I2S_OUT_STREAM
|
||||
if (i2s_out_pulser_status == STEPPING) {
|
||||
uint32_t port_data = atomic_load(&i2s_out_port_data);
|
||||
i2s_clear_o_dma_buffers(port_data);
|
||||
} else if (i2s_out_pulser_status == WAITING) {
|
||||
i2s_clear_o_dma_buffers(0);
|
||||
i2s_out_pulser_status = PASSTHROUGH;
|
||||
}
|
||||
# endif
|
||||
// You need to set the status before calling i2s_out_start()
|
||||
// because the process in i2s_out_start() is different depending on the status.
|
||||
i2s_out_start();
|
||||
I2S_OUT_PULSER_EXIT_CRITICAL();
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Initialize funtion (external function)
|
||||
//
|
||||
int IRAM_ATTR i2s_out_init(i2s_out_init_t& init_param) {
|
||||
if (i2s_out_initialized) {
|
||||
// already initialized
|
||||
return -1;
|
||||
}
|
||||
|
||||
atomic_store(&i2s_out_port_data, init_param.init_val);
|
||||
|
||||
// To make sure hardware is enabled before any hardware register operations.
|
||||
periph_module_reset(PERIPH_I2S0_MODULE);
|
||||
periph_module_enable(PERIPH_I2S0_MODULE);
|
||||
|
||||
// Route the i2s pins to the appropriate GPIO
|
||||
i2s_out_gpio_attach(init_param.ws_pin, init_param.bck_pin, init_param.data_pin);
|
||||
|
||||
/**
|
||||
* Each i2s transfer will take
|
||||
* fpll = PLL_D2_CLK -- clka_en = 0
|
||||
*
|
||||
* fi2s = fpll / N + b/a -- N + b/a = clkm_div_num
|
||||
* fi2s = 160MHz / 2
|
||||
* fi2s = 80MHz
|
||||
*
|
||||
* fbclk = fi2s / M -- M = tx_bck_div_num
|
||||
* fbclk = 80MHz / 2
|
||||
* fbclk = 40MHz
|
||||
*
|
||||
* fwclk = fbclk / 32
|
||||
*
|
||||
* for fwclk = 250kHz(16-bit: 4µS pulse time), 125kHz(32-bit: 8μS pulse time)
|
||||
* N = 10, b/a = 0
|
||||
* M = 2
|
||||
* for fwclk = 500kHz(16-bit: 2µS pulse time), 250kHz(32-bit: 4μS pulse time)
|
||||
* N = 5, b/a = 0
|
||||
* M = 2
|
||||
* for fwclk = 1000kHz(16-bit: 1µS pulse time), 500kHz(32-bit: 2μS pulse time)
|
||||
* N = 2, b/a = 2/1 (N + b/a = 2.5)
|
||||
* M = 2
|
||||
*/
|
||||
|
||||
# ifdef USE_I2S_OUT_STREAM
|
||||
// Allocate the array of pointers to the buffers
|
||||
o_dma.buffers = (uint32_t**)malloc(sizeof(uint32_t*) * I2S_OUT_DMABUF_COUNT);
|
||||
if (o_dma.buffers == nullptr)
|
||||
return -1;
|
||||
|
||||
// Allocate each buffer that can be used by the DMA controller
|
||||
for (int buf_idx = 0; buf_idx < I2S_OUT_DMABUF_COUNT; buf_idx++) {
|
||||
o_dma.buffers[buf_idx] = (uint32_t*)heap_caps_calloc(1, I2S_OUT_DMABUF_LEN, MALLOC_CAP_DMA);
|
||||
if (o_dma.buffers[buf_idx] == nullptr)
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Allocate the array of DMA descriptors
|
||||
o_dma.desc = (lldesc_t**)malloc(sizeof(lldesc_t*) * I2S_OUT_DMABUF_COUNT);
|
||||
if (o_dma.desc == nullptr)
|
||||
return -1;
|
||||
|
||||
// Allocate each DMA descriptor that will be used by the DMA controller
|
||||
for (int buf_idx = 0; buf_idx < I2S_OUT_DMABUF_COUNT; buf_idx++) {
|
||||
o_dma.desc[buf_idx] = (lldesc_t*)heap_caps_malloc(sizeof(lldesc_t), MALLOC_CAP_DMA);
|
||||
if (o_dma.desc[buf_idx] == nullptr)
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Initialize
|
||||
i2s_clear_o_dma_buffers(init_param.init_val);
|
||||
o_dma.rw_pos = 0;
|
||||
o_dma.current = NULL;
|
||||
o_dma.queue = xQueueCreate(I2S_OUT_DMABUF_COUNT, sizeof(uint32_t*));
|
||||
|
||||
// Set the first DMA descriptor
|
||||
I2S0.out_link.addr = (uint32_t)o_dma.desc[0];
|
||||
# endif
|
||||
|
||||
// stop i2s
|
||||
I2S0.out_link.stop = 1;
|
||||
I2S0.conf.tx_start = 0;
|
||||
|
||||
I2S0.int_clr.val = I2S0.int_st.val; //clear pending interrupt
|
||||
|
||||
//
|
||||
// i2s_param_config
|
||||
//
|
||||
|
||||
// configure I2S data port interface.
|
||||
i2s_out_reset_fifo();
|
||||
|
||||
//reset i2s
|
||||
I2S0.conf.tx_reset = 1;
|
||||
I2S0.conf.tx_reset = 0;
|
||||
I2S0.conf.rx_reset = 1;
|
||||
I2S0.conf.rx_reset = 0;
|
||||
|
||||
//reset dma
|
||||
I2S0.lc_conf.in_rst = 1; // Set this bit to reset in DMA FSM. (R/W)
|
||||
I2S0.lc_conf.in_rst = 0;
|
||||
I2S0.lc_conf.out_rst = 1; // Set this bit to reset out DMA FSM. (R/W)
|
||||
I2S0.lc_conf.out_rst = 0;
|
||||
|
||||
//Enable and configure DMA
|
||||
I2S0.lc_conf.check_owner = 0;
|
||||
I2S0.lc_conf.out_loop_test = 0;
|
||||
I2S0.lc_conf.out_auto_wrback = 0; // Disable auto outlink-writeback when all the data has been transmitted
|
||||
I2S0.lc_conf.out_data_burst_en = 0;
|
||||
I2S0.lc_conf.outdscr_burst_en = 0;
|
||||
I2S0.lc_conf.out_no_restart_clr = 0;
|
||||
I2S0.lc_conf.indscr_burst_en = 0;
|
||||
# ifdef USE_I2S_OUT_STREAM
|
||||
I2S0.lc_conf.out_eof_mode = 1; // I2S_OUT_EOF_INT generated when DMA has popped all data from the FIFO;
|
||||
# endif
|
||||
I2S0.conf2.lcd_en = 0;
|
||||
I2S0.conf2.camera_en = 0;
|
||||
I2S0.pdm_conf.pcm2pdm_conv_en = 0;
|
||||
I2S0.pdm_conf.pdm2pcm_conv_en = 0;
|
||||
|
||||
I2S0.fifo_conf.dscr_en = 0;
|
||||
|
||||
# ifdef USE_I2S_OUT_STREAM
|
||||
if (i2s_out_pulser_status == STEPPING) {
|
||||
// Stream output mode
|
||||
I2S0.conf_chan.tx_chan_mod = 4; // 3:right+constant 4:left+constant (when tx_msb_right = 1)
|
||||
I2S0.conf_single_data = 0;
|
||||
} else {
|
||||
// Static output mode
|
||||
I2S0.conf_chan.tx_chan_mod = 3; // 3:right+constant 4:left+constant (when tx_msb_right = 1)
|
||||
I2S0.conf_single_data = init_param.init_val;
|
||||
}
|
||||
# else
|
||||
// For the static output mode
|
||||
I2S0.conf_chan.tx_chan_mod = 3; // 3:right+constant 4:left+constant (when tx_msb_right = 1)
|
||||
I2S0.conf_single_data = init_param.init_val; // initial constant value
|
||||
# endif
|
||||
# if I2S_OUT_NUM_BITS == 16
|
||||
I2S0.fifo_conf.tx_fifo_mod = 0; // 0: 16-bit dual channel data, 3: 32-bit single channel data
|
||||
I2S0.fifo_conf.rx_fifo_mod = 0; // 0: 16-bit dual channel data, 3: 32-bit single channel data
|
||||
I2S0.sample_rate_conf.tx_bits_mod = 16; // default is 16-bits
|
||||
I2S0.sample_rate_conf.rx_bits_mod = 16; // default is 16-bits
|
||||
# else
|
||||
I2S0.fifo_conf.tx_fifo_mod = 3; // 0: 16-bit dual channel data, 3: 32-bit single channel data
|
||||
I2S0.fifo_conf.rx_fifo_mod = 3; // 0: 16-bit dual channel data, 3: 32-bit single channel data
|
||||
// Data width is 32-bit. Forgetting this setting will result in a 16-bit transfer.
|
||||
I2S0.sample_rate_conf.tx_bits_mod = 32;
|
||||
I2S0.sample_rate_conf.rx_bits_mod = 32;
|
||||
# endif
|
||||
I2S0.conf.tx_mono = 0; // Set this bit to enable transmitter’s mono mode in PCM standard mode.
|
||||
|
||||
I2S0.conf_chan.rx_chan_mod = 1; // 1: right+right
|
||||
I2S0.conf.rx_mono = 0;
|
||||
|
||||
# ifdef USE_I2S_OUT_STREAM
|
||||
I2S0.fifo_conf.dscr_en = 1; //connect DMA to fifo
|
||||
# endif
|
||||
I2S0.conf.tx_start = 0;
|
||||
I2S0.conf.rx_start = 0;
|
||||
|
||||
I2S0.conf.tx_msb_right = 1; // Set this bit to place right-channel data at the MSB in the transmit FIFO.
|
||||
I2S0.conf.tx_right_first = 0; // Setting this bit allows the right-channel data to be sent first.
|
||||
|
||||
I2S0.conf.tx_slave_mod = 0; // Master
|
||||
# ifdef USE_I2S_OUT_STREAM
|
||||
I2S0.fifo_conf.tx_fifo_mod_force_en = 1; //The bit should always be set to 1.
|
||||
# endif
|
||||
I2S0.pdm_conf.rx_pdm_en = 0; // Set this bit to enable receiver’s PDM mode.
|
||||
I2S0.pdm_conf.tx_pdm_en = 0; // Set this bit to enable transmitter’s PDM mode.
|
||||
|
||||
// I2S_COMM_FORMAT_I2S_LSB
|
||||
I2S0.conf.tx_short_sync = 0; // Set this bit to enable transmitter in PCM standard mode.
|
||||
I2S0.conf.rx_short_sync = 0; // Set this bit to enable receiver in PCM standard mode.
|
||||
I2S0.conf.tx_msb_shift = 0; // Do not use the Philips standard to avoid bit-shifting
|
||||
I2S0.conf.rx_msb_shift = 0; // Do not use the Philips standard to avoid bit-shifting
|
||||
|
||||
//
|
||||
// i2s_set_clk
|
||||
//
|
||||
|
||||
// set clock (fi2s) 160MHz / 5
|
||||
I2S0.clkm_conf.clka_en = 0; // Use 160 MHz PLL_D2_CLK as reference
|
||||
// N + b/a = 0
|
||||
# if I2S_OUT_NUM_BITS == 16
|
||||
// N = 10
|
||||
I2S0.clkm_conf.clkm_div_num = 10; // minimum value of 2, reset value of 4, max 256 (I²S clock divider’s integral value)
|
||||
# else
|
||||
// N = 5
|
||||
I2S0.clkm_conf.clkm_div_num = 5; // minimum value of 2, reset value of 4, max 256 (I²S clock divider’s integral value)
|
||||
# endif
|
||||
// b/a = 0
|
||||
I2S0.clkm_conf.clkm_div_b = 0; // 0 at reset
|
||||
I2S0.clkm_conf.clkm_div_a = 0; // 0 at reset, what about divide by 0? (not an issue)
|
||||
|
||||
// Bit clock configuration bit in transmitter mode.
|
||||
// fbck = fi2s / tx_bck_div_num = (160 MHz / 5) / 2 = 16 MHz
|
||||
I2S0.sample_rate_conf.tx_bck_div_num = 2; // minimum value of 2 defaults to 6
|
||||
I2S0.sample_rate_conf.rx_bck_div_num = 2;
|
||||
|
||||
# ifdef USE_I2S_OUT_STREAM
|
||||
// Enable TX interrupts (DMA Interrupts)
|
||||
I2S0.int_ena.out_eof = 1; // Triggered when rxlink has finished sending a packet.
|
||||
I2S0.int_ena.out_dscr_err = 0; // Triggered when invalid rxlink descriptors are encountered.
|
||||
I2S0.int_ena.out_total_eof = 1; // Triggered when all transmitting linked lists are used up.
|
||||
I2S0.int_ena.out_done = 0; // Triggered when all transmitted and buffered data have been read.
|
||||
|
||||
// default pulse callback period (μsec)
|
||||
i2s_out_pulse_period = init_param.pulse_period;
|
||||
i2s_out_pulse_func = init_param.pulse_func;
|
||||
|
||||
// Create the task that will feed the buffer
|
||||
xTaskCreatePinnedToCore(i2sOutTask,
|
||||
"I2SOutTask",
|
||||
1024 * 10,
|
||||
NULL,
|
||||
1,
|
||||
nullptr,
|
||||
CONFIG_ARDUINO_RUNNING_CORE // must run the task on same core
|
||||
);
|
||||
|
||||
// Allocate and Enable the I2S interrupt
|
||||
esp_intr_alloc(ETS_I2S0_INTR_SOURCE, 0, i2s_out_intr_handler, nullptr, &i2s_out_isr_handle);
|
||||
esp_intr_enable(i2s_out_isr_handle);
|
||||
# endif
|
||||
|
||||
// Remember GPIO pin numbers
|
||||
i2s_out_ws_pin = init_param.ws_pin;
|
||||
i2s_out_bck_pin = init_param.bck_pin;
|
||||
i2s_out_data_pin = init_param.data_pin;
|
||||
i2s_out_initialized = 1;
|
||||
|
||||
// Start the I2S peripheral
|
||||
i2s_out_start();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
# ifndef I2S_OUT_WS
|
||||
# define I2S_OUT_WS GPIO_NUM_17
|
||||
# endif
|
||||
# ifndef I2S_OUT_BCK
|
||||
# define I2S_OUT_BCK GPIO_NUM_22
|
||||
# endif
|
||||
# ifndef I2S_OUT_DATA
|
||||
# define I2S_OUT_DATA GPIO_NUM_21
|
||||
# endif
|
||||
# ifndef I2S_OUT_INIT_VAL
|
||||
# define I2S_OUT_INIT_VAL 0
|
||||
# endif
|
||||
/*
|
||||
Initialize I2S out by default parameters.
|
||||
|
||||
return -1 ... already initialized
|
||||
*/
|
||||
int IRAM_ATTR i2s_out_init() {
|
||||
i2s_out_init_t default_param = {
|
||||
.ws_pin = I2S_OUT_WS,
|
||||
.bck_pin = I2S_OUT_BCK,
|
||||
.data_pin = I2S_OUT_DATA,
|
||||
.pulse_func = NULL,
|
||||
.pulse_period = I2S_OUT_USEC_PER_PULSE,
|
||||
.init_val = I2S_OUT_INIT_VAL,
|
||||
};
|
||||
return i2s_out_init(default_param);
|
||||
}
|
||||
|
||||
#endif
|
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
i2s_out.h
|
||||
I2SOut.h
|
||||
Part of Grbl_ESP32
|
||||
Header for basic GPIO expander using the ESP32 I2S peripheral
|
||||
2020 - Michiyasu Odaki
|
||||
@@ -35,44 +37,42 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#ifndef i2s_out_h
|
||||
#define i2s_out_h
|
||||
|
||||
// It should be included at the outset to know the machine configuration.
|
||||
#include "config.h"
|
||||
#include "Config.h"
|
||||
|
||||
// If USE_I2S_OUT_STREAM is defined
|
||||
// but the prerequisite USE_I2S_OUT is not defined,
|
||||
// it is forced to be defined.
|
||||
#ifdef USE_I2S_OUT_STREAM
|
||||
#ifndef USE_I2S_OUT
|
||||
#define USE_I2S_OUT
|
||||
#endif
|
||||
# ifndef USE_I2S_OUT
|
||||
# define USE_I2S_OUT
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef USE_I2S_OUT
|
||||
#include <stdint.h>
|
||||
# include <stdint.h>
|
||||
|
||||
/* Assert */
|
||||
#if defined(I2S_OUT_NUM_BITS)
|
||||
#if (I2S_OUT_NUM_BITS != 16) && (I2S_OUT_NUM_BITS != 32)
|
||||
#error "I2S_OUT_NUM_BITS should be 16 or 32"
|
||||
#endif
|
||||
#else
|
||||
#define I2S_OUT_NUM_BITS 32
|
||||
#endif
|
||||
# if defined(I2S_OUT_NUM_BITS)
|
||||
# if (I2S_OUT_NUM_BITS != 16) && (I2S_OUT_NUM_BITS != 32)
|
||||
# error "I2S_OUT_NUM_BITS should be 16 or 32"
|
||||
# endif
|
||||
# else
|
||||
# define I2S_OUT_NUM_BITS 32
|
||||
# endif
|
||||
|
||||
#define I2SO(n) (I2S_OUT_PIN_BASE + n)
|
||||
# define I2SO(n) (I2S_OUT_PIN_BASE + n)
|
||||
|
||||
/* 16-bit mode: 1000000 usec / ((160000000 Hz) / 10 / 2) x 16 bit/pulse x 2(stereo) = 4 usec/pulse */
|
||||
/* 32-bit mode: 1000000 usec / ((160000000 Hz) / 5 / 2) x 32 bit/pulse x 2(stereo) = 4 usec/pulse */
|
||||
#define I2S_OUT_USEC_PER_PULSE 4
|
||||
# define I2S_OUT_USEC_PER_PULSE 4
|
||||
|
||||
#define I2S_OUT_DMABUF_COUNT 5 /* number of DMA buffers to store data */
|
||||
#define I2S_OUT_DMABUF_LEN 2000 /* maximum size in bytes (4092 is DMA's limit) */
|
||||
# define I2S_OUT_DMABUF_COUNT 5 /* number of DMA buffers to store data */
|
||||
# define I2S_OUT_DMABUF_LEN 2000 /* maximum size in bytes (4092 is DMA's limit) */
|
||||
|
||||
#define I2S_OUT_DELAY_DMABUF_MS (I2S_OUT_DMABUF_LEN / sizeof(uint32_t) * I2S_OUT_USEC_PER_PULSE / 1000)
|
||||
#define I2S_OUT_DELAY_MS (I2S_OUT_DELAY_DMABUF_MS * (I2S_OUT_DMABUF_COUNT + 1))
|
||||
# define I2S_OUT_DELAY_DMABUF_MS (I2S_OUT_DMABUF_LEN / sizeof(uint32_t) * I2S_OUT_USEC_PER_PULSE / 1000)
|
||||
# define I2S_OUT_DELAY_MS (I2S_OUT_DELAY_DMABUF_MS * (I2S_OUT_DMABUF_COUNT + 1))
|
||||
|
||||
typedef void (*i2s_out_pulse_func_t)(void);
|
||||
|
||||
@@ -90,19 +90,19 @@ typedef struct {
|
||||
If I2S_OUT_PIN_BASE is set to 128,
|
||||
bit0:Expanded GPIO 128, 1: Expanded GPIO 129, ..., v: Expanded GPIO 159
|
||||
*/
|
||||
uint8_t ws_pin;
|
||||
uint8_t bck_pin;
|
||||
uint8_t data_pin;
|
||||
uint8_t ws_pin;
|
||||
uint8_t bck_pin;
|
||||
uint8_t data_pin;
|
||||
i2s_out_pulse_func_t pulse_func;
|
||||
uint32_t pulse_period; // aka step rate.
|
||||
uint32_t init_val;
|
||||
uint32_t pulse_period; // aka step rate.
|
||||
uint32_t init_val;
|
||||
} i2s_out_init_t;
|
||||
|
||||
/*
|
||||
Initialize I2S out by parameters.
|
||||
return -1 ... already initialized
|
||||
*/
|
||||
int i2s_out_init(i2s_out_init_t &init_param);
|
||||
int i2s_out_init(i2s_out_init_t& init_param);
|
||||
|
||||
/*
|
||||
Initialize I2S out by default parameters.
|
||||
@@ -164,10 +164,10 @@ int i2s_out_set_stepping();
|
||||
void i2s_out_delay();
|
||||
|
||||
/*
|
||||
Set the pulse callback period in microseconds
|
||||
(like the timer period for the ISR)
|
||||
Set the pulse callback period in ISR ticks.
|
||||
(same value of the timer period for the ISR)
|
||||
*/
|
||||
int i2s_out_set_pulse_period(uint32_t period);
|
||||
int i2s_out_set_pulse_period(uint64_t period);
|
||||
|
||||
/*
|
||||
Register a callback function to generate pulse data
|
||||
@@ -188,4 +188,3 @@ int i2s_out_reset();
|
||||
Reference: "ESP32 Technical Reference Manual" by Espressif Systems
|
||||
https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf
|
||||
*/
|
||||
#endif
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
jog.h - Jogging methods
|
||||
Jog.cpp - Jogging methods
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
@@ -21,8 +21,7 @@
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "grbl.h"
|
||||
|
||||
#include "Grbl.h"
|
||||
|
||||
// Sets up valid jog motion received from g-code parser, checks for soft-limits, and executes the jog.
|
||||
uint8_t jog_execute(plan_line_data_t* pl_data, parser_block_t* gc_block) {
|
||||
@@ -34,12 +33,13 @@ uint8_t jog_execute(plan_line_data_t* pl_data, parser_block_t* gc_block) {
|
||||
pl_data->line_number = gc_block->values.n;
|
||||
#endif
|
||||
if (soft_limits->get()) {
|
||||
if (system_check_travel_limits(gc_block->values.xyz)) return (STATUS_TRAVEL_EXCEEDED);
|
||||
if (system_check_travel_limits(gc_block->values.xyz))
|
||||
return (STATUS_TRAVEL_EXCEEDED);
|
||||
}
|
||||
// Valid jog command. Plan, set state, and execute.
|
||||
mc_line(gc_block->values.xyz, pl_data);
|
||||
if (sys.state == STATE_IDLE) {
|
||||
if (plan_get_current_block() != NULL) { // Check if there is a block to execute.
|
||||
if (plan_get_current_block() != NULL) { // Check if there is a block to execute.
|
||||
sys.state = STATE_JOG;
|
||||
st_prep_buffer();
|
||||
st_wake_up(); // NOTE: Manual start. No state machine required.
|
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
jog.h - Jogging methods
|
||||
Jog.h - Jogging methods
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
@@ -20,16 +22,10 @@
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef jog_h
|
||||
#define jog_h
|
||||
|
||||
#include "grbl.h"
|
||||
|
||||
#include "Grbl.h"
|
||||
|
||||
// System motion line numbers must be zero.
|
||||
#define JOG_LINE_NUMBER 0
|
||||
|
||||
// Sets up valid jog motion received from g-code parser, checks for soft-limits, and executes the jog.
|
||||
uint8_t jog_execute(plan_line_data_t *pl_data, parser_block_t *gc_block);
|
||||
|
||||
#endif
|
||||
uint8_t jog_execute(plan_line_data_t* pl_data, parser_block_t* gc_block);
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
limits.c - code pertaining to limit-switches and performing the homing cycle
|
||||
Limits.cpp - code pertaining to limit-switches and performing the homing cycle
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2012-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
@@ -25,7 +25,7 @@
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "grbl.h"
|
||||
#include "Grbl.h"
|
||||
|
||||
uint8_t n_homing_locate_cycle = N_HOMING_LOCATE_CYCLE;
|
||||
|
||||
@@ -33,10 +33,10 @@ xQueueHandle limit_sw_queue; // used by limit switch debouncing
|
||||
|
||||
// Homing axis search distance multiplier. Computed by this value times the cycle travel.
|
||||
#ifndef HOMING_AXIS_SEARCH_SCALAR
|
||||
#define HOMING_AXIS_SEARCH_SCALAR 1.1 // Must be > 1 to ensure limit switch will be engaged.
|
||||
# define HOMING_AXIS_SEARCH_SCALAR 1.1 // Must be > 1 to ensure limit switch will be engaged.
|
||||
#endif
|
||||
#ifndef HOMING_AXIS_LOCATE_SCALAR
|
||||
#define HOMING_AXIS_LOCATE_SCALAR 5.0 // Must be > 1 to ensure limit switch is cleared.
|
||||
# define HOMING_AXIS_LOCATE_SCALAR 5.0 // Must be > 1 to ensure limit switch is cleared.
|
||||
#endif
|
||||
|
||||
void IRAM_ATTR isr_limit_switches() {
|
||||
@@ -52,16 +52,16 @@ void IRAM_ATTR isr_limit_switches() {
|
||||
int evt;
|
||||
xQueueSendFromISR(limit_sw_queue, &evt, NULL);
|
||||
#else
|
||||
#ifdef HARD_LIMIT_FORCE_STATE_CHECK
|
||||
# ifdef HARD_LIMIT_FORCE_STATE_CHECK
|
||||
// Check limit pin state.
|
||||
if (limits_get_state()) {
|
||||
mc_reset(); // Initiate system kill.
|
||||
system_set_exec_alarm(EXEC_ALARM_HARD_LIMIT); // Indicate hard limit critical event
|
||||
mc_reset(); // Initiate system kill.
|
||||
system_set_exec_alarm(EXEC_ALARM_HARD_LIMIT); // Indicate hard limit critical event
|
||||
}
|
||||
#else
|
||||
mc_reset(); // Initiate system kill.
|
||||
system_set_exec_alarm(EXEC_ALARM_HARD_LIMIT); // Indicate hard limit critical event
|
||||
#endif
|
||||
# else
|
||||
mc_reset(); // Initiate system kill.
|
||||
system_set_exec_alarm(EXEC_ALARM_HARD_LIMIT); // Indicate hard limit critical event
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -75,10 +75,11 @@ void IRAM_ATTR isr_limit_switches() {
|
||||
// NOTE: Only the abort realtime command can interrupt this process.
|
||||
// TODO: Move limit pin-specific calls to a general function for portability.
|
||||
void limits_go_home(uint8_t cycle_mask) {
|
||||
if (sys.abort) return; // Block if system reset has been issued.
|
||||
if (sys.abort)
|
||||
return; // Block if system reset has been issued.
|
||||
// Initialize plan data struct for homing motion. Spindle and coolant are disabled.
|
||||
motors_set_homing_mode(cycle_mask, true); // tell motors homing is about to start
|
||||
plan_line_data_t plan_data;
|
||||
motors_set_homing_mode(cycle_mask, true); // tell motors homing is about to start
|
||||
plan_line_data_t plan_data;
|
||||
plan_line_data_t* pl_data = &plan_data;
|
||||
memset(pl_data, 0, sizeof(plan_line_data_t));
|
||||
pl_data->condition = (PL_COND_FLAG_SYSTEM_MOTION | PL_COND_FLAG_NO_FEED_OVERRIDE);
|
||||
@@ -88,28 +89,29 @@ void limits_go_home(uint8_t cycle_mask) {
|
||||
// Initialize variables used for homing computations.
|
||||
uint8_t n_cycle = (2 * n_homing_locate_cycle + 1);
|
||||
uint8_t step_pin[N_AXIS];
|
||||
float target[N_AXIS];
|
||||
float max_travel = 0.0;
|
||||
float target[N_AXIS];
|
||||
float max_travel = 0.0;
|
||||
uint8_t idx;
|
||||
for (idx = 0; idx < N_AXIS; idx++) {
|
||||
// Initialize step pin masks
|
||||
step_pin[idx] = get_step_pin_mask(idx);
|
||||
#ifdef COREXY
|
||||
if ((idx == A_MOTOR) || (idx == B_MOTOR)) step_pin[idx] = (get_step_pin_mask(X_AXIS) | get_step_pin_mask(Y_AXIS));
|
||||
if ((idx == A_MOTOR) || (idx == B_MOTOR))
|
||||
step_pin[idx] = (get_step_pin_mask(X_AXIS) | get_step_pin_mask(Y_AXIS));
|
||||
#endif
|
||||
if (bit_istrue(cycle_mask, bit(idx))) {
|
||||
// Set target based on max_travel setting. Ensure homing switches engaged with search scalar.
|
||||
max_travel = MAX(max_travel, (HOMING_AXIS_SEARCH_SCALAR) * axis_settings[idx]->max_travel->get());
|
||||
max_travel = MAX(max_travel, (HOMING_AXIS_SEARCH_SCALAR)*axis_settings[idx]->max_travel->get());
|
||||
}
|
||||
}
|
||||
// Set search mode with approach at seek rate to quickly engage the specified cycle_mask limit switches.
|
||||
bool approach = true;
|
||||
float homing_rate = homing_seek_rate->get();
|
||||
bool approach = true;
|
||||
float homing_rate = homing_seek_rate->get();
|
||||
uint8_t limit_state, axislock, n_active_axis;
|
||||
do {
|
||||
system_convert_array_steps_to_mpos(target, sys_position);
|
||||
// Initialize and declare variables needed for homing routine.
|
||||
axislock = 0;
|
||||
axislock = 0;
|
||||
n_active_axis = 0;
|
||||
for (idx = 0; idx < N_AXIS; idx++) {
|
||||
// Set target location for active axes and setup computation for homing rate.
|
||||
@@ -132,24 +134,28 @@ void limits_go_home(uint8_t cycle_mask) {
|
||||
// NOTE: This happens to compile smaller than any other implementation tried.
|
||||
auto mask = homing_dir_mask->get();
|
||||
if (bit_istrue(mask, bit(idx))) {
|
||||
if (approach) target[idx] = -max_travel;
|
||||
else target[idx] = max_travel;
|
||||
if (approach)
|
||||
target[idx] = -max_travel;
|
||||
else
|
||||
target[idx] = max_travel;
|
||||
} else {
|
||||
if (approach) target[idx] = max_travel;
|
||||
else target[idx] = -max_travel;
|
||||
if (approach)
|
||||
target[idx] = max_travel;
|
||||
else
|
||||
target[idx] = -max_travel;
|
||||
}
|
||||
// Apply axislock to the step port pins active in this cycle.
|
||||
axislock |= step_pin[idx];
|
||||
}
|
||||
}
|
||||
homing_rate *= sqrt(n_active_axis); // [sqrt(N_AXIS)] Adjust so individual axes all move at homing rate.
|
||||
homing_rate *= sqrt(n_active_axis); // [sqrt(N_AXIS)] Adjust so individual axes all move at homing rate.
|
||||
sys.homing_axis_lock = axislock;
|
||||
// Perform homing cycle. Planner buffer should be empty, as required to initiate the homing cycle.
|
||||
pl_data->feed_rate = homing_rate; // Set current homing rate.
|
||||
plan_buffer_line(target, pl_data); // Bypass mc_line(). Directly plan homing motion.
|
||||
sys.step_control = STEP_CONTROL_EXECUTE_SYS_MOTION; // Set to execute homing motion and clear existing flags.
|
||||
st_prep_buffer(); // Prep and fill segment buffer from newly planned block.
|
||||
st_wake_up(); // Initiate motion
|
||||
pl_data->feed_rate = homing_rate; // Set current homing rate.
|
||||
plan_buffer_line(target, pl_data); // Bypass mc_line(). Directly plan homing motion.
|
||||
sys.step_control = STEP_CONTROL_EXECUTE_SYS_MOTION; // Set to execute homing motion and clear existing flags.
|
||||
st_prep_buffer(); // Prep and fill segment buffer from newly planned block.
|
||||
st_wake_up(); // Initiate motion
|
||||
do {
|
||||
if (approach) {
|
||||
// Check limit state. Lock out cycle axes when they change.
|
||||
@@ -158,8 +164,10 @@ void limits_go_home(uint8_t cycle_mask) {
|
||||
if (axislock & step_pin[idx]) {
|
||||
if (limit_state & bit(idx)) {
|
||||
#ifdef COREXY
|
||||
if (idx == Z_AXIS) axislock &= ~(step_pin[Z_AXIS]);
|
||||
else axislock &= ~(step_pin[A_MOTOR] | step_pin[B_MOTOR]);
|
||||
if (idx == Z_AXIS)
|
||||
axislock &= ~(step_pin[Z_AXIS]);
|
||||
else
|
||||
axislock &= ~(step_pin[A_MOTOR] | step_pin[B_MOTOR]);
|
||||
#else
|
||||
axislock &= ~(step_pin[idx]);
|
||||
#endif
|
||||
@@ -168,21 +176,25 @@ void limits_go_home(uint8_t cycle_mask) {
|
||||
}
|
||||
sys.homing_axis_lock = axislock;
|
||||
}
|
||||
st_prep_buffer(); // Check and prep segment buffer. NOTE: Should take no longer than 200us.
|
||||
st_prep_buffer(); // Check and prep segment buffer. NOTE: Should take no longer than 200us.
|
||||
// Exit routines: No time to run protocol_execute_realtime() in this loop.
|
||||
if (sys_rt_exec_state & (EXEC_SAFETY_DOOR | EXEC_RESET | EXEC_CYCLE_STOP)) {
|
||||
uint8_t rt_exec = sys_rt_exec_state;
|
||||
// Homing failure condition: Reset issued during cycle.
|
||||
if (rt_exec & EXEC_RESET) system_set_exec_alarm(EXEC_ALARM_HOMING_FAIL_RESET);
|
||||
if (rt_exec & EXEC_RESET)
|
||||
system_set_exec_alarm(EXEC_ALARM_HOMING_FAIL_RESET);
|
||||
// Homing failure condition: Safety door was opened.
|
||||
if (rt_exec & EXEC_SAFETY_DOOR) system_set_exec_alarm(EXEC_ALARM_HOMING_FAIL_DOOR);
|
||||
if (rt_exec & EXEC_SAFETY_DOOR)
|
||||
system_set_exec_alarm(EXEC_ALARM_HOMING_FAIL_DOOR);
|
||||
// Homing failure condition: Limit switch still engaged after pull-off motion
|
||||
if (!approach && (limits_get_state() & cycle_mask)) system_set_exec_alarm(EXEC_ALARM_HOMING_FAIL_PULLOFF);
|
||||
if (!approach && (limits_get_state() & cycle_mask))
|
||||
system_set_exec_alarm(EXEC_ALARM_HOMING_FAIL_PULLOFF);
|
||||
// Homing failure condition: Limit switch not found during approach.
|
||||
if (approach && (rt_exec & EXEC_CYCLE_STOP)) system_set_exec_alarm(EXEC_ALARM_HOMING_FAIL_APPROACH);
|
||||
if (sys_rt_exec_alarm) {
|
||||
motors_set_homing_mode(cycle_mask, false); // tell motors homing is done...failed
|
||||
mc_reset(); // Stop motors, if they are running.
|
||||
if (approach && (rt_exec & EXEC_CYCLE_STOP))
|
||||
system_set_exec_alarm(EXEC_ALARM_HOMING_FAIL_APPROACH);
|
||||
if (sys_rt_exec_alarm) {
|
||||
motors_set_homing_mode(cycle_mask, false); // tell motors homing is done...failed
|
||||
mc_reset(); // Stop motors, if they are running.
|
||||
protocol_execute_realtime();
|
||||
return;
|
||||
} else {
|
||||
@@ -197,16 +209,16 @@ void limits_go_home(uint8_t cycle_mask) {
|
||||
delay_ms(I2S_OUT_DELAY_MS);
|
||||
}
|
||||
#endif
|
||||
st_reset(); // Immediately force kill steppers and reset step segment buffer.
|
||||
delay_ms(homing_debounce->get()); // Delay to allow transient dynamics to dissipate.
|
||||
st_reset(); // Immediately force kill steppers and reset step segment buffer.
|
||||
delay_ms(homing_debounce->get()); // Delay to allow transient dynamics to dissipate.
|
||||
// Reverse direction and reset homing rate for locate cycle(s).
|
||||
approach = !approach;
|
||||
// After first cycle, homing enters locating phase. Shorten search to pull-off distance.
|
||||
if (approach) {
|
||||
max_travel = homing_pulloff->get() * HOMING_AXIS_LOCATE_SCALAR;
|
||||
max_travel = homing_pulloff->get() * HOMING_AXIS_LOCATE_SCALAR;
|
||||
homing_rate = homing_feed_rate->get();
|
||||
} else {
|
||||
max_travel = homing_pulloff->get();
|
||||
max_travel = homing_pulloff->get();
|
||||
homing_rate = homing_seek_rate->get();
|
||||
}
|
||||
} while (n_cycle-- > 0);
|
||||
@@ -218,7 +230,7 @@ void limits_go_home(uint8_t cycle_mask) {
|
||||
// triggering when hard limits are enabled or when more than one axes shares a limit pin.
|
||||
int32_t set_axis_position;
|
||||
// Set machine positions for homed limit switches. Don't update non-homed axes.
|
||||
auto mask = homing_dir_mask->get();
|
||||
auto mask = homing_dir_mask->get();
|
||||
auto pulloff = homing_pulloff->get();
|
||||
for (idx = 0; idx < N_AXIS; idx++) {
|
||||
auto steps = axis_settings[idx]->steps_per_mm->get();
|
||||
@@ -228,28 +240,28 @@ void limits_go_home(uint8_t cycle_mask) {
|
||||
#else
|
||||
auto travel = axis_settings[idx]->max_travel->get();
|
||||
if (bit_istrue(mask, bit(idx))) {
|
||||
#ifdef HOMING_FORCE_POSITIVE_SPACE
|
||||
set_axis_position = 0; //lround(settings.homing_pulloff*settings.steps_per_mm[idx]);
|
||||
#else
|
||||
# ifdef HOMING_FORCE_POSITIVE_SPACE
|
||||
set_axis_position = 0; //lround(settings.homing_pulloff*settings.steps_per_mm[idx]);
|
||||
# else
|
||||
set_axis_position = lround((-travel + pulloff) * steps);
|
||||
#endif
|
||||
# endif
|
||||
} else {
|
||||
#ifdef HOMING_FORCE_POSITIVE_SPACE
|
||||
# ifdef HOMING_FORCE_POSITIVE_SPACE
|
||||
set_axis_position = lround((-travel - pulloff) * steps);
|
||||
#else
|
||||
# else
|
||||
set_axis_position = lround(-pulloff * steps);
|
||||
#endif
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
#ifdef COREXY
|
||||
if (idx == X_AXIS) {
|
||||
int32_t off_axis_position = system_convert_corexy_to_y_axis_steps(sys_position);
|
||||
sys_position[A_MOTOR] = set_axis_position + off_axis_position;
|
||||
sys_position[B_MOTOR] = set_axis_position - off_axis_position;
|
||||
sys_position[A_MOTOR] = set_axis_position + off_axis_position;
|
||||
sys_position[B_MOTOR] = set_axis_position - off_axis_position;
|
||||
} else if (idx == Y_AXIS) {
|
||||
int32_t off_axis_position = system_convert_corexy_to_x_axis_steps(sys_position);
|
||||
sys_position[A_MOTOR] = off_axis_position + set_axis_position;
|
||||
sys_position[B_MOTOR] = off_axis_position - set_axis_position;
|
||||
sys_position[A_MOTOR] = off_axis_position + set_axis_position;
|
||||
sys_position[B_MOTOR] = off_axis_position - set_axis_position;
|
||||
} else
|
||||
sys_position[idx] = set_axis_position;
|
||||
#else
|
||||
@@ -257,55 +269,62 @@ void limits_go_home(uint8_t cycle_mask) {
|
||||
#endif
|
||||
}
|
||||
}
|
||||
sys.step_control = STEP_CONTROL_NORMAL_OP; // Return step control to normal operation.
|
||||
motors_set_homing_mode(cycle_mask, false); // tell motors homing is done
|
||||
sys.step_control = STEP_CONTROL_NORMAL_OP; // Return step control to normal operation.
|
||||
motors_set_homing_mode(cycle_mask, false); // tell motors homing is done
|
||||
}
|
||||
|
||||
uint8_t limit_pins[] = {
|
||||
X_LIMIT_PIN,
|
||||
Y_LIMIT_PIN,
|
||||
Z_LIMIT_PIN,
|
||||
A_LIMIT_PIN,
|
||||
B_LIMIT_PIN,
|
||||
C_LIMIT_PIN,
|
||||
};
|
||||
uint8_t limit_pins[MAX_N_AXIS][2] = { { X_LIMIT_PIN, X2_LIMIT_PIN }, { Y_LIMIT_PIN, Y2_LIMIT_PIN }, { Z_LIMIT_PIN, Z2_LIMIT_PIN },
|
||||
{ A_LIMIT_PIN, A2_LIMIT_PIN }, { B_LIMIT_PIN, B2_LIMIT_PIN }, { C_LIMIT_PIN, C2_LIMIT_PIN } };
|
||||
|
||||
uint8_t limit_mask = 0;
|
||||
|
||||
void limits_init() {
|
||||
limit_mask = 0;
|
||||
int mode = INPUT_PULLUP;
|
||||
int mode = INPUT_PULLUP;
|
||||
#ifdef DISABLE_LIMIT_PIN_PULL_UP
|
||||
mode = INPUT;
|
||||
#endif
|
||||
for (int i=0; i<N_AXIS; i++) {
|
||||
uint8_t pin;
|
||||
if ((pin = limit_pins[i]) != UNDEFINED_PIN) {
|
||||
limit_mask |= bit(i);
|
||||
pinMode(pin, mode);
|
||||
if (hard_limits->get()) {
|
||||
attachInterrupt(pin, isr_limit_switches, CHANGE);
|
||||
} else {
|
||||
detachInterrupt(pin);
|
||||
for (int axis = 0; axis < N_AXIS; axis++) {
|
||||
for (int gang_index = 0; gang_index < 2; gang_index++) {
|
||||
uint8_t pin;
|
||||
if ((pin = limit_pins[axis][gang_index]) != UNDEFINED_PIN) {
|
||||
pinMode(pin, mode);
|
||||
limit_mask |= bit(axis);
|
||||
if (hard_limits->get()) {
|
||||
attachInterrupt(pin, isr_limit_switches, CHANGE);
|
||||
} else {
|
||||
detachInterrupt(pin);
|
||||
}
|
||||
grbl_msg_sendf(CLIENT_SERIAL,
|
||||
MSG_LEVEL_INFO,
|
||||
"%c%s Axis limit switch on pin %s",
|
||||
report_get_axis_letter(axis),
|
||||
gang_index ? "2" : " ",
|
||||
pinName(pin).c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Limit Mask %d", limit_mask);
|
||||
|
||||
// setup task used for debouncing
|
||||
limit_sw_queue = xQueueCreate(10, sizeof(int));
|
||||
xTaskCreate(limitCheckTask,
|
||||
"limitCheckTask",
|
||||
2048,
|
||||
NULL,
|
||||
5, // priority
|
||||
5, // priority
|
||||
NULL);
|
||||
}
|
||||
|
||||
// Disables hard limits.
|
||||
void limits_disable() {
|
||||
for (int i=0; i<N_AXIS; i++) {
|
||||
if (limit_pins[i] != UNDEFINED_PIN) {
|
||||
detachInterrupt(i);
|
||||
for (int axis = 0; axis < N_AXIS; axis++) {
|
||||
for (int gang_index = 0; gang_index < 2; gang_index++) {
|
||||
uint8_t pin = limit_pins[axis][gang_index];
|
||||
if (pin != UNDEFINED_PIN) {
|
||||
detachInterrupt(pin);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -315,14 +334,16 @@ void limits_disable() {
|
||||
// number in bit position, i.e. Z_AXIS is bit(2), and Y_AXIS is bit(1).
|
||||
uint8_t limits_get_state() {
|
||||
uint8_t pinMask = 0;
|
||||
for (int i=0; i<N_AXIS; i++) {
|
||||
uint8_t pin;
|
||||
if ((pin = limit_pins[i]) != UNDEFINED_PIN) {
|
||||
pinMask += digitalRead(pin) << i;
|
||||
for (int axis = 0; axis < N_AXIS; axis++) {
|
||||
for (int gang_index = 0; gang_index < 2; gang_index++) {
|
||||
uint8_t pin = limit_pins[axis][gang_index];
|
||||
if (pin != UNDEFINED_PIN) {
|
||||
pinMask |= (digitalRead(pin) << axis);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef INVERT_LIMIT_PIN_MASK // not normally used..unless you have both normal and inverted switches
|
||||
#ifdef INVERT_LIMIT_PIN_MASK // not normally used..unless you have both normal and inverted switches
|
||||
pinMask ^= INVERT_LIMIT_PIN_MASK;
|
||||
#endif
|
||||
if (limit_invert->get()) {
|
||||
@@ -338,11 +359,11 @@ void limits_soft_check(float* target) {
|
||||
if (system_check_travel_limits(target)) {
|
||||
// TODO for debugging only 3 axes right now
|
||||
grbl_msg_sendf(CLIENT_SERIAL,
|
||||
MSG_LEVEL_INFO,
|
||||
"Soft limit error target WPOS X:%5.2f Y:%5.2f Z:%5.2f",
|
||||
target[X_AXIS] - gc_state.coord_system[X_AXIS],
|
||||
target[Y_AXIS] - gc_state.coord_system[Y_AXIS],
|
||||
target[Z_AXIS] - gc_state.coord_system[Z_AXIS]);
|
||||
MSG_LEVEL_INFO,
|
||||
"Soft limit error target WPOS X:%5.2f Y:%5.2f Z:%5.2f",
|
||||
target[X_AXIS] - gc_state.coord_system[X_AXIS],
|
||||
target[Y_AXIS] - gc_state.coord_system[Y_AXIS],
|
||||
target[Z_AXIS] - gc_state.coord_system[Z_AXIS]);
|
||||
|
||||
sys.soft_limit = true;
|
||||
// Force feed hold if cycle is active. All buffered blocks are guaranteed to be within
|
||||
@@ -352,12 +373,13 @@ void limits_soft_check(float* target) {
|
||||
system_set_exec_state_flag(EXEC_FEED_HOLD);
|
||||
do {
|
||||
protocol_execute_realtime();
|
||||
if (sys.abort) return;
|
||||
if (sys.abort)
|
||||
return;
|
||||
} while (sys.state != STATE_IDLE);
|
||||
}
|
||||
mc_reset(); // Issue system reset and ensure spindle and coolant are shutdown.
|
||||
system_set_exec_alarm(EXEC_ALARM_SOFT_LIMIT); // Indicate soft limit critical event
|
||||
protocol_execute_realtime(); // Execute to enter critical event loop and system abort
|
||||
mc_reset(); // Issue system reset and ensure spindle and coolant are shutdown.
|
||||
system_set_exec_alarm(EXEC_ALARM_SOFT_LIMIT); // Indicate soft limit critical event
|
||||
protocol_execute_realtime(); // Execute to enter critical event loop and system abort
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -366,14 +388,14 @@ void limits_soft_check(float* target) {
|
||||
void limitCheckTask(void* pvParameters) {
|
||||
while (true) {
|
||||
int evt;
|
||||
xQueueReceive(limit_sw_queue, &evt, portMAX_DELAY); // block until receive queue
|
||||
vTaskDelay(DEBOUNCE_PERIOD / portTICK_PERIOD_MS); // delay a while
|
||||
xQueueReceive(limit_sw_queue, &evt, portMAX_DELAY); // block until receive queue
|
||||
vTaskDelay(DEBOUNCE_PERIOD / portTICK_PERIOD_MS); // delay a while
|
||||
uint8_t switch_state;
|
||||
switch_state = limits_get_state();
|
||||
if (switch_state) {
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Limit Switch State %08d", switch_state);
|
||||
mc_reset(); // Initiate system kill.
|
||||
system_set_exec_alarm(EXEC_ALARM_HARD_LIMIT); // Indicate hard limit critical event
|
||||
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Limit Switch State %08d", switch_state);
|
||||
mc_reset(); // Initiate system kill.
|
||||
system_set_exec_alarm(EXEC_ALARM_HARD_LIMIT); // Indicate hard limit critical event
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -398,17 +420,17 @@ bool axis_is_squared(uint8_t axis_mask) {
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
if (axis_mask == (1 << A_AXIS)) {
|
||||
if (axis_mask == (1 << A_AXIS)) {
|
||||
#ifdef A_AXIS_SQUARING
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
if (axis_mask == (1 << B_AXIS)) {
|
||||
if (axis_mask == (1 << B_AXIS)) {
|
||||
#ifdef B_AXIS_SQUARING
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
if (axis_mask == (1 << C_AXIS)) {
|
||||
if (axis_mask == (1 << C_AXIS)) {
|
||||
#ifdef C_AXIS_SQUARING
|
||||
return true;
|
||||
#endif
|
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
limits.h - code pertaining to limit-switches and performing the homing cycle
|
||||
Limits.h - code pertaining to limit-switches and performing the homing cycle
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2012-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
@@ -25,14 +27,11 @@
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef grbl_limits_h
|
||||
#define grbl_limits_h
|
||||
|
||||
extern uint8_t n_homing_locate_cycle;
|
||||
|
||||
#define SQUARING_MODE_DUAL 0 // both motors run
|
||||
#define SQUARING_MODE_A 1 // A motor runs
|
||||
#define SQUARING_MODE_B 2 // B motor runs
|
||||
#define SQUARING_MODE_DUAL 0 // both motors run
|
||||
#define SQUARING_MODE_A 1 // A motor runs
|
||||
#define SQUARING_MODE_B 2 // B motor runs
|
||||
|
||||
// Initialize the limits module
|
||||
void limits_init();
|
||||
@@ -55,5 +54,3 @@ bool axis_is_squared(uint8_t axis_mask);
|
||||
|
||||
// A task that runs after a limit switch interrupt.
|
||||
void limitCheckTask(void* pvParameters);
|
||||
|
||||
#endif
|
@@ -1,23 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
// This file is where you choose the machine type, by including
|
||||
// one or more machine definition files as described below.
|
||||
|
||||
#ifndef _machine_h
|
||||
#define _machine_h
|
||||
|
||||
/*
|
||||
PWM
|
||||
Tested on arc_arrow.nc
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#ifndef MACHINE_FILENAME
|
||||
|
||||
// !!! For initial testing, start with test_drive.h which disables
|
||||
// all I/O pins
|
||||
// #include "Machines/atari_1020.h"
|
||||
#include "Machines/test_drive.h"
|
||||
# include "Machines/test_drive.h"
|
||||
|
||||
// !!! For actual use, change the line above to select a board
|
||||
// from Machines/, for example:
|
||||
@@ -48,10 +39,8 @@ PWM
|
||||
// supplied automatically.
|
||||
|
||||
// MACHINE_PATHNAME_QUOTED constructs a path that is suitable for #include
|
||||
#define MACHINE_PATHNAME_QUOTED(name) <Machines/name>
|
||||
# define MACHINE_PATHNAME_QUOTED(name) <src/Machines/name>
|
||||
|
||||
#include MACHINE_PATHNAME_QUOTED(MACHINE_FILENAME)
|
||||
# include MACHINE_PATHNAME_QUOTED(MACHINE_FILENAME)
|
||||
|
||||
#endif // MACHINE_FILENAME
|
||||
|
||||
#endif // _machine_h
|
||||
#endif // MACHINE_FILENAME
|
35
Grbl_Esp32/src/MachineCommon.h
Normal file
35
Grbl_Esp32/src/MachineCommon.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef SPINDLE_TYPE
|
||||
# define SPINDLE_TYPE SPINDLE_TYPE_PWM
|
||||
#endif
|
||||
|
||||
// Grbl setting that are common to all machines
|
||||
// It should not be necessary to change anything herein
|
||||
|
||||
#ifndef GRBL_SPI_FREQ
|
||||
// You can override these by defining them in a board file.
|
||||
// To override, you must set all of them
|
||||
//-1 means use the default board pin
|
||||
# define GRBL_SPI_SS -1
|
||||
# define GRBL_SPI_MOSI -1
|
||||
# define GRBL_SPI_MISO -1
|
||||
# define GRBL_SPI_SCK -1
|
||||
# define GRBL_SPI_FREQ 4000000
|
||||
#endif
|
||||
|
||||
// ESP32 CPU Settings
|
||||
#define F_TIMERS 80000000 // a reference to the speed of ESP32 timers
|
||||
#define F_STEPPER_TIMER 20000000 // frequency of step pulse timer
|
||||
#define STEPPER_OFF_TIMER_PRESCALE 8 // gives a frequency of 10MHz
|
||||
#define STEPPER_OFF_PERIOD_uSEC 3 // each tick is
|
||||
|
||||
#define STEP_PULSE_MIN 2 // uSeconds
|
||||
#define STEP_PULSE_MAX 10 // uSeconds
|
||||
|
||||
// =============== Don't change or comment these out ======================
|
||||
// They are for legacy purposes and will not affect your I/O
|
||||
|
||||
#define STEP_MASK B111111
|
||||
|
||||
#define PROBE_MASK 1
|
@@ -1,3 +1,6 @@
|
||||
#pragma once
|
||||
// clang-format off
|
||||
|
||||
/*
|
||||
3axis_v3.h
|
||||
Part of Grbl_ESP32
|
@@ -1,3 +1,6 @@
|
||||
#pragma once
|
||||
// clang-format off
|
||||
|
||||
/*
|
||||
3axis_v4.h
|
||||
Part of Grbl_ESP32
|
@@ -1,3 +1,6 @@
|
||||
#pragma once
|
||||
// clang-format off
|
||||
|
||||
/*
|
||||
3axis_xyx.h
|
||||
Part of Grbl_ESP32
|
@@ -1,5 +1,8 @@
|
||||
#pragma once
|
||||
// clang-format off
|
||||
|
||||
/*
|
||||
4axis_external_driver_4x.h
|
||||
4axis_external_driver.h
|
||||
Part of Grbl_ESP32
|
||||
|
||||
Pin assignments for the buildlog.net 4-axis external driver board
|
95
Grbl_Esp32/src/Machines/6_pack_MPCNC_stepstick_v1.h
Normal file
95
Grbl_Esp32/src/Machines/6_pack_MPCNC_stepstick_v1.h
Normal file
@@ -0,0 +1,95 @@
|
||||
#pragma once
|
||||
// clang-format off
|
||||
|
||||
/*
|
||||
6_pack_MPCNC_stepstick_v1.h
|
||||
|
||||
Covers all V1 versions V1p0, V1p1, etc
|
||||
|
||||
Part of Grbl_ESP32
|
||||
Pin assignments for the ESP32 I2S 6-axis board
|
||||
2018 - Bart Dring
|
||||
2020 - Mitch Bradley
|
||||
2020 - Michiyasu Odaki
|
||||
Grbl_ESP32 is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl_ESP32. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#define MACHINE_NAME "6 Pack MPCNC XYZXY V1 (StepStick)"
|
||||
|
||||
#ifdef N_AXIS
|
||||
#undef N_AXIS
|
||||
#endif
|
||||
#define N_AXIS 3
|
||||
|
||||
#ifdef ENABLE_SD_CARD
|
||||
#undef ENABLE_SD_CARD
|
||||
#endif
|
||||
|
||||
// === Special Features
|
||||
|
||||
// I2S (steppers & other output-only pins)
|
||||
#define USE_I2S_OUT
|
||||
// Define USE_I2S_OUT_STREAM if buffering is used.
|
||||
// (there will be a delay between the specified I/O operation and the actual I/O execution)
|
||||
#define USE_I2S_OUT_STREAM
|
||||
#undef USE_RMT_STEPS
|
||||
|
||||
#define USE_STEPSTICK // makes sure MS1,2,3 !reset and !sleep are set
|
||||
|
||||
#define I2S_OUT_BCK GPIO_NUM_22
|
||||
#define I2S_OUT_WS GPIO_NUM_17
|
||||
#define I2S_OUT_DATA GPIO_NUM_21
|
||||
|
||||
|
||||
#define X_STEPPER_MS3 I2SO(3) // Labeled X_CS
|
||||
#define Y_STEPPER_MS3 I2SO(6) // Y_CS
|
||||
#define Z_STEPPER_MS3 I2SO(11) // Z_CS
|
||||
#define X2_STEPPER_MS3 I2SO(14) // A_CS
|
||||
#define Y2_STEPPER_MS3 I2SO(19) // B_CS
|
||||
|
||||
#define STEPPER_RESET GPIO_NUM_19
|
||||
|
||||
#define X_DISABLE_PIN I2SO(0)
|
||||
#define X_DIRECTION_PIN I2SO(1)
|
||||
#define X_STEP_PIN I2SO(2)
|
||||
#define X_AXIS_SQUARING
|
||||
|
||||
#define Y_DIRECTION_PIN I2SO(4)
|
||||
#define Y_STEP_PIN I2SO(5)
|
||||
#define Y_DISABLE_PIN I2SO(7)
|
||||
#define Y_AXIS_SQUARING
|
||||
|
||||
#define Z_DISABLE_PIN I2SO(8)
|
||||
#define Z_DIRECTION_PIN I2SO(9)
|
||||
#define Z_STEP_PIN I2SO(10)
|
||||
|
||||
// labeled A on controller
|
||||
#define X2_DIRECTION_PIN I2SO(12)
|
||||
#define X2_STEP_PIN I2SO(13)
|
||||
#define X2_DISABLE_PIN I2SO(15)
|
||||
|
||||
// labeled B on controller
|
||||
#define Y2_DISABLE_PIN I2SO(16)
|
||||
#define Y2_DIRECTION_PIN I2SO(17)
|
||||
#define Y2_STEP_PIN I2SO(18)
|
||||
|
||||
// stepper C unused
|
||||
|
||||
#define X_LIMIT_PIN GPIO_NUM_33
|
||||
#define Y_LIMIT_PIN GPIO_NUM_32
|
||||
#define Z_LIMIT_PIN GPIO_NUM_35
|
||||
#define X2_LIMIT_PIN GPIO_NUM_34 // labeled A
|
||||
#define Y2_LIMIT_PIN GPIO_NUM_39 // labeled B
|
||||
|
||||
|
||||
|
||||
// === Default settings
|
||||
#define DEFAULT_STEP_PULSE_MICROSECONDS I2S_OUT_USEC_PER_PULSE
|
@@ -1,3 +1,6 @@
|
||||
#pragma once
|
||||
// clang-format off
|
||||
|
||||
/*
|
||||
6_pack_stepstick_v1.h
|
||||
|
||||
@@ -46,12 +49,12 @@
|
||||
#define I2S_OUT_DATA GPIO_NUM_21
|
||||
|
||||
|
||||
#define STEPPER_X_MS3 I2SO(3) // X_CS
|
||||
#define STEPPER_Y_MS3 I2SO(6) // Y_CS
|
||||
#define STEPPER_Z_MS3 I2SO(11) // Z_CS
|
||||
#define STEPPER_A_MS3 I2SO(14) // A_CS
|
||||
#define STEPPER_B_MS3 I2SO(19) // B_CS
|
||||
#define STEPPER_C_MS3 I2SO(22) // C_CS
|
||||
#define X_STEPPER_MS3 I2SO(3) // X_CS
|
||||
#define Y_STEPPER_MS3 I2SO(6) // Y_CS
|
||||
#define Z_STEPPER_MS3 I2SO(11) // Z_CS
|
||||
#define A_STEPPER_MS3 I2SO(14) // A_CS
|
||||
#define B_STEPPER_MS3 I2SO(19) // B_CS
|
||||
#define C_STEPPER_MS3 I2SO(22) // C_CS
|
||||
|
||||
#define STEPPER_RESET GPIO_NUM_19
|
||||
|
@@ -1,3 +1,6 @@
|
||||
#pragma once
|
||||
// clang-format off
|
||||
|
||||
/*
|
||||
6_pack_trinamic_V1.h
|
||||
Part of Grbl_ESP32
|
@@ -1,3 +1,6 @@
|
||||
#pragma once
|
||||
// clang-format off
|
||||
|
||||
/*
|
||||
atari_1020.h
|
||||
Part of Grbl_ESP32
|
@@ -1,3 +1,6 @@
|
||||
#pragma once
|
||||
// clang-format off
|
||||
|
||||
/*
|
||||
esp32_printer_controller.h
|
||||
Part of Grbl_ESP32
|
@@ -1,3 +1,6 @@
|
||||
#pragma once
|
||||
// clang-format off
|
||||
|
||||
/*
|
||||
espduino.h
|
||||
Part of Grbl_ESP32
|
@@ -1,3 +1,6 @@
|
||||
#pragma once
|
||||
// clang-format off
|
||||
|
||||
/*
|
||||
foo_6axis.h
|
||||
Part of Grbl_ESP32
|
@@ -1,3 +1,6 @@
|
||||
#pragma once
|
||||
// clang-format off
|
||||
|
||||
/*
|
||||
i2s_out_xxyyzz.h
|
||||
Part of Grbl_ESP32
|
||||
@@ -16,6 +19,7 @@
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl_ESP32. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define MACHINE_NAME "ESP32 I2S XXYYZZ Axis Driver Board (StepStick)"
|
||||
|
||||
#ifdef N_AXIS
|
||||
@@ -55,8 +59,6 @@
|
||||
|
||||
#define STEPPER_RESET GPIO_NUM_19
|
||||
|
||||
#define USE_GANGED_AXES // allow two motors on an axis
|
||||
|
||||
#define X_DISABLE_PIN I2SO(0)
|
||||
#define X_DIRECTION_PIN I2SO(1)
|
||||
#define X_STEP_PIN I2SO(2)
|
@@ -1,3 +1,6 @@
|
||||
#pragma once
|
||||
// clang-format off
|
||||
|
||||
/*
|
||||
i2s_out_xyzabc.h
|
||||
Part of Grbl_ESP32
|
@@ -1,3 +1,6 @@
|
||||
#pragma once
|
||||
// clang-format off
|
||||
|
||||
/*
|
||||
i2s_out_xyzabc_trinamic.h
|
||||
Part of Grbl_ESP32
|
@@ -1,3 +1,6 @@
|
||||
#pragma once
|
||||
// clang-format off
|
||||
|
||||
/*
|
||||
lowrider_v1p2.h
|
||||
Part of Grbl_ESP32
|
||||
@@ -19,19 +22,15 @@
|
||||
along with Grbl_ESP32. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#define MACHINE_NAME "LOWRIDER_V1P2"
|
||||
|
||||
#define USE_GANGED_AXES // allow two motors on an axis
|
||||
|
||||
#define X_STEP_PIN GPIO_NUM_27 // use Z labeled connector
|
||||
#define X_DIRECTION_PIN GPIO_NUM_33 // use Z labeled connector
|
||||
|
||||
#define Y_STEP_PIN GPIO_NUM_14 // use Y labeled connector
|
||||
#define Y2_STEP_PIN GPIO_NUM_21 // ganged motor
|
||||
#define Y_DIRECTION_PIN GPIO_NUM_25 // use Y labeled connector
|
||||
#define Y2_DIRECTION_PIN X_DIRECTION_PIN
|
||||
#define Y2_DIRECTION_PIN Y_DIRECTION_PIN
|
||||
#define Y_AXIS_SQUARING
|
||||
|
||||
#define Z_STEP_PIN GPIO_NUM_12 // use X labeled connector
|
@@ -1,3 +1,6 @@
|
||||
#pragma once
|
||||
// clang-format off
|
||||
|
||||
/*
|
||||
midtbot.h
|
||||
Part of Grbl_ESP32
|
@@ -1,5 +1,8 @@
|
||||
#pragma once
|
||||
// clang-format off
|
||||
|
||||
/*
|
||||
mpcnc.h
|
||||
mpcnc_v1p1.h
|
||||
Part of Grbl_ESP32
|
||||
|
||||
Pin assignments for the Buildlog.net MPCNC controller
|
||||
@@ -27,8 +30,6 @@
|
||||
|
||||
#define MACHINE_NAME "MPCNC_V1P1"
|
||||
|
||||
#define USE_GANGED_AXES // allow two motors on an axis
|
||||
|
||||
#define X_STEP_PIN GPIO_NUM_12
|
||||
#define X2_STEP_PIN GPIO_NUM_22 // ganged motor
|
||||
#define X_AXIS_SQUARING
|
@@ -1,3 +1,6 @@
|
||||
#pragma once
|
||||
// clang-format off
|
||||
|
||||
/*
|
||||
mpcnc_v1p2.h
|
||||
Part of Grbl_ESP32
|
||||
@@ -28,8 +31,6 @@
|
||||
|
||||
#define MACHINE_NAME "MPCNC_V1P2"
|
||||
|
||||
#define USE_GANGED_AXES // allow two motors on an axis
|
||||
|
||||
#define X_STEP_PIN GPIO_NUM_12
|
||||
#define X2_STEP_PIN GPIO_NUM_22 // ganged motor
|
||||
#define X_AXIS_SQUARING
|
@@ -1,3 +1,6 @@
|
||||
#pragma once
|
||||
// clang-format off
|
||||
|
||||
/*
|
||||
pen_laser.h
|
||||
Part of Grbl_ESP32
|
@@ -1,3 +1,6 @@
|
||||
#pragma once
|
||||
// clang-format off
|
||||
|
||||
/*
|
||||
polar_coaster.h
|
||||
Part of Grbl_ESP32
|
@@ -1,3 +1,6 @@
|
||||
#pragma once
|
||||
// clang-format off
|
||||
|
||||
/*
|
||||
spi_daisy_4axis_xyyz.h
|
||||
Part of Grbl_ESP32
|
||||
@@ -39,9 +42,6 @@
|
||||
// The hardware enable pin is tied to ground
|
||||
#define USE_TRINAMIC_ENABLE
|
||||
|
||||
// allow two motors on an axis
|
||||
#define USE_GANGED_AXES
|
||||
|
||||
// Y motor connects to the 1st driver
|
||||
#define X_TRINAMIC_DRIVER 2130 // Which Driver Type?
|
||||
#define X_RSENSE TMC2130_RSENSE_DEFAULT
|
@@ -1,3 +1,6 @@
|
||||
#pragma once
|
||||
// clang-format off
|
||||
|
||||
/*
|
||||
spi_daisy_4axis_xyz.h
|
||||
Part of Grbl_ESP32
|
@@ -1,3 +1,6 @@
|
||||
#pragma once
|
||||
// clang-format off
|
||||
|
||||
/*
|
||||
spi_daisy_4axis_xyza.h
|
||||
Part of Grbl_ESP32
|
||||
@@ -70,21 +73,11 @@
|
||||
#define SPINDLE_OUTPUT_PIN GPIO_NUM_25
|
||||
#define SPINDLE_ENABLE_PIN GPIO_NUM_4
|
||||
|
||||
// Relay operation
|
||||
// Install Jumper near relay
|
||||
// For PWM remove jumper to prevent relay damage
|
||||
// Interlock jumper along top edge needs to be installed for both versions
|
||||
#define USE_RELAY // comment out to use PWM
|
||||
|
||||
#ifdef USE_RELAY
|
||||
#define SPINDLE_TYPE SPINDLE_TYPE_RELAY
|
||||
#else
|
||||
#define SPINDLE_TYPE SPINDLE_TYPE_PWM
|
||||
#endif
|
||||
#define SPINDLE_TYPE SPINDLE_TYPE_RELAY // default use $Spindle/Type=PWM or $Spindle/Type=Laser
|
||||
|
||||
#define PROBE_PIN GPIO_NUM_22
|
||||
|
||||
#define X_LIMIT_PIN GPIO_NUM_36
|
||||
#define Y_LIMIT_PIN GPIO_NUM_39
|
||||
#define Z_LIMIT_PIN GPIO_NUM_34
|
||||
#define A_LIMIT_PIN GPIO_NUM_35
|
||||
#define A_LIMIT_PIN GPIO_NUM_35
|
@@ -1,5 +1,8 @@
|
||||
#pragma once
|
||||
// clang-format off
|
||||
|
||||
/*
|
||||
3axis_v4.h
|
||||
spindle_class_test.h
|
||||
Part of Grbl_ESP32
|
||||
|
||||
Pin assignments for the ESP32 Development Controller, v4.1 and later.
|
@@ -1,3 +1,6 @@
|
||||
#pragma once
|
||||
// clang-format off
|
||||
|
||||
/*
|
||||
template.h
|
||||
Part of Grbl_ESP32
|
@@ -1,3 +1,6 @@
|
||||
#pragma once
|
||||
// clang-format off
|
||||
|
||||
/*
|
||||
test_drive.h
|
||||
Part of Grbl_ESP32
|
@@ -1,3 +1,6 @@
|
||||
#pragma once
|
||||
// clang-format off
|
||||
|
||||
/*
|
||||
tmc2130_pen.h
|
||||
Part of Grbl_ESP32
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
motion_control.c - high level interface for issuing motion commands
|
||||
MotionControl.cpp - high level interface for issuing motion commands
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
@@ -22,23 +22,22 @@
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "grbl.h"
|
||||
#include "Grbl.h"
|
||||
|
||||
// M_PI is not defined in standard C/C++ but some compilers
|
||||
// support it anyway. The following suppresses Intellisense
|
||||
// problem reports.
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
# define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
uint8_t ganged_mode = SQUARING_MODE_DUAL;
|
||||
|
||||
|
||||
// this allows kinematics to be used.
|
||||
void mc_line_kins(float* target, plan_line_data_t* pl_data, float* position) {
|
||||
#ifndef USE_KINEMATICS
|
||||
mc_line(target, pl_data);
|
||||
#else // else use kinematics
|
||||
#else // else use kinematics
|
||||
inverse_kinematics(target, pl_data, position);
|
||||
#endif
|
||||
}
|
||||
@@ -55,10 +54,12 @@ void mc_line(float* target, plan_line_data_t* pl_data) {
|
||||
// from everywhere in Grbl.
|
||||
if (soft_limits->get()) {
|
||||
// NOTE: Block jog state. Jogging is a special case and soft limits are handled independently.
|
||||
if (sys.state != STATE_JOG) limits_soft_check(target);
|
||||
if (sys.state != STATE_JOG)
|
||||
limits_soft_check(target);
|
||||
}
|
||||
// If in check gcode mode, prevent motion by blocking planner. Soft limits still work.
|
||||
if (sys.state == STATE_CHECK_MODE) return;
|
||||
if (sys.state == STATE_CHECK_MODE)
|
||||
return;
|
||||
// NOTE: Backlash compensation may be installed here. It will need direction info to track when
|
||||
// to insert a backlash line motion(s) before the intended line motion and will require its own
|
||||
// plan_check_full_buffer() and check for system abort loop. Also for position reporting
|
||||
@@ -75,17 +76,19 @@ void mc_line(float* target, plan_line_data_t* pl_data) {
|
||||
// If the buffer is full: good! That means we are well ahead of the robot.
|
||||
// Remain in this loop until there is room in the buffer.
|
||||
do {
|
||||
protocol_execute_realtime(); // Check for any run-time commands
|
||||
if (sys.abort) return; // Bail, if system abort.
|
||||
if (plan_check_full_buffer()) protocol_auto_cycle_start(); // Auto-cycle start when buffer is full.
|
||||
else break;
|
||||
protocol_execute_realtime(); // Check for any run-time commands
|
||||
if (sys.abort)
|
||||
return; // Bail, if system abort.
|
||||
if (plan_check_full_buffer())
|
||||
protocol_auto_cycle_start(); // Auto-cycle start when buffer is full.
|
||||
else
|
||||
break;
|
||||
} while (1);
|
||||
// Plan and queue motion into planner buffer
|
||||
// uint8_t plan_status; // Not used in normal operation.
|
||||
plan_buffer_line(target, pl_data);
|
||||
}
|
||||
|
||||
|
||||
// Execute an arc in offset mode format. position == current xyz, target == target xyz,
|
||||
// offset == offset from current xyz, axis_X defines circle plane in tool space, axis_linear is
|
||||
// the direction of helical travel, radius == circle radius, isclockwise boolean. Used
|
||||
@@ -93,42 +96,50 @@ void mc_line(float* target, plan_line_data_t* pl_data) {
|
||||
// The arc is approximated by generating a huge number of tiny, linear segments. The chordal tolerance
|
||||
// of each segment is configured in the arc_tolerance setting, which is defined to be the maximum normal
|
||||
// distance from segment to the circle when the end points both lie on the circle.
|
||||
void mc_arc(float* target, plan_line_data_t* pl_data, float* position, float* offset, float radius,
|
||||
uint8_t axis_0, uint8_t axis_1, uint8_t axis_linear, uint8_t is_clockwise_arc) {
|
||||
void mc_arc(float* target,
|
||||
plan_line_data_t* pl_data,
|
||||
float* position,
|
||||
float* offset,
|
||||
float radius,
|
||||
uint8_t axis_0,
|
||||
uint8_t axis_1,
|
||||
uint8_t axis_linear,
|
||||
uint8_t is_clockwise_arc) {
|
||||
float center_axis0 = position[axis_0] + offset[axis_0];
|
||||
float center_axis1 = position[axis_1] + offset[axis_1];
|
||||
float r_axis0 = -offset[axis_0]; // Radius vector from center to current location
|
||||
float r_axis1 = -offset[axis_1];
|
||||
float rt_axis0 = target[axis_0] - center_axis0;
|
||||
float rt_axis1 = target[axis_1] - center_axis1;
|
||||
float r_axis0 = -offset[axis_0]; // Radius vector from center to current location
|
||||
float r_axis1 = -offset[axis_1];
|
||||
float rt_axis0 = target[axis_0] - center_axis0;
|
||||
float rt_axis1 = target[axis_1] - center_axis1;
|
||||
#ifdef USE_KINEMATICS
|
||||
float previous_position[N_AXIS];
|
||||
float previous_position[N_AXIS];
|
||||
uint16_t n;
|
||||
for (n = 0; n < N_AXIS; n++)
|
||||
previous_position[n] = position[n];
|
||||
#endif
|
||||
// CCW angle between position and target from circle center. Only one atan2() trig computation required.
|
||||
float angular_travel = atan2(r_axis0 * rt_axis1 - r_axis1 * rt_axis0, r_axis0 * rt_axis0 + r_axis1 * rt_axis1);
|
||||
if (is_clockwise_arc) { // Correct atan2 output per direction
|
||||
if (angular_travel >= -ARC_ANGULAR_TRAVEL_EPSILON) angular_travel -= 2 * M_PI;
|
||||
if (is_clockwise_arc) { // Correct atan2 output per direction
|
||||
if (angular_travel >= -ARC_ANGULAR_TRAVEL_EPSILON)
|
||||
angular_travel -= 2 * M_PI;
|
||||
} else {
|
||||
if (angular_travel <= ARC_ANGULAR_TRAVEL_EPSILON) angular_travel += 2 * M_PI;
|
||||
if (angular_travel <= ARC_ANGULAR_TRAVEL_EPSILON)
|
||||
angular_travel += 2 * M_PI;
|
||||
}
|
||||
// NOTE: Segment end points are on the arc, which can lead to the arc diameter being smaller by up to
|
||||
// (2x) arc_tolerance. For 99% of users, this is just fine. If a different arc segment fit
|
||||
// is desired, i.e. least-squares, midpoint on arc, just change the mm_per_arc_segment calculation.
|
||||
// For the intended uses of Grbl, this value shouldn't exceed 2000 for the strictest of cases.
|
||||
uint16_t segments = floor(fabs(0.5 * angular_travel * radius) /
|
||||
sqrt(arc_tolerance->get() * (2 * radius - arc_tolerance->get())));
|
||||
uint16_t segments = floor(fabs(0.5 * angular_travel * radius) / sqrt(arc_tolerance->get() * (2 * radius - arc_tolerance->get())));
|
||||
if (segments) {
|
||||
// Multiply inverse feed_rate to compensate for the fact that this movement is approximated
|
||||
// by a number of discrete segments. The inverse feed_rate should be correct for the sum of
|
||||
// all segments.
|
||||
if (pl_data->condition & PL_COND_FLAG_INVERSE_TIME) {
|
||||
pl_data->feed_rate *= segments;
|
||||
bit_false(pl_data->condition, PL_COND_FLAG_INVERSE_TIME); // Force as feed absolute mode over arc segments.
|
||||
bit_false(pl_data->condition, PL_COND_FLAG_INVERSE_TIME); // Force as feed absolute mode over arc segments.
|
||||
}
|
||||
float theta_per_segment = angular_travel / segments;
|
||||
float theta_per_segment = angular_travel / segments;
|
||||
float linear_per_segment = (target[axis_linear] - position[axis_linear]) / segments;
|
||||
/* Vector rotation by transformation matrix: r is the original vector, r_T is the rotated vector,
|
||||
and phi is the angle of rotation. Solution approach by Jens Geisler.
|
||||
@@ -159,12 +170,12 @@ void mc_arc(float* target, plan_line_data_t* pl_data, float* position, float* of
|
||||
float cos_T = 2.0 - theta_per_segment * theta_per_segment;
|
||||
float sin_T = theta_per_segment * 0.16666667 * (cos_T + 4.0);
|
||||
cos_T *= 0.5;
|
||||
float sin_Ti;
|
||||
float cos_Ti;
|
||||
float r_axisi;
|
||||
float sin_Ti;
|
||||
float cos_Ti;
|
||||
float r_axisi;
|
||||
uint16_t i;
|
||||
uint8_t count = 0;
|
||||
for (i = 1; i < segments; i++) { // Increment (segments-1).
|
||||
uint8_t count = 0;
|
||||
for (i = 1; i < segments; i++) { // Increment (segments-1).
|
||||
if (count < N_ARC_CORRECTION) {
|
||||
// Apply vector rotation matrix. ~40 usec
|
||||
r_axisi = r_axis0 * sin_T + r_axis1 * cos_T;
|
||||
@@ -174,11 +185,11 @@ void mc_arc(float* target, plan_line_data_t* pl_data, float* position, float* of
|
||||
} else {
|
||||
// Arc correction to radius vector. Computed only every N_ARC_CORRECTION increments. ~375 usec
|
||||
// Compute exact location by applying transformation matrix from initial radius vector(=-offset).
|
||||
cos_Ti = cos(i * theta_per_segment);
|
||||
sin_Ti = sin(i * theta_per_segment);
|
||||
cos_Ti = cos(i * theta_per_segment);
|
||||
sin_Ti = sin(i * theta_per_segment);
|
||||
r_axis0 = -offset[axis_0] * cos_Ti + offset[axis_1] * sin_Ti;
|
||||
r_axis1 = -offset[axis_0] * sin_Ti - offset[axis_1] * cos_Ti;
|
||||
count = 0;
|
||||
count = 0;
|
||||
}
|
||||
// Update arc_target location
|
||||
position[axis_0] = center_axis0 + r_axis0;
|
||||
@@ -186,14 +197,15 @@ void mc_arc(float* target, plan_line_data_t* pl_data, float* position, float* of
|
||||
position[axis_linear] += linear_per_segment;
|
||||
#ifdef USE_KINEMATICS
|
||||
mc_line_kins(position, pl_data, previous_position);
|
||||
previous_position[axis_0] = position[axis_0];
|
||||
previous_position[axis_1] = position[axis_1];
|
||||
previous_position[axis_0] = position[axis_0];
|
||||
previous_position[axis_1] = position[axis_1];
|
||||
previous_position[axis_linear] = position[axis_linear];
|
||||
#else
|
||||
mc_line(position, pl_data);
|
||||
#endif
|
||||
// Bail mid-circle on system abort. Runtime command check already performed by mc_line.
|
||||
if (sys.abort) return;
|
||||
if (sys.abort)
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Ensure last segment arrives at target location.
|
||||
@@ -204,15 +216,14 @@ void mc_arc(float* target, plan_line_data_t* pl_data, float* position, float* of
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// Execute dwell in seconds.
|
||||
void mc_dwell(float seconds) {
|
||||
if (sys.state == STATE_CHECK_MODE) return;
|
||||
if (sys.state == STATE_CHECK_MODE)
|
||||
return;
|
||||
protocol_buffer_synchronize();
|
||||
delay_sec(seconds, DELAY_MODE_DWELL);
|
||||
}
|
||||
|
||||
|
||||
// Perform homing cycle to locate and set machine zero. Only '$H' executes this command.
|
||||
// NOTE: There should be no motions in the buffer and Grbl must be in an idle state before
|
||||
// executing the homing cycle. This prevents incorrect buffered plans after homing.
|
||||
@@ -221,23 +232,23 @@ void mc_homing_cycle(uint8_t cycle_mask) {
|
||||
if (user_defined_homing())
|
||||
return;
|
||||
#endif
|
||||
// This give kinematics a chance to do something before normal homing
|
||||
// if it returns true, the homing is canceled.
|
||||
// This give kinematics a chance to do something before normal homing
|
||||
// if it returns true, the homing is canceled.
|
||||
#ifdef USE_KINEMATICS
|
||||
if (kinematics_pre_homing(cycle_mask))
|
||||
return;
|
||||
#endif
|
||||
// Check and abort homing cycle, if hard limits are already enabled. Helps prevent problems
|
||||
// with machines with limits wired on both ends of travel to one limit pin.
|
||||
// TODO: Move the pin-specific LIMIT_PIN call to limits.c as a function.
|
||||
// Check and abort homing cycle, if hard limits are already enabled. Helps prevent problems
|
||||
// with machines with limits wired on both ends of travel to one limit pin.
|
||||
// TODO: Move the pin-specific LIMIT_PIN call to Limits.cpp as a function.
|
||||
#ifdef LIMITS_TWO_SWITCHES_ON_AXES
|
||||
if (limits_get_state()) {
|
||||
mc_reset(); // Issue system reset and ensure spindle and coolant are shutdown.
|
||||
mc_reset(); // Issue system reset and ensure spindle and coolant are shutdown.
|
||||
system_set_exec_alarm(EXEC_ALARM_HARD_LIMIT);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
limits_disable(); // Disable hard limits pin change register for cycle duration
|
||||
limits_disable(); // Disable hard limits pin change register for cycle duration
|
||||
// -------------------------------------------------------------------------------------
|
||||
// Perform homing routine. NOTE: Special motion case. Only system reset works.
|
||||
n_homing_locate_cycle = N_HOMING_LOCATE_CYCLE;
|
||||
@@ -247,65 +258,65 @@ void mc_homing_cycle(uint8_t cycle_mask) {
|
||||
else
|
||||
*/
|
||||
if (cycle_mask) {
|
||||
if (! axis_is_squared(cycle_mask))
|
||||
if (!axis_is_squared(cycle_mask))
|
||||
limits_go_home(cycle_mask); // Homing cycle 0
|
||||
else {
|
||||
ganged_mode = SQUARING_MODE_DUAL;
|
||||
n_homing_locate_cycle = 0; // don't do a second touch cycle
|
||||
ganged_mode = SQUARING_MODE_DUAL;
|
||||
n_homing_locate_cycle = 0; // don't do a second touch cycle
|
||||
limits_go_home(cycle_mask);
|
||||
ganged_mode = SQUARING_MODE_A;
|
||||
n_homing_locate_cycle = N_HOMING_LOCATE_CYCLE; // restore to default value
|
||||
ganged_mode = SQUARING_MODE_A;
|
||||
n_homing_locate_cycle = N_HOMING_LOCATE_CYCLE; // restore to default value
|
||||
limits_go_home(cycle_mask);
|
||||
ganged_mode = SQUARING_MODE_B;
|
||||
limits_go_home(cycle_mask);
|
||||
ganged_mode = SQUARING_MODE_DUAL; // always return to dual
|
||||
ganged_mode = SQUARING_MODE_DUAL; // always return to dual
|
||||
}
|
||||
} // Perform homing cycle based on mask.
|
||||
} // Perform homing cycle based on mask.
|
||||
else
|
||||
#endif
|
||||
{
|
||||
// Search to engage all axes limit switches at faster homing seek rate.
|
||||
if (! axis_is_squared(HOMING_CYCLE_0))
|
||||
if (!axis_is_squared(HOMING_CYCLE_0))
|
||||
limits_go_home(HOMING_CYCLE_0); // Homing cycle 0
|
||||
else {
|
||||
ganged_mode = SQUARING_MODE_DUAL;
|
||||
n_homing_locate_cycle = 0; // don't do a second touch cycle
|
||||
ganged_mode = SQUARING_MODE_DUAL;
|
||||
n_homing_locate_cycle = 0; // don't do a second touch cycle
|
||||
limits_go_home(HOMING_CYCLE_0);
|
||||
ganged_mode = SQUARING_MODE_A;
|
||||
n_homing_locate_cycle = N_HOMING_LOCATE_CYCLE; // restore to default value
|
||||
ganged_mode = SQUARING_MODE_A;
|
||||
n_homing_locate_cycle = N_HOMING_LOCATE_CYCLE; // restore to default value
|
||||
limits_go_home(HOMING_CYCLE_0);
|
||||
ganged_mode = SQUARING_MODE_B;
|
||||
limits_go_home(HOMING_CYCLE_0);
|
||||
ganged_mode = SQUARING_MODE_DUAL; // always return to dual
|
||||
ganged_mode = SQUARING_MODE_DUAL; // always return to dual
|
||||
}
|
||||
#ifdef HOMING_CYCLE_1
|
||||
if (! axis_is_squared(HOMING_CYCLE_1))
|
||||
if (!axis_is_squared(HOMING_CYCLE_1))
|
||||
limits_go_home(HOMING_CYCLE_1);
|
||||
else {
|
||||
ganged_mode = SQUARING_MODE_DUAL;
|
||||
n_homing_locate_cycle = 0; // don't do a second touch cycle
|
||||
ganged_mode = SQUARING_MODE_DUAL;
|
||||
n_homing_locate_cycle = 0; // don't do a second touch cycle
|
||||
limits_go_home(HOMING_CYCLE_1);
|
||||
ganged_mode = SQUARING_MODE_A;
|
||||
n_homing_locate_cycle = N_HOMING_LOCATE_CYCLE; // restore to default value
|
||||
ganged_mode = SQUARING_MODE_A;
|
||||
n_homing_locate_cycle = N_HOMING_LOCATE_CYCLE; // restore to default value
|
||||
limits_go_home(HOMING_CYCLE_1);
|
||||
ganged_mode = SQUARING_MODE_B;
|
||||
limits_go_home(HOMING_CYCLE_1);
|
||||
ganged_mode = SQUARING_MODE_DUAL; // always return to dual
|
||||
ganged_mode = SQUARING_MODE_DUAL; // always return to dual
|
||||
}
|
||||
#endif
|
||||
#ifdef HOMING_CYCLE_2
|
||||
if (! axis_is_squared(HOMING_CYCLE_2))
|
||||
if (!axis_is_squared(HOMING_CYCLE_2))
|
||||
limits_go_home(HOMING_CYCLE_2);
|
||||
else {
|
||||
ganged_mode = SQUARING_MODE_DUAL;
|
||||
n_homing_locate_cycle = 0; // don't do a second touch cycle
|
||||
ganged_mode = SQUARING_MODE_DUAL;
|
||||
n_homing_locate_cycle = 0; // don't do a second touch cycle
|
||||
limits_go_home(HOMING_CYCLE_2);
|
||||
ganged_mode = SQUARING_MODE_A;
|
||||
n_homing_locate_cycle = N_HOMING_LOCATE_CYCLE; // restore to default value
|
||||
ganged_mode = SQUARING_MODE_A;
|
||||
n_homing_locate_cycle = N_HOMING_LOCATE_CYCLE; // restore to default value
|
||||
limits_go_home(HOMING_CYCLE_2);
|
||||
ganged_mode = SQUARING_MODE_B;
|
||||
limits_go_home(HOMING_CYCLE_2);
|
||||
ganged_mode = SQUARING_MODE_DUAL; // always return to dual
|
||||
ganged_mode = SQUARING_MODE_DUAL; // always return to dual
|
||||
}
|
||||
#endif
|
||||
#ifdef HOMING_CYCLE_3
|
||||
@@ -318,15 +329,15 @@ void mc_homing_cycle(uint8_t cycle_mask) {
|
||||
limits_go_home(HOMING_CYCLE_5); // Homing cycle 5
|
||||
#endif
|
||||
}
|
||||
protocol_execute_realtime(); // Check for reset and set system abort.
|
||||
if (sys.abort) {
|
||||
return; // Did not complete. Alarm state set by mc_alarm.
|
||||
protocol_execute_realtime(); // Check for reset and set system abort.
|
||||
if (sys.abort) {
|
||||
return; // Did not complete. Alarm state set by mc_alarm.
|
||||
}
|
||||
// Homing cycle complete! Setup system for normal operation.
|
||||
// -------------------------------------------------------------------------------------
|
||||
// Sync gcode parser and planner positions to homed position.
|
||||
gc_sync_position();
|
||||
plan_sync_position();
|
||||
plan_sync_position();
|
||||
#ifdef USE_KINEMATICS
|
||||
// This give kinematics a chance to do something after normal homing
|
||||
kinematics_post_homing();
|
||||
@@ -335,27 +346,28 @@ void mc_homing_cycle(uint8_t cycle_mask) {
|
||||
limits_init();
|
||||
}
|
||||
|
||||
|
||||
// Perform tool length probe cycle. Requires probe switch.
|
||||
// NOTE: Upon probe failure, the program will be stopped and placed into ALARM state.
|
||||
uint8_t mc_probe_cycle(float* target, plan_line_data_t* pl_data, uint8_t parser_flags) {
|
||||
// TODO: Need to update this cycle so it obeys a non-auto cycle start.
|
||||
if (sys.state == STATE_CHECK_MODE) return (GC_PROBE_CHECK_MODE);
|
||||
if (sys.state == STATE_CHECK_MODE)
|
||||
return (GC_PROBE_CHECK_MODE);
|
||||
// Finish all queued commands and empty planner buffer before starting probe cycle.
|
||||
protocol_buffer_synchronize();
|
||||
if (sys.abort) return (GC_PROBE_ABORT); // Return if system reset has been issued.
|
||||
if (sys.abort)
|
||||
return (GC_PROBE_ABORT); // Return if system reset has been issued.
|
||||
// Initialize probing control variables
|
||||
uint8_t is_probe_away = bit_istrue(parser_flags, GC_PARSER_PROBE_IS_AWAY);
|
||||
uint8_t is_no_error = bit_istrue(parser_flags, GC_PARSER_PROBE_IS_NO_ERROR);
|
||||
sys.probe_succeeded = false; // Re-initialize probe history before beginning cycle.
|
||||
uint8_t is_no_error = bit_istrue(parser_flags, GC_PARSER_PROBE_IS_NO_ERROR);
|
||||
sys.probe_succeeded = false; // Re-initialize probe history before beginning cycle.
|
||||
probe_configure_invert_mask(is_probe_away);
|
||||
// After syncing, check if probe is already triggered. If so, halt and issue alarm.
|
||||
// NOTE: This probe initialization error applies to all probing cycles.
|
||||
if (probe_get_state()) { // Check probe pin state.
|
||||
if (probe_get_state()) { // Check probe pin state.
|
||||
system_set_exec_alarm(EXEC_ALARM_PROBE_FAIL_INITIAL);
|
||||
protocol_execute_realtime();
|
||||
probe_configure_invert_mask(false); // Re-initialize invert mask before returning.
|
||||
return (GC_PROBE_FAIL_INIT); // Nothing else to do but bail.
|
||||
probe_configure_invert_mask(false); // Re-initialize invert mask before returning.
|
||||
return (GC_PROBE_FAIL_INIT); // Nothing else to do but bail.
|
||||
}
|
||||
// Setup and queue probing motion. Auto cycle-start should not start the cycle.
|
||||
mc_line(target, pl_data);
|
||||
@@ -365,48 +377,54 @@ uint8_t mc_probe_cycle(float* target, plan_line_data_t* pl_data, uint8_t parser_
|
||||
system_set_exec_state_flag(EXEC_CYCLE_START);
|
||||
do {
|
||||
protocol_execute_realtime();
|
||||
if (sys.abort) return (GC_PROBE_ABORT); // Check for system abort
|
||||
if (sys.abort)
|
||||
return (GC_PROBE_ABORT); // Check for system abort
|
||||
} while (sys.state != STATE_IDLE);
|
||||
// Probing cycle complete!
|
||||
// Set state variables and error out, if the probe failed and cycle with error is enabled.
|
||||
if (sys_probe_state == PROBE_ACTIVE) {
|
||||
if (is_no_error) memcpy(sys_probe_position, sys_position, sizeof(sys_position));
|
||||
else system_set_exec_alarm(EXEC_ALARM_PROBE_FAIL_CONTACT);
|
||||
if (is_no_error)
|
||||
memcpy(sys_probe_position, sys_position, sizeof(sys_position));
|
||||
else
|
||||
system_set_exec_alarm(EXEC_ALARM_PROBE_FAIL_CONTACT);
|
||||
} else {
|
||||
sys.probe_succeeded = true; // Indicate to system the probing cycle completed successfully.
|
||||
sys.probe_succeeded = true; // Indicate to system the probing cycle completed successfully.
|
||||
}
|
||||
sys_probe_state = PROBE_OFF; // Ensure probe state monitor is disabled.
|
||||
probe_configure_invert_mask(false); // Re-initialize invert mask.
|
||||
protocol_execute_realtime(); // Check and execute run-time commands
|
||||
sys_probe_state = PROBE_OFF; // Ensure probe state monitor is disabled.
|
||||
probe_configure_invert_mask(false); // Re-initialize invert mask.
|
||||
protocol_execute_realtime(); // Check and execute run-time commands
|
||||
// Reset the stepper and planner buffers to remove the remainder of the probe motion.
|
||||
st_reset(); // Reset step segment buffer.
|
||||
plan_reset(); // Reset planner buffer. Zero planner positions. Ensure probing motion is cleared.
|
||||
plan_sync_position(); // Sync planner position to current machine position.
|
||||
st_reset(); // Reset step segment buffer.
|
||||
plan_reset(); // Reset planner buffer. Zero planner positions. Ensure probing motion is cleared.
|
||||
plan_sync_position(); // Sync planner position to current machine position.
|
||||
#ifdef MESSAGE_PROBE_COORDINATES
|
||||
// All done! Output the probe position as message.
|
||||
report_probe_parameters(CLIENT_ALL);
|
||||
#endif
|
||||
if (sys.probe_succeeded) return (GC_PROBE_FOUND); // Successful probe cycle.
|
||||
else return (GC_PROBE_FAIL_END); // Failed to trigger probe within travel. With or without error.
|
||||
if (sys.probe_succeeded)
|
||||
return (GC_PROBE_FOUND); // Successful probe cycle.
|
||||
else
|
||||
return (GC_PROBE_FAIL_END); // Failed to trigger probe within travel. With or without error.
|
||||
}
|
||||
|
||||
|
||||
// Plans and executes the single special motion case for parking. Independent of main planner buffer.
|
||||
// NOTE: Uses the always free planner ring buffer head to store motion parameters for execution.
|
||||
void mc_parking_motion(float* parking_target, plan_line_data_t* pl_data) {
|
||||
if (sys.abort) return; // Block during abort.
|
||||
if (sys.abort)
|
||||
return; // Block during abort.
|
||||
uint8_t plan_status = plan_buffer_line(parking_target, pl_data);
|
||||
if (plan_status) {
|
||||
bit_true(sys.step_control, STEP_CONTROL_EXECUTE_SYS_MOTION);
|
||||
bit_false(sys.step_control, STEP_CONTROL_END_MOTION); // Allow parking motion to execute, if feed hold is active.
|
||||
st_parking_setup_buffer(); // Setup step segment buffer for special parking motion case
|
||||
bit_false(sys.step_control, STEP_CONTROL_END_MOTION); // Allow parking motion to execute, if feed hold is active.
|
||||
st_parking_setup_buffer(); // Setup step segment buffer for special parking motion case
|
||||
st_prep_buffer();
|
||||
st_wake_up();
|
||||
do {
|
||||
protocol_exec_rt_system();
|
||||
if (sys.abort) return;
|
||||
if (sys.abort)
|
||||
return;
|
||||
} while (sys.step_control & STEP_CONTROL_EXECUTE_SYS_MOTION);
|
||||
st_parking_restore_buffer(); // Restore step segment buffer to normal run state.
|
||||
st_parking_restore_buffer(); // Restore step segment buffer to normal run state.
|
||||
} else {
|
||||
bit_false(sys.step_control, STEP_CONTROL_EXECUTE_SYS_MOTION);
|
||||
protocol_exec_rt_system();
|
||||
@@ -417,12 +435,12 @@ void mc_parking_motion(float* parking_target, plan_line_data_t* pl_data) {
|
||||
void mc_override_ctrl_update(uint8_t override_state) {
|
||||
// Finish all queued commands before altering override control state
|
||||
protocol_buffer_synchronize();
|
||||
if (sys.abort) return;
|
||||
if (sys.abort)
|
||||
return;
|
||||
sys.override_ctrl = override_state;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// Method to ready the system to reset by setting the realtime reset command and killing any
|
||||
// active processes in the system. This also checks if a system reset is issued while Grbl
|
||||
// is in a motion state. If so, kills the steppers and sets the system alarm to flag position
|
||||
@@ -434,7 +452,7 @@ void mc_reset() {
|
||||
system_set_exec_state_flag(EXEC_RESET);
|
||||
// Kill spindle and coolant.
|
||||
spindle->stop();
|
||||
coolant_stop();
|
||||
coolant_stop();
|
||||
|
||||
// turn off all digital I/O immediately
|
||||
fast_sys_io_control(0xFF, false);
|
||||
@@ -451,18 +469,18 @@ void mc_reset() {
|
||||
// the steppers enabled by avoiding the go_idle call altogether, unless the motion state is
|
||||
// violated, by which, all bets are off.
|
||||
if ((sys.state & (STATE_CYCLE | STATE_HOMING | STATE_JOG)) ||
|
||||
(sys.step_control & (STEP_CONTROL_EXECUTE_HOLD | STEP_CONTROL_EXECUTE_SYS_MOTION))) {
|
||||
(sys.step_control & (STEP_CONTROL_EXECUTE_HOLD | STEP_CONTROL_EXECUTE_SYS_MOTION))) {
|
||||
if (sys.state == STATE_HOMING) {
|
||||
if (!sys_rt_exec_alarm) system_set_exec_alarm(EXEC_ALARM_HOMING_FAIL_RESET);
|
||||
} else system_set_exec_alarm(EXEC_ALARM_ABORT_CYCLE);
|
||||
st_go_idle(); // Force kill steppers. Position has likely been lost.
|
||||
if (!sys_rt_exec_alarm)
|
||||
system_set_exec_alarm(EXEC_ALARM_HOMING_FAIL_RESET);
|
||||
} else
|
||||
system_set_exec_alarm(EXEC_ALARM_ABORT_CYCLE);
|
||||
st_go_idle(); // Force kill steppers. Position has likely been lost.
|
||||
}
|
||||
ganged_mode = SQUARING_MODE_DUAL; // in case an error occurred during squaring
|
||||
ganged_mode = SQUARING_MODE_DUAL; // in case an error occurred during squaring
|
||||
|
||||
#ifdef USE_I2S_OUT_STREAM
|
||||
i2s_out_reset();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
motion_control.h - high level interface for issuing motion commands
|
||||
MotionControl.h - high level interface for issuing motion commands
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2011-2015 Sungeun K. Jeon
|
||||
@@ -22,26 +24,19 @@
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef motion_control_h
|
||||
#define motion_control_h
|
||||
|
||||
#include "grbl.h"
|
||||
|
||||
#include "Grbl.h"
|
||||
|
||||
// System motion commands must have a line number of zero.
|
||||
#define HOMING_CYCLE_LINE_NUMBER 0
|
||||
#define PARKING_MOTION_LINE_NUMBER 0
|
||||
|
||||
#define HOMING_CYCLE_ALL 0 // Must be zero.
|
||||
#define HOMING_CYCLE_X bit(X_AXIS)
|
||||
#define HOMING_CYCLE_Y bit(Y_AXIS)
|
||||
#define HOMING_CYCLE_Z bit(Z_AXIS)
|
||||
#define HOMING_CYCLE_A bit(A_AXIS)
|
||||
#define HOMING_CYCLE_B bit(B_AXIS)
|
||||
#define HOMING_CYCLE_C bit(C_AXIS)
|
||||
|
||||
#define HOMING_CYCLE_ALL 0 // Must be zero.
|
||||
#define HOMING_CYCLE_X bit(X_AXIS)
|
||||
#define HOMING_CYCLE_Y bit(Y_AXIS)
|
||||
#define HOMING_CYCLE_Z bit(Z_AXIS)
|
||||
#define HOMING_CYCLE_A bit(A_AXIS)
|
||||
#define HOMING_CYCLE_B bit(B_AXIS)
|
||||
#define HOMING_CYCLE_C bit(C_AXIS)
|
||||
|
||||
// Execute linear motion in absolute millimeter coordinates. Feed rate given in millimeters/second
|
||||
// unless invert_feed_rate is true. Then the feed_rate means that the motion should be completed in
|
||||
@@ -53,8 +48,15 @@ void mc_line(float* target, plan_line_data_t* pl_data);
|
||||
// offset == offset from current xyz, axis_XXX defines circle plane in tool space, axis_linear is
|
||||
// the direction of helical travel, radius == circle radius, is_clockwise_arc boolean. Used
|
||||
// for vector transformation direction.
|
||||
void mc_arc(float* target, plan_line_data_t* pl_data, float* position, float* offset, float radius,
|
||||
uint8_t axis_0, uint8_t axis_1, uint8_t axis_linear, uint8_t is_clockwise_arc);
|
||||
void mc_arc(float* target,
|
||||
plan_line_data_t* pl_data,
|
||||
float* position,
|
||||
float* offset,
|
||||
float radius,
|
||||
uint8_t axis_0,
|
||||
uint8_t axis_1,
|
||||
uint8_t axis_linear,
|
||||
uint8_t is_clockwise_arc);
|
||||
|
||||
// Dwell for a specific number of seconds
|
||||
void mc_dwell(float seconds);
|
||||
@@ -73,5 +75,3 @@ void mc_parking_motion(float* parking_target, plan_line_data_t* pl_data);
|
||||
|
||||
// Performs system reset. If in motion state, kills all motion and sets system alarm.
|
||||
void mc_reset();
|
||||
|
||||
#endif
|
53
Grbl_Esp32/src/Motors/Motor.cpp
Normal file
53
Grbl_Esp32/src/Motors/Motor.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
Motor.cpp
|
||||
Part of Grbl_ESP32
|
||||
2020 - Bart Dring
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
TODO
|
||||
Make sure public/private/protected is cleaned up.
|
||||
Only a few Unipolar axes have been setup in init()
|
||||
Get rid of Z_SERVO, just reply on Z_SERVO_PIN
|
||||
Deal with custom machine ... machine_trinamic_setup();
|
||||
Class is ready to deal with non SPI pins, but they have not been needed yet.
|
||||
It would be nice in the config message though
|
||||
Testing
|
||||
Done (success)
|
||||
3 Axis (3 Standard Steppers)
|
||||
MPCNC (ganged with shared direction pin)
|
||||
TMC2130 Pen Laser (trinamics, stallguard tuning)
|
||||
Unipolar
|
||||
TODO
|
||||
4 Axis SPI (Daisy Chain, Ganged with unique direction pins)
|
||||
Reference
|
||||
TMC2130 Datasheet https://www.trinamic.com/fileadmin/assets/Products/ICs_Documents/TMC2130_datasheet.pdf
|
||||
*/
|
||||
|
||||
#include "Motor.h"
|
||||
|
||||
namespace Motors {
|
||||
Motor::Motor() { type_id = MOTOR; }
|
||||
|
||||
void Motor::init() { _homing_mask = 0; }
|
||||
|
||||
void Motor::config_message() {}
|
||||
void Motor::debug_message() {}
|
||||
void Motor::read_settings() {}
|
||||
void Motor::set_disable(bool disable) {}
|
||||
void Motor::set_direction_pins(uint8_t onMask) {}
|
||||
void Motor::step(uint8_t step_mask, uint8_t dir_mask) {}
|
||||
bool Motor::test() { return true; }; // true = OK
|
||||
void Motor::update() {}
|
||||
|
||||
void Motor::set_axis_name() { sprintf(_axis_name, "%c%s", report_get_axis_letter(axis_index), dual_axis_index ? "2" : " "); }
|
||||
|
||||
void Motor::set_homing_mode(uint8_t homing_mask, bool isHoming) { _homing_mask = homing_mask; }
|
||||
}
|
65
Grbl_Esp32/src/Motors/Motor.h
Normal file
65
Grbl_Esp32/src/Motors/Motor.h
Normal file
@@ -0,0 +1,65 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
Motor.h
|
||||
Header file for Motor Classes
|
||||
Here is the hierarchy
|
||||
Motor
|
||||
Nullmotor
|
||||
StandardStepper
|
||||
TrinamicDriver
|
||||
Unipolar
|
||||
RC Servo
|
||||
|
||||
These are for motors coordinated by Grbl_ESP32
|
||||
See motorClass.cpp for more details
|
||||
|
||||
Part of Grbl_ESP32
|
||||
2020 - Bart Dring
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Motors.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace Motors {
|
||||
class Motor {
|
||||
public:
|
||||
Motor();
|
||||
|
||||
virtual void init(); // not in constructor because this also gets called when $$ settings change
|
||||
virtual void config_message();
|
||||
virtual void debug_message();
|
||||
virtual void read_settings();
|
||||
virtual void set_homing_mode(uint8_t homing_mask, bool isHoming);
|
||||
virtual void set_disable(bool disable);
|
||||
virtual void set_direction_pins(uint8_t onMask);
|
||||
virtual void step(uint8_t step_mask, uint8_t dir_mask); // only used on Unipolar right now
|
||||
virtual bool test();
|
||||
virtual void set_axis_name();
|
||||
virtual void update();
|
||||
|
||||
motor_class_id_t type_id;
|
||||
uint8_t is_active = false;
|
||||
|
||||
protected:
|
||||
uint8_t axis_index; // X_AXIS, etc
|
||||
uint8_t dual_axis_index; // 0 = primary 1=ganged
|
||||
|
||||
bool _showError;
|
||||
bool _use_mpos = true;
|
||||
uint8_t _homing_mask;
|
||||
char _axis_name[10]; // this the name to use when reporting like "X" or "X2"
|
||||
};
|
||||
}
|
@@ -1,58 +1,65 @@
|
||||
/*
|
||||
MotorClass.cpp
|
||||
Part of Grbl_ESP32
|
||||
2020 - Bart Dring
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
TODO
|
||||
Make sure public/private/protected is cleaned up.
|
||||
Only a few Unipolar axes have been setup in init()
|
||||
Get rid of Z_SERVO, just reply on Z_SERVO_PIN
|
||||
Deal with custom machine ... machine_trinamic_setup();
|
||||
Class is ready to deal with non SPI pins, but they have not been needed yet.
|
||||
It would be nice in the config message though
|
||||
Testing
|
||||
Done (success)
|
||||
3 Axis (3 Standard Steppers)
|
||||
MPCNC (ganged with shared direction pin)
|
||||
TMC2130 Pen Laser (trinamics, stallguard tuning)
|
||||
Unipolar
|
||||
TODO
|
||||
4 Axis SPI (Daisy Chain, Ganged with unique direction pins)
|
||||
Reference
|
||||
TMC2130 Datasheet https://www.trinamic.com/fileadmin/assets/Products/ICs_Documents/TMC2130_datasheet.pdf
|
||||
Motors.cpp
|
||||
Part of Grbl_ESP32
|
||||
2020 - Bart Dring
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
TODO
|
||||
Make sure public/private/protected is cleaned up.
|
||||
Only a few Unipolar axes have been setup in init()
|
||||
Get rid of Z_SERVO, just reply on Z_SERVO_PIN
|
||||
Deal with custom machine ... machine_trinamic_setup();
|
||||
Class is ready to deal with non SPI pins, but they have not been needed yet.
|
||||
It would be nice in the config message though
|
||||
Testing
|
||||
Done (success)
|
||||
3 Axis (3 Standard Steppers)
|
||||
MPCNC (ganged with shared direction pin)
|
||||
TMC2130 Pen Laser (trinamics, stallguard tuning)
|
||||
Unipolar
|
||||
TODO
|
||||
4 Axis SPI (Daisy Chain, Ganged with unique direction pins)
|
||||
Reference
|
||||
TMC2130 Datasheet https://www.trinamic.com/fileadmin/assets/Products/ICs_Documents/TMC2130_datasheet.pdf
|
||||
*/
|
||||
|
||||
#include "../grbl.h"
|
||||
#include "TrinamicDriverClass.cpp"
|
||||
#include "StandardStepperClass.cpp"
|
||||
#include "UnipolarMotorClass.cpp"
|
||||
#include "RcServoClass.cpp"
|
||||
//#include "SolenoidClass.cpp"
|
||||
#include "Motors.h"
|
||||
|
||||
Motor* myMotor[MAX_AXES][MAX_GANGED]; // number of axes (normal and ganged)
|
||||
static TaskHandle_t readSgTaskHandle = 0; // for realtime stallguard data diaplay
|
||||
#include "Motor.h"
|
||||
#include "../Grbl.h"
|
||||
|
||||
#include "NullMotor.h"
|
||||
#include "StandardStepper.h"
|
||||
#include "UnipolarMotor.h"
|
||||
#include "RcServo.h"
|
||||
#include "TrinamicDriver.h"
|
||||
|
||||
Motors::Motor* myMotor[MAX_AXES][MAX_GANGED]; // number of axes (normal and ganged)
|
||||
static TaskHandle_t readSgTaskHandle = 0; // for realtime stallguard data diaplay
|
||||
static TaskHandle_t servoUpdateTaskHandle = 0;
|
||||
|
||||
uint8_t rmt_chan_num[MAX_AXES][MAX_GANGED];
|
||||
uint8_t rmt_chan_num[MAX_AXES][MAX_GANGED];
|
||||
rmt_item32_t rmtItem[2];
|
||||
rmt_config_t rmtConfig;
|
||||
|
||||
bool motor_class_steps; // true if at least one motor class is handling steps
|
||||
bool motor_class_steps; // true if at least one motor class is handling steps
|
||||
|
||||
void init_motors() {
|
||||
using namespace Motors;
|
||||
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Init Motors");
|
||||
|
||||
#ifdef X_TRINAMIC_DRIVER
|
||||
myMotor[X_AXIS][0] = new TrinamicDriver(X_AXIS, X_STEP_PIN, X_DIRECTION_PIN, X_DISABLE_PIN, X_CS_PIN, X_TRINAMIC_DRIVER, X_RSENSE, get_next_trinamic_driver_index());
|
||||
myMotor[X_AXIS][0] = new TrinamicDriver(
|
||||
X_AXIS, X_STEP_PIN, X_DIRECTION_PIN, X_DISABLE_PIN, X_CS_PIN, X_TRINAMIC_DRIVER, X_RSENSE, get_next_trinamic_driver_index());
|
||||
#elif defined(X_SERVO_PIN)
|
||||
myMotor[X_AXIS][0] = new RcServo(X_AXIS, X_SERVO_PIN, X_SERVO_RANGE_MIN, X_SERVO_RANGE_MAX);
|
||||
#elif defined(X_UNIPOLAR)
|
||||
@@ -64,7 +71,8 @@ void init_motors() {
|
||||
#endif
|
||||
|
||||
#ifdef X2_TRINAMIC_DRIVER
|
||||
myMotor[X_AXIS][1] = new TrinamicDriver(X2_AXIS, X2_STEP_PIN, X2_DIRECTION_PIN, X2_DISABLE_PIN, X2_CS_PIN, X2_TRINAMIC_DRIVER, X2_RSENSE, get_next_trinamic_driver_index());
|
||||
myMotor[X_AXIS][1] = new TrinamicDriver(
|
||||
X2_AXIS, X2_STEP_PIN, X2_DIRECTION_PIN, X2_DISABLE_PIN, X2_CS_PIN, X2_TRINAMIC_DRIVER, X2_RSENSE, get_next_trinamic_driver_index());
|
||||
#elif defined(X2_SERVO_PIN)
|
||||
myMotor[X_AXIS][1] = new RcServo(X2_AXIS, X2_SERVO_PIN, X2_SERVO_RANGE_MIN, X2_SERVO_RANGE_MAX);
|
||||
#elif defined(X2_UNIPOLAR)
|
||||
@@ -75,10 +83,10 @@ void init_motors() {
|
||||
myMotor[X_AXIS][1] = new Nullmotor();
|
||||
#endif
|
||||
|
||||
|
||||
// this WILL be done better with settings
|
||||
#ifdef Y_TRINAMIC_DRIVER
|
||||
myMotor[Y_AXIS][0] = new TrinamicDriver(Y_AXIS, Y_STEP_PIN, Y_DIRECTION_PIN, Y_DISABLE_PIN, Y_CS_PIN, Y_TRINAMIC_DRIVER, Y_RSENSE, get_next_trinamic_driver_index());
|
||||
myMotor[Y_AXIS][0] = new TrinamicDriver(
|
||||
Y_AXIS, Y_STEP_PIN, Y_DIRECTION_PIN, Y_DISABLE_PIN, Y_CS_PIN, Y_TRINAMIC_DRIVER, Y_RSENSE, get_next_trinamic_driver_index());
|
||||
#elif defined(Y_SERVO_PIN)
|
||||
myMotor[Y_AXIS][0] = new RcServo(Y_AXIS, Y_SERVO_PIN, Y_SERVO_RANGE_MIN, Y_SERVO_RANGE_MAX);
|
||||
#elif defined(Y_UNIPOLAR)
|
||||
@@ -90,7 +98,8 @@ void init_motors() {
|
||||
#endif
|
||||
|
||||
#ifdef Y2_TRINAMIC_DRIVER
|
||||
myMotor[Y_AXIS][1] = new TrinamicDriver(Y2_AXIS, Y2_STEP_PIN, Y2_DIRECTION_PIN, Y2_DISABLE_PIN, Y2_CS_PIN, Y2_TRINAMIC_DRIVER, Y2_RSENSE, get_next_trinamic_driver_index());
|
||||
myMotor[Y_AXIS][1] = new TrinamicDriver(
|
||||
Y2_AXIS, Y2_STEP_PIN, Y2_DIRECTION_PIN, Y2_DISABLE_PIN, Y2_CS_PIN, Y2_TRINAMIC_DRIVER, Y2_RSENSE, get_next_trinamic_driver_index());
|
||||
#elif defined(Y2_SERVO_PIN)
|
||||
myMotor[Y_AXIS][1] = new RcServo(Y2_AXIS, Y2_SERVO_PIN, Y2_SERVO_RANGE_MIN, Y2_SERVO_RANGE_MAX);
|
||||
#elif defined(Y2_UNIPOLAR)
|
||||
@@ -101,10 +110,10 @@ void init_motors() {
|
||||
myMotor[Y_AXIS][1] = new Nullmotor();
|
||||
#endif
|
||||
|
||||
|
||||
// this WILL be done better with settings
|
||||
#ifdef Z_TRINAMIC_DRIVER
|
||||
myMotor[Z_AXIS][0] = new TrinamicDriver(Z_AXIS, Z_STEP_PIN, Z_DIRECTION_PIN, Z_DISABLE_PIN, Z_CS_PIN, Z_TRINAMIC_DRIVER, Z_RSENSE, get_next_trinamic_driver_index());
|
||||
myMotor[Z_AXIS][0] = new TrinamicDriver(
|
||||
Z_AXIS, Z_STEP_PIN, Z_DIRECTION_PIN, Z_DISABLE_PIN, Z_CS_PIN, Z_TRINAMIC_DRIVER, Z_RSENSE, get_next_trinamic_driver_index());
|
||||
#elif defined(Z_SERVO_PIN)
|
||||
myMotor[Z_AXIS][0] = new RcServo(Z_AXIS, Z_SERVO_PIN, Z_SERVO_RANGE_MIN, Z_SERVO_RANGE_MAX);
|
||||
#elif defined(Z_UNIPOLAR)
|
||||
@@ -116,7 +125,8 @@ void init_motors() {
|
||||
#endif
|
||||
|
||||
#ifdef Z2_TRINAMIC_DRIVER
|
||||
myMotor[Z_AXIS][1] = new TrinamicDriver(Z2_AXIS, Z2_STEP_PIN, Z2_DIRECTION_PIN, Z2_DISABLE_PIN, Z2_CS_PIN, Z2_TRINAMIC_DRIVER, Z2_RSENSE, get_next_trinamic_driver_index());
|
||||
myMotor[Z_AXIS][1] = new TrinamicDriver(
|
||||
Z2_AXIS, Z2_STEP_PIN, Z2_DIRECTION_PIN, Z2_DISABLE_PIN, Z2_CS_PIN, Z2_TRINAMIC_DRIVER, Z2_RSENSE, get_next_trinamic_driver_index());
|
||||
#elif defined(Z2_SERVO_PIN)
|
||||
myMotor[Z_AXIS][1] = new RcServo(Z2_AXIS, Z2_SERVO_PIN, Z2_SERVO_RANGE_MIN, Z2_SERVO_RANGE_MAX);
|
||||
#elif defined(Z2_UNIPOLAR)
|
||||
@@ -129,7 +139,8 @@ void init_motors() {
|
||||
|
||||
// this WILL be done better with settings
|
||||
#ifdef A_TRINAMIC_DRIVER
|
||||
myMotor[A_AXIS][0] = new TrinamicDriver(A_AXIS, A_STEP_PIN, A_DIRECTION_PIN, A_DISABLE_PIN, A_CS_PIN, A_TRINAMIC_DRIVER, A_RSENSE, get_next_trinamic_driver_index());
|
||||
myMotor[A_AXIS][0] = new TrinamicDriver(
|
||||
A_AXIS, A_STEP_PIN, A_DIRECTION_PIN, A_DISABLE_PIN, A_CS_PIN, A_TRINAMIC_DRIVER, A_RSENSE, get_next_trinamic_driver_index());
|
||||
#elif defined(A_SERVO_PIN)
|
||||
myMotor[A_AXIS][0] = new RcServo(A_AXIS, A_SERVO_PIN, A_SERVO_RANGE_MIN, A_SERVO_RANGE_MAX);
|
||||
#elif defined(A_UNIPOLAR)
|
||||
@@ -141,7 +152,8 @@ void init_motors() {
|
||||
#endif
|
||||
|
||||
#ifdef A2_TRINAMIC_DRIVER
|
||||
myMotor[A_AXIS][1] = new TrinamicDriver(A2_AXIS, A2_STEP_PIN, A2_DIRECTION_PIN, A2_DISABLE_PIN, A2_CS_PIN, A2_TRINAMIC_DRIVER, A2_RSENSE, get_next_trinamic_driver_index());
|
||||
myMotor[A_AXIS][1] = new TrinamicDriver(
|
||||
A2_AXIS, A2_STEP_PIN, A2_DIRECTION_PIN, A2_DISABLE_PIN, A2_CS_PIN, A2_TRINAMIC_DRIVER, A2_RSENSE, get_next_trinamic_driver_index());
|
||||
#elif defined(A2_SERVO_PIN)
|
||||
myMotor[A_AXIS][1] = new RcServo(A2_AXIS, A2_SERVO_PIN, A2_SERVO_RANGE_MIN, A2_SERVO_RANGE_MAX);
|
||||
#elif defined(A2_UNIPOLAR)
|
||||
@@ -154,7 +166,8 @@ void init_motors() {
|
||||
|
||||
// this WILL be done better with settings
|
||||
#ifdef B_TRINAMIC_DRIVER
|
||||
myMotor[B_AXIS][0] = new TrinamicDriver(B_AXIS, B_STEP_PIN, B_DIRECTION_PIN, B_DISABLE_PIN, B_CS_PIN, B_TRINAMIC_DRIVER, B_RSENSE, get_next_trinamic_driver_index());
|
||||
myMotor[B_AXIS][0] = new TrinamicDriver(
|
||||
B_AXIS, B_STEP_PIN, B_DIRECTION_PIN, B_DISABLE_PIN, B_CS_PIN, B_TRINAMIC_DRIVER, B_RSENSE, get_next_trinamic_driver_index());
|
||||
#elif defined(B_SERVO_PIN)
|
||||
myMotor[B_AXIS][0] = new RcServo(B_AXIS, B_SERVO_PIN, B_SERVO_RANGE_MIN, B_SERVO_RANGE_MAX);
|
||||
#elif defined(B_UNIPOLAR)
|
||||
@@ -166,7 +179,8 @@ void init_motors() {
|
||||
#endif
|
||||
|
||||
#ifdef B2_TRINAMIC_DRIVER
|
||||
myMotor[B_AXIS][1] = new TrinamicDriver(B2_AXIS, B2_STEP_PIN, B2_DIRECTION_PIN, B2_DISABLE_PIN, B2_CS_PIN, B2_TRINAMIC_DRIVER, B2_RSENSE, get_next_trinamic_driver_index());
|
||||
myMotor[B_AXIS][1] = new TrinamicDriver(
|
||||
B2_AXIS, B2_STEP_PIN, B2_DIRECTION_PIN, B2_DISABLE_PIN, B2_CS_PIN, B2_TRINAMIC_DRIVER, B2_RSENSE, get_next_trinamic_driver_index());
|
||||
#elif defined(B2_SERVO_PIN)
|
||||
myMotor[B_AXIS][1] = new RcServo(B2_AXIS, B2_SERVO_PIN, B2_SERVO_RANGE_MIN, B2_SERVO_RANGE_MAX);
|
||||
#elif defined(B2_UNIPOLAR)
|
||||
@@ -179,7 +193,8 @@ void init_motors() {
|
||||
|
||||
// this WILL be done better with settings
|
||||
#ifdef C_TRINAMIC_DRIVER
|
||||
myMotor[C_AXIS][0] = new TrinamicDriver(C_AXIS, C_STEP_PIN, C_DIRECTION_PIN, C_DISABLE_PIN, C_CS_PIN, C_TRINAMIC_DRIVER, C_RSENSE, get_next_trinamic_driver_index());
|
||||
myMotor[C_AXIS][0] = new TrinamicDriver(
|
||||
C_AXIS, C_STEP_PIN, C_DIRECTION_PIN, C_DISABLE_PIN, C_CS_PIN, C_TRINAMIC_DRIVER, C_RSENSE, get_next_trinamic_driver_index());
|
||||
#elif defined(C_SERVO_PIN)
|
||||
myMotor[C_AXIS][0] = new RcServo(C_AXIS, C_SERVO_PIN, C_SERVO_RANGE_MIN, C_SERVO_RANGE_MAX);
|
||||
#elif defined(C_UNIPOLAR)
|
||||
@@ -191,7 +206,8 @@ void init_motors() {
|
||||
#endif
|
||||
|
||||
#ifdef C2_TRINAMIC_DRIVER
|
||||
myMotor[C_AXIS][1] = new TrinamicDriver(C2_AXIS, C2_STEP_PIN, C2_DIRECTION_PIN, C2_DISABLE_PIN, C2_CS_PIN, C2_TRINAMIC_DRIVER, C2_RSENSE, get_next_trinamic_driver_index());
|
||||
myMotor[C_AXIS][1] = new TrinamicDriver(
|
||||
C2_AXIS, C2_STEP_PIN, C2_DIRECTION_PIN, C2_DISABLE_PIN, C2_CS_PIN, C2_TRINAMIC_DRIVER, C2_RSENSE, get_next_trinamic_driver_index());
|
||||
#elif defined(C2_SERVO_PIN)
|
||||
myMotor[C_AXIS][1] = new RcServo(C2_AXIS, C2_SERVO_PIN, C2_SERVO_RANGE_MIN, C2_SERVO_RANGE_MAX);
|
||||
#elif defined(C2_UNIPOLAR)
|
||||
@@ -202,61 +218,39 @@ void init_motors() {
|
||||
myMotor[C_AXIS][1] = new Nullmotor();
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef USE_STEPSTICK
|
||||
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Using StepStick Mode");
|
||||
#ifdef STEPPER_MS1
|
||||
digitalWrite(STEPPER_MS1, HIGH);
|
||||
pinMode(STEPPER_MS1, OUTPUT);
|
||||
#endif
|
||||
#ifdef STEPPER_MS2
|
||||
digitalWrite(STEPPER_MS2, HIGH);
|
||||
pinMode(STEPPER_MS2, OUTPUT);
|
||||
#endif
|
||||
#ifdef STEPPER_X_MS3
|
||||
digitalWrite(STEPPER_X_MS3, HIGH);
|
||||
pinMode(STEPPER_X_MS3, OUTPUT);
|
||||
#endif
|
||||
#ifdef STEPPER_Y_MS3
|
||||
digitalWrite(STEPPER_Y_MS3, HIGH);
|
||||
pinMode(STEPPER_Y_MS3, OUTPUT);
|
||||
#endif
|
||||
#ifdef STEPPER_Z_MS3
|
||||
digitalWrite(STEPPER_Z_MS3, HIGH);
|
||||
pinMode(STEPPER_Z_MS3, OUTPUT);
|
||||
#endif
|
||||
#ifdef STEPPER_A_MS3
|
||||
digitalWrite(STEPPER_A_MS3, HIGH);
|
||||
pinMode(STEPPER_A_MS3, OUTPUT);
|
||||
#endif
|
||||
#ifdef STEPPER_B_MS3
|
||||
digitalWrite(STEPPER_B_MS3, HIGH);
|
||||
pinMode(STEPPER_B_MS3, OUTPUT);
|
||||
#endif
|
||||
#ifdef STEPPER_C_MS3
|
||||
digitalWrite(STEPPER_C_MS3, HIGH);
|
||||
pinMode(STEPPER_C_MS3, OUTPUT);
|
||||
#endif
|
||||
#ifdef STEPPER_RESET
|
||||
|
||||
uint8_t ms3_pins[MAX_N_AXIS][2] = { { X_STEPPER_MS3, X2_STEPPER_MS3 }, { Y_STEPPER_MS3, Y2_STEPPER_MS3 }, { Z_STEPPER_MS3, Z2_STEPPER_MS3 },
|
||||
{ A_STEPPER_MS3, A2_STEPPER_MS3 }, { B_STEPPER_MS3, B2_STEPPER_MS3 }, { C_STEPPER_MS3, C2_STEPPER_MS3 } };
|
||||
|
||||
for (int axis = 0; axis < N_AXIS; axis++) {
|
||||
for (int gang_index = 0; gang_index < 2; gang_index++) {
|
||||
uint8_t pin = ms3_pins[axis][gang_index];
|
||||
if (pin != UNDEFINED_PIN) {
|
||||
digitalWrite(pin, HIGH);
|
||||
pinMode(pin, OUTPUT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ifdef STEPPER_RESET
|
||||
// !RESET pin on steppers (MISO On Schematic)
|
||||
digitalWrite(STEPPER_RESET, HIGH);
|
||||
pinMode(STEPPER_RESET, OUTPUT);
|
||||
#endif
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
if (STEPPERS_DISABLE_PIN != UNDEFINED_PIN) {
|
||||
pinMode(STEPPERS_DISABLE_PIN, OUTPUT); // global motor enable pin
|
||||
grbl_msg_sendf(CLIENT_SERIAL,
|
||||
MSG_LEVEL_INFO,
|
||||
"Global stepper disable pin:%s",
|
||||
pinName(STEPPERS_DISABLE_PIN));
|
||||
pinMode(STEPPERS_DISABLE_PIN, OUTPUT); // global motor enable pin
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Global stepper disable pin:%s", pinName(STEPPERS_DISABLE_PIN));
|
||||
}
|
||||
|
||||
// certain motors need features to be turned on. Check them here
|
||||
for (uint8_t axis = X_AXIS; axis < N_AXIS; axis++) {
|
||||
for (uint8_t gang_index = 0; gang_index < 2; gang_index++) {
|
||||
|
||||
if (myMotor[axis][gang_index]->type_id == UNIPOLAR_MOTOR)
|
||||
motor_class_steps = true;
|
||||
|
||||
@@ -272,39 +266,36 @@ void init_motors() {
|
||||
|
||||
if (motors_have_type_id(TRINAMIC_SPI_MOTOR)) {
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "TMCStepper Library Ver. 0x%06x", TMCSTEPPER_VERSION);
|
||||
xTaskCreatePinnedToCore(readSgTask, // task
|
||||
"readSgTask", // name for task
|
||||
4096, // size of task stack
|
||||
NULL, // parameters
|
||||
1, // priority
|
||||
xTaskCreatePinnedToCore(readSgTask, // task
|
||||
"readSgTask", // name for task
|
||||
4096, // size of task stack
|
||||
NULL, // parameters
|
||||
1, // priority
|
||||
&readSgTaskHandle,
|
||||
0 // core
|
||||
);
|
||||
0 // core
|
||||
);
|
||||
if (stallguard_debug_mask->get() != 0)
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Stallguard debug enabled: %d", stallguard_debug_mask->get());
|
||||
}
|
||||
|
||||
if (motors_have_type_id(RC_SERVO_MOTOR)) {
|
||||
xTaskCreatePinnedToCore(servoUpdateTask, // task
|
||||
"servoUpdateTask", // name for task
|
||||
4096, // size of task stack
|
||||
NULL, // parameters
|
||||
1, // priority
|
||||
xTaskCreatePinnedToCore(servoUpdateTask, // task
|
||||
"servoUpdateTask", // name for task
|
||||
4096, // size of task stack
|
||||
NULL, // parameters
|
||||
1, // priority
|
||||
&servoUpdateTaskHandle,
|
||||
0 // core
|
||||
);
|
||||
0 // core
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void servoUpdateTask(void* pvParameters) {
|
||||
TickType_t xLastWakeTime;
|
||||
TickType_t xLastWakeTime;
|
||||
const TickType_t xUpdate = SERVO_TIMER_INT_FREQ; // in ticks (typically ms)
|
||||
|
||||
|
||||
xLastWakeTime = xTaskGetTickCount(); // Initialise the xLastWakeTime variable with the current time.
|
||||
while (true) { // don't ever return from this or the task dies
|
||||
xLastWakeTime = xTaskGetTickCount(); // Initialise the xLastWakeTime variable with the current time.
|
||||
while (true) { // don't ever return from this or the task dies
|
||||
|
||||
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Servo update");
|
||||
|
||||
@@ -328,7 +319,6 @@ bool motors_have_type_id(motor_class_id_t id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void motors_set_disable(bool disable) {
|
||||
static bool previous_state = false;
|
||||
|
||||
@@ -338,7 +328,7 @@ void motors_set_disable(bool disable) {
|
||||
previous_state = disable;
|
||||
|
||||
if (step_enable_invert->get()) {
|
||||
disable = !disable; // Apply pin invert.
|
||||
disable = !disable; // Apply pin invert.
|
||||
}
|
||||
|
||||
digitalWrite(STEPPERS_DISABLE_PIN, disable);
|
||||
@@ -369,7 +359,6 @@ void motors_set_homing_mode(uint8_t homing_mask, bool isHoming) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void motors_set_direction_pins(uint8_t onMask) {
|
||||
static uint8_t previous_val = 255; // should never be this value
|
||||
if (previous_val == onMask)
|
||||
@@ -388,7 +377,7 @@ void motors_set_direction_pins(uint8_t onMask) {
|
||||
// need to be inserted into the order of axes.
|
||||
uint8_t get_next_trinamic_driver_index() {
|
||||
#ifdef TRINAMIC_DAISY_CHAIN
|
||||
static uint8_t index = 1; // they start at 1
|
||||
static uint8_t index = 1; // they start at 1
|
||||
return index++;
|
||||
#else
|
||||
return -1;
|
||||
@@ -397,7 +386,7 @@ uint8_t get_next_trinamic_driver_index() {
|
||||
|
||||
// some motor objects, like unipolar need step signals
|
||||
void motors_step(uint8_t step_mask, uint8_t dir_mask) {
|
||||
if (motor_class_steps) { // determined in init_motors if any motors need to handle steps
|
||||
if (motor_class_steps) { // determined in init_motors if any motors need to handle steps
|
||||
for (uint8_t gang_index = 0; gang_index < 2; gang_index++) {
|
||||
for (uint8_t axis = X_AXIS; axis < N_AXIS; axis++)
|
||||
myMotor[axis][gang_index]->step(step_mask, dir_mask);
|
||||
@@ -406,14 +395,14 @@ void motors_step(uint8_t step_mask, uint8_t dir_mask) {
|
||||
}
|
||||
|
||||
/*
|
||||
This will print StallGuard data that is useful for tuning.
|
||||
This will print StallGuard data that is useful for tuning.
|
||||
*/
|
||||
void readSgTask(void* pvParameters) {
|
||||
TickType_t xLastWakeTime;
|
||||
TickType_t xLastWakeTime;
|
||||
const TickType_t xreadSg = 200; // in ticks (typically ms)
|
||||
|
||||
xLastWakeTime = xTaskGetTickCount(); // Initialise the xLastWakeTime variable with the current time.
|
||||
while (true) { // don't ever return from this or the task dies
|
||||
xLastWakeTime = xTaskGetTickCount(); // Initialise the xLastWakeTime variable with the current time.
|
||||
while (true) { // don't ever return from this or the task dies
|
||||
if (motorSettingChanged) {
|
||||
motors_read_settings();
|
||||
motorSettingChanged = false;
|
||||
@@ -428,13 +417,12 @@ void readSgTask(void* pvParameters) {
|
||||
myMotor[axis][gang_index]->debug_message();
|
||||
}
|
||||
}
|
||||
} // sys.state
|
||||
} // if mask
|
||||
} // sys.state
|
||||
} // if mask
|
||||
vTaskDelayUntil(&xLastWakeTime, xreadSg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef USE_I2S_OUT
|
||||
//
|
||||
// Override default function and insert a short delay
|
||||
@@ -444,32 +432,3 @@ void TMC2130Stepper::switchCSpin(bool state) {
|
||||
i2s_out_delay();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// ============================== Class Methods ================================================
|
||||
|
||||
Motor :: Motor() {
|
||||
type_id = MOTOR;
|
||||
}
|
||||
|
||||
void Motor :: init() {
|
||||
_homing_mask = 0;
|
||||
}
|
||||
|
||||
void Motor :: config_message() {}
|
||||
void Motor :: debug_message() {}
|
||||
void Motor :: read_settings() {}
|
||||
void Motor :: set_disable(bool disable) {}
|
||||
void Motor :: set_direction_pins(uint8_t onMask) {}
|
||||
void Motor :: step(uint8_t step_mask, uint8_t dir_mask) {}
|
||||
bool Motor :: test() {return true;}; // true = OK
|
||||
void Motor :: update() {}
|
||||
|
||||
void Motor :: set_axis_name() {
|
||||
sprintf(_axis_name, "%c%s", report_get_axis_letter(axis_index), dual_axis_index ? "2" : "");
|
||||
}
|
||||
|
||||
void Motor :: set_homing_mode(uint8_t homing_mask, bool isHoming) {
|
||||
_homing_mask = homing_mask;
|
||||
}
|
53
Grbl_Esp32/src/Motors/Motors.h
Normal file
53
Grbl_Esp32/src/Motors/Motors.h
Normal file
@@ -0,0 +1,53 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
Motors.h
|
||||
Header file for Motor Classes
|
||||
Here is the hierarchy
|
||||
Motor
|
||||
Nullmotor
|
||||
StandardStepper
|
||||
TrinamicDriver
|
||||
Unipolar
|
||||
RC Servo
|
||||
|
||||
These are for motors coordinated by Grbl_ESP32
|
||||
See motorClass.cpp for more details
|
||||
|
||||
Part of Grbl_ESP32
|
||||
2020 - Bart Dring
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "../Grbl.h"
|
||||
#include <TMCStepper.h> // https://github.com/teemuatlut/TMCStepper
|
||||
|
||||
extern uint8_t rmt_chan_num[MAX_AXES][2];
|
||||
extern rmt_item32_t rmtItem[2];
|
||||
extern rmt_config_t rmtConfig;
|
||||
|
||||
typedef enum { MOTOR, NULL_MOTOR, STANDARD_MOTOR, TRINAMIC_SPI_MOTOR, UNIPOLAR_MOTOR, RC_SERVO_MOTOR, SOLENOID } motor_class_id_t;
|
||||
|
||||
// These are used for setup and to talk to the motors as a group.
|
||||
void init_motors();
|
||||
uint8_t get_next_trinamic_driver_index();
|
||||
bool motors_have_type_id(motor_class_id_t id);
|
||||
void readSgTask(void* pvParameters);
|
||||
void motors_read_settings();
|
||||
void motors_set_homing_mode(uint8_t homing_mask, bool isHoming);
|
||||
void motors_set_disable(bool disable);
|
||||
void motors_set_direction_pins(uint8_t onMask);
|
||||
void motors_step(uint8_t step_mask, uint8_t dir_mask);
|
||||
void servoUpdateTask(void* pvParameters);
|
||||
|
||||
extern bool motor_class_steps; // true if at least one motor class is handling steps
|
7
Grbl_Esp32/src/Motors/NullMotor.h
Normal file
7
Grbl_Esp32/src/Motors/NullMotor.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "Motor.h"
|
||||
|
||||
namespace Motors {
|
||||
class Nullmotor : public Motor {};
|
||||
}
|
189
Grbl_Esp32/src/Motors/RcServo.cpp
Normal file
189
Grbl_Esp32/src/Motors/RcServo.cpp
Normal file
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
RcServo.cpp
|
||||
|
||||
This allows an RcServo to be used like any other motor. Serrvos
|
||||
do have limitation in travel and speed, so you do need to respect that.
|
||||
|
||||
Part of Grbl_ESP32
|
||||
|
||||
2020 - Bart Dring
|
||||
|
||||
Servos have a limited travel, so they map the travel across a range in
|
||||
the current work coordinatee system. The servo can only travel as far
|
||||
as the range, but the internal axis value can keep going.
|
||||
|
||||
Range: The range is specified in the machine definition file with...
|
||||
#define X_SERVO_RANGE_MIN 0.0
|
||||
#define X_SERVO_RANGE_MAX 5.0
|
||||
|
||||
Direction: The direction can be changed using the $3 setting for the axis
|
||||
|
||||
Homing: During homing, the servo will move to one of the endpoints. The
|
||||
endpoint is determined by the $23 or $HomingDirInvertMask setting for the axis.
|
||||
Do not define a homing cycle for the axis with the servo.
|
||||
You do need at least 1 homing cycle. TODO: Fix this
|
||||
|
||||
Calibration. You can tweak the endpoints using the $10n or nStepsPerMm and
|
||||
$13n or $xMaxTravel setting, where n is the axis.
|
||||
The value is a percent. If you secify a percent outside the
|
||||
the range specified by the values below, it will be reset to 100.0 (100% ... no change)
|
||||
The calibration adjusts in direction of positive momement, so a value above 100% moves
|
||||
towards the higher axis value.
|
||||
|
||||
#define SERVO_CAL_MIN
|
||||
#define SERVO_CAL_MAX
|
||||
|
||||
Grbl_ESP32 is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "RcServo.h"
|
||||
|
||||
namespace Motors {
|
||||
RcServo::RcServo() {}
|
||||
|
||||
RcServo::RcServo(uint8_t axis_index, uint8_t pwm_pin, float min, float max) {
|
||||
type_id = RC_SERVO_MOTOR;
|
||||
this->axis_index = axis_index % MAX_AXES;
|
||||
this->dual_axis_index = axis_index < MAX_AXES ? 0 : 1; // 0 = primary 1 = ganged
|
||||
this->_pwm_pin = pwm_pin;
|
||||
_position_min = min;
|
||||
_position_max = max;
|
||||
init();
|
||||
}
|
||||
|
||||
void RcServo::init() {
|
||||
read_settings();
|
||||
_channel_num = sys_get_next_PWM_chan_num();
|
||||
ledcSetup(_channel_num, SERVO_PULSE_FREQ, SERVO_PULSE_RES_BITS);
|
||||
ledcAttachPin(_pwm_pin, _channel_num);
|
||||
_current_pwm_duty = 0;
|
||||
is_active = true; // as opposed to NullMotors, this is a real motor
|
||||
set_axis_name();
|
||||
config_message();
|
||||
}
|
||||
|
||||
void RcServo::config_message() {
|
||||
grbl_msg_sendf(CLIENT_SERIAL,
|
||||
MSG_LEVEL_INFO,
|
||||
"%s Axis RC Servo motor Output:%d Min:%5.3fmm Max:%5.3fmm",
|
||||
_axis_name,
|
||||
_pwm_pin,
|
||||
_position_min,
|
||||
_position_max);
|
||||
}
|
||||
|
||||
void RcServo::_write_pwm(uint32_t duty) {
|
||||
// to prevent excessive calls to ledcWrite, make sure duty hass changed
|
||||
if (duty == _current_pwm_duty)
|
||||
return;
|
||||
|
||||
_current_pwm_duty = duty;
|
||||
|
||||
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "%s Servo Pwm %d", _axis_name, duty);
|
||||
ledcWrite(_channel_num, duty);
|
||||
}
|
||||
|
||||
// sets the PWM to zero. This allows most servos to be manually moved
|
||||
void RcServo::set_disable(bool disable) {
|
||||
return;
|
||||
_disabled = disable;
|
||||
if (_disabled)
|
||||
_write_pwm(0);
|
||||
}
|
||||
|
||||
void RcServo::set_homing_mode(bool is_homing, bool isHoming) {
|
||||
float home_pos = 0.0;
|
||||
|
||||
if (!is_homing)
|
||||
return;
|
||||
|
||||
if (bit_istrue(homing_dir_mask->get(), bit(axis_index)))
|
||||
home_pos = _position_min;
|
||||
else
|
||||
home_pos = _position_max;
|
||||
|
||||
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Servo set home %d %3.2f", is_homing, home_pos);
|
||||
sys_position[axis_index] = home_pos * axis_settings[axis_index]->steps_per_mm->get(); // convert to steps
|
||||
}
|
||||
|
||||
void RcServo::update() { set_location(); }
|
||||
|
||||
void RcServo::set_location() {
|
||||
uint32_t servo_pulse_len;
|
||||
float servo_pos, mpos, offset;
|
||||
// skip location if we are in alarm mode
|
||||
|
||||
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "locate");
|
||||
_get_calibration();
|
||||
|
||||
if (sys.state == STATE_ALARM) {
|
||||
set_disable(true);
|
||||
return;
|
||||
}
|
||||
|
||||
mpos = system_convert_axis_steps_to_mpos(sys_position, axis_index); // get the axis machine position in mm
|
||||
offset = gc_state.coord_system[axis_index] + gc_state.coord_offset[axis_index]; // get the current axis work offset
|
||||
servo_pos = mpos - offset; // determine the current work position
|
||||
|
||||
// determine the pulse length
|
||||
servo_pulse_len = (uint32_t)mapConstrain(servo_pos, _position_min, _position_max, _pwm_pulse_min, _pwm_pulse_max);
|
||||
|
||||
_write_pwm(servo_pulse_len);
|
||||
}
|
||||
|
||||
void RcServo::read_settings() { _get_calibration(); }
|
||||
|
||||
// this should change to use its own settings.
|
||||
void RcServo::_get_calibration() {
|
||||
float _cal_min = 1.0;
|
||||
float _cal_max = 1.0;
|
||||
|
||||
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Read settings");
|
||||
|
||||
// make sure the min is in range
|
||||
if ((axis_settings[axis_index]->steps_per_mm->get() < SERVO_CAL_MIN) ||
|
||||
(axis_settings[axis_index]->steps_per_mm->get() > SERVO_CAL_MAX)) {
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Servo calibration ($10%d) value error. Reset to 100", axis_index);
|
||||
char reset_val[] = "100";
|
||||
axis_settings[axis_index]->steps_per_mm->setStringValue(reset_val);
|
||||
}
|
||||
|
||||
// make sure the max is in range
|
||||
// Note: Max travel is set positive via $$, but stored as a negative number
|
||||
if ((axis_settings[axis_index]->max_travel->get() < SERVO_CAL_MIN) || (axis_settings[axis_index]->max_travel->get() > SERVO_CAL_MAX)) {
|
||||
grbl_msg_sendf(CLIENT_SERIAL,
|
||||
MSG_LEVEL_INFO,
|
||||
"Servo calibration ($13%d) value error. %3.2f Reset to 100",
|
||||
axis_index,
|
||||
axis_settings[axis_index]->max_travel->get());
|
||||
char reset_val[] = "100";
|
||||
axis_settings[axis_index]->max_travel->setStringValue(reset_val);
|
||||
}
|
||||
|
||||
_pwm_pulse_min = SERVO_MIN_PULSE;
|
||||
_pwm_pulse_max = SERVO_MAX_PULSE;
|
||||
|
||||
if (bit_istrue(dir_invert_mask->get(), bit(axis_index))) { // normal direction
|
||||
_cal_min = 2.0 - (axis_settings[axis_index]->steps_per_mm->get() / 100.0);
|
||||
_cal_max = 2.0 - (axis_settings[axis_index]->max_travel->get() / 100.0);
|
||||
swap(_pwm_pulse_min, _pwm_pulse_max);
|
||||
} else { // inverted direction
|
||||
_cal_min = (axis_settings[axis_index]->steps_per_mm->get() / 100.0);
|
||||
_cal_max = (axis_settings[axis_index]->max_travel->get() / 100.0);
|
||||
}
|
||||
|
||||
_pwm_pulse_min *= _cal_min;
|
||||
_pwm_pulse_max *= _cal_max;
|
||||
|
||||
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Servo calibration min:%1.2f max %1.2f", _pwm_pulse_min, _pwm_pulse_max);
|
||||
}
|
||||
}
|
55
Grbl_Esp32/src/Motors/RcServo.h
Normal file
55
Grbl_Esp32/src/Motors/RcServo.h
Normal file
@@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
RcServo.h
|
||||
|
||||
Part of Grbl_ESP32
|
||||
|
||||
2020 - Bart Dring
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Motor.h"
|
||||
|
||||
#include "RcServoSettings.h"
|
||||
|
||||
namespace Motors {
|
||||
class RcServo : public Motor {
|
||||
public:
|
||||
RcServo();
|
||||
RcServo(uint8_t axis_index, uint8_t pwm_pin, float min, float max);
|
||||
virtual void config_message();
|
||||
virtual void init();
|
||||
void _write_pwm(uint32_t duty);
|
||||
virtual void set_disable(bool disable);
|
||||
virtual void update();
|
||||
void read_settings();
|
||||
void set_homing_mode(bool is_homing, bool isHoming);
|
||||
|
||||
protected:
|
||||
void set_location();
|
||||
void _get_calibration();
|
||||
|
||||
uint8_t _pwm_pin;
|
||||
uint8_t _channel_num;
|
||||
uint32_t _current_pwm_duty;
|
||||
bool _disabled;
|
||||
|
||||
float _position_min;
|
||||
float _position_max; // position in millimeters
|
||||
float _homing_position;
|
||||
|
||||
float _pwm_pulse_min;
|
||||
float _pwm_pulse_max;
|
||||
};
|
||||
}
|
26
Grbl_Esp32/src/Motors/RcServoSettings.h
Normal file
26
Grbl_Esp32/src/Motors/RcServoSettings.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
// this is the pulse range of a the servo. Typical servos are 0.001 to 0.002 seconds
|
||||
// some servos have a wider range. You can adjust this here or in the calibration feature
|
||||
#define SERVO_MIN_PULSE_SEC 0.001 // min pulse in seconds
|
||||
#define SERVO_MAX_PULSE_SEC 0.002 // max pulse in seconds
|
||||
|
||||
#define SERVO_POSITION_MIN_DEFAULT 0.0 // mm
|
||||
#define SERVO_POSITION_MAX_DEFAULT 20.0 // mm
|
||||
|
||||
#define SERVO_PULSE_FREQ 50 // 50Hz ...This is a standard analog servo value. Digital ones can repeat faster
|
||||
|
||||
#define SERVO_PULSE_RES_BITS 16 // bits of resolution of PWM (16 is max)
|
||||
#define SERVO_PULSE_RES_COUNT 65535 // see above TODO...do the math here 2^SERVO_PULSE_RES_BITS
|
||||
|
||||
#define SERVO_TIME_PER_BIT ((1.0 / (float)SERVO_PULSE_FREQ) / ((float)SERVO_PULSE_RES_COUNT)) // seconds
|
||||
|
||||
#define SERVO_MIN_PULSE (uint16_t)(SERVO_MIN_PULSE_SEC / SERVO_TIME_PER_BIT) // in timer counts
|
||||
#define SERVO_MAX_PULSE (uint16_t)(SERVO_MAX_PULSE_SEC / SERVO_TIME_PER_BIT) // in timer counts
|
||||
|
||||
#define SERVO_PULSE_RANGE (SERVO_MAX_PULSE - SERVO_MIN_PULSE)
|
||||
|
||||
#define SERVO_CAL_MIN 20.0 // Percent: the minimum allowable calibration value
|
||||
#define SERVO_CAL_MAX 180.0 // Percent: the maximum allowable calibration value
|
||||
|
||||
#define SERVO_TIMER_INT_FREQ 50.0 // Hz This is the task frequency
|
18
Grbl_Esp32/src/Motors/Solenoid.h
Normal file
18
Grbl_Esp32/src/Motors/Solenoid.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include "RcServo.h"
|
||||
|
||||
namespace Motors {
|
||||
class Solenoid : public RcServo {
|
||||
public:
|
||||
Solenoid();
|
||||
Solenoid(uint8_t axis_index, gpio_num_t pwm_pin, float transition_poiont);
|
||||
void config_message();
|
||||
void set_location();
|
||||
void update();
|
||||
void init();
|
||||
void set_disable(bool disable);
|
||||
|
||||
float _transition_poiont;
|
||||
};
|
||||
}
|
103
Grbl_Esp32/src/Motors/StandardStepper.cpp
Normal file
103
Grbl_Esp32/src/Motors/StandardStepper.cpp
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
StandardStepper.cpp
|
||||
|
||||
This is used for a stepper motor that just requires step and direction
|
||||
pins.
|
||||
TODO: Add an enable pin
|
||||
|
||||
Part of Grbl_ESP32
|
||||
|
||||
2020 - Bart Dring
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "StandardStepper.h"
|
||||
|
||||
namespace Motors {
|
||||
StandardStepper::StandardStepper() {}
|
||||
|
||||
StandardStepper::StandardStepper(uint8_t axis_index, uint8_t step_pin, uint8_t dir_pin, uint8_t disable_pin) {
|
||||
type_id = STANDARD_MOTOR;
|
||||
this->axis_index = axis_index % MAX_AXES;
|
||||
this->dual_axis_index = axis_index < MAX_AXES ? 0 : 1; // 0 = primary 1 = ganged
|
||||
this->step_pin = step_pin;
|
||||
this->dir_pin = dir_pin;
|
||||
this->disable_pin = disable_pin;
|
||||
init();
|
||||
}
|
||||
|
||||
void StandardStepper::init() {
|
||||
_homing_mask = 0;
|
||||
is_active = true; // as opposed to NullMotors, this is a real motor
|
||||
set_axis_name();
|
||||
init_step_dir_pins();
|
||||
config_message();
|
||||
}
|
||||
|
||||
void StandardStepper::init_step_dir_pins() {
|
||||
// TODO Step pin, but RMT complicates things
|
||||
_invert_step_pin = bit_istrue(step_invert_mask->get(), bit(axis_index));
|
||||
pinMode(dir_pin, OUTPUT);
|
||||
|
||||
#ifdef USE_RMT_STEPS
|
||||
rmtConfig.rmt_mode = RMT_MODE_TX;
|
||||
rmtConfig.clk_div = 20;
|
||||
rmtConfig.mem_block_num = 2;
|
||||
rmtConfig.tx_config.loop_en = false;
|
||||
rmtConfig.tx_config.carrier_en = false;
|
||||
rmtConfig.tx_config.carrier_freq_hz = 0;
|
||||
rmtConfig.tx_config.carrier_duty_percent = 50;
|
||||
rmtConfig.tx_config.carrier_level = RMT_CARRIER_LEVEL_LOW;
|
||||
rmtConfig.tx_config.idle_output_en = true;
|
||||
|
||||
# ifdef STEP_PULSE_DELAY
|
||||
rmtItem[0].duration0 = STEP_PULSE_DELAY * 4;
|
||||
# else
|
||||
rmtItem[0].duration0 = 1;
|
||||
# endif
|
||||
|
||||
rmtItem[0].duration1 = 4 * pulse_microseconds->get();
|
||||
rmtItem[1].duration0 = 0;
|
||||
rmtItem[1].duration1 = 0;
|
||||
|
||||
rmt_chan_num[axis_index][dual_axis_index] = sys_get_next_RMT_chan_num();
|
||||
rmt_set_source_clk((rmt_channel_t)rmt_chan_num[axis_index][dual_axis_index], RMT_BASECLK_APB);
|
||||
rmtConfig.channel = (rmt_channel_t)rmt_chan_num[axis_index][dual_axis_index];
|
||||
rmtConfig.tx_config.idle_level = _invert_step_pin ? RMT_IDLE_LEVEL_HIGH : RMT_IDLE_LEVEL_LOW;
|
||||
rmtConfig.gpio_num = gpio_num_t(step_pin); // c is a wacky lang
|
||||
rmtItem[0].level0 = rmtConfig.tx_config.idle_level;
|
||||
rmtItem[0].level1 = !rmtConfig.tx_config.idle_level;
|
||||
rmt_config(&rmtConfig);
|
||||
rmt_fill_tx_items(rmtConfig.channel, &rmtItem[0], rmtConfig.mem_block_num, 0);
|
||||
|
||||
#else
|
||||
pinMode(step_pin, OUTPUT);
|
||||
|
||||
#endif // USE_RMT_STEPS
|
||||
pinMode(disable_pin, OUTPUT);
|
||||
}
|
||||
|
||||
void StandardStepper::config_message() {
|
||||
grbl_msg_sendf(CLIENT_SERIAL,
|
||||
MSG_LEVEL_INFO,
|
||||
"%s Axis standard stepper motor Step:%s Dir:%s Disable:%s",
|
||||
_axis_name,
|
||||
pinName(step_pin).c_str(),
|
||||
pinName(dir_pin).c_str(),
|
||||
pinName(disable_pin).c_str());
|
||||
}
|
||||
|
||||
void StandardStepper::set_direction_pins(uint8_t onMask) { digitalWrite(dir_pin, (onMask & bit(axis_index))); }
|
||||
|
||||
void StandardStepper::set_disable(bool disable) { digitalWrite(disable_pin, disable); }
|
||||
}
|
23
Grbl_Esp32/src/Motors/StandardStepper.h
Normal file
23
Grbl_Esp32/src/Motors/StandardStepper.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include "Motor.h"
|
||||
|
||||
namespace Motors {
|
||||
class StandardStepper : public Motor {
|
||||
public:
|
||||
StandardStepper();
|
||||
StandardStepper(uint8_t axis_index, uint8_t step_pin, uint8_t dir_pin, uint8_t disable_pin);
|
||||
|
||||
virtual void config_message();
|
||||
virtual void init();
|
||||
virtual void set_direction_pins(uint8_t onMask);
|
||||
void init_step_dir_pins();
|
||||
virtual void set_disable(bool disable);
|
||||
uint8_t step_pin;
|
||||
|
||||
protected:
|
||||
bool _invert_step_pin;
|
||||
uint8_t dir_pin;
|
||||
uint8_t disable_pin;
|
||||
};
|
||||
}
|
235
Grbl_Esp32/src/Motors/TrinamicDriver.cpp
Normal file
235
Grbl_Esp32/src/Motors/TrinamicDriver.cpp
Normal file
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
TrinamicDriver.cpp
|
||||
This is used for Trinamic SPI controlled stepper motor drivers.
|
||||
|
||||
Part of Grbl_ESP32
|
||||
2020 - Bart Dring
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
#include "TrinamicDriver.h"
|
||||
|
||||
#include <TMCStepper.h>
|
||||
|
||||
namespace Motors {
|
||||
TrinamicDriver::TrinamicDriver(uint8_t axis_index,
|
||||
uint8_t step_pin,
|
||||
uint8_t dir_pin,
|
||||
uint8_t disable_pin,
|
||||
uint8_t cs_pin,
|
||||
uint16_t driver_part_number,
|
||||
float r_sense,
|
||||
int8_t spi_index) {
|
||||
type_id = TRINAMIC_SPI_MOTOR;
|
||||
this->axis_index = axis_index % MAX_AXES;
|
||||
this->dual_axis_index = axis_index < 6 ? 0 : 1; // 0 = primary 1 = ganged
|
||||
_driver_part_number = driver_part_number;
|
||||
_r_sense = r_sense;
|
||||
this->step_pin = step_pin;
|
||||
this->dir_pin = dir_pin;
|
||||
this->disable_pin = disable_pin;
|
||||
this->cs_pin = cs_pin;
|
||||
this->spi_index = spi_index;
|
||||
|
||||
_homing_mode = TRINAMIC_HOMING_MODE;
|
||||
_homing_mask = 0; // no axes homing
|
||||
|
||||
if (_driver_part_number == 2130)
|
||||
tmcstepper = new TMC2130Stepper(cs_pin, _r_sense, spi_index);
|
||||
else if (_driver_part_number == 5160)
|
||||
tmcstepper = new TMC5160Stepper(cs_pin, _r_sense, spi_index);
|
||||
else {
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Trinamic unsupported p/n:%d", _driver_part_number);
|
||||
return;
|
||||
}
|
||||
|
||||
set_axis_name();
|
||||
|
||||
init_step_dir_pins(); // from StandardStepper
|
||||
|
||||
digitalWrite(cs_pin, HIGH);
|
||||
pinMode(cs_pin, OUTPUT);
|
||||
|
||||
// use slower speed if I2S
|
||||
if (cs_pin >= I2S_OUT_PIN_BASE)
|
||||
tmcstepper->setSPISpeed(TRINAMIC_SPI_FREQ);
|
||||
|
||||
config_message();
|
||||
|
||||
// init() must be called later, after all TMC drivers have CS pins setup.
|
||||
}
|
||||
|
||||
void TrinamicDriver::init() {
|
||||
SPI.begin(); // this will get called for each motor, but does not seem to hurt anything
|
||||
|
||||
tmcstepper->begin();
|
||||
test(); // Try communicating with motor. Prints an error if there is a problem.
|
||||
read_settings(); // pull info from settings
|
||||
set_mode(false);
|
||||
|
||||
_homing_mask = 0;
|
||||
is_active = true; // as opposed to NullMotors, this is a real motor
|
||||
}
|
||||
|
||||
/*
|
||||
This is the startup message showing the basic definition
|
||||
*/
|
||||
void TrinamicDriver::config_message() {
|
||||
grbl_msg_sendf(CLIENT_SERIAL,
|
||||
MSG_LEVEL_INFO,
|
||||
"%s Axis Trinamic TMC%d Step:%s Dir:%s CS:%s Disable:%s Index:%d",
|
||||
_axis_name,
|
||||
_driver_part_number,
|
||||
pinName(step_pin).c_str(),
|
||||
pinName(dir_pin).c_str(),
|
||||
pinName(cs_pin).c_str(),
|
||||
pinName(disable_pin).c_str(),
|
||||
spi_index);
|
||||
}
|
||||
|
||||
bool TrinamicDriver::test() {
|
||||
switch (tmcstepper->test_connection()) {
|
||||
case 1:
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "%s Trinamic driver test failed. Check connection", _axis_name);
|
||||
return false;
|
||||
case 2:
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "%s Trinamic driver test failed. Check motor power", _axis_name);
|
||||
return false;
|
||||
default: grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "%s Trinamic driver test passed", _axis_name); return true;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Read setting and send them to the driver. Called at init() and whenever related settings change
|
||||
both are stored as float Amps, but TMCStepper library expects...
|
||||
uint16_t run (mA)
|
||||
float hold (as a percentage of run)
|
||||
*/
|
||||
void TrinamicDriver::read_settings() {
|
||||
uint16_t run_i_ma = (uint16_t)(axis_settings[axis_index]->run_current->get() * 1000.0);
|
||||
float hold_i_percent;
|
||||
|
||||
if (axis_settings[axis_index]->run_current->get() == 0)
|
||||
hold_i_percent = 0;
|
||||
else {
|
||||
hold_i_percent = axis_settings[axis_index]->hold_current->get() / axis_settings[axis_index]->run_current->get();
|
||||
if (hold_i_percent > 1.0)
|
||||
hold_i_percent = 1.0;
|
||||
}
|
||||
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "%s Current run %d hold %f", _axis_name, run_i_ma, hold_i_percent);
|
||||
|
||||
tmcstepper->microsteps(axis_settings[axis_index]->microsteps->get());
|
||||
tmcstepper->rms_current(run_i_ma, hold_i_percent);
|
||||
}
|
||||
|
||||
void TrinamicDriver::set_homing_mode(uint8_t homing_mask, bool isHoming) {
|
||||
_homing_mask = homing_mask;
|
||||
set_mode(isHoming);
|
||||
}
|
||||
|
||||
/*
|
||||
There are ton of settings. I'll start by grouping then into modes for now.
|
||||
Many people will want quiet and stallgaurd homing. Stallguard only run in
|
||||
Coolstep mode, so it will need to switch to Coolstep when homing
|
||||
*/
|
||||
void TrinamicDriver::set_mode(bool isHoming) {
|
||||
if (isHoming)
|
||||
_mode = TRINAMIC_HOMING_MODE;
|
||||
else
|
||||
_mode = TRINAMIC_RUN_MODE;
|
||||
|
||||
if (_lastMode == _mode)
|
||||
return;
|
||||
_lastMode = _mode;
|
||||
|
||||
switch (_mode) {
|
||||
case TRINAMIC_MODE_STEALTHCHOP:
|
||||
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "TRINAMIC_MODE_STEALTHCHOP");
|
||||
tmcstepper->en_pwm_mode(true);
|
||||
tmcstepper->pwm_autoscale(true);
|
||||
tmcstepper->diag1_stall(false);
|
||||
break;
|
||||
case TRINAMIC_MODE_COOLSTEP:
|
||||
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "TRINAMIC_MODE_COOLSTEP");
|
||||
tmcstepper->en_pwm_mode(false);
|
||||
tmcstepper->pwm_autoscale(false);
|
||||
tmcstepper->TCOOLTHRS(NORMAL_TCOOLTHRS); // when to turn on coolstep
|
||||
tmcstepper->THIGH(NORMAL_THIGH);
|
||||
break;
|
||||
case TRINAMIC_MODE_STALLGUARD:
|
||||
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "TRINAMIC_MODE_STALLGUARD");
|
||||
tmcstepper->en_pwm_mode(false);
|
||||
tmcstepper->pwm_autoscale(false);
|
||||
tmcstepper->TCOOLTHRS(calc_tstep(homing_feed_rate->get(), 150.0));
|
||||
tmcstepper->THIGH(calc_tstep(homing_feed_rate->get(), 60.0));
|
||||
tmcstepper->sfilt(1);
|
||||
tmcstepper->diag1_stall(true); // stallguard i/o is on diag1
|
||||
tmcstepper->sgt(axis_settings[axis_index]->stallguard->get());
|
||||
break;
|
||||
default: grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "TRINAMIC_MODE_UNDEFINED");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
This is the stallguard tuning info. It is call debug, so it could be generic across all classes.
|
||||
*/
|
||||
void TrinamicDriver::debug_message() {
|
||||
uint32_t tstep = tmcstepper->TSTEP();
|
||||
|
||||
if (tstep == 0xFFFFF || tstep < 1) // if axis is not moving return
|
||||
return;
|
||||
float feedrate = st_get_realtime_rate(); //* settings.microsteps[axis_index] / 60.0 ; // convert mm/min to Hz
|
||||
|
||||
grbl_msg_sendf(CLIENT_SERIAL,
|
||||
MSG_LEVEL_INFO,
|
||||
"%s Stallguard %d SG_Val: %04d Rate: %05.0f mm/min SG_Setting:%d",
|
||||
_axis_name,
|
||||
tmcstepper->stallguard(),
|
||||
tmcstepper->sg_result(),
|
||||
feedrate,
|
||||
axis_settings[axis_index]->stallguard->get());
|
||||
}
|
||||
|
||||
// calculate a tstep from a rate
|
||||
// tstep = TRINAMIC_FCLK / (time between 1/256 steps)
|
||||
// This is used to set the stallguard window from the homing speed.
|
||||
// The percent is the offset on the window
|
||||
uint32_t TrinamicDriver::calc_tstep(float speed, float percent) {
|
||||
float tstep =
|
||||
speed / 60.0 * axis_settings[axis_index]->steps_per_mm->get() * (float)(256 / axis_settings[axis_index]->microsteps->get());
|
||||
tstep = TRINAMIC_FCLK / tstep * percent / 100.0;
|
||||
|
||||
return (uint32_t)tstep;
|
||||
}
|
||||
|
||||
// this can use the enable feature over SPI. The dedicated pin must be in the enable mode,
|
||||
// but that can be hardwired that way.
|
||||
void TrinamicDriver::set_disable(bool disable) {
|
||||
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "%s Axis disable %d", _axis_name, disable);
|
||||
|
||||
digitalWrite(disable_pin, disable);
|
||||
|
||||
#ifdef USE_TRINAMIC_ENABLE
|
||||
if (disable)
|
||||
tmcstepper->toff(TRINAMIC_TOFF_DISABLE);
|
||||
else {
|
||||
if (_mode == TRINAMIC_MODE_STEALTHCHOP)
|
||||
tmcstepper->toff(TRINAMIC_TOFF_STEALTHCHOP);
|
||||
else
|
||||
tmcstepper->toff(TRINAMIC_TOFF_COOLSTEP);
|
||||
}
|
||||
#endif
|
||||
// the pin based enable could be added here.
|
||||
// This would be for individual motors, not the single pin for all motors.
|
||||
}
|
||||
}
|
98
Grbl_Esp32/src/Motors/TrinamicDriver.h
Normal file
98
Grbl_Esp32/src/Motors/TrinamicDriver.h
Normal file
@@ -0,0 +1,98 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
TrinamicDriver.h
|
||||
|
||||
Part of Grbl_ESP32
|
||||
|
||||
2020 - Bart Dring
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Motor.h"
|
||||
#include "StandardStepper.h"
|
||||
#include <TMCStepper.h> // https://github.com/teemuatlut/TMCStepper
|
||||
|
||||
#define TRINAMIC_MODE_STEALTHCHOP 0 // very quiet
|
||||
#define TRINAMIC_MODE_COOLSTEP 1 // everything runs cooler so higher current possible
|
||||
#define TRINAMIC_MODE_STALLGUARD 2 // coolstep plus generates stall indication
|
||||
|
||||
#define NORMAL_TCOOLTHRS 0xFFFFF // 20 bit is max
|
||||
#define NORMAL_THIGH 0
|
||||
|
||||
#define TMC2130_RSENSE_DEFAULT 0.11f
|
||||
#define TMC5160_RSENSE_DEFAULT 0.075f
|
||||
|
||||
#define TRINAMIC_SPI_FREQ 100000
|
||||
|
||||
#define TRINAMIC_FCLK 12700000.0 // Internal clock Approx (Hz) used to calculate TSTEP from homing rate
|
||||
|
||||
// ==== defaults OK to define them in your machine definition ====
|
||||
#ifndef TRINAMIC_RUN_MODE
|
||||
# define TRINAMIC_RUN_MODE TRINAMIC_MODE_COOLSTEP
|
||||
#endif
|
||||
|
||||
#ifndef TRINAMIC_HOMING_MODE
|
||||
# define TRINAMIC_HOMING_MODE TRINAMIC_RUN_MODE
|
||||
#endif
|
||||
|
||||
#ifndef TRINAMIC_TOFF_DISABLE
|
||||
# define TRINAMIC_TOFF_DISABLE 0
|
||||
#endif
|
||||
|
||||
#ifndef TRINAMIC_TOFF_STEALTHCHOP
|
||||
# define TRINAMIC_TOFF_STEALTHCHOP 5
|
||||
#endif
|
||||
|
||||
#ifndef TRINAMIC_TOFF_COOLSTEP
|
||||
# define TRINAMIC_TOFF_COOLSTEP 3
|
||||
#endif
|
||||
|
||||
namespace Motors {
|
||||
class TrinamicDriver : public StandardStepper {
|
||||
public:
|
||||
TrinamicDriver(uint8_t axis_index,
|
||||
uint8_t step_pin,
|
||||
uint8_t dir_pin,
|
||||
uint8_t disable_pin,
|
||||
uint8_t cs_pin,
|
||||
uint16_t driver_part_number,
|
||||
float r_sense,
|
||||
int8_t spi_index);
|
||||
|
||||
void config_message();
|
||||
void init();
|
||||
void set_mode(bool isHoming);
|
||||
void read_settings();
|
||||
void trinamic_test_response();
|
||||
void trinamic_stepper_enable(bool enable);
|
||||
void debug_message();
|
||||
void set_homing_mode(uint8_t homing_mask, bool ishoming);
|
||||
void set_disable(bool disable);
|
||||
bool test();
|
||||
|
||||
private:
|
||||
uint32_t calc_tstep(float speed, float percent);
|
||||
|
||||
TMC2130Stepper* tmcstepper; // all other driver types are subclasses of this one
|
||||
uint8_t _homing_mode;
|
||||
uint8_t cs_pin = UNDEFINED_PIN; // The chip select pin (can be the same for daisy chain)
|
||||
uint16_t _driver_part_number; // example: use 2130 for TMC2130
|
||||
float _r_sense;
|
||||
int8_t spi_index;
|
||||
|
||||
protected:
|
||||
uint8_t _mode;
|
||||
uint8_t _lastMode = 255;
|
||||
};
|
||||
}
|
139
Grbl_Esp32/src/Motors/UnipolarMotor.cpp
Normal file
139
Grbl_Esp32/src/Motors/UnipolarMotor.cpp
Normal file
@@ -0,0 +1,139 @@
|
||||
#include "UnipolarMotor.h"
|
||||
|
||||
namespace Motors {
|
||||
UnipolarMotor::UnipolarMotor() {}
|
||||
|
||||
UnipolarMotor::UnipolarMotor(uint8_t axis_index, uint8_t pin_phase0, uint8_t pin_phase1, uint8_t pin_phase2, uint8_t pin_phase3) {
|
||||
type_id = UNIPOLAR_MOTOR;
|
||||
this->axis_index = axis_index % MAX_AXES;
|
||||
this->dual_axis_index = axis_index < MAX_AXES ? 0 : 1; // 0 = primary 1 = ganged
|
||||
_pin_phase0 = pin_phase0;
|
||||
_pin_phase1 = pin_phase1;
|
||||
_pin_phase2 = pin_phase2;
|
||||
_pin_phase3 = pin_phase3;
|
||||
|
||||
_half_step = true; // TODO read from settings ... microstep > 1 = half step
|
||||
|
||||
set_axis_name();
|
||||
init();
|
||||
config_message();
|
||||
}
|
||||
|
||||
void UnipolarMotor::init() {
|
||||
pinMode(_pin_phase0, OUTPUT);
|
||||
pinMode(_pin_phase1, OUTPUT);
|
||||
pinMode(_pin_phase2, OUTPUT);
|
||||
pinMode(_pin_phase3, OUTPUT);
|
||||
_current_phase = 0;
|
||||
}
|
||||
|
||||
void UnipolarMotor::config_message() {
|
||||
grbl_msg_sendf(CLIENT_SERIAL,
|
||||
MSG_LEVEL_INFO,
|
||||
"%s Axis unipolar stepper motor Ph0:%s Ph1:%s Ph2:%s Ph3:%s",
|
||||
_axis_name,
|
||||
pinName(_pin_phase0).c_str(),
|
||||
pinName(_pin_phase1).c_str(),
|
||||
pinName(_pin_phase2).c_str(),
|
||||
pinName(_pin_phase3).c_str());
|
||||
}
|
||||
|
||||
void UnipolarMotor::set_disable(bool disable) {
|
||||
if (disable) {
|
||||
digitalWrite(_pin_phase0, 0);
|
||||
digitalWrite(_pin_phase1, 0);
|
||||
digitalWrite(_pin_phase2, 0);
|
||||
digitalWrite(_pin_phase3, 0);
|
||||
}
|
||||
_enabled = !disable;
|
||||
}
|
||||
|
||||
void UnipolarMotor::step(uint8_t step_mask, uint8_t dir_mask) {
|
||||
uint8_t _phase[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; // temporary phase values...all start as off
|
||||
uint8_t phase_max;
|
||||
|
||||
if (!(step_mask & bit(axis_index)))
|
||||
return; // a step is not required on this interrupt
|
||||
|
||||
if (!_enabled)
|
||||
return; // don't do anything, phase is not changed or lost
|
||||
|
||||
if (_half_step)
|
||||
phase_max = 7;
|
||||
else
|
||||
phase_max = 3;
|
||||
|
||||
if (dir_mask & bit(axis_index)) { // count up
|
||||
if (_current_phase == phase_max)
|
||||
_current_phase = 0;
|
||||
else
|
||||
_current_phase++;
|
||||
} else { // count down
|
||||
if (_current_phase == 0)
|
||||
_current_phase = phase_max;
|
||||
else
|
||||
_current_phase--;
|
||||
}
|
||||
/*
|
||||
8 Step : A – AB – B – BC – C – CD – D – DA
|
||||
4 Step : AB – BC – CD – DA
|
||||
|
||||
Step IN4 IN3 IN2 IN1
|
||||
A 0 0 0 1
|
||||
AB 0 0 1 1
|
||||
B 0 0 1 0
|
||||
BC 0 1 1 0
|
||||
C 0 1 0 0
|
||||
CD 1 1 0 0
|
||||
D 1 0 0 0
|
||||
DA 1 0 0 1
|
||||
*/
|
||||
if (_half_step) {
|
||||
switch (_current_phase) {
|
||||
case 0: _phase[0] = 1; break;
|
||||
case 1:
|
||||
_phase[0] = 1;
|
||||
_phase[1] = 1;
|
||||
break;
|
||||
case 2: _phase[1] = 1; break;
|
||||
case 3:
|
||||
_phase[1] = 1;
|
||||
_phase[2] = 1;
|
||||
break;
|
||||
case 4: _phase[2] = 1; break;
|
||||
case 5:
|
||||
_phase[2] = 1;
|
||||
_phase[3] = 1;
|
||||
break;
|
||||
case 6: _phase[3] = 1; break;
|
||||
case 7:
|
||||
_phase[3] = 1;
|
||||
_phase[0] = 1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (_current_phase) {
|
||||
case 0:
|
||||
_phase[0] = 1;
|
||||
_phase[1] = 1;
|
||||
break;
|
||||
case 1:
|
||||
_phase[1] = 1;
|
||||
_phase[2] = 1;
|
||||
break;
|
||||
case 2:
|
||||
_phase[2] = 1;
|
||||
_phase[3] = 1;
|
||||
break;
|
||||
case 3:
|
||||
_phase[3] = 1;
|
||||
_phase[0] = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
digitalWrite(_pin_phase0, _phase[0]);
|
||||
digitalWrite(_pin_phase1, _phase[1]);
|
||||
digitalWrite(_pin_phase2, _phase[2]);
|
||||
digitalWrite(_pin_phase3, _phase[3]);
|
||||
}
|
||||
}
|
24
Grbl_Esp32/src/Motors/UnipolarMotor.h
Normal file
24
Grbl_Esp32/src/Motors/UnipolarMotor.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include "Motor.h"
|
||||
|
||||
namespace Motors {
|
||||
class UnipolarMotor : public Motor {
|
||||
public:
|
||||
UnipolarMotor();
|
||||
UnipolarMotor(uint8_t axis_index, uint8_t pin_phase0, uint8_t pin_phase1, uint8_t pin_phase2, uint8_t pin_phase3);
|
||||
void init();
|
||||
void config_message();
|
||||
void set_disable(bool disable);
|
||||
void step(uint8_t step_mask, uint8_t dir_mask); // only used on Unipolar right now
|
||||
|
||||
private:
|
||||
uint8_t _pin_phase0;
|
||||
uint8_t _pin_phase1;
|
||||
uint8_t _pin_phase2;
|
||||
uint8_t _pin_phase3;
|
||||
uint8_t _current_phase;
|
||||
bool _half_step;
|
||||
bool _enabled;
|
||||
};
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
nuts_bolts.c - Shared functions
|
||||
NutsBolts.cpp - Shared functions
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
@@ -22,12 +22,9 @@
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "grbl.h"
|
||||
#include "Grbl.h"
|
||||
|
||||
|
||||
|
||||
|
||||
#define MAX_INT_DIGITS 8 // Maximum number of digits in int32 (and float)
|
||||
#define MAX_INT_DIGITS 8 // Maximum number of digits in int32 (and float)
|
||||
|
||||
// Extracts a floating point value from a string. The following code is based loosely on
|
||||
// the avr-libc strtod() function by Michael Stumpf and Dmitry Xmelkov and many freely
|
||||
@@ -37,7 +34,7 @@
|
||||
// be a g-code word on some CNC systems. So, 'E' notation will not be recognized.
|
||||
// NOTE: Thanks to Radu-Eosif Mihailescu for identifying the issues with using strtod().
|
||||
uint8_t read_float(const char* line, uint8_t* char_counter, float* float_ptr) {
|
||||
const char* ptr = line + *char_counter;
|
||||
const char* ptr = line + *char_counter;
|
||||
unsigned char c;
|
||||
// Grab first character and increment pointer. No spaces assumed in line.
|
||||
c = *ptr++;
|
||||
@@ -45,32 +42,36 @@ uint8_t read_float(const char* line, uint8_t* char_counter, float* float_ptr) {
|
||||
bool isnegative = false;
|
||||
if (c == '-') {
|
||||
isnegative = true;
|
||||
c = *ptr++;
|
||||
c = *ptr++;
|
||||
} else if (c == '+')
|
||||
c = *ptr++;
|
||||
// Extract number into fast integer. Track decimal in terms of exponent value.
|
||||
uint32_t intval = 0;
|
||||
int8_t exp = 0;
|
||||
uint8_t ndigit = 0;
|
||||
bool isdecimal = false;
|
||||
uint32_t intval = 0;
|
||||
int8_t exp = 0;
|
||||
uint8_t ndigit = 0;
|
||||
bool isdecimal = false;
|
||||
while (1) {
|
||||
c -= '0';
|
||||
if (c <= 9) {
|
||||
ndigit++;
|
||||
if (ndigit <= MAX_INT_DIGITS) {
|
||||
if (isdecimal) exp--;
|
||||
intval = (((intval << 2) + intval) << 1) + c; // intval*10 + c
|
||||
if (isdecimal)
|
||||
exp--;
|
||||
intval = (((intval << 2) + intval) << 1) + c; // intval*10 + c
|
||||
} else {
|
||||
if (!(isdecimal)) exp++; // Drop overflow digits
|
||||
if (!(isdecimal))
|
||||
exp++; // Drop overflow digits
|
||||
}
|
||||
} else if (c == (('.' - '0') & 0xff) && !(isdecimal))
|
||||
} else if (c == (('.' - '0') & 0xff) && !(isdecimal))
|
||||
isdecimal = true;
|
||||
else
|
||||
break;
|
||||
c = *ptr++;
|
||||
}
|
||||
// Return if no digits have been read.
|
||||
if (!ndigit) return (false); ;
|
||||
if (!ndigit)
|
||||
return (false);
|
||||
;
|
||||
// Convert integer into floating point.
|
||||
float fval;
|
||||
fval = (float)intval;
|
||||
@@ -94,7 +95,7 @@ uint8_t read_float(const char* line, uint8_t* char_counter, float* float_ptr) {
|
||||
*float_ptr = -fval;
|
||||
else
|
||||
*float_ptr = fval;
|
||||
*char_counter = ptr - line - 1; // Set char_counter to next statement
|
||||
*char_counter = ptr - line - 1; // Set char_counter to next statement
|
||||
return (true);
|
||||
}
|
||||
|
||||
@@ -106,40 +107,44 @@ void delay_ms(uint16_t ms) {
|
||||
void delay_sec(float seconds, uint8_t mode) {
|
||||
uint16_t i = ceil(1000 / DWELL_TIME_STEP * seconds);
|
||||
while (i-- > 0) {
|
||||
if (sys.abort) return;
|
||||
if (sys.abort)
|
||||
return;
|
||||
if (mode == DELAY_MODE_DWELL)
|
||||
protocol_execute_realtime();
|
||||
else { // DELAY_MODE_SYS_SUSPEND
|
||||
else { // DELAY_MODE_SYS_SUSPEND
|
||||
// Execute rt_system() only to avoid nesting suspend loops.
|
||||
protocol_exec_rt_system();
|
||||
if (sys.suspend & SUSPEND_RESTART_RETRACT) return; // Bail, if safety door reopens.
|
||||
if (sys.suspend & SUSPEND_RESTART_RETRACT)
|
||||
return; // Bail, if safety door reopens.
|
||||
}
|
||||
delay(DWELL_TIME_STEP); // Delay DWELL_TIME_STEP increment
|
||||
delay(DWELL_TIME_STEP); // Delay DWELL_TIME_STEP increment
|
||||
}
|
||||
}
|
||||
|
||||
// Simple hypotenuse computation function.
|
||||
float hypot_f(float x, float y) { return (sqrt(x * x + y * y)); }
|
||||
|
||||
float hypot_f(float x, float y) {
|
||||
return (sqrt(x * x + y * y));
|
||||
}
|
||||
|
||||
float convert_delta_vector_to_unit_vector(float* vector) {
|
||||
uint8_t idx;
|
||||
float magnitude = 0.0;
|
||||
float magnitude = 0.0;
|
||||
for (idx = 0; idx < N_AXIS; idx++) {
|
||||
if (vector[idx] != 0.0)
|
||||
magnitude += vector[idx] * vector[idx];
|
||||
}
|
||||
magnitude = sqrt(magnitude);
|
||||
magnitude = sqrt(magnitude);
|
||||
float inv_magnitude = 1.0 / magnitude;
|
||||
for (idx = 0; idx < N_AXIS; idx++) vector[idx] *= inv_magnitude;
|
||||
for (idx = 0; idx < N_AXIS; idx++)
|
||||
vector[idx] *= inv_magnitude;
|
||||
return (magnitude);
|
||||
}
|
||||
|
||||
float limit_acceleration_by_axis_maximum(float* unit_vec) {
|
||||
uint8_t idx;
|
||||
float limit_value = SOME_LARGE_VALUE;
|
||||
float limit_value = SOME_LARGE_VALUE;
|
||||
for (idx = 0; idx < N_AXIS; idx++) {
|
||||
if (unit_vec[idx] != 0) // Avoid divide by zero.
|
||||
if (unit_vec[idx] != 0) // Avoid divide by zero.
|
||||
limit_value = MIN(limit_value, fabs(axis_settings[idx]->acceleration->get() / unit_vec[idx]));
|
||||
}
|
||||
// The acceleration setting is stored and displayed in units of mm/sec^2,
|
||||
@@ -151,15 +156,15 @@ float limit_acceleration_by_axis_maximum(float* unit_vec) {
|
||||
|
||||
float limit_rate_by_axis_maximum(float* unit_vec) {
|
||||
uint8_t idx;
|
||||
float limit_value = SOME_LARGE_VALUE;
|
||||
float limit_value = SOME_LARGE_VALUE;
|
||||
for (idx = 0; idx < N_AXIS; idx++) {
|
||||
if (unit_vec[idx] != 0) // Avoid divide by zero.
|
||||
if (unit_vec[idx] != 0) // Avoid divide by zero.
|
||||
limit_value = MIN(limit_value, fabs(axis_settings[idx]->max_rate->get() / unit_vec[idx]));
|
||||
}
|
||||
return (limit_value);
|
||||
}
|
||||
|
||||
float map_float(float x, float in_min, float in_max, float out_min, float out_max) { // DrawBot_Badge
|
||||
float map_float(float x, float in_min, float in_max, float out_min, float out_max) { // DrawBot_Badge
|
||||
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
||||
}
|
||||
|
||||
@@ -167,7 +172,7 @@ uint32_t map_uint32_t(uint32_t x, uint32_t in_min, uint32_t in_max, uint32_t out
|
||||
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
||||
}
|
||||
|
||||
float constrain_float(float in, float min, float max) { // DrawBot_Badge
|
||||
float constrain_float(float in, float min, float max) { // DrawBot_Badge
|
||||
if (in < min)
|
||||
return min;
|
||||
if (in > max)
|
||||
@@ -181,7 +186,5 @@ float mapConstrain(float x, float in_min, float in_max, float out_min, float out
|
||||
}
|
||||
|
||||
bool char_is_numeric(char value) {
|
||||
return (value >= '0' && value <='9');
|
||||
return (value >= '0' && value <= '9');
|
||||
}
|
||||
|
||||
|
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
nuts_bolts.h - Header for system level commands and real-time processes
|
||||
NutsBolts.h - Header for system level commands and real-time processes
|
||||
Part of Grbl
|
||||
Copyright (c) 2014-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
|
||||
@@ -18,10 +20,7 @@
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef nuts_bolts_h
|
||||
#define nuts_bolts_h
|
||||
|
||||
#include "config.h"
|
||||
#include "Config.h"
|
||||
|
||||
#define false 0
|
||||
#define true 1
|
||||
@@ -31,7 +30,7 @@
|
||||
// Axis array index values. Must start with 0 and be continuous.
|
||||
// Note: You set the number of axes used by changing N_AXIS.
|
||||
// Be sure to define pins or servos in the machine definition file.
|
||||
#define X_AXIS 0 // Axis indexing value.
|
||||
#define X_AXIS 0 // Axis indexing value.
|
||||
#define Y_AXIS 1
|
||||
#define Z_AXIS 2
|
||||
#define A_AXIS 3
|
||||
@@ -41,8 +40,8 @@
|
||||
#define MAX_AXES 6
|
||||
#define MAX_GANGED 2
|
||||
|
||||
#define PRIMARY_MOTOR 0
|
||||
#define GANGED_MOTOR 1
|
||||
#define PRIMARY_MOTOR 0
|
||||
#define GANGED_MOTOR 1
|
||||
|
||||
#define X2_AXIS (X_AXIS + MAX_AXES)
|
||||
#define Y2_AXIS (Y_AXIS + MAX_AXES)
|
||||
@@ -53,34 +52,32 @@
|
||||
|
||||
// CoreXY motor assignments. DO NOT ALTER.
|
||||
// NOTE: If the A and B motor axis bindings are changed, this effects the CoreXY equations.
|
||||
#define A_MOTOR X_AXIS // Must be X_AXIS
|
||||
#define B_MOTOR Y_AXIS // Must be Y_AXIS
|
||||
|
||||
|
||||
#define A_MOTOR X_AXIS // Must be X_AXIS
|
||||
#define B_MOTOR Y_AXIS // Must be Y_AXIS
|
||||
|
||||
// Conversions
|
||||
#define MM_PER_INCH (25.40)
|
||||
#define INCH_PER_MM (0.0393701)
|
||||
#define TICKS_PER_MICROSECOND (F_STEPPER_TIMER/1000000) // Different from AVR version
|
||||
#define TICKS_PER_MICROSECOND (F_STEPPER_TIMER / 1000000) // Different from AVR version
|
||||
|
||||
#define DELAY_MODE_DWELL 0
|
||||
#define DELAY_MODE_DWELL 0
|
||||
#define DELAY_MODE_SYS_SUSPEND 1
|
||||
|
||||
// Useful macros
|
||||
#define clear_vector(a) memset(a, 0, sizeof(a))
|
||||
#define clear_vector_float(a) memset(a, 0.0, sizeof(float)*N_AXIS)
|
||||
#define clear_vector_float(a) memset(a, 0.0, sizeof(float) * N_AXIS)
|
||||
// #define clear_vector_long(a) memset(a, 0.0, sizeof(long)*N_AXIS)
|
||||
#define MAX(a,b) (((a) > (b)) ? (a) : (b)) // changed to upper case to remove conflicts with other libraries
|
||||
#define MIN(a,b) (((a) < (b)) ? (a) : (b)) // changed to upper case to remove conflicts with other libraries
|
||||
#define isequal_position_vector(a,b) !(memcmp(a, b, sizeof(float)*N_AXIS))
|
||||
#define MAX(a, b) (((a) > (b)) ? (a) : (b)) // changed to upper case to remove conflicts with other libraries
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b)) // changed to upper case to remove conflicts with other libraries
|
||||
#define isequal_position_vector(a, b) !(memcmp(a, b, sizeof(float) * N_AXIS))
|
||||
|
||||
// Bit field and masking macros
|
||||
//Arduino.h:104:0: note: this is the location of the previous definition
|
||||
//#define bit(n) (1 << n)
|
||||
#define bit_true(x,mask) (x) |= (mask)
|
||||
#define bit_false(x,mask) (x) &= ~(mask)
|
||||
#define bit_istrue(x,mask) ((x & mask) != 0)
|
||||
#define bit_isfalse(x,mask) ((x & mask) == 0)
|
||||
#define bit_true(x, mask) (x) |= (mask)
|
||||
#define bit_false(x, mask) (x) &= ~(mask)
|
||||
#define bit_istrue(x, mask) ((x & mask) != 0)
|
||||
#define bit_isfalse(x, mask) ((x & mask) == 0)
|
||||
|
||||
// Read a floating point value from a string. Line points to the input buffer, char_counter
|
||||
// is the indexer pointing to the current character of the line, while float_ptr is
|
||||
@@ -100,15 +97,16 @@ float convert_delta_vector_to_unit_vector(float* vector);
|
||||
float limit_acceleration_by_axis_maximum(float* unit_vec);
|
||||
float limit_rate_by_axis_maximum(float* unit_vec);
|
||||
|
||||
float mapConstrain(float x, float in_min, float in_max, float out_min, float out_max);
|
||||
float map_float(float x, float in_min, float in_max, float out_min, float out_max);
|
||||
float mapConstrain(float x, float in_min, float in_max, float out_min, float out_max);
|
||||
float map_float(float x, float in_min, float in_max, float out_min, float out_max);
|
||||
uint32_t map_uint32_t(uint32_t x, uint32_t in_min, uint32_t in_max, uint32_t out_min, uint32_t out_max);
|
||||
float constrain_float(float in, float min, float max);
|
||||
bool char_is_numeric(char value);
|
||||
char* trim(char* value);
|
||||
float constrain_float(float in, float min, float max);
|
||||
bool char_is_numeric(char value);
|
||||
char* trim(char* value);
|
||||
|
||||
template <class T> void swap(T& a, T& b) {
|
||||
T c(a); a = b; b = c;
|
||||
template <class T>
|
||||
void swap(T& a, T& b) {
|
||||
T c(a);
|
||||
a = b;
|
||||
b = c;
|
||||
}
|
||||
|
||||
#endif
|
@@ -1,5 +1,5 @@
|
||||
#include "grbl.h"
|
||||
#include "i2s_out.h"
|
||||
#include "Grbl.h"
|
||||
#include "I2SOut.h"
|
||||
|
||||
String pinName(uint8_t pin) {
|
||||
if (pin == UNDEFINED_PIN) {
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user