diff options
| -rw-r--r-- | linz/glasslathe/platformio.ini | 1 | ||||
| -rw-r--r-- | linz/glasslathe/src/main.cpp | 205 |
2 files changed, 173 insertions, 33 deletions
diff --git a/linz/glasslathe/platformio.ini b/linz/glasslathe/platformio.ini index ed9ba0a..1d524b0 100644 --- a/linz/glasslathe/platformio.ini +++ b/linz/glasslathe/platformio.ini | |||
| @@ -12,3 +12,4 @@ | |||
| 12 | platform = atmelsam | 12 | platform = atmelsam |
| 13 | framework = arduino | 13 | framework = arduino |
| 14 | board = mkrzero | 14 | board = mkrzero |
| 15 | lib_deps = Bounce2 | ||
diff --git a/linz/glasslathe/src/main.cpp b/linz/glasslathe/src/main.cpp index cd39208..ee1e8d4 100644 --- a/linz/glasslathe/src/main.cpp +++ b/linz/glasslathe/src/main.cpp | |||
| @@ -1,11 +1,143 @@ | |||
| 1 | #include <Arduino.h> | 1 | #include <Arduino.h> |
| 2 | #include <Bounce2.h> | ||
| 3 | |||
| 4 | // relais board: | ||
| 5 | // A1 = potentiometer | ||
| 6 | // SDA = 24V+ | ||
| 7 | // SCL = direction in | ||
| 8 | |||
| 9 | // PIN A1 potentiometer | ||
| 10 | // PIN 0 | ||
| 11 | // PIN 1 relay 1 | ||
| 12 | // PIN 2 relay 2 | ||
| 13 | // PIN 3 | ||
| 14 | // PIN 4 direction in | ||
| 15 | // PIN 5 motor frequency out | ||
| 16 | // PIN 6 motor direction out | ||
| 17 | // PIN 7 CAN interrupt | ||
| 18 | |||
| 19 | #define POTI_PIN 1 | ||
| 20 | #define DIRECTION_PIN 4 | ||
| 21 | #define MOTOR_FREQUENCY_PIN 5 // hardcoded in SetupTimer() | ||
| 22 | #define MOTOR_DIRECTION_PIN 6 | ||
| 23 | |||
| 24 | #define POT_JITTER_THRESHOLD 20 | ||
| 25 | |||
| 26 | void SetupTimer(); | ||
| 27 | void StopTimer(); | ||
| 28 | void RestartTimer(); | ||
| 29 | void SetFrequencyOutput(uint16_t frequency); | ||
| 30 | void SetMotorOutput(uint16_t rpm); | ||
| 31 | float fscale(int inputValue, float originalMin, float originalMax, | ||
| 32 | float newBegin, float newEnd, float curve); | ||
| 33 | |||
| 34 | Bounce direction_button; | ||
| 35 | const int frequency_max = 6000; | ||
| 36 | |||
| 37 | struct { | ||
| 38 | int direction = 0; | ||
| 39 | int frequency = 0; | ||
| 40 | int potValue = 1023; | ||
| 41 | } current, target; | ||
| 42 | bool timer_enabled = false; | ||
| 2 | 43 | ||
| 3 | #define LED_PIN 4 | 44 | void setup() |
| 4 | #define POT_PIN 2 | 45 | { |
| 46 | Serial.begin(9600); | ||
| 47 | pinMode(MOTOR_FREQUENCY_PIN, OUTPUT); | ||
| 48 | |||
| 49 | direction_button.attach(DIRECTION_PIN, INPUT_PULLUP); | ||
| 50 | target.direction = current.direction = !direction_button.read(); | ||
| 51 | pinMode(MOTOR_DIRECTION_PIN, OUTPUT); | ||
| 52 | digitalWrite(MOTOR_DIRECTION_PIN, target.direction); | ||
| 5 | 53 | ||
| 6 | #define POT_JITTER_THRESHOLD 10 | 54 | SetupTimer(); |
| 55 | } | ||
| 7 | 56 | ||
| 8 | int potValue = 0; | 57 | void loop() |
| 58 | { | ||
| 59 | direction_button.update(); | ||
| 60 | if (direction_button.changed()) | ||
| 61 | { | ||
| 62 | target.direction = !direction_button.read(); | ||
| 63 | Serial.print("target direction: "); | ||
| 64 | Serial.println(target.direction, DEC); | ||
| 65 | } | ||
| 66 | |||
| 67 | int newPotValue = 1023 - analogRead(POTI_PIN); // inverse input values | ||
| 68 | if (newPotValue < 30) | ||
| 69 | newPotValue = 0; | ||
| 70 | else if (newPotValue > 1000) | ||
| 71 | newPotValue = 1023; | ||
| 72 | if (abs(newPotValue - target.potValue) > POT_JITTER_THRESHOLD) | ||
| 73 | { | ||
| 74 | target.potValue = newPotValue; | ||
| 75 | Serial.print("newPotValue: "); | ||
| 76 | Serial.println(newPotValue, DEC); | ||
| 77 | //target.frequency = (int)fscale(target.potValue / 10, 0, 102, 0, frequency_max, -4); | ||
| 78 | target.frequency = map(target.potValue / 10, 0, 102, 0, frequency_max); | ||
| 79 | Serial.print("target frequency: "); | ||
| 80 | Serial.println(target.frequency, DEC); | ||
| 81 | } | ||
| 82 | |||
| 83 | const int step_delay = 300; | ||
| 84 | if (current.frequency != target.frequency || current.direction != target.direction) | ||
| 85 | { | ||
| 86 | if (!timer_enabled && target.frequency != 0) | ||
| 87 | { | ||
| 88 | RestartTimer(); | ||
| 89 | timer_enabled = true; | ||
| 90 | Serial.println("enable motor"); | ||
| 91 | delay(step_delay); | ||
| 92 | } | ||
| 93 | |||
| 94 | /*int step = (current.potValue < 20) ? 1 | ||
| 95 | : (current.potValue < 100) ? 2 | ||
| 96 | : (current.potValue < 300) ? 3 | ||
| 97 | : (current.potValue < 400) ? 5 | ||
| 98 | : (current.potValue < 500) ? 10 | ||
| 99 | : 20;*/ | ||
| 100 | int step = (current.frequency > 5000) ? 1 | ||
| 101 | : (current.frequency > 4500) ? 2 | ||
| 102 | : (current.frequency > 4000) ? 5 | ||
| 103 | : (current.frequency > 3000) ? 10 | ||
| 104 | : (current.frequency > 1000) ? 25 | ||
| 105 | : 50; | ||
| 106 | int frequency = (current.direction == target.direction) ? target.frequency : 0; | ||
| 107 | step = min(abs(frequency - current.frequency), step); | ||
| 108 | if (frequency < current.frequency) | ||
| 109 | step *= -1; | ||
| 110 | current.frequency += step; | ||
| 111 | |||
| 112 | SetFrequencyOutput(current.frequency); | ||
| 113 | //Serial.print("current potValue: "); | ||
| 114 | //Serial.print(current.potValue, DEC); | ||
| 115 | Serial.print("current frequency: "); | ||
| 116 | Serial.println(current.frequency, DEC); | ||
| 117 | delay(step_delay); | ||
| 118 | |||
| 119 | if (current.frequency == 0 && current.direction != target.direction) | ||
| 120 | { | ||
| 121 | StopTimer(); | ||
| 122 | timer_enabled = false; | ||
| 123 | Serial.println("disable motor"); | ||
| 124 | |||
| 125 | current.direction = target.direction; | ||
| 126 | digitalWrite(MOTOR_DIRECTION_PIN, target.direction); | ||
| 127 | Serial.print("changed direction to: "); | ||
| 128 | Serial.println(current.direction, DEC); | ||
| 129 | |||
| 130 | delay(step_delay); | ||
| 131 | } | ||
| 132 | } | ||
| 133 | else if (timer_enabled && newPotValue == 0) | ||
| 134 | { | ||
| 135 | StopTimer(); | ||
| 136 | timer_enabled = false; | ||
| 137 | Serial.println("disable motor"); | ||
| 138 | delay(step_delay); | ||
| 139 | } | ||
| 140 | } | ||
| 9 | 141 | ||
| 10 | void SetupTimer() | 142 | void SetupTimer() |
| 11 | { | 143 | { |
| @@ -25,16 +157,16 @@ void SetupTimer() | |||
| 25 | // Connect the TCC timers to the port outputs - port pins are paired odd PMUO and even PMUXE | 157 | // Connect the TCC timers to the port outputs - port pins are paired odd PMUO and even PMUXE |
| 26 | // F & E specify the timers: TCC0, TCC1 and TCC2 | 158 | // F & E specify the timers: TCC0, TCC1 and TCC2 |
| 27 | PORT->Group[g_APinDescription[5].ulPort].PMUX[g_APinDescription[5].ulPin >> 1].reg = PORT_PMUX_PMUXO_F; | 159 | PORT->Group[g_APinDescription[5].ulPort].PMUX[g_APinDescription[5].ulPin >> 1].reg = PORT_PMUX_PMUXO_F; |
| 28 | 160 | ||
| 29 | // Feed GCLK4 to TCC0 and TCC1 | 161 | // Feed GCLK4 to TCC0 and TCC1 |
| 30 | GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | // Enable GCLK4 to TCC0 and TCC1 | 162 | GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | // Enable GCLK4 to TCC0 and TCC1 |
| 31 | GCLK_CLKCTRL_GEN_GCLK4 | // Select GCLK4 | 163 | GCLK_CLKCTRL_GEN_GCLK4 | // Select GCLK4 |
| 32 | GCLK_CLKCTRL_ID_TCC0_TCC1; // Feed GCLK4 to TCC0 and TCC1 | 164 | GCLK_CLKCTRL_ID_TCC0_TCC1; // Feed GCLK4 to TCC0 and TCC1 |
| 33 | while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization | 165 | while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization |
| 34 | 166 | ||
| 35 | TCC0->WAVE.reg = TCC_WAVE_WAVEGEN_NPWM; // Single slope PWM operation | 167 | TCC0->WAVE.reg = TCC_WAVE_WAVEGEN_NPWM; // Single slope PWM operation |
| 36 | while (TCC0->SYNCBUSY.bit.WAVE); // Wait for synchronization | 168 | while (TCC0->SYNCBUSY.bit.WAVE); // Wait for synchronization |
| 37 | 169 | ||
| 38 | TCC0->PER.reg = 4799; // Set the frequency of the PWM on TCC0 to 10kHz | 170 | TCC0->PER.reg = 4799; // Set the frequency of the PWM on TCC0 to 10kHz |
| 39 | while (TCC0->SYNCBUSY.bit.PER); // Wait for synchronization | 171 | while (TCC0->SYNCBUSY.bit.PER); // Wait for synchronization |
| 40 | 172 | ||
| @@ -42,15 +174,15 @@ void SetupTimer() | |||
| 42 | while (TCC0->SYNCBUSY.bit.CC2); // Wait for synchronization | 174 | while (TCC0->SYNCBUSY.bit.CC2); // Wait for synchronization |
| 43 | TCC0->CC[3].reg = 2399; // TCC0 CC3 - 50% duty-cycle on D12 | 175 | TCC0->CC[3].reg = 2399; // TCC0 CC3 - 50% duty-cycle on D12 |
| 44 | while (TCC0->SYNCBUSY.bit.CC3); // Wait for synchronization | 176 | while (TCC0->SYNCBUSY.bit.CC3); // Wait for synchronization |
| 45 | 177 | ||
| 46 | // Divide the 48MHz signal by 1 giving 48MHz (20.83ns) TCC0 timer tick and enable the timer | 178 | // Divide the 48MHz signal by 1 giving 48MHz (20.83ns) TCC0 timer tick and enable the timer |
| 47 | TCC0->CTRLA.reg |= TCC_CTRLA_PRESCALER_DIV1 | // Divide GCLK4 by 1 | 179 | TCC0->CTRLA.reg |= TCC_CTRLA_PRESCALER_DIV1 | // Divide GCLK4 by 1 |
| 48 | TCC_CTRLA_ENABLE; // Enable the TCC0 output | 180 | TCC_CTRLA_ENABLE; // Enable the TCC0 output |
| 49 | while (TCC0->SYNCBUSY.bit.ENABLE); // Wait for synchronization | 181 | while (TCC0->SYNCBUSY.bit.ENABLE); // Wait for synchronization |
| 50 | 182 | ||
| 51 | //Stop TCC0 counter on MCU initialization (stepper initially stopped) | 183 | //Stop TCC0 counter on MCU initialization (stepper initially stopped) |
| 52 | //TCC0->CTRLBSET.reg = TCC_CTRLBSET_CMD_STOP; // Force the TCC0 timer to STOP | 184 | TCC0->CTRLBSET.reg = TCC_CTRLBSET_CMD_STOP; // Force the TCC0 timer to STOP |
| 53 | //while (TCC0->SYNCBUSY.bit.CTRLB); // Wait for synchronization | 185 | while (TCC0->SYNCBUSY.bit.CTRLB); // Wait for synchronization |
| 54 | } | 186 | } |
| 55 | 187 | ||
| 56 | void StopTimer() | 188 | void StopTimer() |
| @@ -67,15 +199,13 @@ void RestartTimer() | |||
| 67 | while (TCC0->SYNCBUSY.bit.CTRLB); // Wait for synchronization | 199 | while (TCC0->SYNCBUSY.bit.CTRLB); // Wait for synchronization |
| 68 | } | 200 | } |
| 69 | 201 | ||
| 70 | uint32_t stepperFrequencyDivisor = 4799; //Sets the starting frequency equal to 1hz | ||
| 71 | |||
| 72 | void SetFrequencyOutput(uint16_t frequency) | 202 | void SetFrequencyOutput(uint16_t frequency) |
| 73 | { | 203 | { |
| 74 | stepperFrequencyDivisor = round(48000000 / frequency); | 204 | uint32_t stepperFrequencyDivisor = round(48000000 / frequency); |
| 75 | 205 | ||
| 76 | TCC0->PERB.reg = stepperFrequencyDivisor - 1; // Set the starting frequency of the PWM on TCC0 to 1Hz | 206 | TCC0->PERB.reg = stepperFrequencyDivisor - 1; // Set the starting frequency of the PWM on TCC0 to 1Hz |
| 77 | while (TCC0->SYNCBUSY.bit.PERB); // Wait for synchronization | 207 | while (TCC0->SYNCBUSY.bit.PERB); // Wait for synchronization |
| 78 | 208 | ||
| 79 | TCC0->CCB[1].reg = (stepperFrequencyDivisor / 2) - 1; // TCC0 CC2 - 50% duty-cycle | 209 | TCC0->CCB[1].reg = (stepperFrequencyDivisor / 2) - 1; // TCC0 CC2 - 50% duty-cycle |
| 80 | while (TCC0->SYNCBUSY.bit.CCB2); // Wait for synchronization | 210 | while (TCC0->SYNCBUSY.bit.CCB2); // Wait for synchronization |
| 81 | } | 211 | } |
| @@ -86,27 +216,36 @@ void SetMotorOutput(uint16_t rpm) | |||
| 86 | SetFrequencyOutput(rpm * stepperHzToRPM); | 216 | SetFrequencyOutput(rpm * stepperHzToRPM); |
| 87 | } | 217 | } |
| 88 | 218 | ||
| 89 | void setup() | 219 | float fscale(int inputValue, float originalMin, float originalMax, |
| 220 | float newBegin, float newEnd, float curve) | ||
| 90 | { | 221 | { |
| 91 | SetupTimer(); | 222 | // condition curve parameter |
| 92 | } | 223 | curve = constrain(curve, -10, 10); |
| 224 | curve = (curve * -.1) ; // - invert and scale - this seems more intuitive - postive numbers give more weight to high end on output | ||
| 225 | curve = pow(10, curve); // convert linear scale into lograthimic exponent for other pow function | ||
| 93 | 226 | ||
| 94 | void loop() | 227 | // Check for out of range inputValues |
| 95 | { | 228 | inputValue = constrain(inputValue, originalMin, originalMax); |
| 96 | /*int newPotValue = analogRead(POT_PIN); | 229 | |
| 97 | if (abs(newPotValue - potValue) > POT_JITTER_THRESHOLD) | 230 | // Check for originalMin > originalMax - the math for all other cases i.e. negative numbers seems to work out fine |
| 98 | { | 231 | if (originalMin > originalMax) |
| 99 | potValue = newPotValue; | 232 | return 0; |
| 100 | SetFrequencyOutput(map(potValue, 0, 1023, 0, 20000)); | 233 | |
| 101 | }*/ | 234 | // Zero Refference the values |
| 102 | for(uint8_t i = 0; i <= 20; i++) | 235 | float originalRange = originalMax - originalMin; |
| 236 | float zeroRefCurVal = inputValue - originalMin; | ||
| 237 | float normalizedCurVal = zeroRefCurVal / originalRange; // normalize to 0 - 1 float | ||
| 238 | |||
| 239 | float rangedValue = 0; | ||
| 240 | if (newEnd > newBegin) | ||
| 103 | { | 241 | { |
| 104 | SetFrequencyOutput(i * 1000); | 242 | float newRange = newEnd - newBegin; |
| 105 | delay(10000); | 243 | rangedValue = (pow(normalizedCurVal, curve) * newRange) + newBegin; |
| 106 | } | 244 | } |
| 107 | for(uint8_t i = 20; i >= 0; i--) | 245 | else |
| 108 | { | 246 | { |
| 109 | SetFrequencyOutput(i * 1000); | 247 | float newRange = newBegin - newEnd; |
| 110 | delay(10000); | 248 | rangedValue = newBegin - (pow(normalizedCurVal, curve) * newRange); |
| 111 | } | 249 | } |
| 250 | return rangedValue; | ||
| 112 | } | 251 | } |
