# 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 [![MFPi2c_connection.png](https://wiki.kurokesu.com/uploads/images/gallery/2020-08/scaled-1680-/MFPi2c_connection.png)](https://wiki.kurokesu.com/uploads/images/gallery/2020-08/MFPi2c_connection.png)

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 ADDRFUNCTIONBYTE1BYTE2BYTE3BYTE4
#### 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 ADDRFUNCTIONBYTE1BYTE2BYTE3BYTE4
Read command also consists of 5 bytes. FUNCTION repeats last write command value.
R: I2C ADDRFUNCTIONBYTE1BYTE2BYTE3BYTE4
#### Commands
**ADDR****REGISTER NAME****R/W****FUNCTION**
0x02**RESET\_CPU**WReset STM32 CPU
0x03**INIT\_DRV**WReset and initialize motor driver
0x05**AUX\_OUT**WControl AUX output on/off
0x06**MODE** WNormal / forced move
0x07**STOP** WCompulsory stop
0x08**PI\_LEDS** WSwitch on ON or OFF PI LEDs
0x09**MOTOR\_SLEEP\_PWR** WSet motor sleep power
0x0A**MOTOR\_DRV\_PWR** WSet motor working power
0x0B**MOTOR\_SPEED** WSet motor speed
0x0C**PI\_THRESHOLD** WSet PI detector thresholds
0x0D**READ\_STATUS** RRead controller status
0x0E**SET\_MOTOR\_POS** WSet current motor position
0x0F**SET\_MICROSTEPPING**WSet motor micro-stepping mode
0x10**DN\_SWITCH**WIR fitler
0x20**MOVE**WMove motor
#### Command explanation ##### `RESET_CPU` - Reset CPU Resets CPU. Other values are ignored.
**Description****FUNCTION****BYTE1****BYTE2****BYTE3****BYTE4**
Reset CPU0x02ignoredignoredignored**0x32**
##### `INIT_DRV` - Reset motor driver Resets and initializes motor controller. Other values are ignored.
**Description****FUNCTION****BYTE1****BYTE2****BYTE3****BYTE4**
Initialize motor driver0x03ignoredignoredignored**0x32**
##### `AUX_OUT` - Control AUX output Controls GPIO output
**Description****FUNCTION****BYTE1****BYTE2****BYTE3****BYTE4**
Set AUX to Low0x05ignoredignoredignored**0x00**
Set AUX to High0x05ignoredignoredignored**0x01**
##### `MODE` - Normal / forced move Selects between normal and normal+forced move mode
**Description****FUNCTION****BYTE1****BYTE2****BYTE3****BYTE4**
Normal move mode0x06ignoredignored**Channel****0x00**
Normal+Forced move mode0x06ignoredignored**Channel****0x01**
Channel encoding:
**Channel****BYTE3 value**
A0x01
B0x02
C0x03
##### `STOP` - Compulsory stop Stop movement of all motors
**Description****FUNCTION****BYTE1****BYTE2****BYTE3****BYTE4**
Reset CPU0x07ignoredignoredignored**0x32**
##### `PI_LEDS` - Switch on ON or OFF PI LEDs Control LEDs used in homing procedure.
**Description****FUNCTION****BYTE1****BYTE2****BYTE3****BYTE4**
OFF0x08ignoredignoredignored**0x00**
ON0x08ignoredignoredignored**0x01**
##### `MOTOR_SLEEP_PWR` - Set motor sleep power Set motor sleep current
**Description****FUNCTION****BYTE1****BYTE2****BYTE3****BYTE4**
Set current0x09ignoredignored**Channel****Power**
Channel encoding:
**Channel****BYTE3 value**
A0x01
B0x02
C0x03
##### `MOTOR_DRV_PWR` - Set motor working power Set motor operating current
**Description****FUNCTION****BYTE1****BYTE2****BYTE3****BYTE4**
Set current0x0Aignoredignored**Channel****Power**
Channel encoding:
**Channel****BYTE3 value**
A0x01
B0x02
C0x03
D0x04
##### `MOTOR_SPEED` - Set motor speed Set motor speed
**Description****FUNCTION****BYTE1****BYTE2****BYTE3****BYTE4**
Set speed0x0Bignored**Channel****Speed \[15:8\]** **Speed \[7:0\]**
Channel encoding:
**Channel****BYTE2 value**
A0x01
B0x02
C0x03
##### `PI_THRESHOLD` - Set PI detector thresholds Set limit switch optocoupler detector thresholds
**Description****FUNCTION****BYTE1****BYTE2****BYTE3****BYTE4**
Set threshold0x0Cignored**Channel****Signal \[15:8\]** **Signal \[7:0\]**
Channel encoding:
**Channel****BYTE2 value**
A LOW0x01
B LOW0x02
C LOW0x03
A HIGH0x04
B HIGH0x05
C HIGH0x06
##### `READ_STATUS` - Read controller status Read motor status, PI status and motor positions
**Description****FUNCTION****BYTE1****BYTE2****BYTE3****BYTE4**
Set current0x0Dignoredignoredignored**Channel**
Channel encoding:
**Channel****BYTE2 value**
A position0x01
B position0x02
C position0x03
PI\_A status0x04
PI\_B status0x05
PI\_C status0x06
A moving0x07
B moving0x08
C moving0x09
Returns:
**Description****FUNCTION****BYTE1****BYTE2****BYTE3****BYTE4**
Status return value0x0D**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 position0x0E**Channel****Speed \[23:16\]****Speed \[15:8\]** **Speed \[7:0\]**
Channel encoding:
**Channel****BYTE1 value**
A0x01
B0x02
C0x03
##### `SET_MICROSTEPPING` - Set microstepping mode Set microstepping mode for defined channel
**Description****FUNCTION****BYTE1****BYTE2****BYTE3****BYTE4**
Set microstepping0x0Fignoredignored**Channel** **Mode**
Channel encoding:
**Channel****BYTE1 value**
A0x01
B0x02
C0x03
##### `MOVE` - Move motor Move motor defined step count.
**Description****FUNCTION****BYTE1****BYTE2****BYTE3****BYTE4**
Steps0x20**Channel****Direction****Steps \[15:8\]** **Steps \[7:0\]**
Channel encoding:
**Channel****BYTE2 value**
A0x01
B0x02
C0x03

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**
POS10x10ignoredignoredignored**0x00**
POS20x10ignoredignoredignored**0x01**
#### Arduino sketch example Demo output should look like ```shell 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` ```C #include #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` ```C // SCL - A5 // SDA - A4 #include #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; } ```