0

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!

ritchie888
  • 583
  • 3
  • 12
  • 27

1 Answers1

3

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!

payala
  • 1,357
  • 13
  • 28
  • Thanks for your help so far. I've been investigating into this and I'm fairly sure I've got unnecessary delays in my I2C process. I've taken your advice and used an output pin to toggle an LED at certain points in time, I also spent some time on an oscilloscope to see how it looks. The good news is that the I2C clock is sampling at 400KHz (or close enough) so it's not a matter of the clock is set up wrong: http://imgboot.com/user/ritchie888/images/setup1.png – ritchie888 Apr 17 '13 at 10:15
  • I'm using timer1 to call an interrupt and throw a flag at a certain sample rate (checked and working fine). Every poll I'm calling a function to read I2C data. I think your second bullet point is the culprit here. I used example I2C code of microchips website to get an understanding of what to do, but it's waiting for an interrupt to be called (the ACK/NACK) after almost every stage of the I2C process, like sending the start bit, stop bit, and restart bit. From what I understand an ACK isn't necessary for these stages(?) and waiting for them to be called is causing massive delays. Thoughts? – ritchie888 Apr 17 '13 at 10:19
  • If I recall correctly, Microchip's I2C sets interrupt flags for multiple events, not just ACK/NACK, but also Start/Stop, byte read/write, and the like. That's probably what the code is waiting for. However, and everytime I say this I set the controversy, my experience with microchip's sample code is not good (and I love Microchip MCUs). But their sample code isn't neither optimal, maintained, bug free and sometimes I even wonder if it is tested. I have learned to interpret it more like a pseudocode that serves as a guide when you don't know where to start. – payala Apr 17 '13 at 14:05
  • What I do find veery good is their datasheets. They are clear and precise most of the time, so that is my main reference. In your case, I would get a timing of a full byte to see how the start->address->ACK->data->ACK->stop flow and the timing between them. You have a good scope, so you're in luck. That MSO must be mixed-signal, so you can probably hook up the logic analyzer and directly interpret the I2C bus (highly recommended once you start analysing frames). – payala Apr 17 '13 at 14:11
  • Thanks again for your help. I think I'm homing in on the problem. I was setting the internal oscillator to 80MHz (at least I think that's what I was doing). Since removing that and relying on the standard start up oscillator speed, which I believe is 7.37MHz, I'm getting some super fast I2C. Unfortunately with not knowing the clock speed I can't confirm if the interrupt timer (timer1) is working correctly, so I'm calling the I2C command in a while loop, but it's doing this VERY fast, so I think me setting the clock has been the problem. Does I2C have a maximum clock speed? – ritchie888 Apr 17 '13 at 18:04
  • Well, it is possible, mostly because there are many things that can go wrong if your clock isn't properly setup, and given that maaany things depend on your clock setting, there are many chances of things failing. Anyway, for me it would be valuable that you take some tools to debug embedded systems and hardware. The oscilloscope is your main ally, and using I/O pins to signal timings or sequences is very useful. Just a tip, if you suspect on your clock setting... measure the clock pins and verify it. – payala Apr 17 '13 at 22:15
  • Although there is a balance, some things need to be theoretically correct, it is not enough to measure them. Especially if you need some sort of safety or guarantee a determined spec. The most common I2C frequencies are 100kHz and 400kHz, but the limit is specified by the parts connected to the bus (mostly), if you want to go higher speed, be careful with your bus lines RC constant, it may start to be the bottleneck regarding bus speed. You are welcome, I like to help whenever I can. – payala Apr 17 '13 at 22:22
  • Problem solved! Turned out it was nothing to do with I2C or the oscillator. It was me being stupid in the timer interrupt. Every poll of the timer I was turning the timer off, resetting the timer, then turning it back on. I have no idea why I was doing this. Since taking that out and just clearing the flag on each timer interrupt everything is working well. Sorry for my stupidity! Thanks again. – ritchie888 Apr 18 '13 at 14:03
  • Don't worry, when things fail... it's always us!! (99% of the time). Great that it's working now! – payala Apr 18 '13 at 17:08