Welcome to the Slackware Documentation Project

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
howtos:hardware:arm:interfacing_i2c_devices [2014/04/03 21:25 (UTC)]
louigi600 [Communicating With An I2C Device]
howtos:hardware:arm:interfacing_i2c_devices [2019/07/31 01:39 (UTC)] (current)
rramp [Voltage Level Shifting]
Line 139: Line 139:
  
 I hate showing my poor C programming capabilities but here's some code that uses i2c-dev to read stuff from the ITG3200 and takes an average over 10 readings: I hate showing my poor C programming capabilities but here's some code that uses i2c-dev to read stuff from the ITG3200 and takes an average over 10 readings:
- 
-  #include <​sys/​ioctl.h>​ 
-  #include <​errno.h>​ 
-  #include <​string.h>​ 
-  #include <​stdio.h>​ 
-  #include <​stdlib.h>​ 
-  #include <​unistd.h>​ 
-  #include <​linux/​i2c-dev.h>​ 
-  #include <​fcntl.h>​ 
-  #include <​errno.h>​ 
-  ​ 
-  #define I2C_DEVICE "/​dev/​i2c-1"​ 
-  #define I2C_DEV_ADDR 0x69 
-  #define I2C_DEV_SELF 0x0 
-  #define I2C_DEV_INT 0x1a 
-  #define I2C_DEV_REG_START_ADDR 0x1b 
-  #define I2C_DEV_REG_END_ADDR 0x22 
-  ​ 
-  #define TEMP_RAW_OFFSET 13200 
-  #define TEMP_RAW_SENSITIVITY 280 
-  #define TEMP_OFFSET 35 
-  ​ 
-  #define ROT_RAW_SENSITIVITY 14.375 
-  ​ 
-  void read_registers (int file, int *raw) 
-  { char buf[256] = {0}; 
-    int i,j,k; 
-  ​ 
-  /*For some unexpected reason I'm getting responses from the other I2C devices 
-    on the same bus so I'm ignoring data that does not match the WHO AM I reg 
-    and also data that has not set the interrupt register (meaning that data is 
-    not really avalible) 
-  */ 
-    while (buf[0] != 0x69 || buf[26] == 0) 
-    { if (read(file,​buf,​sizeof(buf)) != sizeof(buf))  ​ 
-      { /* ERROR HANDLING: i2c transaction failed */ 
-        printf("​Failed to read from the i2c bus.\n"​);​ 
-        exit(1); 
-      } 
-    } 
-  ​ 
-    j=0; 
-    for(i=I2C_DEV_REG_START_ADDR;​i<​=I2C_DEV_REG_END_ADDR;​i++) 
-    { k= (buf[i] << 8) + buf[i+1]; 
-      if ( k > 32768 ) *(raw+j)= k - 65536; 
-      else *(raw+j)=k; 
-      i++; 
-      j++; 
-    }  
-  } 
-  ​ 
-  main () 
-  { int file,​buffer;​ 
-    int i,j,k; 
-    int raw_data[4];​ 
-    float data[4],​tdata[10],​rxdata[10],​rydata[10],​rzdata[10];​ 
-    char buf[256] = {0}; 
-  ​ 
-    if ((file = open(I2C_DEVICE,​ O_RDWR)) < 0)  
-    { /* ERROR HANDLING: you can check errno to see what went wrong */ 
-      perror("​Failed to open the i2c bus"); 
-      exit(1); 
-    }  
-  ​ 
-    if (ioctl(file,​ I2C_SLAVE, I2C_DEV_ADDR) < 0)  
-    { printf("​Failed to acquire bus access and/or talk to slave.\n"​);​ 
-      /* ERROR HANDLING; you can check errno to see what went wrong */ 
-      exit(1); 
-    } 
-  ​ 
-    for(i=0;​i<​10;​i++) 
-    { read_registers(file,&​raw_data[0]);​ 
-      tdata[i]=TEMP_OFFSET + (((float)raw_data[0] + TEMP_RAW_OFFSET) / TEMP_RAW_SENSITIVITY);​ 
-      rxdata[i]=(float)raw_data[1]/​ ROT_RAW_SENSITIVITY;​ 
-      rydata[i]=(float)raw_data[2]/​ ROT_RAW_SENSITIVITY;​ 
-      rzdata[i]=(float)raw_data[3]/​ ROT_RAW_SENSITIVITY;​ 
-    } 
-    close(file);​ 
-  ​ 
-    for(i=0;​i<​10;​i++) 
-    { data[0]=data[0] + tdata[i]; 
-      data[1]=data[1] + rxdata[i]; 
-      data[2]=data[2] + rydata[i]; 
-      data[3]=data[3] + rzdata[i]; 
-    } 
-    for(i=0;​i<​4;​i++) data[i]=data[i]/​10;​ 
-  ​ 
-    printf("​Temp. : %2.2f \n",​data[0]);​ 
-    printf("​Rot. X : %2.2f \n",​data[1]);​ 
-    printf("​Rot. Y : %2.2f \n",​data[2]);​ 
-    printf("​Rot. Z : %2.2f \n",​data[3]);​ 
-  } 
- 
-With some help from LQ forum I realized that it's a bad idea to bulk dump the whole register set, instaad it's better to probe each register separately. The code that follows does not yet make the avarage like the one above bit it takes 10 consecutive readings without having to skip any data. 
  
   #include <​sys/​ioctl.h>​   #include <​sys/​ioctl.h>​
Line 263: Line 169:
   #define ITG3200_ROT_RAW_SENSITIVITY 14.375   #define ITG3200_ROT_RAW_SENSITIVITY 14.375
   ​   ​
-  void read_itg3200 ​(int file, int *raw, int *reg_array,​int size)+  ​int twosc2int(int twoscomplimentdata) 
 +  { int retval; 
 +    if( twoscomplimentdata > 32768 ) retval = twoscomplimentdata - 65536; 
 +    else retval = twoscomplimentdata;​ 
 +    return retval; 
 +  } 
 +   
 +  float ITG3200_rot_conv(int rawdata) 
 +  { float retval; 
 +    int raw; 
 +   
 +    raw=twosc2int(rawdata);​ 
 +    retval = (float)raw / (float)ITG3200_ROT_RAW_SENSITIVITY;​ 
 +    return retval; 
 +  } 
 +   
 +  float ITG3200_temp_conv(int rawdata) 
 +  { float retval; 
 +    int raw; 
 +   
 +    raw=twosc2int(rawdata);​ 
 +    retval = (float)ITG3200_TEMP_OFFSET + (((float)raw + ITG3200_TEMP_RAW_OFFSET) / ITG3200_TEMP_RAW_SENSITIVITY);​ 
 +    return retval; 
 +  } 
 +   
 +  ​void ITG3200_read ​(int file, int *raw, int *reg_array,​int size)
   { __s32 res;   { __s32 res;
     int i,j,k;     int i,j,k;
Line 269: Line 200:
     for(i=0;​i<​size;​i++)     for(i=0;​i<​size;​i++)
     { k=0;     { k=0;
-      printf("​%2x : ",​*(reg_array + i)); 
       for (j=0;​j<​2;​j++)       for (j=0;​j<​2;​j++)
       {       {
Line 279: Line 209:
         else         else
         { k += (int)res;         { k += (int)res;
-          ​printf("​%4x \n",​k);​ +          *(raw + (i/2))=k;
-          ​*(raw + (i/​2))=k; ​+
         }         }
       }       }
Line 288: Line 217:
   ​   ​
   main ()   main ()
-  { int file,buffer;+  { int file;
     int i,j,k;     int i,j,k;
-    float data[4],​tdata[10],​rxdata[10],​rydata[10],​rzdata[10];​ +    float data[4]={0};​
-    char buf[256] = {0};+
   ​   ​
     int ITG3200_REGS[8]={ITG3200_TH,​ITG3200_TL,​ITG3200_XRH,​ITG3200_XRL,​     int ITG3200_REGS[8]={ITG3200_TH,​ITG3200_TL,​ITG3200_XRH,​ITG3200_XRL,​
Line 308: Line 236:
     }     }
   ​   ​
 +  /*Take an avarage over 10 consecuitve readings on the ITG3200*/
     for (i=0;​i<​10;​i++)     for (i=0;​i<​10;​i++)
-    { read_itg3200(file,&​ITG3200_RAW_DATA[0],&​ITG3200_REGS[0],​sizeof(ITG3200_REGS)/​sizeof(ITG3200_REGS[0]));​ +    { ITG3200_read(file,&​ITG3200_RAW_DATA[0],&​ITG3200_REGS[0],​sizeof(ITG3200_REGS)/​sizeof(ITG3200_REGS[0]));​ 
-      ​printf("​\n"​);+  ​ 
 +      ​data[0] += ITG3200_temp_conv(ITG3200_RAW_DATA[0]);​ 
 +      data[1] += ITG3200_rot_conv(ITG3200_RAW_DATA[1]);​ 
 +      data[2] += ITG3200_rot_conv(ITG3200_RAW_DATA[2]);​ 
 +      data[3] += ITG3200_rot_conv(ITG3200_RAW_DATA[3]);
     }     }
 +    for(i=0;​i<​4;​i++) data[i] /= 10; 
 +  ​
 +    printf("​Temp. : %2.2f \n",​data[0]);​
 +    printf("​Rot. X : %2.2f \n",​data[1]);​
 +    printf("​Rot. Y : %2.2f \n",​data[2]);​
 +    printf("​Rot. Z : %2.2f \n",​data[3]);​
   ​   ​
-    for (i=0;​i<​sizeof(ITG3200_RAW_DATA)/​sizeof(ITG3200_RAW_DATA[0]);​i++) 
-    { printf("​%2x ",​ITG3200_RAW_DATA[i]);​ 
-    } 
-    printf("​\n"​);​ 
     close(file);​     close(file);​
   }   }
 +
  
 ====== Voltage Level Shifting ====== ====== Voltage Level Shifting ======
 You may end up with heterogeneous voltage level devices and if you have many devices the correct way to work around this problem is by using bidirectional I2C voltage level shifters like the [[ http://​www.ti.com/​lit/​ds/​symlink/​pca9306.pdf |PCA9306]], but if you only have a few devices all grouped up in a neat PCB like the 10DOF IMU unit you might want to give a simpler system a try. You may end up with heterogeneous voltage level devices and if you have many devices the correct way to work around this problem is by using bidirectional I2C voltage level shifters like the [[ http://​www.ti.com/​lit/​ds/​symlink/​pca9306.pdf |PCA9306]], but if you only have a few devices all grouped up in a neat PCB like the 10DOF IMU unit you might want to give a simpler system a try.
-This is how I connected my 5v IMU pcb to a 3.3v I2C bus on my RaspberryPI:​ I took as educated guess that 4.4v (5v with a 4148 diode in series) would still be a tolerable power supply voltage for the whole IMU pcb, this would most likely allow all the I2C devices on the IMU pcb to recognize a minimum of 3.08v (4.4 * 0.7) as the lowest reliable logic level 1 tension allowing it to inter-operate with the PI's 3.3v logig levels. I was not able to find if the PI has internal pullups on the I2C bus or if they have to be externally placed so in doubt I put in 10k pullups between the 4.4v power line and the 2 data lines. I was the able to correctly detect the sensors on the IMU pcb.   +This is how I connected my 5v IMU pcb to a 3.3v I2C bus on my RaspberryPI:​ I took as educated guess that 4.4v (5v with a 4148 diode in series) would still be a tolerable power supply voltage for the whole IMU pcb, this would most likely allow all the I2C devices on the IMU pcb to recognize a minimum of 3.08v (4.4 * 0.7) as the lowest reliable logic level 1 tension allowing it to inter-operate with the PI's 3.3v logic levels. I was not able to find if the PI has internal pullups on the I2C bus or if they have to be externally placed so in doubt I put in 10k pullups between the 4.4v power line and the 2 data lines. I was the able to correctly detect the sensors on the IMU pcb.   
  
 ====== Sources ====== ====== Sources ======

In Other Languages
QR Code
QR Code howtos:hardware:arm:interfacing_i2c_devices (generated for current page)