chipKIT® Development Platform

Inspired by Arduino™

i2c with multiple devices issue

Created Mon, 13 Feb 2017 18:57:04 +0000 by acm45


acm45

Mon, 13 Feb 2017 18:57:04 +0000

Hi,

I've a chipKIT Max32 board and I'm usign the wire library to read/write an IO expander and to drive a display. The firmware work perfectly if I read/write only the IO expander or only the display, as I put all together it works only if I reduce the frequency of display writes, otherwise it get stuck. In my application I can't reduce the frequency as I need to read the IO expander inputs at maximum frequency. I can't find out why this happens, I've only a Wire.begin(), simply seems that the i2c hardware stops working.

Thank you for your support

Regards


rasmadrak

Mon, 13 Feb 2017 21:24:04 +0000

Hi there!

How are you rendering your display? All rows in one go, or one row per update? The common thing to do is to do a single row per update, giving a nice even brightness to all rows and keeping timing consistent. May I see the code for your update routine?

Also, for display updates; I would suggest using SPI I/O expanders (faster) or SPI directly in Max32 (even faster) instead of using I2C. I update my DMD (for a pinball) at 20MHZ instead of 100-400KHz which is common for I2C. That's at least 50x faster, and I'm more than certain that your display can update very fast. :)


acm45

Thu, 16 Feb 2017 19:48:07 +0000

Hi rasmadrak,

I'm usign Seeedstudio library for the display with page update. I know that there are other SPI I/O expanders, but the board has the i2c to save IO pin of the microcontroller.

include <SeeedOLED.h>
#include <Wire2.h>
// Definition PIN
#define LED1 5
#define LED2 6
#define BLUE_RST 25
#define SELECTOR 73
#define IP_RESET 76
#define PWRD_WIFI 77
#define SCL2 12
#define BUTTON_INT 22
#define LIGHT_SENSOR_INT 3


// Constant definition
#define I2C_IO_EXP_ADDR 0x27
#define I2C_IO_EXP_ADDR_R 0x4F
#define I2C_IO_EXP_ADDR_READ 0x4F
#define I2C_IO_EXP_IODIR 0x00
#define I2C_IO_EXP_IPOL 0x01
#define I2C_IO_EXP_GPINTEN 0x02
#define I2C_IO_EXP_IOCON 0x05
#define I2C_IO_EXP_GPPU 0x06
#define I2C_IO_EXP_GPIO 0x09
#define I2C_IO_EXP_OLAT 0x0A

#define I2C_LCD_ADDRESS 0x78

#define INT_LUCE 0
#define INT_ENC_A 1
#define INT_ENC_B 2

// Analog pin
#define TEMP_OUT 0
#define TEMP_REF 1

float temperature = 0;
const byte IO_EXPANDER_SETUP_IODIR[2] = {I2C_IO_EXP_IODIR, 0x7F};
const byte IO_EXPANDER_SETUP_GPPU[2] = {I2C_IO_EXP_GPPU, 0x80};
const byte IO_EXPANDER_SETUP_INT[2] = {I2C_IO_EXP_GPINTEN, 0x03};
const byte IO_EXPANDER_OUTPUT[2] = {I2C_IO_EXP_OLAT, 0x00};
const byte IO_EXPANDER_READ_INPUT[2] = {I2C_IO_EXP_GPIO , 0x00};
uint32_t result = 0;
byte pulsanti[1]={0};
int test = 0;
bool fail;
int c = 3;
int c_reg = 0;
int cycle_counter = 0;
int luce_counter = 0;
int luce_counter2 = 0;
volatile int led_state = LOW;
volatile int led_state2 = LOW;


void setup() {  
  pinMode(LED1, OUTPUT);        
  pinMode(LED2, OUTPUT);      
  pinMode(PWRD_WIFI, OUTPUT);     
  pinMode(IP_RESET, INPUT);
  pinMode(SELECTOR, INPUT);
  pinMode(BUTTON_INT, INPUT);
  
  pinMode(LIGHT_SENSOR_INT, INPUT);
  
  
  // ***************************************
  // Setup IO expander
  Wire2.begin();
  Wire2.beginTransmission(I2C_IO_EXP_ADDR);
  Wire2.send(IO_EXPANDER_SETUP_IODIR[0]);
  Wire2.send(IO_EXPANDER_SETUP_IODIR[1]);
  Wire2.endTransmission();
  
  Wire2.beginTransmission(I2C_IO_EXP_ADDR);
  Wire2.send(IO_EXPANDER_OUTPUT[0]);
  Wire2.send(IO_EXPANDER_OUTPUT[1]);
  Wire2.endTransmission();
  
  Wire2.beginTransmission(I2C_IO_EXP_ADDR);
  Wire2.send(IO_EXPANDER_SETUP_GPPU[0]);
  Wire2.send(IO_EXPANDER_SETUP_GPPU[1]);
  Wire2.endTransmission();
  
  Wire2.beginTransmission(I2C_IO_EXP_ADDR);
  Wire2.send(I2C_IO_EXP_IOCON);
  Wire2.send(0x00);
  Wire2.endTransmission();
  
  Wire2.beginTransmission(I2C_IO_EXP_ADDR);
  Wire2.send(IO_EXPANDER_SETUP_INT[0]);
  Wire2.send(IO_EXPANDER_SETUP_INT[1]);
  Wire2.endTransmission(1);
  // ***************************************      
  // Turn Off wi-fi
  digitalWrite(PWRD_WIFI, HIGH);  
  SeeedOled.init();  //initialze SEEED OLED display
  SeeedOled.clearDisplay();          //clear the screen and set start position to top left corner
  SeeedOled.setNormalDisplay();      //Set display to normal mode (i.e non-inverse mode)
  SeeedOled.setPageMode();           //Set addressing mode to Page Mode
  SeeedOled.setTextXY(0,0);          //Set the cursor to Xth Page, Yth Column
}
  
void loop() {
  
  // Read the IO expander only if the BUTTON_INT is low
  if (digitalRead(BUTTON_INT) == 0)
  {
    Wire2.beginTransmission(I2C_IO_EXP_ADDR);
    Wire2.send(0x09);
  
    Wire2.requestFrom(I2C_IO_EXP_ADDR,1);
    while(Wire2.available())    // slave may send less than requested
    {
      c = Wire2.receive();
    }    
    if (bitRead(c,1)  == 0)
    {
       Wire2.beginTransmission(I2C_IO_EXP_ADDR);
      Wire2.send(IO_EXPANDER_OUTPUT[0]);
      Wire2.send(128);
      Wire2.endTransmission(1);
    }
      
    else
     {
       Wire2.beginTransmission(I2C_IO_EXP_ADDR);
      Wire2.send(IO_EXPANDER_OUTPUT[0]);
      Wire2.send(0);
      Wire2.endTransmission(1);      
     }    
  }
  
   digitalWrite(LED2, led_state);
   digitalWrite(LED1, led_state2);
    delay(100);
    
    if (c!= c_reg)
    {
      c_reg = c;
     //SeeedOled.clearDisplay();          //clear the screen and set start position to top left corner
     // SeeedOled.setNormalDisplay();      //Set display to normal mode (i.e non-inverse mode)
     // SeeedOled.setPageMode();           //Set addressing mode to Page Mode
     SeeedOled.setTextXY(0,1);          //Set the cursor to Xth Page, Yth Column
     if (bitRead(c,0)  == 0)
     {
        digitalWrite(LED1, HIGH);
        SeeedOled.putString("PB 1 ON "); //Print the String
     }
      else
      {
         digitalWrite(LED1, LOW);
        SeeedOled.putString("PB 1 OFF "); //Print the String
      }
     
     SeeedOled.setTextXY(1,1);          //Set the cursor to Xth Page, Yth Column
     
     if (bitRead(c,1)  == 0)
     {
      // digitalWrite(LED2, HIGH); 
       SeeedOled.putString("PB 2 ON "); //Print the String
     }
      else
      {
       //digitalWrite(LED2, LOW);
        SeeedOled.putString("PB 2 OFF "); //Print the String
      }
    }
    
    if (cycle_counter%10 == 0)
    {
      temperature = analogRead(TEMP_OUT);
      temperature = temperature - analogRead(TEMP_REF);
      temperature = temperature * 0.488;
      SeeedOled.setTextXY(2,1);
      SeeedOled.putString("Temp: ");
      SeeedOled.putFloat(temperature,1);
      SeeedOled.putString(" C");
    }
    cycle_counter++;

}

I'm using the Wire2 library that use the second i2c port of the chipkit. I can't use the first port as I use it for external interrupts. Form many test seems that the i2c stop working during the display update; as I previously wrote, if I remove the display section no problem at all, same thing if I remove the IO expander section, the display works properly.

Regards


rasmadrak

Fri, 17 Feb 2017 10:43:29 +0000

Hi there,

I'm not familiar with the Wire2-library, but one thing that comes to mind: You run beginTransmission() but vary the endTransmission variable from (1) / (). Shouldn't this always be endTransmission()?


acm45

Sat, 18 Feb 2017 14:09:32 +0000

Hi,

the wire2 library is the same as wire for the first channel, the EndTransmission parameter has no effect, the issue comes after a while suddenly.

Regards


rasmadrak

Wed, 22 Feb 2017 12:29:17 +0000

It sounds like there might be some sync issues that appear after a while. Perhaps the I2C-resistor values are wrong?


acm45

Wed, 22 Feb 2017 18:56:55 +0000

I2C-resistors values are 2k7 and are ok, signals are clear. It's something related to the firmware libraries, like a double begin() but I can't find it.


rasmadrak

Thu, 23 Feb 2017 13:55:00 +0000

Here's one piece that might cause trouble.

// Read the IO expander only if the BUTTON_INT is low
//...
    Wire2.beginTransmission(I2C_IO_EXP_ADDR);
    //...
    while(Wire2.available())    // slave may send less than requested
    {
      c = Wire2.receive();
    }    
    if (bitRead(c,1)  == 0)
    {
       Wire2.beginTransmission(I2C_IO_EXP_ADDR); <-- Calls a new beginTransmission before the last request was ended? 
      //...
    }     
    else
     {
       Wire2.beginTransmission(I2C_IO_EXP_ADDR); <-- Calls a new beginTransmission before the last request was ended? 
       //...
     }    
  }
  
  //...

acm45

Thu, 23 Feb 2017 21:20:24 +0000

Hi, Thanks for the advice but I've already added the code Wire2.endTransmission(), nothing changed.