diff --git a/src/SerialSolver_i2c.cpp b/src/SerialSolver_i2c.cpp new file mode 100644 index 0000000..bc06cea --- /dev/null +++ b/src/SerialSolver_i2c.cpp @@ -0,0 +1,42 @@ +/** + * @file SerialSolver_i2c.cpp + * @brief I2C command handling for DEMIR controller + * @author Muhammet Şam Rossiter + * @date 2025 + */ + +#include "SerialSolver.h" +#include "motor.h" +#include "controller.h" + +void SerialSolver::proccessI2CCommand(uint8_t* data, uint8_t length) { + if (length < 2) return; + + uint8_t motorIndex = data[0]; + uint8_t command = data[1]; + int16_t param = 0; + + if (length >= 4) { + param = (data[2] << 8) | data[3]; + } + + switch (command) { + case 0x01: // set motor speed + Controller.set_uManuel(param, motorIndex); + break; + case 0x02: // enable motor + Motor.enable(motorIndex); + break; + case 0x03: // disable motor + Motor.disable(motorIndex); + break; + case 0x04: // reset encoder + Motor.resetPosition(motorIndex); + break; + case 0x05: // set position reference + Controller.setPositionReference(param, motorIndex); + break; + default: + break; + } +} diff --git a/src/conf.h b/src/conf.h new file mode 100644 index 0000000..cae197a --- /dev/null +++ b/src/conf.h @@ -0,0 +1,14 @@ +#ifndef CONF_H +#define CONF_H + +// Serial configuration +#define BAUDRATE 115200 +#define TIMEOUT 100 // Serial timeout in ms + +// I2C configuration - +#define MOTOR_CONTROLLER_ADDR_1 0x08 + +// Control loop timing +#define LOOP_RATE_MS 3 // Main control loop rate + +#endif // CONF_H diff --git a/src/i2c_comm.cpp b/src/i2c_comm.cpp new file mode 100644 index 0000000..3d57bad --- /dev/null +++ b/src/i2c_comm.cpp @@ -0,0 +1,55 @@ +/** + * @file i2c_comm.cpp + * @brief I2C communication interface implementation for DEMIR controller + * @author Şam Rossiter + * @date 2025 + * @details Implements I2C master/slave routines for sending commands to + * the DEMIR motor controller. References controller I2C addresses + * defined in conf.h + */ + +#include +#include "i2c_comm.h" +#include "conf.h" // for I2C addresses +#include "controller.h" // for Solver +#include "motor.h" // for Motor + +uint8_t i2cCmdBuffer[I2C_CMD_BUF_SIZE]; +uint8_t i2cCmdIndex = 0; + +/** + * @brief I2C receive event callback + * @param byteCount Number of bytes received + * @details Called when I2C master writes data to this controller. + * Buffers incoming command and triggers Solver for processing. + */ +void receiveI2CCommand(int byteCount) { + while (Wire.available() && i2cCmdIndex < I2C_CMD_BUF_SIZE) { + i2cCmdBuffer[i2cCmdIndex++] = Wire.read(); + } + if (i2cCmdIndex > 0) { + Solver.proccessI2CCommand(i2cCmdBuffer, i2cCmdIndex); + i2cCmdIndex = 0; + } +} + +/** + * @brief I2C request event callback + * @details Called when I2C master requests data from this controller. + * Sends the current motor position (MOTOR_1) as a 4-byte response. + */ +void sendI2CResponse() { + uint32_t pos = Motor.getPosition(MOTOR_1); + Wire.write((uint8_t*)&pos, sizeof(pos)); +} + +/** + * @brief Initialize I2C interface + * @param slaveAddress I2C address of this controller + * @details Configures Wire library in slave mode and attaches receive/request callbacks. + */ +void initI2C(uint8_t slaveAddress) { + Wire.begin(slaveAddress); // join I2C bus with defined address + Wire.onReceive(receiveI2CCommand); // attach receive handler + Wire.onRequest(sendI2CResponse); // attach request handler +} diff --git a/src/i2c_comm.h b/src/i2c_comm.h new file mode 100644 index 0000000..b1da60f --- /dev/null +++ b/src/i2c_comm.h @@ -0,0 +1,22 @@ +/** + * @file i2c_comm.h + * @brief I2C communication interface for DEMIR motor controller + * @author Sam Rossiter + * @date 2025 + * @details Handles receiving commands and sending responses over I2C. + */ + +#pragma once +#include +#include "controller.h" +#include "motor.h" +#include "SerialSolver.h" + +#define DEMIR_I2C_ADDR 0x10 +#define I2C_CMD_BUF_SIZE 8 + +extern uint8_t i2cCmdBuffer[I2C_CMD_BUF_SIZE]; +extern uint8_t i2cCmdIndex; + +void receiveI2CCommand(int byteCount); +void sendI2CResponse(); diff --git a/src/main.cpp b/src/main.cpp index 05a15ee..40d1299 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,15 +1,15 @@ /** * @file main.cpp - * @brief Main application entry point for DEMIR motor controller + * @brief Main application entry point for DEMIR motor controller with I2C support * @author Muhammet Şükrü Demir - * @date 2020 - * @version 1.1.1 - * @details This is the main application file that initializes the DEMIR motor control - * system and implements the main control loop with serial command processing, - * motor control execution, and data logging capabilities. + * @date 2025 + * @version 1.1.2 + * @details Initializes DEMIR motor control system, implements main control loop, + * handles serial and I2C commands, motor control execution, and data logging. */ #include +#include #include "Motion.h" #include "MotorDriver.h" @@ -18,84 +18,67 @@ #include "com_def.h" #include "conf.h" #include "controller.h" +#include "i2c_comm.h" // I2C interface header /// @brief Main control loop rate in milliseconds uint8_t loopRate = 3; /** * @brief Arduino setup function - system initialization - * @details Initializes serial communication, motor drivers, and status LEDs. - * Performs LED test sequence to verify hardware functionality. */ void setup() { - // Initialize serial communication - Serial.begin( BAUDRATE ); - while ( !Serial ) { - // Wait for serial port to initialize - } - Serial.setTimeout( TIMEOUT ); + Serial.begin(BAUDRATE); + while (!Serial) {} + Serial.setTimeout(TIMEOUT); + + Serial.println(F("DEMIR v1.1.2")); - // Print system identification - Serial.println( F( "DEMIR v1.1.1" ) ); - - // Initialize motor driver subsystem Driver.init(); - Serial.println( F( "ok!" ) ); + Serial.println(F("ok!")); - // Initialize status LEDs - pinMode( STATUS_LED_BLUE, OUTPUT ); - pinMode( STATUS_LED_RED, OUTPUT ); + pinMode(STATUS_LED_BLUE, OUTPUT); + pinMode(STATUS_LED_RED, OUTPUT); - // LED startup test sequence - digitalWrite( STATUS_LED_BLUE, HIGH ); - delay( 300 ); - digitalWrite( STATUS_LED_BLUE, LOW ); + digitalWrite(STATUS_LED_BLUE, HIGH); + delay(300); + digitalWrite(STATUS_LED_BLUE, LOW); - digitalWrite( STATUS_LED_RED, HIGH ); - delay( 300 ); - digitalWrite( STATUS_LED_RED, LOW ); + digitalWrite(STATUS_LED_RED, HIGH); + delay(300); + digitalWrite(STATUS_LED_RED, LOW); + + // Initialize I2C interface + Wire.begin(DEMIR_I2C_ADDR); + Wire.onReceive(receiveI2CCommand); + Wire.onRequest(sendI2CResponse); } /** * @brief Arduino main loop function - * @details Implements the main control loop with timing control, motor driver execution, - * data logging, and serial command processing. Runs continuously at specified - * loop rate for real-time motor control. */ void loop() { - // Update timing for control loop - Controller.currentTime = millis(); ///< Current timestamp - Controller.deltaT - = Controller.currentTime - Controller.oldTime; ///< Time since last control update - - // Execute control loop at specified rate - if ( Controller.deltaT >= loopRate ) // Execute when deltaT exceeds loopRate - { + Controller.currentTime = millis(); + Controller.deltaT = Controller.currentTime - Controller.oldTime; + + if (Controller.deltaT >= loopRate) { Controller.oldTime = Controller.currentTime; - + // Execute motor control algorithms Driver.run(); // Handle data logging if enabled - if ( Solver.logEnable ) // Check if logging is enabled - { - switch ( Solver.logWhat ) // Determine what to log - { + if (Solver.logEnable) { + switch (Solver.logWhat) { case LOG_POSITION: - /// Log current motor position - Solver.logForMatlab[ Solver.logCounter ] = ( unsigned long ) Motor.getPosition( MOTOR_1 ); + Solver.logForMatlab[Solver.logCounter] = (unsigned long)Motor.getPosition(MOTOR_1); break; case LOG_CURRENT: - /// Log current sensor data (not implemented) - // unsigned long tempHex = *( unsigned long* ) &totalCurrent; - // logForMatlab[ Solver.logCounter ] = tempHex; break; } - - // Check if log buffer is full - if ( ++Solver.logCounter == Solver.logSize ) { - Solver.logEnable = false; // Disable logging - Solver.logCounter = 0; // Reset counter + + if (++Solver.logCounter == Solver.logSize) { + Solver.logEnable = false; + Solver.logCounter = 0; } } } @@ -104,15 +87,13 @@ void loop() { Solver.proccessCommands(); // Send logged data to MATLAB if requested - if ( Solver.sendLogToMatlab ) { + if (Solver.sendLogToMatlab) { Solver.sendLogToMatlab = false; - - // Transmit logged data as 4-byte values - for ( uint16_t j = 0; j < Solver.logSize; j++ ) { - Serial.write( Solver.logForMatlab[ j ] ); ///< LSB - Serial.write( Solver.logForMatlab[ j ] >> 8 ); ///< Byte 1 - Serial.write( Solver.logForMatlab[ j ] >> 16 ); ///< Byte 2 - Serial.write( Solver.logForMatlab[ j ] >> 24 ); ///< MSB + for (uint16_t j = 0; j < Solver.logSize; j++) { + Serial.write(Solver.logForMatlab[j]); + Serial.write(Solver.logForMatlab[j] >> 8); + Serial.write(Solver.logForMatlab[j] >> 16); + Serial.write(Solver.logForMatlab[j] >> 24); } } }