How to speed up I2C writes

Firmware/software/electronics/mechanics
Post Reply
japreiss
Beginner
Posts: 12
Joined: Thu Mar 24, 2016 1:17 am

How to speed up I2C writes

Post by japreiss »

Hi all, based on my discussion with arnaud, I got an Adafruit I2C 16-channel PWM deck so I can use the Crazyflie as a flight controller for a hexarotor. I am now getting the board up and running. Unfortunately, it takes a long time to transfer the I2C commands for 6 motors over I2C: about 500 usec according to my measurements. I think this might be too slow to run in the main loop since I am also running the Kalman filter and a nonlinear controller.

I thought of a few possible ways to address this problem:

1. Increase the I2C clock speed on the deckBus.

2. Add an asynchronous I2C write function to i2cdev.h. If I understand correctly that the I2C driver uses interrupts when writing. So, could the I2C driver store my message data in a buffer and read it as needed in the ISR, while my stabilizer loop is doing other computations? Right now my stabilizer loop must wait for the whole transfer to finish before continuing, but it seems to just be waiting on a semaphore.

3. Slow down the main loop - but this is obviously not ideal.


Any thoughts?

(btw, also happy to contribute my pca9685 driver back to mainline. It doesn't support every feature of the hardware, but enough to drive ESCs.)
japreiss
Beginner
Posts: 12
Joined: Thu Mar 24, 2016 1:17 am

Re: How to speed up I2C writes

Post by japreiss »

By the way, my data payload is a single 24-byte write. According to my calculations, at 400kHz this should take about 580 uSec, which agrees with what I see on my oscilloscope.

The pca9685 supports 1MHz "fast mode plus" i2c. EDIT: some others in the STM series do too, but apparently the stm32f4xx does not (ref. manual, page 840). Too bad!
arnaud
Bitcraze
Posts: 2538
Joined: Tue Feb 06, 2007 12:36 pm

Re: How to speed up I2C writes

Post by arnaud »

Hi, I would say that the solution is to send asynchronously and let the stabilizer loop continues. This way there will 'just' be a delay between the end of the loop and the time the new PWM values are out but the loop does not have to wait for the values to be out.

I am not sure of the best way to do that though, the most simple I can think about is to create a high priority task that do only motor update, with a queue or a semaphore you can unlock this task to write the values. It seems a bit overkill to create a task only for that but it should work fine.

Edit: Btw it would be awesome if you could contribute the driver :-)
imcinerney
Beginner
Posts: 3
Joined: Tue Aug 01, 2017 3:19 am

Re: How to speed up I2C writes

Post by imcinerney »

The best way to do the asynchronous transmission would be to use the DMA with the I2C bus. You would need to set the auto increment flag on the PCA9685 (so after each data byte written it automatically moves to the next) so you can write multiple bytes at once. Then you can send all the updates in a single I2C transaction (provided you utilize the channels that are next to each other in the register map).

The DMA would handle transferring the bytes into the transmit register when needed, and will stop once it sends the desired number of bytes. This is a hardware function of the chip, so you don't need to have a thread managing the I2C interface. Ideally, you would also put a callback function to be called when the transmission is complete to catch any errors that may have occurred.
arnaud
Bitcraze
Posts: 2538
Joined: Tue Feb 06, 2007 12:36 pm

Re: How to speed up I2C writes

Post by arnaud »

The I2C driver already uses DMA, the problem here lies in the API: currently the transfer function will launch a transfers, wait for it to finish and then return the result, it is synchronous.

I agree that an asynchronous call with callback would feel better than a new task but it will require to making a new asynchronous API for I2C and having callback can be a bit tricky (for instance you need to keep a list of callbacks, one for each concurrent I2C request, we use only static memory so we need to choose upfront how many concurrent request we can accept). I am not sure it is worth the effort.
japreiss
Beginner
Posts: 12
Joined: Thu Mar 24, 2016 1:17 am

Re: How to speed up I2C writes

Post by japreiss »

I implemented the separate task approach using a one-element queue. It works, but introduces some timing jitter of around 200 usec. However the input PWM frequency of my ESCs is only 400Hz (2500 usec period), so I don't think the effect of the jitter will be significant. I will wait until flight tests to say for sure :)

I guess one way to reduce jitter would be to somehow ensure that the I2C task polling the queue is always scheduled to run immediately after the stabilizer task.
arnaud
Bitcraze
Posts: 2538
Joined: Tue Feb 06, 2007 12:36 pm

Re: How to speed up I2C writes

Post by arnaud »

If your task has a higher priority than the stabilizer task, it should execute right when you push the new value in the queue (it will preempt the stabilizer task). What priority have you set for your task?
Post Reply