Feelix
  • Feelix Documentation
  • Getting started
    • Designing Effects
      • Torque Effects
      • Position Effects
      • Velocity Effects
      • (In)dependent Effects
    • Effect Library
    • Creating Collections
  • Create and edit
    • Edit tools
    • Effect Settings
    • Layers
    • Grid
    • Export Effects
    • TensorFlow
  • Uploading files
    • Setting up STM32
    • Setting up ESP32
    • Connect and Upload
    • Hardware Settings
    • Troubleshooting Feelix
  • Hardware support
    • Hardware
    • PCB pinout
    • Setup
    • Dependencies
    • FeelixEffect Docs
      • Functions and Parameters
      • Setup
      • Motor control
      • Import Effects
        • Import Haptic Effect
        • Import Velocity Effect
      • I2C communication
        • One Way Communication
        • Two Way Communication
  • Downloads
    • Feelix Design Tool
    • Feelix Arduino Library
    • 3D Models
    • Old Library Releases
Powered by GitBook
On this page
  • ESP32 Master
  • Feelix I2C Master
  • Feelix I2C Slave

Was this helpful?

  1. Hardware support
  2. FeelixEffect Docs
  3. I2C communication

Two Way Communication

PreviousOne Way CommunicationNextFeelix Design Tool

Last updated 3 days ago

Was this helpful?

Install in the Arduino IDE and open and run the code below from Examples > Feelix MiniDriver Effects > I2C communication > Two way communication

ESP32 Master

The code below was tested with DOIT ESP32 DEVKIT V1 available at . Follow to add the board to the boards manager of your Arduino IDE.

Please open this code from the 'Examples' folder within the Arduino IDE. Otherwise associated links and resources will not function correctly.

/* ESP32_i2c_comm_request_master v1.1
Example code to send data from a Master ESP32 (DOIT ESP32 DEVKIT V1) to Slave Feelix,
consecutive requesting data from the Slave to Master.
Slave address set to: 0x71
Uses a modified library of SerialTransfer
https://github.com/tommag/SerialTransfer/tree/i2c-request
*/

#include <Arduino.h>
#include <Wire.h>
#include "src/SerialTransfer/I2CTransfer.h"

#define define_I2C_master

#define SLAVE_01_ADDRESS 0x71

#define ESP32_SCL 22
#define ESP32_SDA 21


I2CTransfer transfer;

//adapt data structure to your needs make sure slave side is the same
struct __attribute__((packed)) {
  float velocity;
  int angle;
  uint8_t count;
} dataToSend;

struct __attribute__((packed)) {
  uint16_t return_value;
  uint8_t count;
} returnData;

char arr[] = "hello";

uint8_t variable_PacketID;

uint16_t randNumber;

// Callback function
void requestData() {
  transfer.rxObj(returnData);
  Serial.println((String) "Return:\t" + returnData.return_value + "\t" + returnData.count);
}

//supplied as a reference - persistent allocation required
const functionPtr callbackArr[] = { requestData };

void setup() {
  delay(1000);

  Serial.begin(115200);

  Wire1.begin(ESP32_SDA, ESP32_SCL);
  Wire1.setClock(100000);

  configST config;
  config.debug = true;
  config.callbacks = callbackArr;
  config.callbacksLen = sizeof(callbackArr) / sizeof(functionPtr);

  transfer.begin(Wire1, config);

  variable_PacketID = 0;
}

void loop() {
  // use this variable to keep track of how many
  // bytes we're stuffing in the transmit buffer
  uint16_t sendSize = 0;

  randNumber = random(1000, 4000);

  dataToSend.velocity = (float) randNumber / 1000.00;

  Serial.print("Send velocity:\t");
  Serial.println(dataToSend.velocity);

  // Stuff buffer with struct
  sendSize = transfer.txObj(dataToSend, sendSize);

  // Stuff buffer with array
  sendSize = transfer.txObj(arr, sendSize);

  // Send buffer
  transfer.sendData(sendSize, variable_PacketID, SLAVE_01_ADDRESS);

  // Generate some changing data
  dataToSend.count++;

  // toggle PacketID to show off the callbacks in slave example
  variable_PacketID++;
  if (variable_PacketID > 1) {
    variable_PacketID = 0;
  }

  delay(250);

  // Request data from Slave
  transfer.requestDatum(sizeof(returnData), SLAVE_01_ADDRESS);

  delay(250);
}

Feelix I2C Master

When you are using a Feelix as Master instead of another 3v3 logic microcontroller, connect Feelix MASTER to Master input in Feelink and follow the example below.

/* Feelix_i2c_comm_request_master v1.1
Example code to send data from a Master Feelix to Slave Feelix,
consecutive requesting data from the Slave to Master.
Uses a modified library of SerialTransfer
https://github.com/tommag/SerialTransfer/tree/i2c-request
*/

#include <Feelix.h>

#define SLAVE_01_ADDRESS 0x71
//#define SLAVE_01_ADDRESS 0x72
#define COMMUNICATION_SPEED 300

/* initialize Feelix */
Feelix feelix = Feelix();

//adapt data structure to your needs make sure slave side is the same
struct __attribute__((packed)) {
  float velocity;
  int angle;
  uint8_t count;
} dataToSend;

struct __attribute__((packed)) {
  uint16_t return_value;
  uint8_t count;
} returnData;

char arr[] = "hello";

int last_send_time = 0; /* variable to keep track of last time data was sent */
bool SEND_DATA = true; /* TRUE when sending data FALSE when requesting data*/
uint8_t variable_PacketID; /* id to select callback function at SLAVE */

uint16_t randomNumber;

/* Callback function - receive incoming data from slave */
void requestData()
{
  feelix.transfer.rxObj(returnData);  
  Serial.println((String) "Velocity slave:\t" + ((float) returnData.return_value / 1000.00) + "\t" + returnData.count);
}

/* supplied as a reference - persistent allocation required */
const functionPtr callbackArr[] = {requestData};


void setup()
{
  delay(100);
  
  Serial.begin(115200);

  /* callback settings*/
  feelix.config.debug = true;
  feelix.config.callbacks = callbackArr;
  feelix.config.callbacksLen = sizeof(callbackArr) / sizeof(functionPtr);

  /* initialize Feelix as I2C_MASTER_TWOWAY: Default NO_COMMUNICATION */
  feelix.init(State::I2C_MASTER_TWOWAY);

  /* directly set motion control type of the simpleFOC bldc controller 
   *(https://docs.simplefoc.com/closed_loop_motion_control) 
   */
  feelix.bldc->controller = MotionControlType::velocity;
  variable_PacketID = 0;
}


void loop()
{

  feelix.run();

  /* Run all functions other then motor control inside this if statement 
   * control speed with COMMUNICATION_SPEED variable
   */
  if (millis() - last_send_time > COMMUNICATION_SPEED) {
    last_send_time = millis();
    
    feelix.blinkStatusLED();
    
    if (SEND_DATA) {      
    
      randomNumber = random(1000, 4000);

      dataToSend.angle = (int) (feelix.angle * 1000);
      dataToSend.velocity = feelix.velocity;
    
      // use this variable to keep track of how many
      // bytes we're stuffing in the transmit buffer
      uint16_t sendSize = 0;

      // Stuff buffer with struct
      sendSize = feelix.transfer.txObj(dataToSend, sendSize);

      // Stuff buffer with array
      sendSize = feelix.transfer.txObj(arr, sendSize);

      // Send buffer
      feelix.transfer.sendData(sendSize, variable_PacketID, SLAVE_01_ADDRESS);
      feelix.toggleLED(STM32_LED_ORANGE);

      Serial.println((String) "Count: " + dataToSend.count + "\tAngle: " + dataToSend.angle + "\tVelocity: " + dataToSend.velocity);

      dataToSend.count++;

      // toggle PacketID to show off the callbacks in slave example
      variable_PacketID++;
      if (variable_PacketID > 1) {
        variable_PacketID = 0;
      }

    } else if (!SEND_DATA) {
      //Request data from Slave
      feelix.transfer.requestDatum(sizeof(returnData), SLAVE_01_ADDRESS);
    }
    SEND_DATA = !SEND_DATA;
  }

  feelix.bldc->loopFOC();
  /* cast integer variable as float to divide by 1000.00 */
  feelix.bldc->move(((float) randomNumber / 1000.00));
  
  delay(1);
}

Feelix I2C Slave

For communication with ESP32 Master or Feelix Master, connect Feelix SLAVE to Slave input in Feelink and follow the example below.

/* Feelix_i2c_comm_request_slave v1.1
Example code to receive data from Master Feelix, 
and sending data back to Master on request.
Uses a modified library of SerialTransfer
https://github.com/tommag/SerialTransfer/tree/i2c-request
*/

#include <Feelix.h>

/* define address of slave: needs to be similar to slave address specified in Master */
#define SLAVE_01_ADDRESS 0x71
/* communication speed: change to */

/* initialize Feelix */
Feelix feelix = Feelix();

float masterVelocity = 0.0;

//adapt data structure to your needs make sure slave side is the same
/* struct to setup data structure of incoming data */
struct __attribute__((packed)) {
  float velocity;
  int angle;
  uint8_t count;
} dataToSend;

/* struct to setup data structure of outgoing data */
struct __attribute__((packed)) {
  uint16_t return_value;
  uint8_t count;
} returnData;

char arr[6];


const uint8_t loop_interval = 100;
volatile uint8_t loop_count = 0;

/* Callback functions. 
 * Depending on the action that needs to be performed based on 
 * data input you can create different callback functions.
 */
void mode1() {
  // use this variable to keep track of how many
  // bytes we've processed from the receive buffer
  uint16_t recSize = 0;
  recSize = feelix.transfer.rxObj(dataToSend, recSize);
  recSize = feelix.transfer.rxObj(arr, recSize);

  masterVelocity = dataToSend.velocity;

  /* print incoming data */
  Serial.println((String) "Mode 1:\t" + dataToSend.count + "\t" + ((float)dataToSend.angle / 1000.00) + "\t" + dataToSend.velocity + "\t" + arr);

  /* toggle orange LED when data is coming in */
  feelix.toggleLED(STM32_LED_ORANGE);
}


void mode2() {
  // use this variable to keep track of how many
  // bytes we've processed from the receive buffer
  uint16_t recSize = 0;
  recSize = feelix.transfer.rxObj(dataToSend, recSize);
  recSize = feelix.transfer.rxObj(arr, recSize);

  masterVelocity = dataToSend.velocity;

  /* print incoming data */
  Serial.println((String) "Mode 2:\t" + dataToSend.count + "\t" + 
    ((float)dataToSend.angle / 1000.00) + "\t" + dataToSend.velocity + "\t" + arr);

  /* toggle orange LED when data is coming in */
  feelix.toggleLED(STM32_LED_ORANGE);
}

// supplied as a reference - persistent allocation required.
const functionPtr callbackArr[] = { mode1, mode2 };


void I2C_RequestHandler() {
  feelix.transfer.replyWithDatum(returnData);

  returnData.return_value = (int) (feelix.velocity * 1000);
  returnData.count++;

  /* print return data */
  Serial.println((String) "reply: " + returnData.count + "\treturn value: " + 
    returnData.return_value);
}


void setup() {

  Serial.begin(115200);

  delay(1000);

  /* callback settings I2C communication */
  feelix.config.debug = true;
  feelix.config.callbacks = callbackArr;
  feelix.config.callbacksLen = sizeof(callbackArr) / sizeof(functionPtr);

  /* Initialize Feelix as SLAVE for two way communication 
   * The address should be the same as the SLAVE address specified in the MASTER code
   */
  feelix.init(State::I2C_SLAVE_TWOWAY, SLAVE_01_ADDRESS);

  /* bind request handler
   * Handler fires when master requests data
   */
  feelix.onRequestI2C(&I2C_RequestHandler);

  /* directly set motion control type of the simpleFOC bldc controller 
   *(https://docs.simplefoc.com/closed_loop_motion_control) 
   */
  feelix.bldc->controller = MotionControlType::velocity;
}




void loop() {
  /* read angle, velocity and direction
   * this function needs to update at a high frequency */
  feelix.run();

  /* If statement for functions within the loop that need to be called less frequently.
   * Adapt frequency by changing loop_interval variable
   * E.g. for printing values and reading sensors;
   */
  if (loop_count++ > loop_interval) {
    loop_count = 0;

    feelix.blinkStatusLED();
    
    /* print angle and velocity */
    /* Serial.println((String) "Angle: " + feelix.angle + "\tAngleDeg: "
     + feelix.angleDeg + "\tVelocity:" + feelix.velocity);    
     */
  }
  
  /* Move the motor at same speed as master you can change this to your needs using the motion control functions in SimpleFOC 
   * or play haptic effects using the Feelix library. 
   * Motion control function (https://docs.simplefoc.com/closed_loop_motion_control) */
  feelix.bldc->loopFOC();
  feelix.bldc->move(masterVelocity);
}
TinyTronics
these steps
Arduino Library for Feelix Effects