High speed reading digital pins.

Im reading a step and direction signal.

Im using pin9 and pin10 on a Micro Pro

The code below executes but im missing steps.....

the range of pwm is 0-255 and i use directionpin (9) to determine if a pulse on steppin (10) shall increase or decrease the value in PWMOUT. Stepping from 0 to 255 and back to zero randomly gives me a final pwm value of between 0 and 5. Printing the value of the PWM every change shows that the highest value of pwm reached is between 248 and 255. i also see some overflow negative steps beeing ignored. Am i missing something or is the Micro to slow or is it my code that is to slow?

Suggestions? Fixes?

INFO: The step/dir signal generator generates 256 steps/rev and 6000 rev/min and having an acceleration setting of 1000000rev/square_second.

sketch_jun02b.ino (2 KB)

bx3me:
ng or is the Micro to slow or is it my code that is to slow?

Yes, your code is so slow.
You are outbraking the sketch with Serial.println(/) until the loop speed is nearly zero.

In general your loop function loks like
void loop()
{
Serial.println(PWMOUT); // Print PWM Value
}

With 9600 baud serial speed you can send 960 characters per second at most.

So if PWMOUT is three digits and print line (println) adds two control characters for "carriage return" and "line feed" you try to send 5 characters each time the loop runs.

But as you can only send 960 characters per second at most due to a very slow baud rate, this means each run through the loop needs 5/960s =more than 5 millisconds. This means your loop will run slower than 200 times per second.

With such a slow loop function, outbraked to less than 200 runs per second, you cannot detect fast changing signals with a frequency of more than 100 Hertz.

Perhaps use a higher baudrate such like Serial.begin(250000) and never stuff the Serial send buffer until it is full and delays your sketch with each additional character you try to stuff into the send buffer while it is filled up to maximum buffer size!

Input very appreciated! tnks!

OK I understand the serial not beeing fast so i made some changes.
Im upping the serial speed to 250000, removed all unnecessary code and tried having the analog write in two different places. but still im missing steps. I tried setting the step generator at different speeds but no matter if i step slowly or fast, stepping up and down between 25% and 75% causes the pwm to drift which i interpretate as missed steps.

Any other changes i can do?

Updated sketch attached....

Updated sketch attached....

Where? You didn't replace code in a previous reply did you? That makes anyone that commented on code that no longer exists look like an idiot. That is NOT the way to get help here.

You aren't paying for the bandwidth. Post modified code in a new reply.

For short code it is better to embed the code in your post, using code tags, like this:

/* Pro Micro Test Code
   by: Nathan Seidle
   modified by: Jim Lindblom
   SparkFun Electronics
   date: September 16, 2013
   license: Public Domain - please use this code however you'd like.
   It's provided as a learning tool.

   This code is provided to show how to control the SparkFun
   ProMicro's TX and RX LEDs within a sketch. It also serves
   to explain the difference between Serial.print() and
   Serial1.print().
*/
//int timerFlag = 0;
int PWMOUT = 0;
const byte STEPPIN = 10;
const byte DIRPIN = 9;
const byte  PWMOUTPIN = 3;
//const byte  GREENLEDPIN = 17;
//unsigned long timer;
//bool RXLEDSTATE = 0;;

void setPWM(int PWMChange) {
  
  if(PWMOUT+PWMChange < 255 && PWMOUT + PWMChange > 0)  //Only change the value of the pwn if the new value is within the bounds of PWM Out
  {
 //Serial.println(PWMChange);
 PWMOUT += PWMChange;  //Adding a negative value renders a subtraction
//    if(RXLEDSTATE){
//      RXLEDSTATE = !RXLEDSTATE;
//      RXLED1;}
//    else{
//      RXLEDSTATE = !RXLEDSTATE;
//      RXLED0;}      
  }
  analogWrite(PWMOUTPIN,PWMOUT);    //Set new PWM value
  while(digitalRead(STEPPIN)== HIGH);    //Waiting for the step pulse to end.
  //timerFlag = 1;                     //A step has been made.
  //timer = millis();                  //The time of the step.
}
void setup()
{
    pinMode(PWMOUTPIN, OUTPUT);
  pinMode(DIRPIN, INPUT);
  pinMode(STEPPIN, INPUT);
  //pinMode(GREENLEDPIN, OUTPUT);
  //timer = 0;

 Serial.begin(9600); //This pipes to the serial monitor
 //Serial1.begin(9600); //This is the UART, pipes to sensors attached to board
}

void loop()
{
 Serial.println(PWMOUT);  // Print PWM Value
  //if((millis() - timer) > 100 && timerFlag == 1) {
    //timerFlag = 0;
  }
  if(digitalRead(STEPPIN) == HIGH) {    //Searching for a pulse.
    if(digitalRead(DIRPIN) == LOW) {    //Direction Foward/Right.
      setPWM(-1);
      //TXLED0;
    }
    else {                         //Direction Back/Left.
      setPWM(1);                    //Making a step.
      //TXLED1;
    }
  }
}

Read this before posting a programming question

How to use this forum

Also please don't modify your original post after someone makes a suggestion. Make a new post with your modified code, so people can follow through the train of suggestions without them looking silly.

Maybe see if you can use interrupts ?

..... Yes missed the attacing part... sorry...
Here goes...

sketch_jun02b.ino (1.14 KB)

I did some math:

I want to process 255 steps within 1/100 of a second. This means handling 255*100 step pulses every second. Reading my code i need to process three digitalRead and one analogWrite every pulse. Doing some reading online tells me that a digitalRead takes about 8us which adds up to 24us for the reads and analogWrite i have not found any info on but i assume it is about twice the time of a digitalRead which would end up in 40us each cycle total.

A rough estimation is that i should have 50% headroom for each cycle so speed of my code should not render missing steps.

For sake of experimenting i lowered the frequency of step pulses to roughly 1/10 of my target but found myself losing even more steps?!?

Can someone explain?

digitalWrite should be roughly the same speed really. 48 µs would be rather long. You can use digitalReadFast and digitalWriteFast which gets the time down to a few processor clock cycles.

https://code.google.com/archive/p/digitalwritefast/downloads

bx3me:
I did some math:

I want to process 255 steps within 1/100 of a second. This means handling 255*100 step pulses every second. Reading my code i need to process three digitalRead and one analogWrite every pulse. Doing some reading online tells me that a digitalRead takes about 8us which adds up to 24us for the reads and analogWrite i have not found any info on but i assume it is about twice the time of a digitalRead which would end up in 40us each cycle total.

A rough estimation is that i should have 50% headroom for each cycle so speed of my code should not render missing steps.

For sake of experimenting i lowered the frequency of step pulses to roughly 1/10 of my target but found myself losing even more steps?!?

Can someone explain?

What length are the ticks? If you are going to read ticks that way, then at least you will want to ensure you don't read the same tick twice.

boolean foundTick=false;
while (digitalRead(pin)==HIGH) foundTick=true;

if (foundTick) ...

This type of processing is what interrupts are made for. But now bedtime. :slight_smile:

You could try this (untested, compiled only) interrupt driven version.
I moved the STEPPIN to pin 2 to use an interrupt to detect the rising edge.

const byte STEPPIN = 2; // was 10
const byte DIRPIN = 9;
const byte PWMOUTPIN = 3;

int PWMOUT = 0;
volatile char stepDir;

void setPWM(char PWMChange) {
  int newPWM = PWMOUT + PWMChange;
  if (newPWM <= 255 && newPWM >= 0) { //check bounds
    PWMOUT = newPWM;
  }
}

void getOnRising() {
  if (digitalRead(DIRPIN)) {    // decrease.
    stepDir = -1;
  } else {
    stepDir = 1;
  }
}

void setup()
{
  pinMode(PWMOUTPIN, OUTPUT);
  pinMode(DIRPIN, INPUT);
  pinMode(STEPPIN, INPUT);
  Serial.begin(250000);
  attachInterrupt(digitalPinToInterrupt(STEPPIN), getOnRising, RISING);
}

void printPWM()
{
  static unsigned long LASTPRINT = 0;
  if (millis() - LASTPRINT > 1000) {
    Serial.println(PWMOUT);
    LASTPRINT = millis();
  }
}

void loop()
{
  if (stepDir) {
    char stepDirCopy = stepDir;
    stepDir = 0;
    setPWM(stepDirCopy);
    analogWrite(PWMOUTPIN, PWMOUT);
  }
  printPWM();
}