I'm finding that when I'm using Timer 1 that the micros() function stops functioning correctly. I thought that:
Arduino internal functions (except PWM on pins 9. 10 which i'm not using) use timer 0
micros() function doesn't actually rely on a timer (but millis does)
If i call
TCCR1B |= (1 << CS11) | (1 << CS10);
in setup().
The micros function will start reporting sporadic values after about 0.25s. E.g. the micros() will increase at a very low rate after that, and often go backwards.
I'm testing on an Arduino Uno.
I'm also trying to check if the timer interrupt being called might be too heavy. It's not doing anything much except some integer maths and one digitalWrite.
According to the datasheet, "”8-bit Timer/Counter0 with PWM” on page 93 and ”16-bit Timer/Counter1 with PWM” on page 111 share the same prescaler module, but the Timer/Counters can have different prescaler settings. The description below applies to both Timer/Counter1 and Timer/Counter0."
So it's likely not an interaction with clock select, but you have only 64 clocks to perform the interrupt and exit it. There's some overhead in entering and exiting the interrupt. And DigitalWrite isn't as fast as you think. So without counting instruction clock cycles, I think I'd pursue the line of thought from your last statement -- lighten the load in that interrupt by just setting a flag and then exit. Handle the flag in the main loop. When you're talking microseconds, it's especially important to get out of that ISR quickly. Pseudocode:
volatile uint8_t timerflag = 0;
ISR <timer1_whatever>
{
timerflag = 1;
}
back in main loop:
if (timerflag == 1)
{
<do something>
timerflag = 0; // reset for next interrupt
}
Make sure your timeflag is declared as volatile since it's being changed inside an interrupt and checked outside the interrupt.
Related
I have steppers stepping during an interrupt timer at 50 and have all my code working between the interrupts until I tried reading serial commands more than one character long.
I'm getting dropped bytes so my strings are missing a letter every 4-5 chars. I researched all day to try and figure out a solution but have come up with nothing. If I don't use an interrupt my stepper stops for 2 seconds reading a one char serial input as a string.
My goal is to have a remote control app sending speed commands. I need help working this problem out.
https://sourceforge.net/p/open-slider/code/ci/master/tree/OpenSliderFirmware/
String incomingString = "";
if (Serial.available() > 0) {
incomingString = Serial.readString();
Serial.println(incomingString);
}
Using Accelstepper library
interrupt:
//Interrupt Timer1
void ISR_stepperManager() {
Slide.runSpeed();
Xaxis.runSpeed();
Yaxis.runSpeed();
}
Quick answer: you don't if the interrupt timer is cutting in too often.
I resolved the problem by using a variable interrupt timer and a step multiplier. Basically the steps are called every time the timer interrupts instead of checking millis inside the interrupt function. This solved many issues. The speed of the stepper is now controlled by the interrupt timer. This gave me more free cycles to fully read the incoming serial without corruption and improved efficiency. Calling more steps per cycle when doing over 4k steps/s also improved efficiency requiring less cycles for a high rate of steps.
The serial is processed one char per cycle to prevent blocking.
Overall, if you are using serial and an interrupt timer, any interrupt happening < 100us you should be cautious how much code you are running during the interrupt. It will cause issues with incoming serial and user inputs. A few lines of code in a 25us timer interrupt, incoming serial will not function.
i'm not sure if it will help to your problem, but i saw along the time that the String type is not safe to use when other things need to happened.
i prefer to use char array and read one char at a time.
while(Serial.available())
{
data[x] = Serial.read();
x++;
}
i'm finding it much more reliable.
hope it's help!
The Arduino A/D converter takes about 0.1ms according to the manual. Actually, my tests show that on an Uno I can execute about 7700 per second in a loop.
Unfortunately analogRead waits while the reading is being performed, making it difficult to get anything done.
I wish to interleave computation with a series of A/D conversions. Is there any way of initiating the analogRead, then checking the timing and getting the completed value later? If this needs to be low-level and non-portable to other versions, I can deal with that.
Looking for a solution that would allow sampling all the channels on an Arduino on a regular basis, then sending data via SPI or I2C. I am willing to consider interrupts, but the sampling must remain extremely periodic.
Yes, you can start an ADC conversion without waiting for it to complete. Instead of using analogRead, check out Nick Gammon's example here, in the "Read Without Blocking" section.
To achieve a regular sample rate, you can either:
1) Let it operate in free-running mode, where it takes samples as fast as it can, or
2) Use a timer ISR to start the ADC, or
3) Use millis() to start a conversion periodically (a common "polling" solution). Be sure to step to the next conversion time by adding to the previously calculated conversion time, not by adding to the current time:
uint32_t last_conversion_time;
void setup()
{
...
last_conversion_time = millis();
}
void loop()
{
if (millis() - last_conversion_time >= ADC_INTERVAL) {
<start a new conversion here>
// Assume we got here as calculated, even if there
// were small delays
last_conversion_time += ADC_INTERVAL; // not millis()+ADC_INTERVAL!
// If there are other delays in your program > ADC_INTERVAL,
// you won't get back in time, and your samples will not
// be regularly-spaced.
Regardless of how you start the conversion periodically, you can either poll for completion or attach an ISR to be called when it is complete.
Be sure to use the volatile keyword for variables which are shared between the ISR and loop.
The function of the program I am writing is to stream incoming analog data from a sensor to a program on my computer across the USB port. For a little fun, I've decided to add a button to the program that will turn on/off a lamp. The lamp will be connected to a relay, which is connected to the arduino. I know how to go about programming it, but I want to know if this will interrupt the sensor data transfer?
I will get the current state of the light (HIGH(1) or LOW(0)) from the arduino when the button is pressed, then write to the arduino (HIGH(1) or LOW(0)) depending on the current state. I have a 5 second delay between each loop of the arduino program, for reasons related to the sensor output; however, I think I'm going to have to change this so that when the button is pressed, it is not missed by the arduino loop, or is that not possible?
I thought I read somewhere that you can't transmit/receive streaming data on the same serial line...in which case, I will need the Mega.
You have to remember and think of the Arduino as a single threaded device. While it is doing anything it is not able to do anything else. Period! In regard to the serial port however, the buffer will still accept incoming data on RX, however if an overflow situation occurs whilst blocked, management is impossible.
See the following taken directly from the Arduino reference
Certain things do go on while the delay() function is controlling the Atmega chip however, because the delay function does not disable interrupts. Serial communication that appears at the RX pin is recorded, PWM (analogWrite) values and pin states are maintained, and interrupts will work as they should. Reference
Now in saying that when you are setting the delay to 5 seconds between loops ( delay(5000) ) you are essentially blocking it from doing anything else almost full stop.
The Arduino framework exposes a a counter ( millis() ) that basically runs from the moment of boot for roughly 50 days in increments of one (1) millisecond. See Arduino - millis()
In your application you would define (remember) what loop you were due to run & when the said loop had finished so to not allow the other loop to run until the millis() counter was a defined amount more than your count. (Remember to define the count as a long)
Then what you do is move your loops out into separate functions that will only execute if the if statement return true...
for example...
long interval = 5000; // Define interval outside of the main loop
long previousCount = 0; // Used to store milli count when finished
int loopPosition = 1;
void loop()
{
if ((long)millis() - previousCount >= 5000 )
// This if statement will only return true every 5 seconds (5000ms)
{
if (loopPosition == 1)
{
function_One();
previousCount = millis(); // Redefine previousCount to now
loopPosition++; // Increment loop position
}
else if (loopPosition == 2)
{
function_Two();
previousCount = millis();
loopPosition--; // Decrement loop position
}
}
// Do Anything Here You Want
// - While ever the if statement above returns false
// the loop will move to this without hesitation so
// you can do things like monitor a pin low / high scenario.
}
void function_One()
{
// Do Your First Loop
}
void function_Two()
{
// Do Your Second Loop
}
The above will stop any delay you are using from blocking awesomeness, and to more of a point, almost make delay obsolete if implemented correctly under the right scenarios.
In regard to your serial data comment, like i said at the top of this article, the Arduino can only do one thing at a time. Transmitting and receiving at exactly the same time is impossible even with the Mega. In saying that a board like the 'Uno' for example is only capable of one serial interface, where as the 'Mega' is capable of four.
Best of luck....
NB- For a beginner reading this, the following tutorial / example covers what i have above in fairly simple terms and is a great building block for further awesomeness! Arduino - Blink Without Delay
I have a program that utilizes the Servo library and an external interrupt routine. From my understanding the Servo library uses a Timer1 interrupt to send pulses to the servo to maintain position. I am wondering what the impact is on the micros() count since it does not increment during an interrupt.
The external interrupt routine in my code is for a tachometer. It determines the time between pulses using micros(). I am concerned that the Servo library will cause drift of the millis() and micros() counters and make the speed inaccurate. The tachometer may have to sense a 10,000 RPM speed so about 167 Hz.
Eventually I will implement PID control using servos and tachometer.
volatile unsigned long period;
unsigned long microseconds;
void setup(){
Serial.begin(9600);
pinMode(tachometerPin, INPUT);
pinMode(led, OUTPUT);
attachInterrupt(0, tachometer, RISING); // set external interrupt
throttle.attach(throttlePin); // attach servo objects to pins
fuel.attach(fuelPin);
throttle.writeMicroseconds(throttle_idle); // set servo positions
fuel.writeMicroseconds(fuel_neutral);
}
void loop(){
Serial.println(calculateSpeed());
}
float calculateSpeed(){
/* Calculate speed of engine in RPM */
float s = 60.0/(period*0.000001);
return(s);
}
void tachometer() {
/* Determine time between rotations of engine (pulses from tachometer) */
period = micros() - microseconds;
microseconds = micros();
}
Even tachometer() and the function that updates millis() are called from an interrupt, so even it would "break" your code.
How much would this ruin your lecture? Not very much. Arduino 2009, with using a crystal for 16 MHz, has a drift of many seconds at day. Arduino Uno, which uses a less precise oscillator, would drift a lot more.
So, unless you are doing a lot of calculation in the interrupt routine, you are fine. Also remember that a micros() call cost you 4 µs (in fact you will see it growing 4 by 4... or this was to have Timer0 to overflow every second? Take a look at the timer prescaler; you can change it if it does not break the Servo lib. It will break millis() and micros(), and you can use Timer1 or Timer2, but Timer0 is the only 16-bit timer, so it depends on you), so this is your real precision killer.
I would suggest to eliminate the function call in the interrupt:
unsigned long tmpTime;
void tachometer() {
/* Determine time between rotations of engine (pulses from tachometer) */
tmpTime = micros();
period = tmpTime - microseconds;
microseconds = tmpTime;
}
And even attachInterrupt call an ISR that call your function. You may implement attachInterrupt by yourself so you implement the ISR directly (one fewer function call, and function calls are relatively expensive as you have to work with the stack and registers).
Also don't use micros(), which does a lot of things (read the Timer0 actual count, and calculate count to µs, and is a function call); just read the timer register directly and do the difference with that value, and do the translation of count to µs into loop(). That way it should be a lot faster.
I'm not writing code as you just have to open Arduino's library and look at what they do, and replicate it by yourself. It is quite easy as you have a working example, an ATmega datasheet and a lot of tutorials on timers, interrupts and even PWM.
I have a piece of code in Arduino (Avr) which I want to execute without it being interrupted by an interrupt that also operates on variables used in this piece of code. I don't want that interrupt to be lost while the piece of code is being executed; rather, I want to have the interrupt be postponed for a short time. I only want to postpone this one interrupt, not all interrupts.
Right now I'm clearing that interrupt mask and setting it again after the code is finished. Is this working? This is what the code looks like:
Piece of code I don't want being interrupted by that interrupt (timer1 overflow interrupt, in this case):
TIMSK1 = 0; //Set Timer1 Mask off. Just postponed ???? I hope so.
int c = buffer[reading_pointer];
reading_pointer = (reading_pointer + 1)%SIZE_OF_BUFFER;
something_on_buffer = false;
//buffer and something_on_buffer are set on Timer1 interrupt.
TIMSK1 |= (1 << TOIE1); //Enable timer1 again.
something_on_buffer and buffer are set also on Timer1, there would be a conflict if the interrupt executes in the middle of reading the buffer and setting something_on_buffer in this piece of code, and that's the reason I want to postpone Timer1 interrupts for this few lines of code. Just to be sure. How to do this? Is this the right way?
Your approach looks fine.
Generally, processors have a flag register for the interrupts, and a register to enable the interrupts. At each step, the processor checks the and of the flags and enable bits to see if it should run an interrupt. That is, the enable bits don't control whether the flag is set, only if the set flag induces the interrupt to run.
If you enable an interrupt by setting the bit and the flag is already set, the interrupt with run before the next machine instruction.
If the interrupt is not enabled, the flag bit can still be set by the condition.