GithubHelp home page GithubHelp logo

Comments (14)

Naguissa avatar Naguissa commented on July 16, 2024
  • You lib would be perfectly fitted for this purpose, isn't it?

Yes, it's just what I made it for :-)

This library uses a non-abundant resource, a hardware timer, in order to provide the ability to accurately call a function in a timed manner.

Very important: You need to keep callback function (timed_function in this example) as fast as possible, specillay when using short intervals.

The way this library works is to manage only one callback function at a time, so to change interval you only need to call any attach function again; the library will clean old function and data and will use the new provided data.

  • Could you advise me on how the sktech should "listen" to the host computer for the change? serialevent?
    You advice would be welcome, as I'm really starting with arduino/stm32.

This is a possible Skeleton:

#include "Arduino.h"
#include "uTimerLib.h"

// Initial timer value, in microseconds:
uint32_t us = 20000; // 20 milliseconds as default.

volatile bool GPIODataOutPutPinA = 0;
int pinA = 0;
// [...]
volatile bool GPIODataOutPutPinZ = 0;
int pinZ = 999;

// For Serial:
byte incomingByte;

void timed_function() {
	// GPIODataOutPutPinA ... GPIODataOutPutPinZ calculations, as needed. Maybe on loop
	digitalWrite(pinA, GPIODataOutPutPinA);
	// [...]
	digitalWrite(pinZ, GPIODataOutPutPinZ);
}



void setup() {
	Serial.begin(57600);
	TimerLib.setInterval_us(timed_function, us);
	prevMillis = millis();
}


void loop() {
	// GPIODataOutPutPinA ... GPIODataOutPutPinZ calculations, as needed. Maybe on timed_function

	if (Serial.available() > 0) {
		// read the incoming byte:
        incomingByte = Serial.read();
		// Do whatever....


		// You have a new timing? Apply it:
		us = 30000; // example of new timing, 30 milliseconds
		TimerLib.setInterval_us(timed_function, us);

	}

}

from utimerlib.

Naguissa avatar Naguissa commented on July 16, 2024

Was that useful? Any more question?

from utimerlib.

OhSoGood avatar OhSoGood commented on July 16, 2024

from utimerlib.

OhSoGood avatar OhSoGood commented on July 16, 2024

Well, from test & trial, it seems the minimum interval between two calls (ie the value of TIMER_INTERVAL_us) is around 500us for the Maple Mini. Given the few instructions your code and mine do, and given the 72MHz cpu, that surprises me a lot.

Any thought about this?

from utimerlib.

Naguissa avatar Naguissa commented on July 16, 2024

It depends on callback function and program.

In your example, you're using Serial. Serial, when using STM32Duino with Maple Mini, also uses interrupts:

http://www.stm32duino.com/viewtopic.php?t=1139

This means interrupts may overlap.

Also there's an interrupt to maintain micros, milis, etc. language functionality. If you want more efficiency and/or shorter periods you need to disable that.

And, to sum up, you have all function calls in timer processing and interrupt processing, that sums-up a bunch of instructions.

So, at the end, you have 33*72 = 2376 max instructions in a 33us period interrupt, and it's quite little room to do complex operations (included uTimerLib operations). And will be affected by other interrupts (HardwareSerial, micros/milis/delay, etc).

If you want to disable time interrupts you need to disable systick timer: http://docs.leaflabs.com/static.leaflabs.com/pub/leaflabs/maple-docs/0.0.12/timers.html#jitter

systick_disable();
systick_enable();

And maybe not the best option, but you can overclock the maple mini if really needed, at expenses of loosing Serial AutoReset when programming (well, it fails a lot for me, on Linux...): http://storage8.static.itmages.com/i/18/0326/h_1522044675_8430203_d93488ee55.png

from utimerlib.

Naguissa avatar Naguissa commented on July 16, 2024

Oh, you also loose USB serial when Overclocking it!

from utimerlib.

OhSoGood avatar OhSoGood commented on July 16, 2024

Thank you for the link about serial interrupts. I have actually inverted the logic: I put my high-rate code in the loop function and there, I managed to execute it every few microsec, which is nice. Even with the smallest code, timer interrupts were too slow (maybe still my fault and my bad code?).

I have yet to implement serial interrupts. I'll keep you informed if you wish.

from utimerlib.

Naguissa avatar Naguissa commented on July 16, 2024

No, no! You don't need to implement that, it's on the core.

What I was referring to is that all these interrupts are already running in your maple, as they are part of Arduino and STM32duino cores.

You can disable them if you want but they run by default (well, HardwareSerial only if you init the serial port).

from utimerlib.

OhSoGood avatar OhSoGood commented on July 16, 2024

from utimerlib.

Naguissa avatar Naguissa commented on July 16, 2024

You CAN write your own ISR for Serial but you don't need it.

The problem is all ISRs, as one ISR cannot interrupt other one, so millis/micros or Serial can delay UtimerLib ISR.

from utimerlib.

Naguissa avatar Naguissa commented on July 16, 2024

I have doing some tests, but still nothing conclusive.

As your sketch reports, there're some huge max times, like 1.000 us delayed. Ttested with different periods, always around 1000us delay.

But if you check interrupts per second number is correct.

That said, I manage two scenarios, unfortunately I can only prove them with a logic analyzer and I have no time to do whole setup now:

  • Serial and systimer producing delays to uTimerLib interrupt. It can happen quite easily, but it's very strange that delay is always same number of microseconds.

  • Systimer not updating correctly when we are at our interrupts, so micos/milis functions can give some wrong value from time to time. It's quite strange but it could explain why we always have same delay (1000us) but still getting correct execution number by period.

Explanation here: https://arduino.stackexchange.com/questions/22212/using-millis-and-micros-inside-an-interrupt-routine

I'll try an idea now.....

from utimerlib.

Naguissa avatar Naguissa commented on July 16, 2024

YES!!!

It's the "micros()" call on timed_function!

Test this modification!!

    #include "uTimerLib.h"

    // How many microseconds between two timer calls, ie two GPIO batchs.
    #define TIMER_INTERVAL_us 33
    // The speed of the serial communication line with the host, in bauds.
    #define SERIAL_BAUDS 9600

    volatile int totalOccurences = 0;
    volatile int minWaitTime = 100000000000;
    volatile int maxWaitTime = 0;
    volatile int prevStart = 0;
    int launchTime_ms;


    volatile unsigned int currentMicros = 0;


    void setup() {
       // Initialize serial communications with host
       Serial.begin(SERIAL_BAUDS);

       // Initialize timer
       TimerLib.setInterval_us(timed_function, TIMER_INTERVAL_us);
       launchTime_ms = millis();
    }

    void loop() {
       // The loop listens to the host and takes order from it
       static bool isFirst = true;
    currentMicros = micros();

       char c;
       while (Serial.available()) {
         c = Serial.read();
         if(isFirst)
         {
           isFirst = false;
           Serial.println("MinWait\tMaxWait\tCalls/sec\t#");
         }
         int nowTime_ms = millis();
         float ellapsed_s = (nowTime_ms - launchTime_ms) / 1000.0;

         // Beware: do not reuse twice volative variables (they may change), copy them locally instead.
         Serial.print(minWaitTime);
         Serial.print("\t");
         Serial.print(maxWaitTime);
         Serial.print("\t");
         Serial.print(totalOccurences / ellapsed_s);
         Serial.print("\t");
         Serial.println(ellapsed_s);

         // Reset min/max values.
         minWaitTime = 100000000000;
         maxWaitTime = 0;
       }
           currentMicros = micros();

    }

    /*
      * The timer callback.
      */
    void timed_function() {
       unsigned int startTime = currentMicros;

       unsigned int prevStartTime = prevStart;
       prevStart = startTime;
       unsigned int currentWait = startTime - prevStartTime;

       totalOccurences++;

       if(currentWait < 100000000) { // Tough way to manage overflow of 'micros'
         if(currentWait < minWaitTime) {
           minWaitTime = currentWait;
         } else if (currentWait > maxWaitTime) {
           maxWaitTime = currentWait;
         }
       }
    }


from utimerlib.

OhSoGood avatar OhSoGood commented on July 16, 2024

Hi @Naguissa,
You're kind of crazy man, as crazy as I think I am :)
Good job, you had a nice analysis and/or intuition.
I confirm that works on my maple mini (re :) ). Thanks!

I still wonder what's best, knowing that I'd need to write on several GPIOs (with BRSS) once every 33µS with as much regularity as possible,

  1. put the big / high-frequency GPIO-write job in the loop, and make my own UsbSerial UART handler
  2. put the big / high-frequency GPIO-write job in the loop, and listen to SerialUSB (aka Serial on STM32) within the loop.
  3. put the big / high-frequency GPIO-write job in your timer, and listen to SerialUSB in the loop function
    Do you have an opinion on it?

from utimerlib.

Naguissa avatar Naguissa commented on July 16, 2024

Yes, more or less... ;-) You are welcome!

I have one similar project (but with longer period) and I will go with option 3.

But, for writing GPIO, I would consider using direct PORT writing in your case, because digitalWrite adds a lot of extra instructions and can make it skip cycles. You can always use digitalWrite and change it later if you observe problems:

https://jeelabs.org/2010/01/06/pin-io-performance/

In short, digitalRead / digitalWrite does a lot of checks and operations that makes it slower. It's safier, but slower....

from utimerlib.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.