Module for MPU9150

Showroom for MicroPython related hardware projects.
Target audience: Users wanting to show off their project!
User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: Module for MPU9150

Post by dhylands » Fri Oct 17, 2014 1:45 am

The HAL doesn't disable interrupts anywhere.

It's quite possible that it needs to.

Normally the HW isn't all that sensitive to timing, but occasionally, it will be. So if an interrupt occurs at just the wrong time, it can change the timing of an operation which then triggers your behaviour.

Instead of using optical encoders, you might want to just fire up a timer and crank up the frequency. Write an interrupt handler which just increments a number or something simple like that:
https://github.com/dhylands/upy-example ... /atomic.py

Then you'd need to go through the I2C HAL driver and try disabling interrupts around blocks of code to try and see if you can figure out which portions are affected.

User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Module for MPU9150

Post by pythoncoder » Fri Oct 17, 2014 3:35 pm

This morning I hacked the module code which reads the raw accelerometer data to disable interrupts while it performs the I2C memory read. I haven't seen a crash or timeout since. So I'm convinced that the problem lies in the I2C library. For people wanting to use the MPU9150 and the library I'd offer the following comments.

1. If you're not using interrupts it will work.
2. If you are, and can tolerate interrupts being disabled for about 250uS, modify the library code to disable interrupts for the duration of memory reads, at least for any readings which you're performing repeatedly.

Evidently the problem needs to be fixed, especially as some I2C devices require reads of many more than six bytes at a time. The idea of using a timer interrupt is great (I'd introduce a deliberate 50uS delay into the handler to mimic my conditions). However I can imagine the process being time consuming as the HAL code looks rather complex. I suggest that someone with an understanding of the I2C protocol and the code suggests areas which may be time critical to provide some focus for the debugging effort - I'd imagine that most of it works as a state machine and can tolerate unexpected delays.

Regards, Pete
Peter Hinch
Index to my micropython libraries.

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: Module for MPU9150

Post by dhylands » Fri Oct 17, 2014 4:14 pm

I imagine that the timing constraint comes from the device in question, and probably not the I2C library itself, but that's really just speculation on my part.

User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Module for MPU9150

Post by pythoncoder » Mon Oct 20, 2014 7:00 am

I've spent many hours trying to replicate this bug using timers and trying to understand its cause. I've not made much headway. But disabling interrupts has fixed the issue for me and may be an adequate solution for most use cases. So I feel I've taken this as far as I can. Here is a summary of my conclusions:

1. For @Turbinenreiter I've suggested a mod to the driver enabling the user to control its behaviour.
2. I've described my attempts to understand and replicate the bug in case anyone else fancies taking up the challenge.
3. It's a moot point whether the problem is resticted to the MPU9150 or whether other I2C devices might be affected.

1. Since all communications with the MPU9150 are via I2C memory read and write functions I suggest modifying the MPU9150 class as follows. Provide a disable_interrupts property set by an argument to the class constructor. Have methods for performing I2C memory read and I2C memory write which test this property: if set, save the state of the interrupt enable bit, disable interrupts, perform the r/w, then restore IE to its previous state. Replace calls to self._mpu_i2c.mem_write and self._mpu_i2c.mem_read with calls to the new methods. Users who encounter the bug and can tolerate having interrupts disabled for 250uS can thus use the workround.

2. I've studied the datasheet for the MPU9150 and can't see any time delays which might cause the problem. I've looked at the I2C protocol and, as far as I can see, master and slave operate as state machines and should be tolerant of delays caused by the master's CPU taking time to handle interrupts. But I'm new to I2C; there is a problem, so I'm evidently missing something. I attempted to replicate the bug using timers as follows. I set up two timers running at slightly different frequencies close to 1KHz. Each had a callback being a lambda function which waited 60uS, replicating the time taken by my own ISR. My main loop read the accelerometer every 1mS. This, I thought, replicated my system with two asynchronous optical incremental encoders but with frequencies doubled and reads to the MPU9150 occuring at about ten times my rate. Yet in hours of runing I only saw the fault once, and that during initialisation of the MPU9150.

Clearly it's not an easy one to replicate, yet I and @Turbinenreiter have encountered it and it is fatal. I have some experience of optical incremental encoders and they can be unruly devices, notably in the presence of vibration. It's possible that mine are occasionally producing interrupt storms. Yet, as far as I can measure, they are working with expected precision.

3. It would be interesting to know if other I2C devices might be affected or whether it's specific to the MPU9150. Unfortunately I'm not in a position to test this.

In conclusion I think tracking down the bug would be challenging. We have a workround which may be adequate for most, if not all, potential users. I suggest we implemet the workround and call it a day.

Regards, Pete
Peter Hinch
Index to my micropython libraries.

Turbinenreiter
Posts: 288
Joined: Sun May 04, 2014 8:54 am

Re: Module for MPU9150

Post by Turbinenreiter » Mon Oct 20, 2014 12:47 pm

@pythoncoder:
thanks for putting that much work into this!
If you want, you can send me a pull request for your proposed changes on github (or drop the code here) and I will merge it. If not, I will implement it myself, but it may take a while until I find time to do that.

User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Module for MPU9150

Post by pythoncoder » Tue Oct 21, 2014 12:07 pm

@Turbinenreiter
I've produced some modified code and I think I've uploaded it to github - I must confess I'm very much a n00b when it comes to git and github so do tell me if I've got it wrong.

I've logged a bug on github as I think that the Micropython I2C commands should return a subclass of Exception rather than the base class. If this is accepted we could replace the hairy "except:" lines with a more sanitary "except Exceptiontype:" formulation.

Finally you'll notice that the first read which returns the chip_id doesn't use my new read() function. My attempts to use it were rewarded with a total crash for reasons which remain unclear at the moment.

Hope this helps,

Pete
Peter Hinch
Index to my micropython libraries.

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: Module for MPU9150

Post by dhylands » Tue Oct 21, 2014 2:24 pm

Without looking at the details, why couldn't you just use:

Code: Select all

try:
    ..somethng...
except Exception:
    ..deal with excepttion...
It's not clear to me why using a more derived Exception class buys you anything?

Turbinenreiter
Posts: 288
Joined: Sun May 04, 2014 8:54 am

Re: Module for MPU9150

Post by Turbinenreiter » Tue Oct 21, 2014 3:45 pm

@pythoncoder
I made the pull request on Github - have a look over there.

@dhylands

I think what he means is if you have:

Code: Select all

try:
    ..something...
    ..something else...
except Exception:
    ..deal with excepttion...
you wouldn't know if something or something else failed.

User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Module for MPU9150

Post by pythoncoder » Tue Oct 21, 2014 4:31 pm

Writing

Code: Select all

try:
   potentially a number of lines of code
except Exception:
   ...
is generally regarded as bad practice and can make debugging code difficult. For example it's handy to be able to silently trap some types of events but without also silently trapping errors in your code such as division by zero...

Regards, Pete
Last edited by pythoncoder on Tue Oct 21, 2014 4:48 pm, edited 1 time in total.
Peter Hinch
Index to my micropython libraries.

User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Module for MPU9150

Post by pythoncoder » Tue Oct 21, 2014 4:44 pm

@Turbinenreiter
I've posted another update on github aimed at improving the exception handling. The unpleasant except: code has now been localised to my read and write methods pending the I2C module being modified to emit a custom exception. The user can now handle nonexistent, unplugged or incorrectly specified devices thus:

Code: Select all

from mpu9150 import MPU9150, MPU9150_Exception
try:
    obj_mpu = MPU9150()
except MPU9150_Exception as response:
    print(response) # Then presumably shut down the application in an orderly fashion
It should also make future changes to the code easier to manage, since unspecific except: clauses can be pigs for hiding bugs.

The build also gets rid of the issue I mentioned regarding the chip_id read which was down to finger trouble on my part,

Regards, Pete
Peter Hinch
Index to my micropython libraries.

Post Reply