-1

I have this code:

enter image description here


The output looks like this:

output

Why are there non-periodically some extremely large values?

Thanks

3
  • 1
    Serial.println waits if the TX buffer is full. And ATmega32u4 handles the USB port in the background – Juraj Jan 27 '20 at 9:51
  • is there a way to make it faster? – Dominik Jašek Jan 27 '20 at 9:52
  • 1
    No code as image please. Copy and paste the code as text and format it with the {} button – chrisl Jan 27 '20 at 22:50
3

As explained by theSealion in his answer, this may be due to the different background tasks performed by the microcontroller. However, I personally find that 1 ms looks excessive. My guess is that the main culprit is the USB stack pushing all those bytes down the wire.

In order to check this, I wrote the following program. It measures a histogram of the loop execution times and then prints it through the serial port. Since the data is only printed after the measurements are done, the serial port does not do any work while the timings are being measured.

const int HISTOGRAM_LENGTH = 512;

uint16_t histogram[HISTOGRAM_LENGTH];

void print_histogram() {
    Serial.println(F("t (us)  count"));
    Serial.println(F("-------------"));
    for (int i = 0; i < HISTOGRAM_LENGTH; i++) {
        if (histogram[i] == 0) continue;  // skip zeros
        Serial.print(i * 4);
        Serial.print('\t');
        Serial.println(histogram[i]);
    }
    Serial.println(F("-------------"));
    Serial.flush();
}

void setup() {
    Serial.begin(9600);
}

void loop() {
    static uint32_t last_time;
    uint32_t now = micros();
    uint32_t dt = now - last_time;
    uint32_t bin = dt / 4;  // resolution of micros() is 4 us
    if (bin >= HISTOGRAM_LENGTH)
        bin = HISTOGRAM_LENGTH - 1;
    if (++histogram[bin] == UINT16_MAX) {
        print_histogram();
        exit(0);
    }
    last_time = now;
}

These are the results when run on an Arduino Uno:

t (us)  count
-------------
8       21888
12      65535
16      632
20      323
56      1
-------------

This shows that most loop iterations take 8–12 µs. Those iterations that were interrupted took 16–20 µs. The outlier at 56 µs is most likely the time between the program starting and the very first iteration of loop().

Here, the only interrupt source that affects the measurements is the timer interrupt. It fired exactly 955 times during the measurement period, which is consistent with the number of samples recorded at 16–20 µs. We can see from this data that the timer interrupt takes roughly 8 µs to run, which is quite reasonable. Again, I would not consider a 1 ms delay as reasonable.

1

There are be several "tasks" and interrupts that run in the background and they influence how often the loop() function is called.

For example timer, usart ...

They all need some attention from time to time. If the need some really fixed execution time you must use something like a hardware timer.

and by the way: a maximum of ~1.1ms is not bad for such a small controller. :-)

And as a addition to your question in your comments: I don't think there is a way to make the loop faster. As long as you need the other tasks, you have do give them some time.

4
  • Thanks theSealion! In addition, the original problem for this question was that I am driving a stepper motor and I need to communicate with Raspberry Pi using UART. The problem is that when I send some data about the motor to RPi and the motor is already spinning very fast, I often loose a step because there is just way too big delay. Do you have any idea how to solve this? – Dominik Jašek Jan 27 '20 at 10:10
  • I don't know how the arduino stepper library is implemented and why you are loosing steps, but in general: Make sure you don't use any busy waits. Especially when you are communication with the Rapsberry (do not wait for characters to be available). – theSealion Jan 27 '20 at 10:45
  • Alright, I am still figuring out the source of loosing steps and I think I found it. I think it has nothing to do with Serial.print. I would like to run stepper at 3000 steps per second. That means one pulse each 333,3 microsecond. And obviously when there is a ~1.1ms delay, it is too long delay not to loose a step. BTW I am using AccelStepper library. Is there some possibility to figure this out – Dominik Jašek Jan 27 '20 at 11:29
  • I don't understand "a maximum of ~1.1ms is not bad" – Juraj Jan 27 '20 at 16:13
0

In addition, the original problem for this question was that I am driving a stepper motor and I need to communicate with Raspberry Pi using UART. The problem is that when I send some data about the motor to RPi and the motor is already spinning very fast, I often loose a step

Your stepper code has to run very consistently to maintain 3000 steps/sec without jitter or dropping steps. It must not have to wait for communication or any other task but be able to issue the next step command on-time. Some possible techniques to accomplish this:

  • Don't post an entire message to the Pi but send only a few characters at a time, between steps.
  • Talk to the Pi in shorter, tightly coded messages, and let the Pi expand them if it needs to.
  • Use the highest baud rate the Uno & Pi can reliably use.
  • Issue step commands in a timer-driven interrupt routine, with any stepper housekeeping done in the background, between step-commands.
  • Use a faster processor.
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.