|
| 1 | +/**************************************************************************************************************************** |
| 2 | + PWM_StepperControl.ino |
| 3 | + |
| 4 | + For STM32F/L/H/G/WB/MP1 boards |
| 5 | + Written by Khoi Hoang |
| 6 | +
|
| 7 | + Built by Khoi Hoang https://github.com/khoih-prog/STM32_PWM |
| 8 | + Licensed under MIT license |
| 9 | +
|
| 10 | + Hardware-based multi-channel PWM wrapper library for STM32F/L/H/G/WB/MP1 boards |
| 11 | + |
| 12 | + Credits of Paul van Dinther (https://github.com/dinther). Check https://github.com/khoih-prog/RP2040_PWM/issues/16 |
| 13 | +*****************************************************************************************************************************/ |
| 14 | + |
| 15 | +// Use with Stepper-Motor driver, such as TMC2209 |
| 16 | + |
| 17 | +#if !( defined(STM32F0) || defined(STM32F1) || defined(STM32F2) || defined(STM32F3) ||defined(STM32F4) || defined(STM32F7) || \ |
| 18 | + defined(STM32L0) || defined(STM32L1) || defined(STM32L4) || defined(STM32H7) ||defined(STM32G0) || defined(STM32G4) || \ |
| 19 | + defined(STM32WB) || defined(STM32MP1) || defined(STM32L5)) |
| 20 | + #error This code is designed to run on STM32F/L/H/G/WB/MP1 platform! Please check your Tools->Board setting. |
| 21 | +#endif |
| 22 | + |
| 23 | +// These define's must be placed at the beginning before #include "ESP32_PWM.h" |
| 24 | +// _PWM_LOGLEVEL_ from 0 to 4 |
| 25 | +// Don't define _PWM_LOGLEVEL_ > 0. Only for special ISR debugging only. Can hang the system. |
| 26 | +#define _PWM_LOGLEVEL_ 4 |
| 27 | + |
| 28 | +#define USING_MICROS_RESOLUTION true //false |
| 29 | + |
| 30 | +#include "STM32_PWM.h" |
| 31 | + |
| 32 | +///////////////////////////////////////////////// |
| 33 | + |
| 34 | +// Change the pin according to your STM32 board. There is no single definition for all boards. |
| 35 | +#define pin0 PA0 |
| 36 | +#define pin1 D1 |
| 37 | +#define pin2 D2 |
| 38 | +#define pin3 D3 |
| 39 | +#define pin4 D4 |
| 40 | +#define pin5 D5 |
| 41 | +#define pin6 D6 |
| 42 | +#define pin7 D7 |
| 43 | + |
| 44 | +#define pin8 D8 |
| 45 | +#define pin9 D9 |
| 46 | +#define pin10 D10 |
| 47 | +#define pin11 D11 |
| 48 | +#define pin12 D12 |
| 49 | +#define pin13 D13 |
| 50 | +#define pin14 D14 |
| 51 | +#define pin15 D15 |
| 52 | +#define pin16 D16 |
| 53 | + |
| 54 | +////////////////////////////////////////////////////// |
| 55 | + |
| 56 | +// Change the pin according to your STM32 board. There is no single definition for all boards. |
| 57 | + |
| 58 | +#if ( defined(STM32F1) && ( defined(ARDUINO_BLUEPILL_F103CB) || defined(ARDUINO_BLUEPILL_F103C8) ) ) |
| 59 | + |
| 60 | + #warning Using BLUEPILL_F103CB / BLUEPILL_F103C8 pins |
| 61 | + |
| 62 | + // For F103CB => pin0, pin4, pin10 ============>> TimerIndex = 1, 2, 0 |
| 63 | + #define STEP_PIN pin3 |
| 64 | + |
| 65 | +#elif ( defined(STM32F7) && defined(ARDUINO_NUCLEO_F767ZI) ) |
| 66 | + |
| 67 | + #warning Using NUCLEO_F767ZI pins |
| 68 | + |
| 69 | + // For F767ZI => pin0, pin3, pin9/10 ============>> TimerIndex = 1, 0, 3 |
| 70 | + #define STEP_PIN pin3 |
| 71 | + |
| 72 | +#elif ( defined(STM32L5) && defined(ARDUINO_NUCLEO_L552ZE_Q) ) |
| 73 | + |
| 74 | + #warning Using NUCLEO_L552ZE_Q pins |
| 75 | + |
| 76 | + // For NUCLEO_L552ZE_Q => pin0, pin3, pin9/10 ============>> TimerIndex = 1, 0, 3 |
| 77 | + #define STEP_PIN pin3 |
| 78 | + |
| 79 | +#elif ( defined(STM32H7) && defined(ARDUINO_NUCLEO_H743ZI2) ) |
| 80 | + |
| 81 | + #warning Using NUCLEO_H743ZI2 pins |
| 82 | + |
| 83 | + // For NUCLEO_L552ZE_Q => pin0, pin3, pin9/10 ============>> TimerIndex = 1, 0, 3 |
| 84 | + #define STEP_PIN pin3 |
| 85 | + |
| 86 | +#else |
| 87 | + |
| 88 | + // For ??? => pin0, pin3, pin9/10 ============>> TimerIndex = 1, 0, 3 |
| 89 | + #define STEP_PIN pin3 |
| 90 | + |
| 91 | +#endif |
| 92 | + |
| 93 | +////////////////////////////////////////////////////// |
| 94 | + |
| 95 | +#define DIR_PIN pin1 |
| 96 | + |
| 97 | +TIM_TypeDef *stepperTimer; |
| 98 | + |
| 99 | +HardwareTimer *stepper; |
| 100 | + |
| 101 | +uint32_t channel; |
| 102 | + |
| 103 | +int previousSpeed = 0; |
| 104 | + |
| 105 | +// The Stepper RPM will be ( speed * 60 ) / steps-per-rev |
| 106 | +// For example, 28BYJ-48 Stepper Motor (https://lastminuteengineers.com/28byj48-stepper-motor-arduino-tutorial/) has 32 Steps/Rev |
| 107 | +// Speed = 640 Hz => Stepper RPM = (640 * 60 / 32) = 1200 RPM |
| 108 | +void setSpeed(int speed) |
| 109 | +{ |
| 110 | + // Do nothing if same speed |
| 111 | + if (speed == previousSpeed) |
| 112 | + return; |
| 113 | + |
| 114 | + Serial.print(F("setSpeed = ")); |
| 115 | + Serial.println(speed); |
| 116 | + |
| 117 | + // Create new instance for new speed |
| 118 | + if (stepper) |
| 119 | + delete stepper; |
| 120 | + |
| 121 | + stepper = new HardwareTimer(stepperTimer); |
| 122 | + |
| 123 | + if (speed == 0) |
| 124 | + { |
| 125 | + // Use DC = 0 to stop stepper |
| 126 | + stepper->setPWM(channel, STEP_PIN, 500, 0, nullptr); |
| 127 | + } |
| 128 | + else |
| 129 | + { |
| 130 | + // Set the frequency of the PWM output and a duty cycle of 50% |
| 131 | + digitalWrite(DIR_PIN, (speed < 0)); |
| 132 | + stepper->setPWM(channel, STEP_PIN, abs(speed), 50, nullptr); |
| 133 | + } |
| 134 | + |
| 135 | + previousSpeed = speed; |
| 136 | +} |
| 137 | + |
| 138 | +void initPWM(uint32_t step_pin) |
| 139 | +{ |
| 140 | + // Using pin = PA0, PA1, etc. |
| 141 | + PinName pinNameToUse = digitalPinToPinName(step_pin); |
| 142 | + |
| 143 | + // Automatically retrieve TIM instance and channel associated to pin |
| 144 | + // This is used to be compatible with all STM32 series automatically. |
| 145 | + stepperTimer = (TIM_TypeDef *) pinmap_peripheral(pinNameToUse, PinMap_PWM); |
| 146 | + |
| 147 | + if (stepperTimer != nullptr) |
| 148 | + { |
| 149 | + uint8_t timerIndex = get_timer_index(stepperTimer); |
| 150 | + |
| 151 | + // pin => 0, 1, etc |
| 152 | + channel = STM_PIN_CHANNEL(pinmap_function( pinNameToUse, PinMap_PWM)); |
| 153 | + |
| 154 | + Serial.print("stepperTimer = 0x"); |
| 155 | + Serial.print( (uint32_t) stepperTimer, HEX); |
| 156 | + Serial.print(", channel = "); |
| 157 | + Serial.print(channel); |
| 158 | + Serial.print(", TimerIndex = "); |
| 159 | + Serial.print(get_timer_index(stepperTimer)); |
| 160 | + Serial.print(", PinName = "); |
| 161 | + Serial.println( pinNameToUse ); |
| 162 | + |
| 163 | + stepper = new HardwareTimer(stepperTimer); |
| 164 | + |
| 165 | + // SetPWM object and passed just a random frequency of 500 steps/s |
| 166 | + // The Stepper RPM will be ( speed * 60 ) / steps-per-revolution |
| 167 | + // The duty cycle is how you turn the motor on and off |
| 168 | + previousSpeed = 500; |
| 169 | + stepper->setPWM(channel, step_pin, previousSpeed, 0, nullptr); |
| 170 | + } |
| 171 | + else |
| 172 | + { |
| 173 | + Serial.println("ERROR => Wrong pin, You have to select another one. Skip NULL stepperTimer"); |
| 174 | + } |
| 175 | +} |
| 176 | + |
| 177 | +void setup() |
| 178 | +{ |
| 179 | + pinMode(STEP_PIN, OUTPUT); |
| 180 | + digitalWrite(STEP_PIN, LOW); |
| 181 | + pinMode(DIR_PIN, OUTPUT); |
| 182 | + digitalWrite(DIR_PIN, LOW); |
| 183 | + |
| 184 | + Serial.begin(115200); |
| 185 | + |
| 186 | + while (!Serial && millis() < 5000); |
| 187 | + |
| 188 | + delay(100); |
| 189 | + |
| 190 | + Serial.print(F("\nStarting PWM_StepperControl on ")); |
| 191 | + Serial.println(BOARD_NAME); |
| 192 | + Serial.println(STM32_PWM_VERSION); |
| 193 | + |
| 194 | + initPWM(STEP_PIN); |
| 195 | +} |
| 196 | + |
| 197 | +void loop() |
| 198 | +{ |
| 199 | + // The Stepper RPM will be ( speed * 60 ) / steps-per-rev |
| 200 | + setSpeed(2000); |
| 201 | + delay(3000); |
| 202 | + |
| 203 | + // Stop before reversing |
| 204 | + setSpeed(0); |
| 205 | + delay(3000); |
| 206 | + |
| 207 | + // Reversing |
| 208 | + setSpeed(-1000); |
| 209 | + delay(3000); |
| 210 | + |
| 211 | + // Stop before reversing |
| 212 | + setSpeed(0); |
| 213 | + delay(3000); |
| 214 | +} |
0 commit comments