-
Notifications
You must be signed in to change notification settings - Fork 80
/
Copy pathStepperISR.h
206 lines (190 loc) · 6.14 KB
/
StepperISR.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
#include <stdint.h>
#include "FastAccelStepper.h"
#include "fas_arch/common.h"
// Here are the global variables to interface with the interrupts
// These variables control the stepper timing behaviour
#define QUEUE_LEN_MASK (QUEUE_LEN - 1)
struct queue_entry {
uint8_t steps; // if 0, then the command only adds a delay
uint8_t toggle_dir : 1;
uint8_t countUp : 1;
uint8_t moreThanOneStep : 1;
uint8_t hasSteps : 1;
#if defined(SUPPORT_EXTERNAL_DIRECTION_PIN)
// if repeat_entry==1, then this entry shall be repeated.
// This mechanism only works for pauses (steps == 0)
// Used for external direction pin
uint8_t repeat_entry : 1;
uint8_t dirPinState : 1;
#endif
uint16_t ticks;
#if defined(SUPPORT_QUEUE_ENTRY_END_POS_U16)
uint16_t end_pos_last16;
#endif
#if defined(SUPPORT_QUEUE_ENTRY_START_POS_U16)
uint16_t start_pos_last16;
#endif
};
class StepperQueue {
public:
struct queue_entry entry[QUEUE_LEN];
// In case of forceStopAndNewPosition() the adding of commands has to be
// temporarily suspended
volatile bool ignore_commands;
volatile uint8_t read_idx; // ISR stops if readptr == next_writeptr
volatile uint8_t next_write_idx;
bool dirHighCountsUp;
uint8_t dirPin;
// a word to isRunning():
// if isRunning() is false, then the _QUEUE_ is not running.
//
// For esp32 this does NOT mean, that the HW is finished.
// The timer is still counting down to zero until it stops at 0.
// But there will be no interrupt to process another command.
// So the queue requires startQueue() again
//
// Due to the rmt version of esp32, there has been the needed to
// provide information, that device is not yet ready for new commands.
// This has been called isReadyForCommands().
//
#if defined(SUPPORT_ESP32)
volatile bool _isRunning;
bool _nextCommandIsPrepared;
inline bool isRunning() { return _isRunning; }
bool isReadyForCommands();
bool use_rmt;
uint8_t _step_pin;
uint16_t _getPerformedPulses();
#endif
#ifdef SUPPORT_ESP32_MCPWM_PCNT
const void* driver_data;
#endif
#ifdef SUPPORT_ESP32_RMT
RMT_CHANNEL_T channel;
bool _rmtStopped;
#if ESP_IDF_VERSION_MAJOR == 4
bool bufferContainsSteps[2];
#else
bool lastChunkContainsSteps;
rmt_encoder_handle_t _tx_encoder;
#endif
#endif
#if defined(SUPPORT_DIR_PIN_MASK)
volatile SUPPORT_DIR_PIN_MASK* _dirPinPort;
SUPPORT_DIR_PIN_MASK _dirPinMask;
#endif
#if defined(SUPPORT_DIR_TOGGLE_PIN_MASK)
volatile SUPPORT_DIR_TOGGLE_PIN_MASK* _dirTogglePinPort;
SUPPORT_DIR_TOGGLE_PIN_MASK _dirTogglePinMask;
#endif
#if defined(SUPPORT_AVR)
volatile bool _noMoreCommands;
volatile bool _isRunning;
inline bool isRunning() { return _isRunning; }
inline bool isReadyForCommands() { return true; }
enum channels channel;
#endif
#if defined(SUPPORT_SAM)
uint8_t _step_pin;
uint8_t _queue_num;
void* driver_data;
volatile bool _hasISRactive;
bool isRunning();
bool _connected;
inline bool isReadyForCommands() { return true; }
volatile bool _pauseCommanded;
volatile uint32_t timePWMInterruptEnabled;
#endif
#if defined(TEST)
volatile bool _isRunning;
inline bool isReadyForCommands() { return true; }
inline bool isRunning() { return _isRunning; }
#endif
struct queue_end_s queue_end;
uint16_t max_speed_in_ticks;
void init(uint8_t queue_num, uint8_t step_pin);
inline uint8_t queueEntries() {
fasDisableInterrupts();
uint8_t rp = read_idx;
uint8_t wp = next_write_idx;
fasEnableInterrupts();
inject_fill_interrupt(0);
return (uint8_t)(wp - rp);
}
inline bool isQueueFull() { return queueEntries() == QUEUE_LEN; }
inline bool isQueueEmpty() { return queueEntries() == 0; }
#if defined(SUPPORT_EXTERNAL_DIRECTION_PIN)
inline bool isOnRepeatingEntry() {
return entry[read_idx & QUEUE_LEN_MASK].repeat_entry == 1;
}
inline uint8_t dirPinState() {
return entry[read_idx & QUEUE_LEN_MASK].dirPinState;
}
inline void clearRepeatingFlag() {
entry[read_idx & QUEUE_LEN_MASK].repeat_entry = 0;
}
#endif
int8_t addQueueEntry(const struct stepper_command_s* cmd, bool start);
int32_t getCurrentPosition();
uint32_t ticksInQueue();
bool hasTicksInQueue(uint32_t min_ticks);
bool getActualTicksWithDirection(struct actual_ticks_s* speed);
inline uint16_t getMaxSpeedInTicks() { return max_speed_in_ticks; }
// startQueue is always called
void startQueue();
void forceStop();
void _initVars();
void connect();
void disconnect();
#ifdef SUPPORT_ESP32_MCPWM_PCNT
bool isReadyForCommands_mcpwm_pcnt();
void init_mcpwm_pcnt(uint8_t channel_num, uint8_t step_pin);
void startQueue_mcpwm_pcnt();
void forceStop_mcpwm_pcnt();
uint16_t _getPerformedPulses_mcpwm_pcnt();
void connect_mcpwm_pcnt();
void disconnect_mcpwm_pcnt();
#endif
#ifdef SUPPORT_ESP32_RMT
bool isReadyForCommands_rmt();
void init_rmt(uint8_t channel_num, uint8_t step_pin);
void startQueue_rmt();
#if ESP_IDF_VERSION_MAJOR == 4
void stop_rmt(bool both);
#else
bool _channel_enabled;
#endif
void forceStop_rmt();
uint16_t _getPerformedPulses_rmt();
void connect_rmt();
void disconnect_rmt();
#endif
void setDirPin(uint8_t dir_pin, bool _dirHighCountsUp) {
dirPin = dir_pin;
dirHighCountsUp = _dirHighCountsUp;
#if defined(SUPPORT_DIR_PIN_MASK)
if ((dir_pin != PIN_UNDEFINED) && ((dir_pin & PIN_EXTERNAL_FLAG) == 0)) {
_dirPinPort = portOutputRegister(digitalPinToPort(dir_pin));
_dirPinMask = digitalPinToBitMask(dir_pin);
}
#endif
#if defined(SUPPORT_DIR_TOGGLE_PIN_MASK)
if ((dir_pin != PIN_UNDEFINED) && ((dir_pin & PIN_EXTERNAL_FLAG) == 0)) {
_dirTogglePinPort = portInputRegister(digitalPinToPort(dir_pin));
_dirTogglePinMask = digitalPinToBitMask(dir_pin);
}
#endif
}
#if SUPPORT_UNSAFE_ABS_SPEED_LIMIT_SETTING == 1
void setAbsoluteSpeedLimit(uint16_t ticks) { max_speed_in_ticks = ticks; }
#endif
void adjustSpeedToStepperCount(uint8_t steppers);
static bool isValidStepPin(uint8_t step_pin);
static int8_t queueNumForStepPin(uint8_t step_pin);
};
extern StepperQueue fas_queue[NUM_QUEUES];
#if defined(SUPPORT_CPU_AFFINITY)
void fas_init_engine(FastAccelStepperEngine* engine, uint8_t cpu_core);
#else
void fas_init_engine(FastAccelStepperEngine* engine);
#endif