This way works! In the Serial Monitor it prints out the value of counter just like expected!
In the main loop I use the Gyro value and get nice results. But for a reason would need to have the mpu.update() function call more often, i.e in the interrupt. This way I will always have more up to date Gyro values.
So in code below I move mpu.update() to interrupt function
Now to the problem: When I do this, the program gets stuck. It will print out the "Be", (first 2 letters of the print before mpu.update();
But then it gets stuck and nothing more gets printed.
Remember that the interrupt logic is disabled before the control goes to ISR. The Serial.print() method is not supposed to work in ISR as the said method requires enabled interrupt logic for its working. So, move all the print() commands to the loop() function and things should be alright.
It sure does seem like that. Even after removing the print statements in the interrupt and only having mpu.update() it does not work.
Is there any way to be able to call the mpu.update() function in the interrupt?
Or maybe, is there another way I can get more frequent updates without writing mpu.update() every other line?
Your interrupt happens 3.8 times a second. If your loop() is faster than that you would get a higher sample rate by calling mpu.update() in loop(). If you loop() runs slower than that, calling mpu.update() in the ISR (if that was possible) would fetch data that would never be processed.
Either way, calling mpu.update() in loop() is the right way to do it.
The following simple experiment shows that the MCU disables the Global Interrupt Enable Logic before arriving at the ISR and yet the string "Hello" is being printed nicely at 1-sec interval in the ISR which indicates that the interrupt logic has been re-enabled.
However, this facility has been (probably) added for debugging purposes. Test Sketch:
@dendanne
You may play around with the following sketch taken from the Examples of the IDE. The sketch works fine with my MPU6050 and try to print the angles in the ISR; the result is same as yours meaning prints only two characters.
So, execute the update() method in loop() function, change the time parameter to suit your update rates. Sketch:
#include "Wire.h"
#include <MPU6050_light.h>
MPU6050 mpu(Wire);
unsigned long timer = 0;
void setup() {
Serial.begin(9600);
Wire.begin();
byte status = mpu.begin();
Serial.print(F("MPU6050 status: "));
Serial.println(status);
while(status!=0){ } // stop everything if could not connect to MPU6050
Serial.println(F("Calculating offsets, do not move MPU6050"));
delay(1000);
// mpu.upsideDownMounting = true; // uncomment this line if the MPU6050 is mounted upside-down
mpu.calcOffsets(); // gyro and accelero
Serial.println("Done!\n");
}
void loop() {
mpu.update();
if((millis()-timer)>10){ // print data every 10ms
Serial.print("X : ");
Serial.print(mpu.getAngleX());
Serial.print("\tY : ");
Serial.print(mpu.getAngleY());
Serial.print("\tZ : ");
Serial.println(mpu.getAngleZ());
timer = millis();
}
}
Output:
MPU6050 status: 0
Calculating offsets, do not move MPU6050
Done!
X : 37.38 Y : 51.99 Z : -2.64
X : 34.48 Y : 47.95 Z : -2.66
X : 31.80 Y : 44.22 Z : -2.67
X : 29.32 Y : 40.82 Z : -2.69
Interrupt Version:
#include "Wire.h"
#include <MPU6050_light.h>
MPU6050 mpu(Wire);
unsigned long timer = 0;
void setup()
{
Serial.begin(9600);
Wire.begin();
byte status = mpu.begin();
Serial.print(F("MPU6050 status: "));
Serial.println(status);
while (status != 0) { } // stop everything if could not connect to MPU6050
Serial.println(F("Calculating offsets, do not move MPU6050"));
delay(1000);
// mpu.upsideDownMounting = true; // uncomment this line if the MPU6050 is mounted upside-down
mpu.calcOffsets(); // gyro and accelero
Serial.println("Done!\n");
//-------------------------
TCCR1A = 0x00;
TCCR1B = 0x00;
TCNT1 = 49911; //1-sec time delay
TCCR1B = 0x05; //division factor 1024
bitSet(TIMSK1, TOIE1);
}
void loop()
{
/* mpu.update();
if ((millis() - timer) > 10) { // print data every 1-sec
Serial.print("X : ");
Serial.print(mpu.getAngleX());
Serial.print("\tY : ");
Serial.print(mpu.getAngleY());
Serial.print("\tZ : ");
Serial.println(mpu.getAngleZ());
timer = millis();
}*/
}
ISR(TIMER1_OVF_vect)
{
mpu.update();
Serial.print("X : ");
Serial.print(mpu.getAngleX());
Serial.print("\tY : ");
Serial.print(mpu.getAngleY());
Serial.print("\tZ : ");
Serial.println(mpu.getAngleZ());
}
Output:
DoMPU6050 status: 0
Calculating offsets, do not move MPU6050
Do
We already know that a serial print can work in interrupt context, the contentious part is what happens when the output buffer is filled in interrupt context
asm("cli");
for (size_t i = 0; i < 20; i++) {
Serial.println("This should fill the buffer up nicely.");
}
Serial.println("And we are still here.");
Serial.flush();
asm("sei");
Depends on which Arduino core you are using. The AVR core switches to polling when the buffer is full and interrupts are disabled.
// If the output buffer is full, there's nothing for it other than to
// wait for the interrupt handler to empty it a bit
while (i == _tx_buffer_tail) {
if (bit_is_clear(SREG, SREG_I)) {
// Interrupts are disabled, so we'll have to poll the data
// register empty flag ourselves. If it is set, pretend an
// interrupt has happened and call the handler to free up
// space for us.
if(bit_is_set(*_ucsra, UDRE0))
_tx_udr_empty_irq();
} else {
// nop, the interrupt handler will free up space for us
}
}
Thanks for your responses!
Here is the situation:
I mpu.update() in a main loop so I can get gyro values. No problemos!
This works fine as long as I do not have any delay() in the main loop to.
But I have delays! And what happens then is that the gyro says the correct angle, but after the delay the first values it says is totally random (anywhere from -150 to 150 degrees). This I think is because it takes a couple of mpu.update() in a row for the angle to stabilize.
The angle values being say -50 when it is actually say 0 degrees really messes with my code and gives me head-scratching bugs.
So what I was thinking therefore was to have the mpu.update() in a timer interrupt so that it is always updated, even though there is a delay() going on. But this clearly did not work.
Does anyone have an idea what I could try to get a continuous update on the mcu. (note that the delay(3000) I use does not have to be exactly 3000, I don't care if it becomes 2500 or 3500 if that helps with the solution).