Comments (14)
- 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.
Was that useful? Any more question?
from utimerlib.
from utimerlib.
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.
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.
Oh, you also loose USB serial when Overclocking it!
from utimerlib.
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.
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.
from utimerlib.
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.
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.
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.
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,
- put the big / high-frequency GPIO-write job in the loop, and make my own UsbSerial UART handler
- put the big / high-frequency GPIO-write job in the loop, and listen to SerialUSB (aka Serial on STM32) within the loop.
- 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.
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)
- change TimerLib.setInterval_us(timed_function, myVar); HOT 10
- Check 32U4 compatibility HOT 1
- Error: no matching function for call to 'HardwareTimer::attachInterrupt HOT 14
- ESP32 Timer precision HOT 3
- clearTimer() does not work in 1.6.5 ( it does in 1.6.4 ) HOT 4
- Timer crash in esp32 HOT 2
- STM32 compilation fails with error about Timer3 HOT 3
- 'Timer3' was not declared in this scope; HOT 2
- unprecisse timing on SAMD21 (Arduino Zero) HOT 5
- FreeRTOS Compatibility on ESP32? HOT 1
- Support SAMD HOT 24
- imprecisse timing on SAMD21 (Arduino Zero)
- [question] Does it support setting multiple timers? HOT 10
- Suport SAMD51
- Possible memory hog on stm32 HOT 1
- SAMD21 Timing Incorrect HOT 2
- Small timeout trigger callback_function immediately (ATMEGA328) HOT 5
- Support SAMD11 HOT 2
- ARDUINO_STM32 - setInterval_s not correctly trigged HOT 7
- Arduino_Core_STM32 compatibility HOT 5
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from utimerlib.