Shop OBEX P1 Docs P2 Docs Learn Events
[RESOLVED] First attempt at I2C — Parallax Forums

[RESOLVED] First attempt at I2C

WildatheartWildatheart Posts: 195
edited 2014-12-23 06:48 in Propeller 1
This is my first attempt at using I2C with the propeller. The program below hangs after joining the master bus, but I am guessing more than that will need to be corrected even though I get a successful build. Thanks in advance for your help.
/*
  Using PPDB:
  Test I2C OSEPP IR proximity sensor module 
      http://osepp.com/products/sensors-arduino-compatible/osepp-ir-proximity-sensor-module/ 
  SW1 and SW2 are shorted for address 0x20
  Assume master controller has pull-ups, therefore SB1 and SB2 are left open.  
      See PDF schematic at bottom of OSEPP web page.
*/

#include "simpletools.h"                      // Include simpletools header

i2c *i2cBus;                                   // I2C bus ID

const     int IRsensor_SCL = 28;                                  // Propeller pin 28
const     int IRsensor_SDA = 29;                                   // Propeller pin 29   

int sensorADDR = 0b0100000;                                    // Device address 0x20
int memADDR = 0;                                            // Presume only 1 device register ?
                                                    
int main()
{
  i2cBus = i2c_newbus(IRsensor_SCL, IRsensor_SDA, 0);            // Join the I2C bus master (Mode 0 indicates pull-up 
  print ("Joined master bus \n");                                //   resistors present on the SDA & SCL lines)
  while(1)
  {
    while((i2c_busy(i2cBus,sensorADDR)))                        // Wait here if sensor is busy
    {        
    int val = 0;                                                  // Prepare val for new reading
    i2c_in(i2cBus, sensorADDR, memADDR, 1, (char*)&val, 1);
    print("value = %d \n", val);                                    // Print the sensor reading
    pause (500);
    }    
  }    
}

Comments

  • Hal AlbachHal Albach Posts: 747
    edited 2014-12-21 18:01
    I'm not 100% certain but I think the device address you are using is trying to address device 0x40. If the actual device address is 0x20 then the 7 bit address should be 0b0010000. Try using the 7 bit binary address instead of the variable sensorADDR and see if that works.
    I use the same I2C function in my projects and use 0b1010000 for the EEPROM (address 0xA0) and 0b1100000 for a compass (address 0xC0) and using the 7 bit binary for the device address it all works. The 7 bit address has bit 0, the R/W bit, removed.
    EDIT: I just modified my EEPROM code and defined a variable "int eeadr = 0b1010000; and the program continues to access the EEPROM. So if you change the variable sensorADDR assignment to 0b0010000 it should work.
  • WildatheartWildatheart Posts: 195
    edited 2014-12-21 18:54
    Revised address to 0b0010000 and removed the "!" from the "while busy" statement. Now value always = 0.

    I am suspecting the need for pull-ups on the SCL and SDA lines?
  • Hal AlbachHal Albach Posts: 747
    edited 2014-12-21 19:17
    Definitely put pullup resistors on the bus. Your first statement in Main() ;
      i2cBus = i2c_newbus(IRsensor_SCL, IRsensor_SDA, 0);            // Join the I2C bus master (Mode 0 indicates pull-up 
      print ("Joined master bus \n");                                //   resistors present on the SDA & SCL lines)
    
    The last parameter being 0 means that the I2C bus will have pullup resistors instead of the propeller I/O driving the bus high and low. The propeller does not provide the pullups in mode 0, you have to provide them. Actually, per the I2C Specification, pullups are required. I use 4.7K resistors and never have any problems. Just be sure to use 3.3 Volts as the pullup source, not 5 - keeps the prop happy.

    edit (again!) Just noticed you are using the PPDB, and the schematics indicate that it is using one 10K resistor as a pullup on the SDA (P29) line. Add a 10K to SCL line.
    Just looked up the device you are using and there seems to be some confusion re device address. The OSEPP site for the IR module clearly states the device address is 0x20, but the I2C interface chip on the module is a PCA9534, which, according to all data sheets shows a device address of 0b0100000.
    For the i2c_in statement, I would define a char variable at the beginning of main and use that variable name for the data field. Change "(char*)&val" to whatever name you use for the data variable.
    On the module the schematic shows two switches, A1 and A2, both need to be closed to keep the low nibble of the device address at 0.
  • WildatheartWildatheart Posts: 195
    edited 2014-12-22 12:18
    Sensor address appears to be 0b0010000 else attempts to use address 0b0100000 will cause the program to hang at the request to join the bus.

    Added 10K between 3.3V and SCL (pin 28) as recommended. Also renamed (char*)&val with a char variable as recommended. Still no go.

    But I have noticed that if I set val = 5 the loop will cycle and print the value received as 5. So among other possible problems the “i2c_in” is not functioning as intended.

    I’m guessing that memADDR or the parameters in “i2c_in” are not set properly.
  • Hal AlbachHal Albach Posts: 747
    edited 2014-12-22 13:02
    I found this sketch on their web site, it may provide some guidance as to the communications required, read the comments for the setup function to turn on the sensor . So, before you can read any data from the sensor you first have to write to it.
    IR Proximity Sensor Module
    Setup
    Connect one end of the cable into either Molex connectors on the sensor
    Connect the other end of the cable to the Arduino board:
    RED: 5V
    WHITE:  I2C SDA (pin A4 on Uno; pin 20 on Mega)
    BLACK: GND
    GREY: I2C SCL (pin A5 on Uno; pin 21 on Mega)
    Set the DIP switch on the sensor to set the sensor address (check back of sensor for possible addresses)
     
    Example Sketch
    // OSEPP IR Proximity Sensor Example Sketch
    // by OSEPP <http://www.osepp.com>
    
    // This sketch demonstrates interactions with the IR Proximity Sensor
    
    #include <Wire.h>
    
    // Possible sensor addresses (suffix correspond to DIP switch positions)
    #define SENSOR_ADDR_OFF_OFF  (0x26)
    #define SENSOR_ADDR_OFF_ON   (0x22)
    #define SENSOR_ADDR_ON_OFF   (0x24)
    #define SENSOR_ADDR_ON_ON    (0x20)
    
    // Set the sensor address here
    const uint8_t sensorAddr = SENSOR_ADDR_OFF_OFF;
    
    // One-time setup
    void setup()
    {
       // Start the serial port for output
       Serial.begin(9600);
    
       // Join the I2C bus as master
       Wire.begin();
    
       // Turn on the sensor by configuring pin 1 of the GPIO expander to be an
       // output pin; the default output value is already HI so there's no need
       // to change it
       WriteByte(sensorAddr, 0x3, 0xFE);
    }
    
    // Main program loop
    void loop()
    {
       uint8_t val;
    
       // Get the value from the sensor
       if (ReadByte(sensorAddr, 0x0, &val) == 0)
       {
          // The second LSB indicates if something was not detected, i.e.,
          // LO = object detected, HI = nothing detected
          if (val & 0x2)
          {
             Serial.println("Nothing detected");
          }
          else
          {
             Serial.println("Object detected");
          }
       }
       else
       {
          Serial.println("Failed to read from sensor");
       }
    
       // Run again in 1 s (1000 ms)
       delay(1000);
    }
    
    // Read a byte on the i2c interface
    int ReadByte(uint8_t addr, uint8_t reg, uint8_t *data)
    {
       // Do an i2c write to set the register that we want to read from
       Wire.beginTransmission(addr);
       Wire.write(reg);
       Wire.endTransmission();
    
       // Read a byte from the device
       Wire.requestFrom(addr, (uint8_t)1);
       if (Wire.available())
       {
          *data = Wire.read();
       }
       else
       {
          // Read nothing back
          return -1;
       }
    
       return 0;
    }
    
    // Write a byte on the i2c interface
    void WriteByte(uint8_t addr, uint8_t reg, byte data)
    {
       // Begin the write sequence
       Wire.beginTransmission(addr);
    
       // First byte is to set the register pointer
       Wire.write(reg);
    
       // Write the data byte
       Wire.write(data);
    
       // End the write sequence; bytes are actually transmitted now
       Wire.endTransmission();
    }
    - See more at: http://osepp.com/learning-centre/start-here/ir-proximity-sensor-module/#sthash.s7X5gwaf.dpuf
    
  • edited 2014-12-22 17:28
    Here is some code adjusted per posts to to this point. Sorry if it still doesn't work, I don't have this particular sensor to test. If it doesn't work as-is, retry with while(i2c_busy... and i2c_stop commented. Side note: 3 bytes per exchange is a good sign, but not a guaranty.
    /*
      Using PPDB:
      Test I2C OSEPP IR proximity sensor module 
          http://osepp.com/products/sensors-arduino-compatible/osepp-ir-proximity-sensor-module/ 
      SW1 and SW2 are shorted for address 0x20
      Assume master controller has pull-ups, therefore SB1 and SB2 are left open.  
          See PDF schematic at bottom of OSEPP web page.
    */
    
    #include "simpletools.h"                      // Include simpletools header
    
    i2c *i2cBus;                                  // I2C bus ID
    
    const int i2c_SCL = 28;                       // Propeller pin 28
    const int i2c_SDA = 29;                       // Propeller pin 29   
    
    const int irProx0 = 0x20;                     // Address 0x20 named irProx0
    
    int main()
    {
      i2cBus = i2c_newbus(i2c_SCL, i2c_SDA, 0);   // Declare I2C bus with pullups
                          
      int reg = 0x3;                              // Declare/init reg & data
      char data = 0xFE; 
      int b = i2c_out(i2cBus, irProx0, reg, 1,    // Turn on sensor
                                     &data, 1);
                                     
      print("Bytes sent = %d\n", b);              // Addr + reg + data = 3
    
      while(1)                                    // Main loop
      {
        while(i2c_busy(i2cBus, irProx0));         // Wait here if sensor is busy
        i2c_stop(i2cBus);                         // Might be needed
    
        reg = 0;                                  // Set reg to 0
        data = 0;                                 // Prepare data for new reading
        b = i2c_in(i2cBus, irProx0, reg, 1,       // Check irProx0 sensor
                                  &data, 1);
    
        print("Bytes total = %d\n");               // Addr + reg out + data in = 3
    
        int val = (data >> 2) & 1;                 // Isolate detection bit
        if(b == 3) print("val = %d \n", val);      // Print detection status
        
        pause (500);                               // 1/2 sec before repeat
      }    
    }
    
  • WildatheartWildatheart Posts: 195
    edited 2014-12-23 06:48
    With Andy's example in #7... Bytes sent = 3. Bytes total = 3.

    int val = (data >> 2) & 1; needs to be changed to int val = (data >> 1) & 1;

    Example code works with or without i2c_busy and/or i2c_stop

    Andy, after your review of the changes one of us should pass this on to OSEPP to promote this sensor's use with the Propeller. Thanks Hal and Andy for your interest and help.
Sign In or Register to comment.