Ok, I've worked on 4 improvements (some of them oriented to my application):
1) I've found out that I2CBytes is slower than using a separate I2CWrite plus an I2CRead (I don't know if there is any major drawback, but I believe I2CBytes has advantages). So I used this to decrease the running time of both functions (HiTechnic angle, and mindsensors NXTMMX).
With this I decreased from 16ms to 14ms.
2) To decrease time on the NXTMMX reading function, I gathered both positions in the same packet asked through I2C. I don't really understand why this isn't the default option, since it takes the same time as asking for a single tachometer value, since they are in consecutive registers.
With this, I got half time spent to get the values: 14ms for both values.
3) I need values from 2 different Angle sensors. Because I was using the same function to retrieve info, I had to protect it, which was making them not running "at the same time" when using different threads. By duplicating them with different names, I solved this problem and got a much faster result. Thanks to this post:
https://sourceforge.net/apps/phpbb/mind ... 018&p=9750
Using 2 threads reading both sensors and a third thread waiting for completion of both, I got 18,5ms per read, instead of 28ms with a single function protected by safecall.
All 4 values (2 tachometers + 2 angles) with concurrent threads are collected in around 21,5ms/read.
4) Instead of having threads in parallel getting the values all the time, I combined the readings in a single loop and saved the values in global variables. This removed any time consumed in "while" statements or whatever else. Instead of ~21,5 I got ~16,25ms.
Here are the codes for the separate functions and the function with all readings together. Note that I assumed some addresses and register values, instead of keeping them as parameters to send when calling.
Code: Select all
void ReadAngle_Custom(byte port, int &Angle, long &AccAngle, int &RPM)
{
byte cmdbuf[] = {0x02, 0x42};
byte buf[10];
byte nByteReady = 0;
byte loop, n;
while (I2CStatus(port, nByteReady) == STAT_COMM_PENDING);
I2CWrite(port, 8, cmdbuf);
while (I2CStatus(port, nByteReady) == STAT_COMM_PENDING);
n = I2CRead(port, 8, buf);
if ( n == NO_ERR ) {
Angle = buf[0]*2 + buf[1];
AccAngle = buf[2]*0x1000000 + buf[3]*0x10000+
buf[4]*0x100 + buf[5];
RPM = buf[6]*0x100 + buf[7];
while (I2CStatus(port, nByteReady) == STAT_COMM_PENDING);
} else {
Angle = 0; AccAngle = 0; RPM = 0;
}
}
Code: Select all
void MMX_ReadTachometers(byte port, long & tacho1, long & tacho2)
{
byte cmdbuf[] = {0x06, 0x62};
unsigned byte buf[10];
byte nByteReady = 0;
byte n;
while (I2CStatus(port, nByteReady) == STAT_COMM_PENDING);
n = I2CWrite(port, 8, cmdbuf);
while (I2CStatus(port, nByteReady) == STAT_COMM_PENDING);
n = I2CRead(port, 8, buf);
if(n == NO_ERR) {
tacho1 = buf[0] + (buf[1]<<8) + (buf[2]<<16) + (buf[3]<<24);
tacho2 = buf[4] + (buf[5]<<8) + (buf[6]<<16) + (buf[7]<<24);
while (I2CStatus(port, nByteReady) == STAT_COMM_PENDING);
} else {
tacho1 = 0; tacho2 = 0;
}
}
Code: Select all
void ReadAllValues(byte a1port, byte a2port, byte mmxport){
byte cmdbuf1[] = {0x02, 0x42}; // Angle1
byte cmdbuf2[] = {0x02, 0x42}; // Angle2
byte cmdbuf3[] = {0x06, 0x62}; // MMX
byte buf1[10], buf2[10], buf3[10];
byte nByteReady1 = 0, nByteReady2 = 0, nByteReady3 = 0;
byte n1, n2, n3;
byte ready1 = 0, ready2 = 0, ready3 = 0;
while (I2CStatus(a1port, nByteReady1) == STAT_COMM_PENDING);
I2CWrite(a1port, 8, cmdbuf1);
while (I2CStatus(a2port, nByteReady2) == STAT_COMM_PENDING);
I2CWrite(a2port, 8, cmdbuf2);
while (I2CStatus(mmxport, nByteReady3) == STAT_COMM_PENDING);
I2CWrite(mmxport, 8, cmdbuf3);
while (I2CStatus(a1port, nByteReady1) == STAT_COMM_PENDING);
n1 = I2CRead(a1port, 8, buf1);
while (I2CStatus(a2port, nByteReady2) == STAT_COMM_PENDING);
n2 = I2CRead(a2port, 8, buf2);
while (I2CStatus(mmxport, nByteReady3) == STAT_COMM_PENDING);
n3 = I2CRead(mmxport, 8, buf3);
if (n1 == NO_ERR){
angle1 = buf1[0]*2 + buf1[1];
accAngle1 = buf1[2]*0x1000000 + buf1[3]*0x10000+
buf1[4]*0x100 + buf1[5];
rpm1 = buf1[6]*0x100 + buf1[7];
} else {
angle1 = 0; accAngle1 = 0; rpm1 = 0;
}
if (n2 == NO_ERR){
angle2 = buf2[0]*2 + buf2[1];
accAngle2 = buf2[2]*0x1000000 + buf2[3]*0x10000+
buf2[4]*0x100 + buf2[5];
rpm2 = buf2[6]*0x100 + buf2[7];
} else {
angle2 = 0; accAngle2 = 0; rpm2 = 0;
}
if (n3 == NO_ERR){
tacho1 = buf3[0] + (buf3[1]<<8) + (buf3[2]<<16) + (buf3[3]<<24);
tacho2 = buf3[4] + (buf3[5]<<8) + (buf3[6]<<16) + (buf3[7]<<24);
} else {
tacho1 = 0; tacho2 = 0;
}
}
Also note that I don't care if I have only one ready to read. The variables are only updated after all of them are read from the I2C devices, because synchronization is helpful in my application. Besides that, in my case, they take approximately the same time to read. One could keep reading "asynchronously". Every time a reading was complete, the I2CWrite would be sent again, in an infinite loop.