Question

I'm having trouble trying to sample I2C slave devices using a dsPIC33f microcontroller.

I am using the PICs internal timer1 timer to 'tick' over at a defined sampling rate and grab the necessary data. Unfortunately the results aren't being obtained fast enough and I'm not sure why. One of my slave devices is the ADXL345 accelerometer which has a maximum output data rate of 3600Hz. I don't need nearly this high, but I don't seem to be successfully sampling anywhere above around 50Hz.

The I2C is set up at 'fast mode' of 400KHz. The absolute max I would want to sample the accelerometer at is 1KHz, although this would be overkill, I'm really more interested around 128Hz. The parameters for the accelerometer that I've set are:

  • Data format (0x31) - self test off, interrupt inverted off, full resolution on, justify bit off, range bit +/-16g.
  • Data rate (0x2C) - low power mode off (normal mode), output data rate mode 400Hz (I have read in the datasheet that 400KHz I2C will only support as high as 800Hz, so I'm playing it safe with 400Hz).
  • Power control (0x2D) - autosleep off, measurement mode on, sleep bit off, sleep mode sampling rate 8Hz (although not used, so can be ignored).
  • Interrupts (0x2E) - data ready interrupt enabled, everything else off.

I'm using timer1 to sample at a specified sampling rate, I know the sampling rate is working sufficiently as I have a counter which outputs a message after the counter reaches one minute; I use a stopwatch to make sure it's right. For example, at 100Hz sampling rate I wait for the counter to count to 6,000 (100 * 60) and display a message, if the stopwatch is at 1 minute when I see that message I know it's sampling at least to some accuracy.

When I attempt to sample just from the accelerometer (I2C multiple byte read mode, read all six bytes in one call), it's not performing fast enough. Using my stopwatch method it seems to be taking about a minute and 15 seconds to do a job that should take one minute (sampling at 100Hz), i.e. it's not processing the I2C command fast enough. Higher sampling rates adds more to the delay.

I have a feeling it's something to do with the I2C clock and timer1 not being synchronised and therefore there's unnecessary waiting involved in my call for accelerometer data. I can't image that the 400KHz clock for I2C is insufficient, but please correct me if I'm wrong.

How should I be reading data from I2C slave devices correctly? I also have a gyroscope and magnetometer that I want to be reading at a sufficiently high sampling rate, the magnetometer has a limit of 160Hz, so as I say, 128Hz sampling rate would be fine for allk three devices. Trying to read from all three devices at once obviously adds to the slower than expected sampling.

I will also be collecting analogue data from 4 pins simultaneously (ADC 10bit). This code is already implemented and I can read the analogue data at 1KHz with the sampling rate working as expecting, it's just the I2C devices that are acting slow!

I would expect the accelerometer to be fine when trying to sample at 100Hz, when I can output at 3600Hz (800Hz max for I2C) but it's really struggling and I don't know what else to try.

Cheers!

Was it helpful?

Solution

OK, this may be many things:

  • The simplest explanation in your case is a som misconfiguration with that timer you are using to trigger the pollings. I would need to know how you are using this, is it triggering an interrupt where you set a flag to trigger the accelerometer polling? are you polling the timer manually to trigger the accelerometer polling. In any case, toggling an output pin high and low when that happens and seeing it with the oscilloscope will give you valuable information. Are all polling periods longer, or are there just some of them that are taking much more than expected?

  • The one that I have seen more often is a slow I2C handling routines. Your I2C might be set up at 400KHz, and that is indeed the speed at which the bits of a byte are read and written, but there is some processing time between bytes that depends very heavily on your code complexity. In your case, since you are using multiple byte read mode, this time isn't actually between bytes, but between polling cycles. But it is strange that this would be your problem, it's not such a frequent polling nor large data reads.

  • What I would do in your case (having some sort of measurement equipment, which you seem to have), is to check that all the timings are as you expect. Don't assume anything, measure it and verify that it is doing what you expect. In this regard, I would start with the easiest things. Is the clock running at 400kHz? Are the six bytes being read without delays between them? Are there the expected idle gaps between pollings? Is the I2C bus getting stuck (SDA and/or SCL low for long period of time) between pollings? are there any unexpected communications or activity on the bus apart from the ones with the accelerometer? These are some of the things that I would check to get a clue of what might be going wrong. The golden rule here is Don't speculate, measure it!

  • If everything above is perfect and as expected, just with a longer time period between pollings in a stable manner. I would start checking the timing of the sofware to get an idea of how much time is going in each routine, I have seen many software developers surprised by how much time some apparently simple operations can take. To do this, use the output pin bit toggling described in the first bullet point. Use a couple of IO ports, so you have two markers one on each channel of the scope, and change the place on the code where you toggle those bits, just play with it to check for any slow parts of the code. If you want another golden rule for this, divide and conquer. Set your markers at the highest abstraction routines, and dig lower dividing the slow part of code until you find what's wrong.

Try this, and let me know if it helped.

Cheers, and good luck!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top