Controlling over I2C port
Applies to EVB.1.2.0 firmware where I2C is implemented
Slave address: 0x33
About
In order to simplify I2C communication, firmware utilizes one one direction read/write operations. All commands expect 5 bytes, where first byte is function address, remaining bytes is payload.
USB-CDC works in parallel with I2C functionality and independently, but it is recommended to use single communication channel once controller is initialized.
Wiring
In order to avoid power loops, do not connect both (SCF4 and Arduino) USB ports at the same time.
Write data
All commands are fixed length consisting of 5 bytes.
W: I2C ADDR | FUNCTION | BYTE1 | BYTE2 | BYTE3 | BYTE4 |
Read data
First issue write command (register values are ignored). This step performs necessary calculations and fills memory with registers ready for reading in next step.
W: I2C ADDR | FUNCTION | BYTE1 | BYTE2 | BYTE3 | BYTE4 |
Read command also consists of 5 bytes. FUNCTION repeats last write command value.
R: I2C ADDR | FUNCTION | BYTE1 | BYTE2 | BYTE3 | BYTE4 |
Commands
ADDR | REGISTER NAME | R/W | FUNCTION |
0x02 | RESET_CPU | W | Reset STM32 CPU |
0x03 | INIT_DRV | W | Reset and initialize motor driver |
0x05 | AUX_OUT | W | Control AUX output on/off |
0x06 | MODE |
W | Normal / forced move |
0x07 | STOP |
W | Compulsory stop |
0x08 | PI_LEDS |
W | Switch on ON or OFF PI LEDs |
0x09 | MOTOR_SLEEP_PWR |
W | Set motor sleep power |
0x0A | MOTOR_DRV_PWR |
W | Set motor working power |
0x0B | MOTOR_SPEED |
W | Set motor speed |
0x0C | PI_THRESHOLD |
W | Set PI detector thresholds |
0x0D | READ_STATUS |
R | Read controller status |
0x0E | SET_MOTOR_POS |
W | Set current motor position |
0x0F | SET_MICROSTEPPING | W | Set motor micro-stepping mode |
0x10 | DN_SWITCH | W | IR fitler |
0x20 | MOVE | W | Move motor |
Command explanation
RESET_CPU
- Reset CPU
Resets CPU. Other values are ignored.
Description | FUNCTION | BYTE1 | BYTE2 | BYTE3 | BYTE4 |
Reset CPU | 0x02 | ignored | ignored | ignored | 0x32 |
INIT_DRV
- Reset motor driver
Resets and initializes motor controller. Other values are ignored.
Description | FUNCTION | BYTE1 | BYTE2 | BYTE3 | BYTE4 |
Initialize motor driver | 0x03 | ignored | ignored | ignored | 0x32 |
AUX_OUT
- Control AUX output
Controls GPIO output
Description | FUNCTION | BYTE1 | BYTE2 | BYTE3 | BYTE4 |
Set AUX to Low | 0x05 | ignored | ignored | ignored | 0x00 |
Set AUX to High | 0x05 | ignored | ignored | ignored | 0x01 |
MODE
- Normal / forced move
Selects between normal and normal+forced move mode
Description | FUNCTION | BYTE1 | BYTE2 | BYTE3 | BYTE4 |
Normal move mode | 0x06 | ignored | ignored | Channel | 0x00 |
Normal+Forced move mode | 0x06 | ignored | ignored | Channel | 0x01 |
Channel encoding:
Channel | BYTE3 value |
A | 0x01 |
B | 0x02 |
C | 0x03 |
STOP
- Compulsory stop
Stop movement of all motors
Description | FUNCTION | BYTE1 | BYTE2 | BYTE3 | BYTE4 |
Reset CPU | 0x07 | ignored | ignored | ignored | 0x32 |
PI_LEDS
- Switch on ON or OFF PI LEDs
Control LEDs used in homing procedure.
Description | FUNCTION | BYTE1 | BYTE2 | BYTE3 | BYTE4 |
OFF | 0x08 | ignored | ignored | ignored | 0x00 |
ON | 0x08 | ignored | ignored | ignored | 0x01 |
MOTOR_SLEEP_PWR
- Set motor sleep power
Set motor sleep current
Description | FUNCTION | BYTE1 | BYTE2 | BYTE3 | BYTE4 |
Set current | 0x09 | ignored | ignored | Channel | Power |
Channel encoding:
Channel | BYTE3 value |
A | 0x01 |
B | 0x02 |
C | 0x03 |
MOTOR_DRV_PWR
- Set motor working power
Set motor operating current
Description | FUNCTION | BYTE1 | BYTE2 | BYTE3 | BYTE4 |
Set current | 0x0A | ignored | ignored | Channel | Power |
Channel encoding:
Channel | BYTE3 value |
A | 0x01 |
B | 0x02 |
C | 0x03 |
D | 0x04 |
MOTOR_SPEED
- Set motor speed
Set motor speed
Description | FUNCTION | BYTE1 | BYTE2 | BYTE3 | BYTE4 |
Set speed | 0x0B | ignored | Channel | Speed [15:8] |
Speed [7:0] |
Channel encoding:
Channel | BYTE2 value |
A | 0x01 |
B | 0x02 |
C | 0x03 |
PI_THRESHOLD
- Set PI detector thresholds
Set limit switch optocoupler detector thresholds
Description | FUNCTION | BYTE1 | BYTE2 | BYTE3 | BYTE4 |
Set threshold | 0x0C | ignored | Channel | Signal [15:8] |
Signal [7:0] |
Channel encoding:
Channel | BYTE2 value |
A LOW | 0x01 |
B LOW | 0x02 |
C LOW | 0x03 |
A HIGH | 0x04 |
B HIGH | 0x05 |
C HIGH | 0x06 |
READ_STATUS
- Read controller status
Read motor status, PI status and motor positions
Description | FUNCTION | BYTE1 | BYTE2 | BYTE3 | BYTE4 |
Set current | 0x0D | ignored | ignored | ignored | Channel |
Channel encoding:
Channel | BYTE2 value |
A position | 0x01 |
B position | 0x02 |
C position | 0x03 |
PI_A status | 0x04 |
PI_B status | 0x05 |
PI_C status | 0x06 |
A moving | 0x07 |
B moving | 0x08 |
C moving | 0x09 |
Returns:
Description | FUNCTION | BYTE1 | BYTE2 | BYTE3 | BYTE4 |
Status return value | 0x0D | Value [31:24] | Value [23:16] | Value [15:8] | Value [7:0] |
SET_MOTOR_POS
- Set position
Redefine current position
Description | FUNCTION | BYTE1 | BYTE2 | BYTE3 | BYTE4 |
Set position | 0x0E | Channel | Speed [23:16] | Speed [15:8] |
Speed [7:0] |
Channel encoding:
Channel | BYTE1 value |
A | 0x01 |
B | 0x02 |
C | 0x03 |
SET_MICROSTEPPING
- Set microstepping mode
Set microstepping mode for defined channel
Description | FUNCTION | BYTE1 | BYTE2 | BYTE3 | BYTE4 |
Set microstepping | 0x0F | ignored | ignored | Channel |
Mode |
Channel encoding:
Channel | BYTE1 value |
A | 0x01 |
B | 0x02 |
C | 0x03 |
MOVE
- Move motor
Move motor defined step count.
Description | FUNCTION | BYTE1 | BYTE2 | BYTE3 | BYTE4 |
Steps | 0x20 | Channel | Direction | Steps [15:8] |
Steps [7:0] |
Channel encoding:
Channel | BYTE2 value |
A | 0x01 |
B | 0x02 |
C | 0x03 |
MAX steps is: 0xFFFF-1 = 0xFFFE
Theia lens exceeds 0xFFFF step count, thus absolute positioning has to be implemented on client side code
DN_SWITCH
- IR filter swith
Switch filter to day or night position
Description | FUNCTION | BYTE1 | BYTE2 | BYTE3 | BYTE4 |
POS1 | 0x10 | ignored | ignored | ignored | 0x00 |
POS2 | 0x10 | ignored | ignored | ignored | 0x01 |
Arduino sketch example
Demo output should look like
SCF4-M I2C tester
Init driver
Set microstepping
Move mode
PI LEDS
Set drive pwr
Set sleep pwr
Set motor speeds
Set PI thresholds
Read status: posA
D 0 0 0 0
Read status: PI A
D 0 0 0 1
Homing A
Homing B
Move +A
Move -A
Move +B
Move -B
Move +C
Move -C
Set position
DN 0
DN 1
DN 0
DN 1
Last return from I2C port: ok
Loop...
tester.ino
#include <Wire.h>
#define CH_A 0x01
#define CH_B 0x02
#define CH_C 0x03
#define CH_D 0x04
#define CCW 0
#define CW 1
void err_print(byte err)
{
if (err == 0)
{
Serial.println("ok");
}
else if (err==4)
{
Serial.println("failed");
}
}
void setup()
{
Wire.begin();
Serial.begin(115200);
while (!Serial);
Serial.println("\nSCF4-M I2C tester\n");
}
void loop()
{
byte error;
Serial.println("Init driver");
SCF4_INIT_DRIVER();
Serial.println("Set microstepping");
SCF4_MICROSTEPPING(2, CH_A);
SCF4_MICROSTEPPING(2, CH_B);
SCF4_MICROSTEPPING(6, CH_C);
Serial.println("Move mode");
SCF4_MODE(0x00, CH_A);
SCF4_MODE(0x00, CH_B);
SCF4_MODE(0x00, CH_C);
Serial.println("PI LEDS");
SCF4_PI_LEDS(0x01);
Serial.println("Set drive pwr");
SCF4_DRV_PWR(180, CH_A);
SCF4_DRV_PWR(180, CH_B);
SCF4_DRV_PWR(180, CH_C);
SCF4_DRV_PWR(90, CH_D);
Serial.println("Set sleep pwr");
SCF4_SLEEP_PWR(50, CH_A);
SCF4_SLEEP_PWR(50, CH_B);
SCF4_SLEEP_PWR(50, CH_C);
Serial.println("Set motor speeds");
SCF4_MOTOR_SPEED(5000, CH_A);
SCF4_MOTOR_SPEED(5000, CH_B);
SCF4_MOTOR_SPEED(5000, CH_C);
Serial.println("Set PI thresholds");
SCF4_PI_THRESHOLD(2000, 0x01);
SCF4_PI_THRESHOLD(2000, 0x02);
SCF4_PI_THRESHOLD(2000, 0x03);
SCF4_PI_THRESHOLD(3000, 0x04);
SCF4_PI_THRESHOLD(3000, 0x05);
SCF4_PI_THRESHOLD(3000, 0x06);
Serial.println("Read status: posA");
SCF4_READ_STATUS(0x01);
Serial.println("Read status: PI A");
SCF4_READ_STATUS(0x04);
Serial.println("Homing A");
MOVE(30000, CW, CH_A);
delay(2000);
SCF4_MODE(0x01, CH_A);
MOVE(0x100, CCW, CH_A);
delay(15000); // status reading is not implemented, for testing 15s timeout is used
SCF4_MODE(0x00, CH_A);
SET_MOTOR_POS(100, CH_A);
Serial.println("Homing B");
MOVE(30000, CW, CH_B);
delay(2000);
SCF4_MODE(0x01, CH_B);
MOVE(0x100, CCW, CH_B);
delay(15000); // status reading is not implemented, for testing 15s timeout is used
SCF4_MODE(0x00, CH_B);
SET_MOTOR_POS(100, CH_B);
// normal operation starts here
Serial.println("Move +A");
MOVE(0xFFFE, CW, CH_A);
delay(5000);
Serial.println("Move -A");
MOVE(0xFFFE, CCW, CH_A);
delay(5000);
Serial.println("Move +B");
MOVE(0xFFFE, CW, CH_B);
delay(5000);
Serial.println("Move -B");
MOVE(0xFFFE, CCW, CH_B);
delay(5000);
Serial.println("Move +C");
MOVE(1000, CW, CH_C);
delay(2000);
Serial.println("Move -C");
MOVE(1000, CCW, CH_C);
delay(2000);
Serial.println("Set position");
//SET_MOTOR_POS(100, 0x01);
//SET_MOTOR_POS(200, 0x01);
//SET_MOTOR_POS(300, 0x01);
//STOP();
Serial.println("DN 0");
DN_SWITCH(0);
delay(1000);
Serial.println("DN 1");
DN_SWITCH(1);
delay(1000);
Serial.println("DN 0");
DN_SWITCH(0);
delay(1000);
Serial.println("DN 1");
DN_SWITCH(1);
delay(1000);
Serial.print("Last return from I2C port: ");
err_print(error);
Serial.println("Loop...");
while(1)
{
}
}
scf4_i2c.ino
// SCL - A5
// SDA - A4
#include <Wire.h>
#define SCF4_ADDR 0x33
// SCF4 is not signaling busy status, thus fixed delay is added
// If next I2C command is sent too soon it might be ignored
#define I2C_SLEEP 200
byte SCF4_AUX(byte status)
{
byte function = 0x05;
byte error;
//byte w1 = (counter&0xFF);
//byte w2 = ((counter>>8)&0xFF);
//byte w3 = ((counter>>16)&0xFF);
//byte w4 = ((counter>>24)&0xFF);
Wire.beginTransmission(SCF4_ADDR);
Wire.write(function);
Wire.write(0);
Wire.write(0);
Wire.write(0);
Wire.write(status);
error = Wire.endTransmission();
delay(I2C_SLEEP);
return error;
}
byte SCF4_RESET_CPU(void)
{
byte function = 0x02;
byte error;
Wire.beginTransmission(SCF4_ADDR);
Wire.write(function);
Wire.write(0);
Wire.write(0);
Wire.write(0);
Wire.write(0x32);
error = Wire.endTransmission();
delay(I2C_SLEEP);
return error;
}
byte SCF4_INIT_DRIVER(void)
{
byte function = 0x03;
byte error;
Wire.beginTransmission(SCF4_ADDR);
Wire.write(function);
Wire.write(0);
Wire.write(0);
Wire.write(0);
Wire.write(0x32);
error = Wire.endTransmission();
delay(I2C_SLEEP);
return error;
}
byte SCF4_MODE(byte mode, byte ch)
{
byte function = 0x06;
byte error;
Wire.beginTransmission(SCF4_ADDR);
Wire.write(function);
Wire.write(0);
Wire.write(0);
Wire.write(ch);
Wire.write(mode);
error = Wire.endTransmission();
delay(I2C_SLEEP);
return error;
}
byte SCF4_PI_LEDS(byte mode)
{
byte function = 0x08;
byte error;
Wire.beginTransmission(SCF4_ADDR);
Wire.write(function);
Wire.write(0);
Wire.write(0);
Wire.write(0);
Wire.write(mode);
error = Wire.endTransmission();
delay(I2C_SLEEP);
return error;
}
byte SCF4_SLEEP_PWR(byte pwr, byte ch)
{
byte function = 0x09;
byte error;
Wire.beginTransmission(SCF4_ADDR);
Wire.write(function);
Wire.write(0);
Wire.write(0);
Wire.write(ch);
Wire.write(pwr);
error = Wire.endTransmission();
delay(I2C_SLEEP);
return error;
}
byte SCF4_DRV_PWR(byte pwr, byte ch)
{
byte function = 0x0A;
byte error;
Wire.beginTransmission(SCF4_ADDR);
Wire.write(function);
Wire.write(0);
Wire.write(0);
Wire.write(ch);
Wire.write(pwr);
error = Wire.endTransmission();
delay(I2C_SLEEP);
return error;
}
byte SCF4_MOTOR_SPEED(int speed, byte ch)
{
byte function = 0x0B;
byte error;
Wire.beginTransmission(SCF4_ADDR);
Wire.write(function);
Wire.write(0);
Wire.write(ch);
Wire.write(highByte(speed));
Wire.write(lowByte(speed));
error = Wire.endTransmission();
delay(I2C_SLEEP);
return error;
}
byte SCF4_PI_THRESHOLD(int level, byte ch)
{
byte function = 0x0C;
byte error;
Wire.beginTransmission(SCF4_ADDR);
Wire.write(function);
Wire.write(0);
Wire.write(ch);
Wire.write(highByte(level));
Wire.write(lowByte(level));
error = Wire.endTransmission();
delay(I2C_SLEEP);
return error;
}
byte SCF4_READ_STATUS(byte ch)
{
byte function = 0x0D;
byte error;
/*
* channel:
* 0x00 - dummy, reads 0x87, 0x65, 0x43, 0x21
* 0x01 - chA.position
* 0x02 - chB.position
* 0x03 - chC.position
* 0x04 - piA.status
* 0x05 - piB.status
* 0x06 - piC.status
* 0x07 - chA.moving
* 0x08 - chB.moving
* 0x09 - chC.moving
*/
Wire.beginTransmission(SCF4_ADDR);
Wire.write(function);
Wire.write(0);
Wire.write(0);
Wire.write(0);
Wire.write(ch);
error = Wire.endTransmission();
delay(I2C_SLEEP);
byte w1 = 0xff;
byte w2 = 0xff;
byte w3 = 0xff;
byte w4 = 0xff;
byte w5 = 0xff;
Wire.requestFrom(SCF4_ADDR, 5);
w1 = Wire.read();
w2 = Wire.read();
w3 = Wire.read();
w4 = Wire.read();
w5 = Wire.read();
Serial.print(w1, HEX);
Serial.print(" ");
Serial.print(w2, HEX);
Serial.print(" ");
Serial.print(w3, HEX);
Serial.print(" ");
Serial.print(w4, HEX);
Serial.print(" ");
Serial.print(w5, HEX);
Serial.println();
delay(I2C_SLEEP);
// TODO: return read values
return error;
}
byte SET_MOTOR_POS(int pos, byte ch)
{
byte function = 0x0E;
byte error;
Wire.beginTransmission(SCF4_ADDR);
Wire.write(function);
Wire.write(ch);
Wire.write(0);
Wire.write(highByte(pos));
Wire.write(lowByte(pos));
error = Wire.endTransmission();
delay(I2C_SLEEP);
return error;
}
byte MOVE(unsigned int steps, byte dir, byte ch)
{
byte function = 0x20;
byte error;
Wire.beginTransmission(SCF4_ADDR);
Wire.write(function);
Wire.write(ch);
Wire.write(dir);
Wire.write(highByte(steps));
Wire.write(lowByte(steps));
error = Wire.endTransmission();
delay(I2C_SLEEP);
return error;
}
byte DN_SWITCH(byte mode)
{
byte function = 0x10;
byte error;
Wire.beginTransmission(SCF4_ADDR);
Wire.write(function);
Wire.write(0);
Wire.write(0);
Wire.write(0);
Wire.write(mode);
error = Wire.endTransmission();
delay(I2C_SLEEP);
return error;
}
byte SCF4_MICROSTEPPING(byte stepping, byte ch)
{
byte function = 0x0F;
byte error;
Wire.beginTransmission(SCF4_ADDR);
Wire.write(function);
Wire.write(0);
Wire.write(0);
Wire.write(ch);
Wire.write(stepping);
error = Wire.endTransmission();
delay(I2C_SLEEP);
return error;
}
byte STOP(void)
{
byte function = 0x07;
byte error;
Wire.beginTransmission(SCF4_ADDR);
Wire.write(function);
Wire.write(0);
Wire.write(0);
Wire.write(0);
Wire.write(0x32);
error = Wire.endTransmission();
delay(I2C_SLEEP);
return error;
}