Changing the code to run faster - direct port manipulation HELP!

Hello,
I need a program for faster communication between the encoder and Arduino mini pulse and direction pin.
I enclose the old program which works but at a higher speed encoderja losing the signal for faster movement of the stepper motor.

void setup () {
  //set up the various outputs
  pinMode(motor_step, OUTPUT);
  pinMode(motor_direction, OUTPUT);
  
  // then the encoder inputs
  pinMode(encoder_a, INPUT);
  pinMode(encoder_b, INPUT);
  // enable pullup as we are using an open collector encoder
  digitalWrite(encoder_a, HIGH); 
  digitalWrite(encoder_b, HIGH); 
  
  // encoder pin on interrupt 0 (pin 2)
  attachInterrupt(0, encoderPinChangeA, CHANGE);
  // encoder pin on interrupt 1 (pin 3)
  attachInterrupt(1, encoderPinChangeB, CHANGE);
  encoder = 0; //reseet the encoder position to 0
}

void loop() {
  //do stuff dependent on encoder position here
  //such as move a stepper motor to match encoder position
  //if you want to make it 1:1 ensure the encoder res matches the motor res by dividing/multiplying
  if (encoder > 0) {
    digitalWrite(motor_direction, HIGH);// move stepper in reverse
    digitalWrite(motor_step, HIGH);
    digitalWrite(motor_step, LOW);
    delayMicroseconds(600); //_delay_us(200); //modify to alter speed
    motor_position++;
    encoder = 0; //encoder--;
  }
  else if (encoder < 0) {
    digitalWrite (motor_direction, LOW); //move stepper forward
    digitalWrite (motor_step, HIGH);
    digitalWrite (motor_step, LOW);
    delayMicroseconds(600); //_delay_us(200); //modify to alter speed
    motor_position--;
    encoder = 0; //encoder++;
  }
}

Replaced by direct manipulation port. Program has no errors but does not work.

void setup () {
  //set up the various outputs
  pinMode(motor_step, OUTPUT);
  pinMode(motor_direction, OUTPUT);

  // then the encoder inputs
  pinMode(encoder_a, INPUT);
  pinMode(encoder_b, INPUT);

  // enable pullup as we are using an open collector encoder
  digitalWrite(encoder_a, HIGH); 
  digitalWrite(encoder_b, HIGH); 

  // encoder pin on interrupt 0 (pin 2)
  attachInterrupt(0, encoderPinChangeA, CHANGE);
  // encoder pin on interrupt 1 (pin 3)
  attachInterrupt(1, encoderPinChangeB, CHANGE);
  encoder = 0; //reseet the encoder position to 0
}

void loop() {
  //do stuff dependent on encoder position here
  //such as move a stepper motor to match encoder position
  //if you want to make it 1:1 ensure the encoder res matches the motor res by dividing/multiplying
  if (encoder > 0) {

    //digitalWrite(motor_direction, HIGH);// move stepper in reverse
    PORTD = PORTD | 0b00100000;
    //digitalWrite(motor_step, HIGH);
    PORTD = PORTD | 0b00010000;
    //digitalWrite(motor_step, LOW);
    PORTD = PORTD & 0b11101111;
    delayMicroseconds(600); //_delay_us(200); //modify to alter speed
    motor_position++;
    encoder = 0; //encoder--;
  }
  else if (encoder < 0) {
    //digitalWrite (motor_direction, LOW); //move stepper forward
    PORTD = PORTD & 0b11011111; 
    //digitalWrite (motor_step, HIGH);
    PORTD = PORTD | 0b00010000;
    //digitalWrite (motor_step, LOW);
    PORTD = PORTD & 0b11101111;
    delayMicroseconds(600); //_delay_us(200); //modify to alter speed
    motor_position--;
    encoder = 0; //encoder++;
  }
}

All of your declarations and your ISR routines are missing so the code won't compile.

Correction, commented out your lines and put the replacement lines with them

#define encoder_a 2 
#define encoder_b 3 
#define motor_step 4 
#define motor_direction 5 

#include <delay.h>
volatile long motor_position, encoder;

byte inputA;
byte inputB;

void setup () {
  //set up the various outputs
  pinMode(motor_step, OUTPUT);
  pinMode(motor_direction, OUTPUT);

  // then the encoder inputs
  pinMode(encoder_a, INPUT);
  pinMode(encoder_b, INPUT);

  // enable pullup as we are using an open collector encoder
  digitalWrite(encoder_a, HIGH); 
  digitalWrite(encoder_b, HIGH); 

  // encoder pin on interrupt 0 (pin 2)
  attachInterrupt(0, encoderPinChangeA, CHANGE);
  // encoder pin on interrupt 1 (pin 3)
  attachInterrupt(1, encoderPinChangeB, CHANGE);
  encoder = 0; //reseet the encoder position to 0
}

void loop() {
  //do stuff dependent on encoder position here
  //such as move a stepper motor to match encoder position
  //if you want to make it 1:1 ensure the encoder res matches the motor res by dividing/multiplying
  if (encoder > 0) {

    //digitalWrite(motor_direction, HIGH);// move stepper in reverse
    PORTD = PORTD | 0b00100000;
    //digitalWrite(motor_step, HIGH);
    PORTD = PORTD | 0b00010000;
    //digitalWrite(motor_step, LOW);
    PORTD = PORTD & 0b11101111;
    delayMicroseconds(600); //_delay_us(200); //modify to alter speed
    motor_position++;
    encoder = 0; //encoder--;
  }
  else if (encoder < 0) {
    //digitalWrite (motor_direction, LOW); //move stepper forward
    PORTD = PORTD & 0b11011111; 
    //digitalWrite (motor_step, HIGH);
    PORTD = PORTD | 0b00010000;
    //digitalWrite (motor_step, LOW);
    PORTD = PORTD & 0b11101111;
    delayMicroseconds(600); //_delay_us(200); //modify to alter speed
    motor_position--;
    encoder = 0; //encoder++;
  }
}

void encoderPinChangeA() {
  inputA = (PIND & 0b00000100) >>2; // result is 0b00000001 if input is high, 0b00000000 if input is low.
  inputB = (PIND & 0b00001000)>>3; //result is 0b00000001 if input is high, 0b00000000 if input is low.
    //if (digitalRead(encoder_a)==digitalRead(encoder_b)) {
  if (inputA == inputB){
    encoder--;
  }
  else{
    encoder++;
  }
}
void encoderPinChangeB() {
  inputA = (PIND & 0b00000100) >>2; // result is 0b00000001 if input is high, 0b00000000 if input is low.
  inputB = (PIND & 0b00001000)>>3; // result is 0b00000001 if input is high, 0b00000000 if input is low.
    //if (digitalRead(encoder_a) != digitalRead(encoder_b)) {
  if (inputA != inputB){
    encoder--;
  }
  else {
    encoder++;
  }
}

You might be interested in the "digitalwritefast" header: https://code.google.com/p/digitalwritefast/

It can change your pinMode(), digitalRead() and digitalWrite() calls into direct port manipulation whenever the pin number is a compile-time constant. Just include the header and change the pinMode(), digitalRead() and digitalWrite() calls to pinModeFast(), digitalReadFast() and digitalWriteFast(). This will make your code just as fast and more readable.

We can write for example, because is write digitalWriteFast code is error.

I don't see why your PIND stuff isn't working.

[Edit to add ...] I was thinking of an Uno, but you are using a mini so maybe the pin mapping is different. [/edit]

Try writing a short sketch that explores that and nothing else - and just showing the values you get. Don't bother with interrupts for this purpose.

Then extend the short sketch bit by bit (sorry for the pun) until it nearly matches the real code.

...R

Hi Robin2,
If I leave the rest and just replace with this code works but I have not faster.
Work this code

void loop() {
  //do stuff dependent on encoder position here
  //such as move a stepper motor to match encoder position
  //if you want to make it 1:1 ensure the encoder res matches the motor res by dividing/multiplying
  if (encoder > 0) {
    digitalWrite(motor_direction, HIGH);// move stepper in reverse
    digitalWrite(motor_step, HIGH);
    digitalWrite(motor_step, LOW);
    delayMicroseconds(600); //_delay_us(200); //modify to alter speed
    motor_position++;
    encoder = 0; //encoder--;
  }
  else if (encoder < 0) {
    digitalWrite (motor_direction, LOW); //move stepper forward
    digitalWrite (motor_step, HIGH);
    digitalWrite (motor_step, LOW);
    delayMicroseconds(600); //_delay_us(200); //modify to alter speed
    motor_position--;
    encoder = 0; //encoder++;
  }
}

This not work

void loop() {
  //do stuff dependent on encoder position here
  //such as move a stepper motor to match encoder position
  //if you want to make it 1:1 ensure the encoder res matches the motor res by dividing/multiplying
  if (encoder > 0) {

    //digitalWrite(motor_direction, HIGH);// move stepper in reverse
    PORTD = PORTD | 0b00100000;
    //digitalWrite(motor_step, HIGH);
    PORTD = PORTD | 0b00010000;
    //digitalWrite(motor_step, LOW);
    PORTD = PORTD & 0b11101111;
    delayMicroseconds(600); //_delay_us(200); //modify to alter speed
    motor_position++;
    encoder = 0; //encoder--;
  }
  else if (encoder < 0) {
    //digitalWrite (motor_direction, LOW); //move stepper forward
    PORTD = PORTD & 0b11011111; 
    //digitalWrite (motor_step, HIGH);
    PORTD = PORTD | 0b00010000;
    //digitalWrite (motor_step, LOW);
    PORTD = PORTD & 0b11101111;
    delayMicroseconds(600); //_delay_us(200); //modify to alter speed
    motor_position--;
    encoder = 0; //encoder++;
  }
}

Maybe the 600 microsecond delay is too much. That's 9,600 instruction cycles. Reducing that by a few is not going to make your look run much faster. Did you try reducing the delays?

When you say that you code is not running fast enough, what do you mean? What are the symptoms?

You do know that by changing encoder++ and encoder-- to 'encoder = 0;' you are throwing away input pulses. If you are expecting the motor to track the input knob you will have to change those back.

Direct port manipulation really is fast, so you may have to add calls to delayMicroseconds () or asm nops to control the timing if it is too fast. Here you are driving a stepper controller I think, most of which specify a 5--10us minimum step pulse length, so digitalWrite() is actually slow enough to work (usually, since its about 4us), whereas the 125ns pulses direct port manipulation gives are way too fast.

I agree with @johnwasser, you need to tell us what you are trying to achieve and why the existing speed isn't good enough rather than focusing on how to achieve faster speeds

...R

There is no problem in speed stepper motor, rpm motor set with "delayMicroseconds(600);" The problem is the encoder. If you quickly turn encoder motor turns slowly. If the encoder slowly turning turns faster and more accurately. If I measure the signal with an oscilloscope has the correct encoder pulses in both fast and slow turn. I agree with MarkT. Motor direction and motor pulse signal output are too fast. And driver card is not keeping pace with the signal. What about now.

@Mikistromar, I find your description very confusing. It would help greatly if you could give a longer and more detailed description.

It sounds like you have suitable code to move your stepper motor as fast as you want.

It also sounds like you are trying to detect pulses from an encoder (what is it attached to?) but some of the encoder pulses are missed if you move the encoder too fast.

If the motor is working OK why are you using direct port manipulation to send it step pulses that are probably too short. Why not just use digitalWrite()?

Have you tried just reading the encoder without bothering with the motor until such time as you get the encoder reading correct?

Are you aware that it may be possible to move the encoder too fast for the motor, regardless of how cleverly the program is written. It may be necessary to count the encoder steps and then give the motor time to catch up. That would mean separating the reading of the encoder from the movement of the motor.

...R

Robin2, a little complicated. I'm reworking epson printer. I get a signal from Epson printers. This is the same as a digital signal used by the encoder. If you are using more expensive servo motors and controllers then it works. I would like to do it as cheaply as possible. Arduino Mini is 5USD, Siemens controller obout 500USD, 30USD stepper motor, servo motor 330USD, 10USD driver for stepper, servo driver for 350USD. You understand why I'm doing this is difficult but doable.

View the video for easier to understand. https://www.youtube.com/watch?v=zvDLuKG90eM

Understand the problem. Epson printer has a very fast movement and Arduino mini program can not in such a short time to process all the impulses it receives. Therefore, the engine slows down instead of the 3x greater rate of turn

The problem is solved, I replaced the driver and now also works on direct manipulation port. Thanks for all the replies I have a lot of work that I succeed. Any suggestions are welcome.