Today I only want to give a small update on the function to read out the data of the temperature array of the grid-eye sensor. Until now I read out the data of one sensor pixel at once (which is 2 bytes) and then switch to the next pixel. This is a little bit unfortunate because the adressing of the sensor and the byte has to be done each time and a lot of overhead is generated.
It is much faster to read out as much bytes as possible at one read access. This is what I did today.
Therefore I used the function i2c_smbus_read_i2c_block_data. This function allows to read a block of data at once. It is limited to 32 byte because this is a restriction of the SMBus. Nevertheless this is much more than the 2 bytes I read out before and less overhead is generated. The data of the 64 pixels of the temperature sensor is stored in 128 bytes. So I have to read out 4 blocks of 32 bytes each.
The downside of this approach is that the source code is not as self explaining as it was before. Here is the code which does the same as in my previous blog post Stove Assistant - Bernhard - Pi Chef #3 - Connect Panasonic Grid-Eye sensor to Raspberry Pi :
#include <stdio.h> #include <stdlib.h> #include <linux/i2c-dev.h> #include <fcntl.h> #include <unistd.h> #include <opencv2/opencv.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/contrib/contrib.hpp> int main(void) { int file; int addr=0x68; // adress of AMG88xx int x,y; // variables to got through the array signed short int internal_temp; signed short int pixel_temp[64]; // array for pixel temperatures int end=1; // variable to end program printf("Pi Chef Stove Assistant Demo with AMG88xx\n"); // print start message if((file=open("/dev/i2c-1",O_RDWR))<0) // open i2c-bus { perror("cannot open i2c-1"); exit(1); } if(ioctl(file, I2C_SLAVE, addr)<0) // open slave { perror("cannot open slave address"); exit(1); } internal_temp=(signed short)(i2c_smbus_read_word_data(file, 0x0e)<<4); internal_temp=internal_temp/16; printf("Internal Temp: %f C (0x%04X = %i)\n",(float)internal_temp*0.0625,internal_temp,internal_temp); cv::Mat outSmall(8,8,CV_8UC1); // create opencv mat for sensor data cv::Mat outSmallnorm(8,8,CV_8UC1); // create opencv mat for normalized data cv::Mat outColor; // create opencv mat for color output while(end==1) // check end variable { cv::TickMeter t; t.start(); // start timer x=i2c_smbus_read_i2c_block_data(file,0x80,32,(__u8*)pixel_temp); // read first 32 byte / 16 temperature pixels from sensor x=i2c_smbus_read_i2c_block_data(file,0xa0,32,(__u8*)pixel_temp+32); // read next 32 byte / 16 temperature pixels from sensor x=i2c_smbus_read_i2c_block_data(file,0xc0,32,(__u8*)pixel_temp+64); // read next 32 byte / 16 temperature pixels from sensor x=i2c_smbus_read_i2c_block_data(file,0xe0,32,(__u8*)pixel_temp+96); // read last 32 byte / 16 temperature pixels from sensor for(x=0;x<64;x++) { pixel_temp[x]=(signed short)(pixel_temp[x]<<4)/16; // set pixel_temp to original value } for(x=0;x<8;x++) { for(y=0;y<8;y++) { outSmall.at(x,y)=pixel_temp[x*8+y]; // copy temperature pixels into opencv mat } } t.stop(); // stop timer printf("Time: %f ms\n", (double)t.getTimeMilli() / t.getCounter()); // print result of timer cv::normalize(outSmall,outSmallnorm,255,0,cv::NORM_MINMAX); // normalize Mat to values between 0 and 255 cv::resize(outSmallnorm,outSmallnorm,cv::Size(256,256)); // resize Mat to 256 x 256 pixel cv::applyColorMap(outSmallnorm,outColor,cv::COLORMAP_JET); // generate colored output with colormap cv::imshow("AMG88xx",outColor); // display mat on screen char key = cv::waitKey(500); // check keys for input if(key=='e') end=0; // end if e was pressed } printf("ended regularly!\n"); // print end message close(file); return 0; }
In the source code I also added an OpenCV timer to measure the duration of the code execution.
With my old code it took 52 ms to get the data from the sensor.
Now it takes only 20 ms.
So the new code is 2.5 times faster. Not bad for this little change.