Cross-Platform I2C Help


#1

I have asked in the past about the possibilities of cross-platform multiplayer, but I only recently started trying to implement a little test. Unfortunately I don’t exactly know what I’m doing when it comes to I2C, just the high-level concepts.

I’m trying to do something a bit weird, where I’m trying to interface with a Gamebuino Classic running a simple 2-player pong game, but right now I’m just trying to get it to acknowledge that the Pokitto is sending anything, even wrong data. The Gamebuino is using the Arduino Wire library, but I figured if the protocol is the same it should work across libraries and devices. Right now I’m trying to have the Pokitto be the slave and the Gamebuino be the master, so I just try to detect on the Pokitto that data is requested of it and to send garbage data back. However, the Pokitto never acknowledges it got any messages from the master at all, and the Gamebuino acts like nothing is connected.

Here’s my test code I’m running on the Pokitto:

#include "Pokitto.h"

Pokitto::Core pokitto;

I2CSlave slave(P0_5, P0_4);

int my_status = 0;
uint8_t try_address = 0;

int main()
{
char buf[10];
char msg[] = "Slave!";
pokitto.begin();
pokitto.setFrameRate(60);

int x = 0;

while (pokitto.isRunning())
{
  if (pokitto.update())
  {
    slave.address(try_address);
    int i = slave.receive();
    switch (i) {
      case I2CSlave::ReadAddressed:
        slave.write(msg, strlen(msg) + 1); // Includes null char
        my_status = 1;
        break;
      case I2CSlave::WriteGeneral:
        slave.read(buf, 10);
        printf("Read G: %s\n", buf);
        my_status = 2;
        break;
      case I2CSlave::WriteAddressed:
        slave.read(buf, 10);
        printf("Read A: %s\n", buf);
        my_status = 3;
        break;
   }
    if( my_status == 0 ){
      try_address++;
    }
    pokitto.display.clear();
    pokitto.display.setCursor(1,1);
    pokitto.display.println(x);
    ++x;
    pokitto.display.println(my_status);
    pokitto.display.println(try_address);
    pokitto.display.println(buf);
   if( my_status == 0 ){
     for(int i = 0; i < 10; i++) buf[i] = 0;    // Clear buffer
   }
  }
}

return 0;
}

Right now I’m cycling through every i2c slave address and trying to receive with that address just in case I don’t have the right address, because I don’t know if I have the right address.

On the gamebuino it apparently is using address 2, which is supposedly reserved. However, the Wire lib docs say it uses 7-bit addresses and that some addresses needed to be shifted, so I just wasn’t sure whether there would be a difference in the way addresses are handled in each library.

Here’s the code for the master in the multiplayer pong game on Gamebuino: https://github.com/Gamebuino/Gamebuino-Classic/blob/master/examples/3.Advanced/PongMulti/master.ino

I also have double and triple checked that my wires are connected to the correct pins. I can verify the game works between a Gamebuino Classic and Makerbuino.


#2

I²C requires pullup resistors (normally 4.7K) on the SCL and SDA lines. I don’t know if either the Pokitto or Gamebuino provide these on board. If not, you’ll have to add these in yourself (if you haven’t already).

Edit: I just looked at the Makerbuino schematic as see that it does include 4.7K pullups. Based on what I said above, this may be why it works between Gamebuino and Makerbuino but not between Gamebuino and Pokitto.

Edit 2: The Gamebuino schematics show pullups included, as well, so you can pretty much ignore this post.


#3

Pokitto schematics will be in the first ever Pokitto mag edited by @torbuntu. I am working on a clean presentation of all the systems and subsystems.

I2C pullups are included on Pokitto also

image


#4

The Gamebuino can not acknowledge anything, if the I2C is using the wrong address

I know I2C on Pokitto does work, because the volume control is an I2C controlled digital potentiometer.


#5

Here is the data on the MCP4018 digipot. You can look at that and relevant code in PokittoLib to get an idea how the I2C addressing works.

https://www.digikey.fi/product-detail/en/microchip-technology/MCP4018T-503E-LT/MCP4018T-503E-LTCT-ND/2060154


#6

Oops. Let me double check that.


#7

Ok, so @wuuff

You see here the MCP4018 being called using the SoftwareI2C :slight_smile:

int Pokitto::setHWvolume(uint8_t v) {
    HWvolume=v;
    if (HWvolume>127) HWvolume=127;
    //HWvolume = 0x7F&v;
    //if (!volpotError) return volpot.put(HWvolume); //use normal I2C
    /* fallback method for broken MCP4018 */
    SoftwareI2C swvolpot(P0_4, P0_5); //swapped SDA,SCL
    swvolpot.write(0x5e,HWvolume);
	return HWvolume;
}

#8

What happened is Daniel routed the SDA & SCL lines to the MCP4018 the wrong way around. I asked him to fix it for v2 but he forgot.

I am sorry that I just now remember all the details.

Only the MCP4018 is routed wrong, the SDA and SCL lines of the I2C are correct in the PEX connector on Pokitto’s head

The reason why I did not insist on fixing it again is because the MCP4018 is rarely called and is not a speed-critical component. So the SoftwareI2C works perfectly fine with it.

My suggestion is that you look at how the MCP4018 is being addressed using SoftwareI2C and then try to use SoftwareI2C to talk to Gamebuino. In that way you will know 100% for sure if you’re sending and receiving stuff or not.

There may be something else that I am now forgetting, possibly the fact that I2C addresses are sometimes expressed in different ways. I don’t have time to research it just right now

The softwareI2C to MCP4018 is re-initialized on every call to adjust the HW volume. So you can switch the SDA and SCL around to call your I2C component or use hardware I2C. It will not conflict.


#9

Thanks for the help, I’ll give that a try when I have time and report my results.


#10

I have managed to get the Pokitto to act as an I2C master when connected to a Gamebuino, and it can successfully send and receive data. At first, the connection was really unstable, and it turns out that SoftwareI2C uses 1Mhz as a default frequency, while the Gamebuino uses 100Khz. Once I set the Pokitto to use the same frequency, it worked great. Here’s the test code I was using to talk to Gamebuino pong, in case it helps anybody:

Summary
#include "Pokitto.h"
#include "SoftwareI2C.h"

Pokitto::Core pokitto;

SoftwareI2C otherdevice(P0_5, P0_4);

uint8_t try_address = 4;

#define PLAYER_Y 10
#define BALL_X 20
#define BALL_Y 21

int main()
{
  uint8_t buf[10];
  char outbuf[10];
  uint8_t msg[] = {PLAYER_Y,0,BALL_X,10,BALL_Y,10};
  pokitto.begin();
  pokitto.setFrameRate(60);
  otherdevice.setFrequency(100000); //100 Khz
  int x = 0;
  while (pokitto.isRunning())
  {
    if (pokitto.update())
    {
      otherdevice.read(try_address,buf,2); // Request slave data
      switch (buf[0]) {
        case PLAYER_Y:
          sprintf(outbuf,"%d",(uint8_t)buf[1]);
          msg[1] = (uint8_t)buf[1];// Mirror slave's paddle
          break;
        case 0:
          sprintf(outbuf,"Nope");
          break;
        default:
          sprintf(outbuf,"SOMETHING:%d",(uint8_t)buf[0]);
          break;
      }
      if( pokitto.buttons.released(BTN_DOWN) ){
        try_address--;
      }
      if( pokitto.buttons.released(BTN_UP) ){
        try_address++;
      }
      pokitto.display.clear();
      pokitto.display.setCursor(1,1);
      pokitto.display.println(x);
      ++x;
      pokitto.display.println((int)try_address);
      pokitto.display.println(outbuf);
      msg[3] = x % 84; // Continually move ball's x coordinate
      otherdevice.write(try_address,msg,6); // Send master data
    }
  }
  return 0;
}

However, it looks like SoftwareI2C only supports being an I2C master, and not a slave, which I think means it can’t be used to connect two Pokittos together. I was hoping to be able to make a prototype using a Gamebuino that could eventually be used to connect two Pokittos. The Pokitto has an object called I2CSlave that I was originally trying to use, but I still can’t get any results when trying to use that. I’m still stuck on whether the code is even functional for I2CSlave.