2013年2月3日日曜日

Raspberry Pi で Grove I2c Motor Driver

 前回の Grove I2C Motor Driver を Raspberry Pi で動かしてみました。この Grove I2C Motor Dirver はMotor Driverのボードに6V以上のモータ用電源を供給することで、ロジック用の電源もそこから生成(外部から供給でない)するので、3.3Vでは使えません。むしろ、自分の所で作った5Vを外部に供給するっていう、いらないんだけど・・・っていう仕様です。
 そこで、3.3VのRaspbery Pi の IOと接続するために秋月のレベル変換モジュールを間にかませます。Motor Driver側はさっき余計だって言った5Vがちょうど使えます。この5VをVCC、あとはSDAとSCLとGNDを接続します。変換モジュールのOEを5Vに吊っておきます。Raspberry Pi がわも3.3VとSDA、SCL、GNDを接続して、実験開始。


 Raspberry Pi 側の配線はこんなかんじですが、GPIOの端子に関しては、こちらがリファレンス。

 で、まあ、動いたことは動いたんですが・・・


 動くことは動くんですが、エラーが返ってきます。


 ACKが帰ってこない(NAK応答)とかでしょうか。この辺は今度時間のあるときにバスアナというかロジアナを引っ張り出してきて調べてみようと思います。そういえば、以前、プルアップ抵抗を余計に付けたら動かなかったみたいなこともあったし、Arduinoと比べるとシビア(っていうか、Arduinoはプルアップ抵抗入れ忘れても動くし、デバイスに内蔵しているところに並列に余計に入れても駆動しちゃうような心の広さ?があるんだよね)なんでしょうか。


#include <stdio.h>
#include <stdlib.h>
#include <linux/i2c-dev.h>
#include <fcntl.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

#include <wiringPi.h>

// Grove I2C MotorDriver レジスタ定義。
#define SET_PWM_AB (0x82)
#define SET_FREQ (0x84)
#define CHG_ADDR (0x83)
#define CHANEL_SET (0xaa)
#define MOTOR1_SPD (0xa1)
#define MOTOR2_SPD (0xa5)

// Grove I2C MotorDriver アドレス。
static unsigned char MOTOR_DRIVER_ADDRESS = 0x28;

char *i2cFileName = "/dev/i2c-1";    // I2Cポートのファイル名。
//char *i2cFileName = "/dev/i2c-0";    // 初期ロットは i2c-0 だった。

// 関数プロトタイプ。
void setMotor(unsigned char motor_no,
     unsigned char direction,
     unsigned char speed);
void setMotorSpeed(int motor_no, int speed);

int main(int argc, char **argv)
{
 printf("***** Grove I2C Motor Driver test *****\n");
 
 // モータドライブテスト。
 setMotorSpeed(1, 40);
 setMotorSpeed(2, -40);
 delay(10000);
 setMotorSpeed(1, 0);
 setMotorSpeed(2, 0);
 
 return 0;
}

void setMotor(unsigned char motor_no,
     unsigned char direction,
     unsigned char speed)
{
 int fd;     // ファイルディスクリプタ
 unsigned char buf[10];
 
 int address = (int)MOTOR_DRIVER_ADDRESS; // デバイスアドレス。
 
 // I2CポートをRead/Write属性でオープン。
 if ((fd = open(i2cFileName, O_RDWR)) < 0) {
  printf("Failed to open i2c port\n");
  exit(1);
 }

 // ポートオプションと通信先デバイスアドレスの設定。
 if (ioctl(fd, I2C_SLAVE, address) < 0) {
  printf("Unable to get bus access to talk to slave\n");
  exit(1);
 }
 
 // モータNo, 方向, 速さの順に送出。
 buf[0] = motor_no;
 buf[1] = direction;
 buf[2] = speed;
 if ((write(fd, buf, 3)) != 3) {
  printf("Error writing to i2c slave\n");
  // 現時点ではコマンドはMotorDriver側で処理されるが、
  // エラーとなるので、エラー処理をコメントアウトしている。
  // ACKが返っていない(NAKが返っている)?
  // 後日、バスアナで調査。
  //close(fd);
  //exit(1);
 }
 
 close(fd);
}

void setMotorSpeed(int motor_no, int speed)
{
 unsigned char spd;
 unsigned char dir;
 
 if ((motor_no < 1) && (motor_no > 2)) return;
 
 if (speed < 0)
 {
  dir = 2;
  spd = (unsigned char)(-speed);
 }
 else
 {
  dir = 1;
  spd = (unsigned char)speed;
 }
 
 if (motor_no == 1)
 {
  setMotor(MOTOR1_SPD, dir, spd);
 }
 else
 {
  setMotor(MOTOR2_SPD, dir, spd);
 }
}