gin66 / FastAccelStepper

A high speed stepper library for Atmega 168/328p (nano), Atmega32u4, Atmega 2560, ESP32, ESP32S2, ESP32S3, ESP32C3 and Atmel SAM Due
MIT License
282 stars 67 forks source link

shift register outputs for DIR/EN cannot exceed 2 stepper motors #243

Closed plpers closed 3 months ago

plpers commented 3 months ago

I have a project where I'd like to control 12 stepper motors with one ESP32. When writing the prototype, I found that assigning EN and DIR to shift register output, for some reason when I create virtual pins higher than 134, the library stops working. So as a result, I can create Enable pins like

define Stepper1EnablePin 1

define Stepper1DirPin 2

define Stepper2EnablePin 3

define Stepper2DirPin 4

and everything works great, using the example code including adding a callback to SPI to send some info to update pins in the required callback. when called the bitwise OR converts say Stepper1 Enable Pin to 129, Dir to 130, and so on.

However when adding more *stepper3 using the factory method, and using

define Stepper3EnablePin 5... converting using the bitwise OR to convert to 134, etc the library stops working.

I am using Version 3.11 on platformio. Any thoughts why this might be happening?

plpers commented 3 months ago

Interestingly, I can get 4 steppers to work but only with blocking move() commands. Any thoughts if I am exceeding a queue length, or similar, that I need to be mindful of when using the stepperengine?

gin66 commented 3 months ago

It would be of help, if example code can be shared, which illustrates the problem. Based on the problem description, I have no clue, what is going on. Besides, stop working means what exactly?

plpers commented 3 months ago

Sorry, not the best bugreport in the world :) Here is some code to take a peek at. Sorry about all the chickenscratch about as I was just getting a feel for the problem before I get out the Jlink. main_Issue 243.zip

Per how I programmed the device, I expect a good output to look like this: Good_Pulse_Output.zip Unless otherwise noted, I generally get good outputs. However, some pins magically don't work, and as I start to add more pins, I start to see problems.

Pertinent lines where pin assignment doesn't work are in 24-38. I have them listed below for reference:

define dirPinStepper1 129

define enablePinStepper1 130

define stepPinStepper1 2

define dirPinStepper2 131 //If I number as 21, and enablePinStepper2 as 18, this works. if I number as 131 and 132 then I get what looks like an EN signal on Stepper 3. (See Video)

define enablePinStepper2 132

define stepPinStepper2 4

EN_Signal_Defect.zip

define dirPinStepper3 19 //numbered as 19 this works. If I change to 51, then stepper 4 stops outputting pulses. Steppers 1, 2, 3 unaffected. please note: Ignore this defect, I was not able to get it to reproduce easily

define enablePinStepper3 21

define stepPinStepper3 22

See Poor Pulse Output for if I change to 51. Poor_Pulse_Output.zip

define dirPinStepper4 137 //numbered as 67 this works. If I change to 137 then stepper 3 starts outputting what looks like an EN signal. (see video) Stepper 1, 2, 4 unaffected.

define enablePinStepper4 27

define stepPinStepper4 23

EN_Signal_Defect.zip

If I add two more steppers, I get weird behavior again: main_Issue 243_6Stepper.zip

define dirPinStepper1 129

define enablePinStepper1 130

define stepPinStepper1 2

define dirPinStepper2 133

define enablePinStepper2 134

define stepPinStepper2 4 //

define dirPinStepper3 132

define enablePinStepper3 131

define stepPinStepper3 22

define dirPinStepper4 135

define enablePinStepper4 136

define stepPinStepper4 23

define dirPinStepper5 140 //adding this stepper and stepper 6 , I get EN signals on pin 19/18 (steppers 5 and 6) all other steppers not affected. Not sure why this is. Same behavior as previous EN Signal Problems.

define enablePinStepper5 139

define stepPinStepper5 19

EN_Signal_Defect.zip

define dirPinStepper6 137

define enablePinStepper6 138

define stepPinStepper6 18 // OC1B in case of AVR

plpers commented 3 months ago

Also- for main Issue243.cpp, the 4 stepper file - I just tried to download myself the zip file to reproduce - and now the issue creating an EN-Like signal isn't there. Something is really weird.

I'll try to dig into it a little more with Jlink first. However the 6stepper file is reproducible. Also I just tried to add a 5th stepper to the 4 stepper file and I got the same "poor pulse output" behavior as before. I corrected an error where i was assigning the same pin twice, and no dice. I cant seem to get above 4 stepper motors somehow....

gin66 commented 3 months ago

I have had a look at the main issue 243 6stepper.zip file.

Findings:

plpers commented 3 months ago

Thanks for the reply. A couple questions:

spi is not used for digital pins. I am attempting to use the HSPI bus. Per https://docs.espressif.com/projects/esp-idf/en/v3.3.6/api-reference/peripherals/spi_master.html that is

define HSPI_MISO 12

define HSPI_MOSI 13

define HSPI_SCLK 14

define HSPI_SS 15

or perhaps I am mistaken? my understanding is that VSPI and HSPI are available for applications, SPI0 and SPI1 are for the ESP's flash use. SPI is working ok as far as I can tell.

setExternalPin() only strips bit 7 (external pin flag) and uses this as pin number got it. So In other words, I need to use pin numbers > 170 (170 = 128+ 42, the highest ESP numbered pin per your link) is that correct? In syntax this could be written as setEnablePin(43 | PIN_EXTERNAL_FLAG).

please check possible esp32 pinning. as per that document, pin numbers higher than 33 cannot be used. which esp32 variant/board do you use? I use the ESP32 Devkit V1, which has pins exposed up to 35.

you enable Serial, so pin 1 is not available. Just to confirm: does this mean a pin definition of 129 will collide with GPIO1? it seems in the example from the repo then, setExternalPin(pin, value) if you set a pin to 129, will result in pinMode(1, OUTPUT). Is that correct?

if setExternalPin() is called every 4ms, then the call does not return the expected value and the stepper task tries on each cycle again and again. Ah I see. read too fast. I added a register that acts as a dummy for now. I got it working up through stepper 6, but then i had to skip some pin numbers to make it work. The ESP appears to be crashing if I add more than 6 steppers. See semiworking.txt. semi_working.txt

gin66 commented 3 months ago

in setExternalPin() a constant value is set: spiCommand(hspi, 0b01010101);. Apparently the shift register has nothing to do with any pin value.

The PIN_EXTERNAL_FLAG aka bit 7 marks a pin value to be external. The valid range is then 0…127. There is no relation anymore to the valid pin range.

The pin collision using value 1 is happening, because the current setExternalPin() uses this value and then sets the esp32 pin.

My expectation would be a routine like:

uint16_t spi_pins=0; // current value of the shift register
bool setExternalPin(uint8_t pin, uint8_t value) {
  uint8_t spi_pin = pin & ~EXTERNAL_FLAG;
  if (spi_pin >= 16) return !value;  // error case
  uint16_t pin_flag = 1<<spi_pin;
  spi_pins |= pin_flag;
  if (!value) {
     spi_pins ^= pin_flag;
  }

  spiCommand(hspi, spi_pins);

  // assume spiCommand never fails and sets the pin successfully 
  return value;;
}
gin66 commented 3 months ago

recommendation is, to first check, that the setExternalPin() is working as expected - without any stepper or FastAccelStepper. Only the shiftregister and a measurement device (or LED connected).

plpers commented 3 months ago

the shift register i'll tighten up - i have not been using a stepper motor, only checking that step pulses are good. I decided to write the fake spi transfer just to check if the esp32 was getting bogged down with tasks or not. (I realize the spi transfer does nothing, sorry for the confusion)

I'll try and clarify the remaining issues when i am back (currently traveling)

plpers commented 3 months ago

Hi @gin66 thanks for looking at the code. The main problem was that i referenced a bad array and I am frankly not sure how it worked at all. I discovered it once i got out the jlink and lo and behold the numbers in my pinArray that held external register state were optimized out by the compiler and not watchable :)

Now it's working just fine after a really dumb mistake. Once again, thanks for a great library. I am closing as not a defect.

I do have a question, however: it appears from bench testing that the queue depth is shared among all steppers. Is this true? What I observe is if I have a stripped mainloop like this

void loop() {
      stepper1->move(100);
      stepper1->move(-100;
      stepper2->move(100);
      stepper2->move(-100);
      stepper3->move(100);
      stepper3->move(-100);
}

stepper3 will eventually stop getting pulses. you can see how on the oscilloscope stepper 1 starts hogging all the CPU time eventually. If I move to 100000 steps they all share nicely, and all steppers up to 12 keep moving.

If so, is there a way to confirm if a move() command successfully got into queue or not? I believe a lot of the issues I saw once I corrected my code are around overwhelming the queue (assuming it is shared) this way I could write a repeat routine to attempt to re-add the command to queue.

plpers commented 3 months ago

Not a defect, developer implementation error