15.8. Example I²C code for Linux in C

The example C code below uses the I²C API provided by the Linux kernel to send and receive data from a Jrk G2. It demonstrates how to set the target of the Jrk by sending a “Set target” command and how to read variables using a “Get variables” command. This code only works on Linux.

If you are using a Raspberry Pi, please note that the Raspberry Pi’s hardware I²C module has a bug that causes this code to not work reliably. As a workaround, we recommend enabling the i2c-gpio overlay and using the I²C device that it provides. To do this, add the line dtoverlay=i2c-gpio to /boot/config.txt and reboot. The overlay documentation has information about the parameters you can put on that line, but those parameters are not required. Connect the Jrk’s SDA line to GPIO23 and connect the Jrk’s SCL line to GPIO24. The i2c-gpio overlay creates a new I²C device which is usually named /dev/i2c-3, and the code below uses that device. To give your user permission to access I²C busses without being root, you might have to add yourself to the i2c group by running sudo usermod -a -G i2c $(whoami) and restarting.

// Uses the Linux I2C API to send and receive data from a Jrk G2.
// NOTE: The Jrk's input mode must be "Serial / I2C / USB".
// NOTE: For reliable operation on a Raspberry Pi, enable the i2c-gpio
//   overlay and use the I2C device it provides (usually /dev/i2c-3).
// NOTE: You might need to change the 'const char * device' line below
//   to specify the correct I2C device.
// NOTE: You might need to change the `const uint8_t address' line below
// to match the device number of your Jrk.

#include <fcntl.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <stdint.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <unistd.h>

// Opens the specified I2C device.  Returns a non-negative file descriptor
// on success, or -1 on failure.
int open_i2c_device(const char * device)
{
  int fd = open(device, O_RDWR);
  if (fd == -1)
  {
    perror(device);
    return -1;
  }
  return fd;
}

// Sets the target, returning 0 on success and -1 on failure.
//
// For more information about what this command does, see the "Set Target"
// command in the "Command reference" section of the Jrk G2 user's guide.
int jrk_set_target(int fd, uint8_t address, uint16_t target)
{
  uint8_t command[] = {
    (uint8_t)(0xC0 + (target & 0x1F)),
    (uint8_t)((target >> 5) & 0x7F),
  };
  struct i2c_msg message = { address, 0, sizeof(command), command };
  struct i2c_rdwr_ioctl_data ioctl_data = { &message, 1 };
  int result = ioctl(fd, I2C_RDWR, &ioctl_data);
  if (result != 1)
  {
    perror("failed to set target");
    return -1;
  }
  return 0;
}

// Gets one or more variables from the Jrk (without clearing them).
// Returns 0 for success, -1 for failure.
int jrk_get_variable(int fd, uint8_t address, uint8_t offset,
  uint8_t * buffer, uint8_t length)
{
  uint8_t command[] = { 0xE5, offset };
  struct i2c_msg messages[] = {
    { address, 0, sizeof(command), command },
    { address, I2C_M_RD, length, buffer },
  };
  struct i2c_rdwr_ioctl_data ioctl_data = { messages, 2 };
  int result = ioctl(fd, I2C_RDWR, &ioctl_data);
  if (result != 2)
  {
    perror("failed to get variables");
    return -1;
  }
  return 0;
}

// Gets the Target variable from the jrk or returns -1 on failure.
int jrk_get_target(int fd, uint8_t address)
{
  uint8_t buffer[2];
  int result = jrk_get_variable(fd, address, 0x02, buffer, sizeof(buffer));
  if (result) { return -1; }
  return buffer[0] + 256 * buffer[1];
}

// Gets the Feedback variable from the jrk or returns -1 on failure.
int jrk_get_feedback(int fd, uint8_t address)
{
  // 0x04 is the offset of the feedback variable in the "Variable reference"
  // section of the Jrk user's guide.  The variable is two bytes long.
  uint8_t buffer[2];
  int result = jrk_get_variable(fd, address, 0x04, buffer, sizeof(buffer));
  if (result) { return -1; }
  return buffer[0] + 256 * buffer[1];
}

int main()
{
  // Choose the I2C device.
  const char * device = "/dev/i2c-3";

  // Set the I2C address of the Jrk (the device number).
  const uint8_t address = 11;

  int fd = open_i2c_device(device);
  if (fd < 0) { return 1; }

  int feedback = jrk_get_feedback(fd, address);
  if (feedback < 0) { return 1; }
  printf("Feedback is %d.\n", feedback);

  int target = jrk_get_target(fd, address);
  if (target < 0) { return 1; }
  printf("Target is %d.\n", target);

  int new_target = (target < 2048) ? 2248 : 1848;
  printf("Setting target to %d.\n", new_target);
  int result = jrk_set_target(fd, address, new_target);
  if (result) { return 1; }

  close(fd);
  return 0;
}

Related Products

Jrk G2 18v19 USB Motor Controller with Feedback
Jrk G2 24v13 USB Motor Controller with Feedback
Jrk G2 18v27 USB Motor Controller with Feedback
Jrk G2 24v21 USB Motor Controller with Feedback
Jrk G2 21v3 USB Motor Controller with Feedback
Jrk G2 21v3 USB Motor Controller with Feedback (Connectors Soldered)
Log In
Pololu Robotics & Electronics
Shopping cart
(702) 262-6648
Same-day shipping, worldwide
Menu
Shop Blog Forum Support
My account Comments or questions? About Pololu Contact Ordering information Distributors