-->
Page 1 of 1

Arduino as I2C slave

PostPosted: Sun Mar 29, 2015 2:22 pm
by KRavEN
Worked this out this morning and thought I would share. First thing I've done in LUA so please let me know if it could be done better.

This is on a cactus micro board I got from Tindie that is a 3.3v 8mhz atmega32u4 coupled with an ESP-11 module. I had to wire the GPIO0 and GPIO1 to the SCL and SDA lines and I switched the default jumpers from using SoftwareSerial on pins 11 and 12 to hardware serial. Max serial pass-through is 57600 because of known timing issues with the atmega32u4 running at 8mhz.

The code is a basic example showing how to set a digital pin state or the analogWrite value of a pwm pin. Should be easy to build on and add commands to get input pin values, analog sensor values, etc... Right now the arduino methods return the pin and value that was set as there's no way to get the value of an output pin. This is mainly to show how to get a multi-byte value back from the slave.

Arduino Sketch
Code: Select all#include <Wire.h>
#define ESP_CH_EN         13
#define SLAVE_ADDRESS     0x29
#define TWI_FREQ_SETTING  400000L   // 400KHz for I2C
#define CPU_FREQ          8000000L  // 8MHz

uint8_t command; // which command was requested (if any)
uint8_t pin;
uint8_t value;

enum {
  I2C_CMD_SET_DIGITAL_PIN = 1,
  I2C_CMD_SET_PWM_PIN = 2
};

void requestEvent(){
  if (command > 0) {
    uint8_t response[2];
    response[0] = pin;
    response[1] = value;
    pinMode(pin, INPUT);
    pinMode(pin, OUTPUT);

    switch (command) {
      case I2C_CMD_SET_DIGITAL_PIN:
        digitalWrite(pin, (value) ? HIGH : LOW);
        break;

      case I2C_CMD_SET_PWM_PIN:
        analogWrite(pin, value);
        break;
    }

    Wire.write(response, sizeof response);
    command = 0;
  }
}

void receiveEvent(int bytesReceived) {
  if (bytesReceived == 3) {
    command = Wire.read();
    pin = Wire.read();
    value = Wire.read();
  }
}


void setup() {
  command = 0;
  Serial.begin(57600);
  while (!Serial) {
    ; // wait for serial port to connect
  }
  Serial1.begin(57600);

  // Enable esp8266
  pinMode(ESP_CH_EN, OUTPUT);
  digitalWrite(ESP_CH_EN, HIGH);

  Wire.begin(SLAVE_ADDRESS);
//  TWBR = ((CPU_FREQ / TWI_FREQ_SETTING) - 16) / 2;
  Wire.onRequest(requestEvent);
  Wire.onReceive(receiveEvent);
}


void loop() {
  while (Serial.available()) {
    Serial1.write(Serial.read());
  }

  while (Serial1.available()) {
    Serial.write(Serial1.read());
  }
}


nodemcu code
Code: Select allfunction write_pin(dev_addr, command, pin, value)
  i2c.start(id)
  i2c.address(id, dev_addr, i2c.TRANSMITTER)
  i2c.write(id, command)
  i2c.write(id, pin)
  i2c.write(id, value)
  i2c.stop(id)
  i2c.start(id)
  i2c.address(id, dev_addr,i2c.RECEIVER)
  result=i2c.read(id,2)
  i2c.stop(id)
  --print("Pin " .. string.byte(result,1) .. " value is " .. string.byte(result,2) )
end

id = 0
sda = 4 -- GPIO2
scl = 3 -- GPIO0
slaveAddr = 0x29
digitalPinCommand = 1
pwmPinCommand = 2
digitalPin = 8
pwmPin = 9
state = 0
brightness = 0
fadeAmount = 5

i2c.setup(id,sda,scl,i2c.SLOW)

tmr.alarm(0, 1000, 1,
  function()
    state = not state
    write_pin(slaveAddr, digitalPinCommand, digitalPin, (state and 1 or 0))
  end
)

tmr.alarm(1, 30, 1,
  function()
    write_pin(slaveAddr, pwmPinCommand, pwmPin, brightness)
    brightness = brightness + fadeAmount
    if brightness == 0 or brightness == 255 then
      fadeAmount = -fadeAmount
    end
  end
)

Re: Arduino as I2C slave

PostPosted: Sun Mar 29, 2015 3:21 pm
by alonewolfx2
thanks for your good work. i will try

Re: Arduino as I2C slave

PostPosted: Sat Oct 31, 2015 9:47 pm
by Rogan Dawes
Has anyone tried this with the Rev2 Cactus Micro? I assume I will only have to connect the GPIO's to the SDA and SCL pins, since the Rev2 is already using the hardware serial ports. What sort of data rate was achievable using this technique?