Learning I2C - circuit help

Discussion in 'Embedded Systems and Microcontrollers' started by Captain E, Jul 10, 2015.

  1. Captain E

    Thread Starter Member

    Jun 16, 2015
    81
    6
    Hello fellow humans!
    I'm currently taking the challenge of learning about I2C, and have now learnt about this for a couple of days.

    It's time for my first circuit!
    I'm going to learn by making several circuits doing different things, and at the same time learn what is happening.
    The first thing I'm trying to do is simple to access and configure the IODIRB chip of my MCP23018, (datasheet link) which I understand sets port side B's pins (GPB0-GPB7) as either outputs or inputs, and by reading the datasheet: (text 1.6.1, page 18)

    .. I found that this is the way to do this. I'm trying to set all the GPBX as outputs, and I connected GPB0 to my Arduino UNO's analog input pin A0, so I can read it and see if the voltage is HIGH.

    I understand that writing to the IODIRX SETS the IO pins low/high, and if I want to READ them I use GPIOX.

    I'm using the Wire.h (link here) library, and I made this code, added below. I commented out what I understand (or think?) the code is doing, and I also put a lot of Serial prints for debugging with my computer.

    Code (Text):
    1. #include <Wire.h>
    2.  
    3. void setup() {
    4.   Serial.begin(9600);
    5.   while(!Serial); //wait for Serial to start
    6.   Serial.print("Voltage at Arduino analog A0 BEFORE: ");
    7.   Serial.println(analogRead(A0));
    8.   Serial.println("------------------------");
    9.   Serial.println("WIRE: beginning");
    10.   Wire.begin(); //join i2c bus (no parameters=join as master)
    11.   Serial.println("WIRE: started");
    12.   Wire.beginTransmission(0x20);  //begin transmission with MCP23018. 0x20 is the adress for the MCP23018 in hexadecimal, with ADDR connected to ground.
    13.   Serial.println("WIRE: transmission begun");                  
    14.   Wire.write(0x00);  //register address to talk to
    15.                      //0x01=IODIRB register address (with help from the datasheet, page.7 TABLE 1-1)
    16.   Serial.println("WIRE: wrote register address");
    17.   Wire.write(0x00); //00000000=0x00 in hexadecimal
    18.                     //=sets GPIO-B0 to PPIO-B7 as outputs?
    19.   Serial.println("WIRE: GPIO-B5 set as output?");
    20.   Wire.endTransmission();
    21.   Serial.println("WIRE: transmission ended");
    22.   Serial.println("------------------------");
    23.   Serial.print("Voltage at Arduino analog A0 AFTER: ");
    24.   Serial.println(analogRead(A0));
    25.   Serial.println("------------------------");
    26. }
    27.  
    28. void loop() {
    29.   delay(1000); //we no need this C:
    30. }
    Would love if someone could try to help me get this working, because it isn't..

    Here is the Serial outputs I get:

    Code (Text):
    1. Voltage at Arduino analog A0 BEFORE: 1
    2. ------------------------
    3. WIRE: beginning
    4. WIRE: started
    5. WIRE: transmission begun
    6. WIRE: wrote register address
    7. WIRE: GPIO-B5 set as output?
    8. WIRE: transmission ended
    9. ------------------------
    10. Voltage at Arduino analog A0 AFTER: 0
    11. ------------------------
    12.  
    ..so I guess the code isn't THAT BAD as it seems to be a possible code for something o.o

    Thank you all in advance! U guys are the best :3
     
  2. Papabravo

    Expert

    Feb 24, 2006
    10,135
    1,786
    The direction register does not set the pins high or low. It only controls the direction. The value, high or low, is set by the output latch register.
    Since pins default to input, the two step process, is to set the value in the output latch, then set the direction register. At this point the output will go to the value defined by the output latch. Check to see what value is in the output latch at power on/reset. If the default value is 0, that is why your example seemed to work.
     
  3. Captain E

    Thread Starter Member

    Jun 16, 2015
    81
    6
    ooh I see!
    I missunderstood "When a bit is clear, the corresponding pin becomes an output" a bit..

    I have now got a code which first sets GPB0-GPB7 pins HIGH, and then sets GPB0-GPB7 to outputs, as you said I should.

    Code (Text):
    1. #include <Wire.h>
    2.  
    3. void setup() {
    4.   Serial.begin(9600);
    5.   while(!Serial); //wait for Serial to start
    6.   Serial.print("Voltage at Arduino analog A0 BEFORE: ");
    7.   Serial.println(analogRead(A0));
    8.   Wire.begin(); //join i2c bus (no parameters=join as master)
    9.  
    10.   Wire.beginTransmission(0x20); //connect to MCP23018, with address 0x20 (ADDR to GND)
    11.   Wire.write(0x13); //talk to GPIOB register
    12.   Wire.write(0xFF); //sets all outputs HIGH
    13.   Wire.endTransmission();
    14.  
    15.   Wire.beginTransmission(0x20);
    16.   Wire.write(0x00);  //talk to IODIRB register
    17.   Wire.write(0x00); //set GPB0-GPB7 as outputs
    18.   Wire.endTransmission();
    19.  
    20.   delay(400);
    21.  
    22.   Serial.println("------------------------");
    23.   Serial.print("Voltage at Arduino analog A0 AFTER: ");
    24.   Serial.println(analogRead(A0));
    25.   Serial.println("------------------------");
    26. }
    27.  
    28. void loop() {
    29.   delay(1000); //no need for this loop
    30. }

    Still not quite there yet, as the value of analog pin A0 is the same before and after is about 30, so LOW. (about ±5 with more attempts)

    Something you can see that I'm missing?

    I can make a schematics of my circuit if you would need that. General info about it:
    - SCL and SDA lines are connected to the Arduino UNO's analog input pins A5 and A4, and both have got a pullup resistor at 4.7kOhms to +5V.
    - MCP23018 ADDR pin is connected to GND/0V and Vss to +5V.
    - GPB0, which is connected to Analog pin A0, also got a pull down resistor at 10MOhms

    I'd guess there is more connections the I2C device needs to 5V/GND maybe.
    ________
    Thanks a lot for helping me, I really appreciate it! :)
     
  4. Papabravo

    Expert

    Feb 24, 2006
    10,135
    1,786
    I believe the outputs are open-drain. What this means is that the output stage has only a pull down transistor (an N-channel FET). It needs an external pullup resistor to make a satisfactory high level. The equivalent circuit in bipolar logic is called an open collector.

    Here are some additional references
    https://en.wikipedia.org/wiki/Open_collector
    http://www.mcc-us.com/open-collectorfaq.htm
    http://letsmakerobots.com/node/39125

    One advantage of these outputs is that you can connect them together without damaging them, and get another level of logic. Connect two open drain outputs together and the output is high only if both of them are, and is low if either one is low. This is often done with interrupt lines:

    and the DeMorganized logis is:
    a LOW .OR. a LOW is a LOW
     
  5. Captain E

    Thread Starter Member

    Jun 16, 2015
    81
    6
    I'm stuck a bit.. If I add a pullup resistor from my output pin (GPB0) to +5V, the analog pin A0 immediately gets HIGH. (analogRead 1023).
    ..and it's the same with different values of the pullup resistor.
    If I remove the pullup resistor, analog pin A0 reads ~400 out of 1023.

    The MCP23018 has got a PULL-UP RESISTOR CONFIGURATION REGISTER which controls the pull-up resistors for the port pins.
    If a bit is set the corresponding port pin is internally pulled up with an internal resistor.
    1 = Pull-up enabled. 0 = Pull-up disabled.

    Is this what you mean that I need? (but internal, so I wont need this as external?)

    <attempt1>
    - Using the internal GPPU - GPIO PULL-UP RESISTOR REGISTER - pull-up enabled for all pins.
    - Output pin directly wired to Analog input pin A0 on the Arduino UNO.

    Code:

    Code (Text):
    1. #include <Wire.h>
    2.  
    3. void setup() {
    4.  
    5.   Serial.begin(9600);
    6.   while(!Serial); //wait for Serial to start
    7.   Serial.print("Voltage at Arduino analog A0 BEFORE: ");
    8.   Serial.println(analogRead(A0));
    9.   Wire.begin(); //join i2c bus (no parameters=join as master)
    10.  
    11.   Wire.beginTransmission(0x20); //connect to MCP23018, with address 0x20 (ADDR to GND)
    12.   Wire.write(0x0D); //talk to GPPUB register
    13.   Wire.write(0xFF); //enable pullup on all IO-B pins (1=enabled, 0=disabled)
    14.   Wire.endTransmission();
    15.    
    16.  
    17.   Wire.beginTransmission(0x20);
    18.   Wire.write(0x13); //talk tao GPIOB register
    19.   Wire.write(0x00); //sets all outputs HIGH
    20.   Wire.endTransmission();
    21.  
    22.  
    23.   Wire.beginTransmission(0x20);
    24.   Wire.write(0x01);  //talk to IODIRB register
    25.   Wire.write(0x00); //set GPB0-GPB7 as outputs
    26.   Wire.endTransmission();
    27.  
    28.   delay(400);
    29.  
    30.   Serial.println("------------------------");
    31.   Serial.print("Voltage at Arduino analog A0 AFTER: ");
    32.   Serial.println(analogRead(A0));
    33.   Serial.println("------------------------");
    34. }
    35.  
    36. void loop() {
    37.   delay(1000);
    38.   Serial.println(analogRead(A0));
    39. }
    Results:

    Code (Text):
    1.  
    2. Voltage at Arduino analog A0 BEFORE: 369
    3. ------------------------
    4. Voltage at Arduino analog A0 AFTER: 348
    5. ------------------------
    6. 491
    7. 494
    8. 493
    9. 485
    10. 483
    11. 491
    12. 485
    13.  
    <attempt2>
    -
    using an external pull-up resistor on my output pin, without any internal pull-up
    - output pin connected to +5V (with a resistor) and analog pin A0 on the Arduino UNO.

    Code:

    Code (Text):
    1. #include <Wire.h>
    2.  
    3. void setup() {
    4.  
    5.   Serial.begin(9600);
    6.   while(!Serial); //wait for Serial to start
    7.   Serial.print("Voltage at Arduino analog A0 BEFORE: ");
    8.   Serial.println(analogRead(A0));
    9.   Wire.begin(); //join i2c bus (no parameters=join as master)
    10.  
    11.   Wire.beginTransmission(0x20); //connect to MCP23018, with address 0x20 (ADDR to GND)
    12.   Wire.write(0x0D); //talk to GPPUB register
    13.   Wire.write(0x00); //disable pullup on all IO-B pins (1=enabled, 0=disabled)
    14.   Wire.endTransmission();
    15.    
    16.  
    17.   Wire.beginTransmission(0x20);
    18.   Wire.write(0x13); //talk tao GPIOB register
    19.   Wire.write(0x00); //sets all outputs HIGH
    20.   Wire.endTransmission();
    21.  
    22.  
    23.   Wire.beginTransmission(0x20);
    24.   Wire.write(0x01);  //talk to IODIRB register
    25.   Wire.write(0x00); //set GPB0-GPB7 as outputs
    26.   Wire.endTransmission();
    27.  
    28.   delay(400);
    29.  
    30.   Serial.println("------------------------");
    31.   Serial.print("Voltage at Arduino analog A0 AFTER: ");
    32.   Serial.println(analogRead(A0));
    33.   Serial.println("------------------------");
    34. }
    35.  
    36. void loop() {
    37.   delay(1000);
    38.   Serial.println(analogRead(A0));
    39. }

    Results:


    Code (Text):
    1. Voltage at Arduino analog A0 BEFORE: 1023
    2. ------------------------
    3. Voltage at Arduino analog A0 AFTER: 1023
    4. ------------------------
    5. 1023
    6. 1023
    7. 1023
    8. 1023
    9. 1023
    10. 1023
    11. 1023
    12. 1023
    13.  

    </attempts2>



    Shouldn't both work? I have added pullup resistors both internal and external, as you said I should.

    Something is wrong here :/

    Maybe something is wrong with my circuit, so I made a schematics of it, just in case there is something wrong there:
    (this image, with an EXTERNAL pull-up resistor)

    [​IMG]

    Thanks a lot!
     
  6. Captain E

    Thread Starter Member

    Jun 16, 2015
    81
    6
    ~BUMPILY BUMB~

    (PapaBravo has helped A LOT but I'm not quite there yet, so I'd be very happy for any help provided) :))
     
  7. Captain E

    Thread Starter Member

    Jun 16, 2015
    81
    6
    What happened, PapaBravo? :/
     
  8. DickCappels

    Moderator

    Aug 21, 2008
    2,647
    631
    Bump
     
  9. OBW0549

    Well-Known Member

    Mar 2, 2015
    1,300
    879
    Since you are apparently having difficulties with an Arduino application, you might try getting help in the Arduino forums, at http://forum.arduino.cc/
     
  10. Papabravo

    Expert

    Feb 24, 2006
    10,135
    1,786
    Like most processors I often have to service high priority interrupts. I may have some time to look at things this evening.
     
    theonewho likes this.
  11. Captain E

    Thread Starter Member

    Jun 16, 2015
    81
    6
    Thank you! DickCappels, OBW0549 and Papabravo: thanks for wanting to help me, you are all awesome.

    Still stuck with the circuit though.
    Thanks again, guys!

    ~ Cpt. E

    Moderator's note: Some text removed for clarity. Thread moved to Embedded Systems where it is hoped to receive more attention.
     
    Last edited by a moderator: Jul 16, 2015
Loading...