PD-Stepper/Software/Basic_Functionality_Test/Basic_Functionality_Test.ino

228 lines
6.2 KiB
C++

/* Code to test the basic functionality of the USB PD Stepper Driver and Controller
*
* Note this only uses the step and fir pins to interface with the TMC2209. See other examples for more advanced serial commms
* by Things by Josh 2024
*/
#include <Wire.h> //For I2C for encoder
/////////////////////////
// Pin Defines //
/////////////////////////
//TMC2209 Stepper Driver
#define TMC_EN 21
#define STEP 5
#define DIR 6
#define MS1 1
#define MS2 2
#define SPREAD 7
#define TMC_TX 17
#define TMC_RX 18
#define DIAG 20
#define INDEX 11
//PD Trigger (CH224K)
#define PG 15 //power good singnal (dont enable stepper untill this is good)
#define CFG1 38
#define CFG2 48
#define CFG3 47
//AS5600 Hall Effect Encoder
#define SCL 9
#define SDA 8
//Other
#define VBUS 4
#define NTC 7
#define LED1 10
#define LED2 12
#define SW1 35
#define SW2 36
#define SW3 37
#define AUX1 14
#define AUX2 13
////////////////////////////
// Global Variable Defines //
////////////////////////////
//TMC2209 Stepper Driver
unsigned long lastStep = 0; //time of last step
int stepDelay = 100; //delay (microseconds) between steps (AKA Speed)
int motorDir = 0; //Stepper motor direction
//PD Trigger (CH224K)
bool PGState = 0;
//AS5600 Hall Effect Encoder
#define AS5600_ADDRESS 0x36 // I2C address of the AS5600 sensor
signed long total_encoder_counts = 0;
//Other
float VBusVoltage = 0;
float VREF = 3.3;
const float DIV_RATIO = 0.1189427313; //20k&2.7K Voltage Divider
//LED Flash
long lastFlash = 0;
int flashInt = 100;
bool flashState = 0;
//Step state
bool lastState = 0;
void setup() {
//TMC2209 Stepper Driver Setup (Simple not using serial comms)
pinMode(TMC_EN, OUTPUT);
pinMode(STEP, OUTPUT);
pinMode(DIR, OUTPUT);
pinMode(MS1, OUTPUT);
pinMode(MS1, OUTPUT);
// pinMode(SPREAD, OUTPUT);
// pinMode(INDEX, INPUT);
// pinMode(DIAG, INPUT); //will need to be attached to interrupt for sensorless homing
digitalWrite(TMC_EN, HIGH); //High to disable on startup
digitalWrite(MS1, LOW); //Microstep resolution configuration (internal pull-down resistors: MS2, MS1: 00: 1/8, 01: 1/32, 10: 1/64 11: 1/16
digitalWrite(MS2, LOW);
digitalWrite(DIR, motorDir); //set direction at start
//PD Trigger Setup
pinMode(PG, INPUT);
pinMode(CFG1, OUTPUT);
pinMode(CFG2, OUTPUT);
pinMode(CFG3, OUTPUT);
// 5V 9V 12V 15V 20V (Can also be changed on the fly)
digitalWrite(CFG1, LOW); // 1 0 0 0 0
digitalWrite(CFG2, LOW); // - 0 0 1 1
digitalWrite(CFG3, HIGH); // - 0 1 1 0
//General/Other Setup
pinMode(LED1, OUTPUT);
pinMode(LED2, OUTPUT);
pinMode(SW1, INPUT);
pinMode(SW2, INPUT);
pinMode(SW3, INPUT);
// pinMode(AUX1, INPUT); //can be set to anything
// pinMode(AUX2, INPUT); //can be set to anything
pinMode(NTC, INPUT);
pinMode(VBUS, INPUT);
digitalWrite(LED1, LOW);
digitalWrite(LED2, LOW);
///////////////////////////////////////
// Can't auto enter bootloader mode if
// serial.begin has been called
// so hold down SW2 on boot to enable serial
// if you need to read outputs but not program
///////////////////////////////////////
//(Can also manually enter bootloader mode by holding BOOT, press RST, release BOOT)
if (digitalRead(SW2) == LOW){ //push = LOW
Serial.begin(115200);
Serial.println("Code Starting");
}
//AS5600 Hall Encoder Setup
Wire.begin(SDA, SCL); //start wire with earlier defined pins
}
void loop() {
readVoltage(); //read and output voltage as well as PG status from PD trigger
runMotor(); //run the stepper motor at set speed and direction (ensure readVoltage() called first to get PGState)
readEncoder();
if (millis() - lastFlash > flashInt){
lastFlash = millis();
digitalWrite(LED1, flashState);
if (flashState == 0){
flashState = 1;
} else {
flashState = 0;
}
}
}
//run the stepper motor at set speed and direction (ensure readVoltage() called first to get PGState)
void runMotor(){
PGState = digitalRead(PG); //Low = power good!
if (PGState == 0){ //only enable motor if correct voltage seen (to stop motor running off laptop 5V when programming)
digitalWrite(TMC_EN, LOW); //low to enable (should really only do this on state change)
digitalWrite(DIR, digitalRead(SW3)); //low to enable (should really only do this on state change)
if (micros() - lastStep > stepDelay){
lastStep = micros();
digitalWrite(STEP, lastState);
if (lastState == 0){
lastState = 1;
} else {
lastState = 0;
}
}
} else{
digitalWrite(TMC_EN, HIGH); //disable stepper as voltage not as expected (should really only do this on state change)
}
}
//read and output voltage as well as PG status from PD trigger
void readVoltage(){
int ADCValue = analogRead(VBUS);
VBusVoltage = ADCValue * (VREF / 4096.0) / DIV_RATIO;
PGState = digitalRead(PG); //Low = power good!
Serial.print("Voltage Read: ");
Serial.print(VBusVoltage);
Serial.println("V");
Serial.print("PG Status: ");
Serial.println(PGState);
}
//read the AS5600 encoder via I2C
void readEncoder(){
int raw_counts;
static int prev_raw_counts = 0;
static signed long revolutions = 0;
float angle;
// Request the raw encoder counts from the AS5600 sensor
Wire.beginTransmission(AS5600_ADDRESS);
Wire.write(0x0C); // Register address for raw angle output (0x0C)
Wire.endTransmission(false);
Wire.requestFrom(AS5600_ADDRESS, 2); // Request 2 bytes of data
if (Wire.available() >= 2) {
raw_counts = Wire.read() << 8 | Wire.read(); // Combine two bytes to get the counts value
}
// Convert raw counts to angle in degrees if that is what's needed
angle = (raw_counts * 360.0) / 4096.0;
// Check to see if it has gone past "home" over one full rotation
if (prev_raw_counts > 3000 && raw_counts < 1000) {
revolutions++;
} else if (prev_raw_counts < 1000 && raw_counts > 3000) {
revolutions--;
}
// Update the previous raw counts
prev_raw_counts = raw_counts;
total_encoder_counts = raw_counts + (4096 * revolutions);
Serial.println("");
Serial.print("Encoder Counts: ");
Serial.println(total_encoder_counts);
Serial.println("");
}