@@ -14,122 +14,176 @@ typedef struct {
1414 mcpwm_io_signals_t mcpwm_a;
1515 mcpwm_io_signals_t mcpwm_b;
1616 mcpwm_io_signals_t mcpwm_c;
17+ } bldc_motor_slots_t ;
18+ typedef struct {
19+ int pin1A;
20+ mcpwm_dev_t * mcpwm_num;
21+ mcpwm_unit_t mcpwm_unit;
22+ mcpwm_operator_t mcpwm_operator1;
23+ mcpwm_operator_t mcpwm_operator2;
24+ mcpwm_io_signals_t mcpwm_1a;
25+ mcpwm_io_signals_t mcpwm_1b;
26+ mcpwm_io_signals_t mcpwm_2a;
27+ mcpwm_io_signals_t mcpwm_2b;
28+ } stepper_motor_slots_t ;
1729
18- } motor_slots_t ;
19-
20- // define motor slots array
21- motor_slots_t esp32_motor_slots[4 ] = {
30+ // define bldc motor slots array
31+ bldc_motor_slots_t esp32_bldc_motor_slots[4 ] = {
2232 {_EMPTY_SLOT, &MCPWM0, MCPWM_UNIT_0, MCPWM_OPR_A, MCPWM0A, MCPWM1A, MCPWM2A}, // 1st motor will be MCPWM0 channel A
2333 {_EMPTY_SLOT, &MCPWM0, MCPWM_UNIT_0, MCPWM_OPR_B, MCPWM0B, MCPWM1B, MCPWM2B}, // 2nd motor will be MCPWM0 channel B
2434 {_EMPTY_SLOT, &MCPWM1, MCPWM_UNIT_1, MCPWM_OPR_A, MCPWM0A, MCPWM1A, MCPWM2A}, // 3rd motor will be MCPWM1 channel A
2535 {_EMPTY_SLOT, &MCPWM1, MCPWM_UNIT_1, MCPWM_OPR_B, MCPWM0B, MCPWM1B, MCPWM2B} // 4th motor will be MCPWM1 channel B
2636 };
2737
28- #endif
38+ // define stepper motor slots array
39+ stepper_motor_slots_t esp32_stepper_motor_slots[2 ] = {
40+ {_EMPTY_SLOT, &MCPWM1, MCPWM_UNIT_0, MCPWM_OPR_A, MCPWM_OPR_B, MCPWM0A, MCPWM1A, MCPWM0B, MCPWM1B}, // 1st motor will be on MCPWM1
41+ {_EMPTY_SLOT, &MCPWM0, MCPWM_UNIT_0, MCPWM_OPR_A, MCPWM_OPR_B, MCPWM0A, MCPWM1A, MCPWM0B, MCPWM1B}, // 1st motor will be on MCPWM0
42+ };
2943
44+ // configuring high frequency pwm timer
45+ // https://hackaday.io/project/169905-esp-32-bldc-robot-actuator-controller
46+ void _configureTimerFrequency (long pwm_frequency, mcpwm_dev_t * mcpwm_num, mcpwm_unit_t mcpwm_unit){
3047
31- // function setting the high pwm frequency to the supplied pins
32- // - hardware speciffic
33- // supports Arudino/ATmega328, STM32 and ESP32
34- void _setPwmFrequency (const int pinA, const int pinB, const int pinC, const int pinD) {
35- #if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__) // if arduino uno and other ATmega328p chips
36- // High PWM frequency
48+ mcpwm_config_t pwm_config;
49+ pwm_config.frequency = pwm_frequency; // frequency
50+ pwm_config.cmpr_a = 0 ; // duty cycle of PWMxA = 50.0%
51+ pwm_config.cmpr_b = 0 ; // duty cycle of PWMxB = 50.0%
52+ pwm_config.counter_mode = MCPWM_UP_DOWN_COUNTER; // Up-down counter (triangle wave)
53+ pwm_config.duty_mode = MCPWM_DUTY_MODE_0; // Active HIGH
54+ mcpwm_init (mcpwm_unit, MCPWM_TIMER_0, &pwm_config); // Configure PWM0A & PWM0B with above settings
55+ mcpwm_init (mcpwm_unit, MCPWM_TIMER_1, &pwm_config); // Configure PWM0A & PWM0B with above settings
56+ mcpwm_init (mcpwm_unit, MCPWM_TIMER_2, &pwm_config); // Configure PWM0A & PWM0B with above settings
57+
58+ _delay (100 );
59+
60+ mcpwm_stop (mcpwm_unit, MCPWM_TIMER_0);
61+ mcpwm_stop (mcpwm_unit, MCPWM_TIMER_1);
62+ mcpwm_stop (mcpwm_unit, MCPWM_TIMER_2);
63+ mcpwm_num->clk_cfg .prescale = 0 ;
64+
65+ mcpwm_num->timer [0 ].period .prescale = 4 ;
66+ mcpwm_num->timer [1 ].period .prescale = 4 ;
67+ mcpwm_num->timer [2 ].period .prescale = 4 ;
68+ _delay (1 );
69+ mcpwm_num->timer [0 ].period .period = 2048 ;
70+ mcpwm_num->timer [1 ].period .period = 2048 ;
71+ mcpwm_num->timer [2 ].period .period = 2048 ;
72+ _delay (1 );
73+ mcpwm_num->timer [0 ].period .upmethod = 0 ;
74+ mcpwm_num->timer [1 ].period .upmethod = 0 ;
75+ mcpwm_num->timer [2 ].period .upmethod = 0 ;
76+ _delay (1 );
77+ mcpwm_start (mcpwm_unit, MCPWM_TIMER_0);
78+ mcpwm_start (mcpwm_unit, MCPWM_TIMER_1);
79+ mcpwm_start (mcpwm_unit, MCPWM_TIMER_2);
80+
81+ mcpwm_sync_enable (mcpwm_unit, MCPWM_TIMER_0, MCPWM_SELECT_SYNC_INT0, 0 );
82+ mcpwm_sync_enable (mcpwm_unit, MCPWM_TIMER_1, MCPWM_SELECT_SYNC_INT0, 0 );
83+ mcpwm_sync_enable (mcpwm_unit, MCPWM_TIMER_2, MCPWM_SELECT_SYNC_INT0, 0 );
84+ _delay (1 );
85+ mcpwm_num->timer [0 ].sync .out_sel = 1 ;
86+ _delay (1 );
87+ mcpwm_num->timer [0 ].sync .out_sel = 0 ;
88+ }
89+
90+ #elif defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__) // if arduino uno and other ATmega328p chips
91+ // set pwm frequency to 32KHz
92+ void _pinHighFrequency (const int pin){
93+ // High PWM frequency
3794 // https://sites.google.com/site/qeewiki/books/avr-guide/timers-on-the-atmega328
38- if (pinA == 5 || pinA == 6 || pinB == 5 || pinB == 6 || pinC == 5 || pinC == 6 || pinD == 5 || pinD == 6 ) {
95+ if (pin == 5 || pin == 6 ) {
3996 TCCR0A = ((TCCR0A & 0b11111100 ) | 0x01 ); // configure the pwm phase-corrected mode
4097 TCCR0B = ((TCCR0B & 0b11110000 ) | 0x01 ); // set prescaler to 1
4198 }
42- if (pinA == 9 || pinA == 10 || pinB == 9 || pinB == 10 || pinC == 9 || pinC == 10 || pinD == 9 || pinD == 10 )
99+ if (pin == 9 || pin == 10 )
43100 TCCR1B = ((TCCR1B & 0b11111000 ) | 0x01 ); // set prescaler to 1
44- if (pinA == 3 || pinA == 11 || pinB == 3 || pinB == 11 || pinC == 3 || pinC == 11 || pinD == 3 || pinD == 11 )
101+ if (pin == 3 || pin == 11 )
45102 TCCR2B = ((TCCR2B & 0b11111000 ) | 0x01 );// set prescaler to 1
46103
104+ }
47105#elif defined(_STM32_DEF_) // if stm chips
48-
49- analogWrite (pinA, 0 );
50- analogWriteFrequency (50000 ); // set 50kHz
51- analogWriteResolution (12 ); // resolution 12 bit 0 - 4096
52- analogWrite (pinB, 0 );
53- analogWriteFrequency (50000 ); // set 50kHz
54- analogWriteResolution (12 ); // resolution 12 bit 0 - 4096
55- analogWrite (pinC, 0 );
56- analogWriteFrequency (50000 ); // set 50kHz
106+ // configure High PWM frequency
107+ void _setHighFrequency (const long freq, const int pin){
108+ analogWrite (pin, 0 );
109+ analogWriteFrequency (freq);
57110 analogWriteResolution (12 ); // resolution 12 bit 0 - 4096
58- if (pinD) {
59- analogWrite (pinD, 0 );
60- analogWriteFrequency (50000 ); // set 50kHz
61- analogWriteResolution (12 ); // resolution 12 bit 0 - 4096
62- }
111+ }
63112#elif defined(__arm__) && defined(CORE_TEENSY) // if teensy 3x / 4x / LC boards
64- analogWrite (pinA, 0 );
65- analogWriteFrequency (pinA, 50000 ); // set 50kHz
66- analogWrite (pinB, 0 );
67- analogWriteFrequency (pinB, 50000 ); // set 50kHz
68- analogWrite (pinC, 0 );
69- analogWriteFrequency (pinC, 50000 ); // set 50kHz
70- if (pinD) {
71- analogWrite (pinD, 0 );
72- analogWriteFrequency (50000 ); // set 50kHz
73- }
74- #elif defined(ESP_H) // if esp32 boards
113+ // configure High PWM frequency
114+ void _setHighFrequency (const long freq, const int pin){
115+ analogWrite (pin, 0 );
116+ analogWriteFrequency (freq);
117+ }
118+ #endif
75119
76- motor_slots_t m_slot = {};
77120
78- // determine which motor are we connecting
79- // and set the appropriate configuration parameters
80- for (int i = 0 ; i < 4 ; i++){
81- if (esp32_motor_slots[i].pinA == _EMPTY_SLOT){ // put the new motor in the first empty slot
82- esp32_motor_slots[i].pinA = pinA;
83- m_slot = esp32_motor_slots[i];
84- break ;
85- }
86- }
87-
88- // configure pins
89- mcpwm_gpio_init (m_slot.mcpwm_unit , m_slot.mcpwm_a , pinA);
90- mcpwm_gpio_init (m_slot.mcpwm_unit , m_slot.mcpwm_b , pinB);
91- mcpwm_gpio_init (m_slot.mcpwm_unit , m_slot.mcpwm_c , pinC);
121+ // function setting the high pwm frequency to the supplied pins
122+ // - hardware speciffic
123+ // supports Arudino/ATmega328, STM32 and ESP32
124+ void _setPwmFrequency (const long pwm_frequency,const int pinA, const int pinB, const int pinC, const int pinD) {
125+ #if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__) // if arduino uno and other ATmega328p chips
126+ // High PWM frequency
127+ // - always max 32kHz
128+ _pinHighFrequency (pinA);
129+ _pinHighFrequency (pinB);
130+ _pinHighFrequency (pinC);
131+ if (pinD != NOT_SET) _pinHighFrequency (pinD); // stepper motor
92132
93- mcpwm_config_t pwm_config;
94- pwm_config.frequency = 4000000 ; // frequency = 20000Hz
95- pwm_config.cmpr_a = 0 ; // duty cycle of PWMxA = 50.0%
96- pwm_config.cmpr_b = 0 ; // duty cycle of PWMxB = 50.0%
97- pwm_config.counter_mode = MCPWM_UP_DOWN_COUNTER; // Up-down counter (triangle wave)
98- pwm_config.duty_mode = MCPWM_DUTY_MODE_0; // Active HIGH
99- mcpwm_init (m_slot.mcpwm_unit , MCPWM_TIMER_0, &pwm_config); // Configure PWM0A & PWM0B with above settings
100- mcpwm_init (m_slot.mcpwm_unit , MCPWM_TIMER_1, &pwm_config); // Configure PWM0A & PWM0B with above settings
101- mcpwm_init (m_slot.mcpwm_unit , MCPWM_TIMER_2, &pwm_config); // Configure PWM0A & PWM0B with above settings
133+ #elif defined(_STM32_DEF_) || (defined(__arm__) && defined(CORE_TEENSY)) // if stm32 or teensy 3x / 4x / LC boards
134+ if (pwm_frequency == NOT_SET) pwm_frequency = 500000 ; // default frequency 50khz
135+ else pwm_frequency = constrain (pwm_frequency, 0 , 50000 ); // constrain to 50kHz max
136+ _setHighFrequency (pwm_frequency, pinA);
137+ _setHighFrequency (pwm_frequency, pinB);
138+ _setHighFrequency (pwm_frequency, pinC);
139+ if (pinD != NOT_SET) _setHighFrequency (pwm_frequency, pinD); // stepper motor
102140
103- _delay (100 );
141+ #elif defined(ESP_H) // if esp32 boards
142+ if (pwm_frequency == NOT_SET) pwm_frequency = 400000 ; // default frequency 40khz
143+ else pwm_frequency = constrain (pwm_frequency, 0 , 50000 ); // constrain to 50kHz max
104144
105- mcpwm_stop (m_slot.mcpwm_unit , MCPWM_TIMER_0);
106- mcpwm_stop (m_slot.mcpwm_unit , MCPWM_TIMER_1);
107- mcpwm_stop (m_slot.mcpwm_unit , MCPWM_TIMER_2);
108- m_slot.mcpwm_num ->clk_cfg .prescale = 0 ;
145+ if (pinD == NOT_SET){
146+ bldc_motor_slots_t m_slot = {};
109147
110- m_slot.mcpwm_num ->timer [0 ].period .prescale = 4 ;
111- m_slot.mcpwm_num ->timer [1 ].period .prescale = 4 ;
112- m_slot.mcpwm_num ->timer [2 ].period .prescale = 4 ;
113- _delay (1 );
114- m_slot.mcpwm_num ->timer [0 ].period .period = 2048 ;
115- m_slot.mcpwm_num ->timer [1 ].period .period = 2048 ;
116- m_slot.mcpwm_num ->timer [2 ].period .period = 2048 ;
117- _delay (1 );
118- m_slot.mcpwm_num ->timer [0 ].period .upmethod = 0 ;
119- m_slot.mcpwm_num ->timer [1 ].period .upmethod = 0 ;
120- m_slot.mcpwm_num ->timer [2 ].period .upmethod = 0 ;
121- _delay (1 );
122- mcpwm_start (m_slot.mcpwm_unit , MCPWM_TIMER_0);
123- mcpwm_start (m_slot.mcpwm_unit , MCPWM_TIMER_1);
124- mcpwm_start (m_slot.mcpwm_unit , MCPWM_TIMER_2);
148+ // determine which motor are we connecting
149+ // and set the appropriate configuration parameters
150+ for (int i = 0 ; i < 4 ; i++){
151+ if (esp32_bldc_motor_slots[i].pinA == _EMPTY_SLOT){ // put the new motor in the first empty slot
152+ esp32_bldc_motor_slots[i].pinA = pinA;
153+ m_slot = esp32_bldc_motor_slots[i];
154+ break ;
155+ }
156+ }
157+
158+ // configure pins
159+ mcpwm_gpio_init (m_slot.mcpwm_unit , m_slot.mcpwm_a , pinA);
160+ mcpwm_gpio_init (m_slot.mcpwm_unit , m_slot.mcpwm_b , pinB);
161+ mcpwm_gpio_init (m_slot.mcpwm_unit , m_slot.mcpwm_c , pinC);
125162
126- mcpwm_sync_enable (m_slot.mcpwm_unit , MCPWM_TIMER_0, MCPWM_SELECT_SYNC_INT0, 0 );
127- mcpwm_sync_enable (m_slot.mcpwm_unit , MCPWM_TIMER_1, MCPWM_SELECT_SYNC_INT0, 0 );
128- mcpwm_sync_enable (m_slot.mcpwm_unit , MCPWM_TIMER_2, MCPWM_SELECT_SYNC_INT0, 0 );
129- _delay (1 );
130- m_slot.mcpwm_num ->timer [0 ].sync .out_sel = 1 ;
131- _delay (1 );
132- m_slot.mcpwm_num ->timer [0 ].sync .out_sel = 0 ;
163+ // configure the timer
164+ _configureTimerFrequency (pwm_frequency, m_slot.mcpwm_num , m_slot.mcpwm_unit );
165+
166+ }else {
167+ stepper_motor_slots_t m_slot = {};
168+ // determine which motor are we connecting
169+ // and set the appropriate configuration parameters
170+ for (int i = 0 ; i < 2 ; i++){
171+ if (esp32_stepper_motor_slots[i].pin1A == _EMPTY_SLOT){ // put the new motor in the first empty slot
172+ esp32_stepper_motor_slots[i].pin1A = pinA;
173+ m_slot = esp32_stepper_motor_slots[i];
174+ break ;
175+ }
176+ }
177+
178+ // configure pins
179+ mcpwm_gpio_init (m_slot.mcpwm_unit , m_slot.mcpwm_1a , pinA);
180+ mcpwm_gpio_init (m_slot.mcpwm_unit , m_slot.mcpwm_1b , pinB);
181+ mcpwm_gpio_init (m_slot.mcpwm_unit , m_slot.mcpwm_2a , pinC);
182+ mcpwm_gpio_init (m_slot.mcpwm_unit , m_slot.mcpwm_2b , pinD);
183+
184+ // configure the timer
185+ _configureTimerFrequency (pwm_frequency, m_slot.mcpwm_num , m_slot.mcpwm_unit );
186+ }
133187#endif
134188}
135189
@@ -142,12 +196,12 @@ void _writeDutyCycle(float dc_a, float dc_b, float dc_c, int pinA, int pinB, in
142196#if defined(ESP_H) // if ESP32 boards
143197 // determine which motor slot is the motor connected to
144198 for (int i = 0 ; i < 4 ; i++){
145- if (esp32_motor_slots [i].pinA == pinA){ // if motor slot found
199+ if (esp32_bldc_motor_slots [i].pinA == pinA){ // if motor slot found
146200 // se the PWM on the slot timers
147201 // transform duty cycle from [0,1] to [0,2047]
148- esp32_motor_slots [i].mcpwm_num ->channel [0 ].cmpr_value [esp32_motor_slots [i].mcpwm_operator ].cmpr_val = dc_a*2047 ;
149- esp32_motor_slots [i].mcpwm_num ->channel [1 ].cmpr_value [esp32_motor_slots [i].mcpwm_operator ].cmpr_val = dc_b*2047 ;
150- esp32_motor_slots [i].mcpwm_num ->channel [2 ].cmpr_value [esp32_motor_slots [i].mcpwm_operator ].cmpr_val = dc_c*2047 ;
202+ esp32_bldc_motor_slots [i].mcpwm_num ->channel [0 ].cmpr_value [esp32_bldc_motor_slots [i].mcpwm_operator ].cmpr_val = dc_a*2047 ;
203+ esp32_bldc_motor_slots [i].mcpwm_num ->channel [1 ].cmpr_value [esp32_bldc_motor_slots [i].mcpwm_operator ].cmpr_val = dc_b*2047 ;
204+ esp32_bldc_motor_slots [i].mcpwm_num ->channel [2 ].cmpr_value [esp32_bldc_motor_slots [i].mcpwm_operator ].cmpr_val = dc_c*2047 ;
151205 break ;
152206 }
153207 }
@@ -171,7 +225,18 @@ void _writeDutyCycle(float dc_a, float dc_b, float dc_c, int pinA, int pinB, in
171225// ESP32 uses MCPWM
172226void _writeDutyCycle (float dc_1a, float dc_1b, float dc_2a, float dc_2b, int pin1A, int pin1B, int pin2A, int pin2B){
173227#if defined(ESP_H) // if ESP32 boards
174- // not sure how to handle this
228+ // determine which motor slot is the motor connected to
229+ for (int i = 0 ; i < 2 ; i++){
230+ if (esp32_stepper_motor_slots[i].pin1A == pin1A){ // if motor slot found
231+ // se the PWM on the slot timers
232+ // transform duty cycle from [0,1] to [0,2047]
233+ esp32_stepper_motor_slots[i].mcpwm_num ->channel [0 ].cmpr_value [esp32_stepper_motor_slots[i].mcpwm_operator1 ].cmpr_val = dc_1a*2047 ;
234+ esp32_stepper_motor_slots[i].mcpwm_num ->channel [1 ].cmpr_value [esp32_stepper_motor_slots[i].mcpwm_operator1 ].cmpr_val = dc_1b*2047 ;
235+ esp32_stepper_motor_slots[i].mcpwm_num ->channel [0 ].cmpr_value [esp32_stepper_motor_slots[i].mcpwm_operator2 ].cmpr_val = dc_2a*2047 ;
236+ esp32_stepper_motor_slots[i].mcpwm_num ->channel [1 ].cmpr_value [esp32_stepper_motor_slots[i].mcpwm_operator2 ].cmpr_val = dc_2b*2047 ;
237+ break ;
238+ }
239+ }
175240#elif defined(_STM32_DEF_) // STM32 devices
176241 // transform duty cycle from [0,1] to [0,4095]
177242 analogWrite (pin1A, 4095.0 *dc_1a);
0 commit comments