Motor Evaluation Kit NEVC-MCTRL-100-t01-1.0.0
Firmware for NEVB-MCTRL-100-01 for trapezoidal control of BLDC motors using Hall-effect sensors
Loading...
Searching...
No Matches
main.ino
Go to the documentation of this file.
1/* This file has been prepared for Doxygen automatic documentation generation.*/
31#define __AVR_ATmega32U4__ 1
32
33// Include main Arduino library for basic Arduino functions
34#include <Arduino.h>
35
36// Include AVR input/output definitions for low-level hardware control
37#include <avr/io.h>
38
39// Define ISR macro for IntelliSense, else include AVR interrupt handling
40// library
41#ifdef __INTELLISENSE__
42#define ISR(vector) void vector(void)
43#else
44#include <avr/interrupt.h>
45#endif
46
47// Define __LPM macro for IntelliSense, else include AVR program space utility
48// library
49#ifdef __INTELLISENSE__
50#define __LPM(x) 0
51#else
52#include <avr/pgmspace.h>
53#endif
54
55// Include standard integer type definitions
56#include <stdint.h>
57
58// Include motor control related headers
59#include "main.h"
60#include "tables.h"
61#include "fault.h"
62#include "scpi.h"
63#include "filter.h"
64
65// Include PID control algorithm if closed-loop speed control is enabled
66#if (SPEED_CONTROL_METHOD == SPEED_CONTROL_CLOSED_LOOP)
67#include "pid.h"
68#endif
69
77
85
91
105volatile uint16_t commutationTicks = 0;
118volatile uint16_t lastCommutationTicks = 0xffff;
119
125volatile uint8_t speedInput = 0;
126
132volatile uint8_t speedOutput = 0;
133
161volatile uint16_t current = 0;
162
190volatile uint16_t gateVref = 0;
191
200
201#if (SPEED_CONTROL_METHOD == SPEED_CONTROL_CLOSED_LOOP)
203pidData_t pidParameters;
204#endif
205
211void setup(void)
212{
213 // Load motor configs
214 ConfigsInit();
215
216 // Initialize flags.
217 FlagsInit();
218
219 // Check if remote mode requested.
220 RemoteUpdate();
221
222 // Initialize peripherals.
223 PortsInit(); // depends on motorFlags.remote
224 ADCInit(); // include self-test + loop until board detected must be before TimersInit
225 PLLInit();
226 TimersInit();
227
228#if (SPEED_CONTROL_METHOD == SPEED_CONTROL_CLOSED_LOOP)
229 PIDInit(PID_K_P, PID_K_I, PID_K_D, &pidParameters);
230#endif
231
232 if (motorFlags.remote == TRUE)
233 {
234 // Start serial interface with 115200 bauds.
235 Serial.begin(115200);
236 // while (!Serial); // wait for serial to finish initializing
237
238 // Initialise SCPI subsystem if remote mode.
239 SCPI_Init(&scpi_context,
242 scpi_units_def,
246 }
247 else
248 {
249 // Update direction before enable flag.
251 // Do not update enable flag until everything is ready.
252 EnableUpdate();
253 }
254
255 // Set up pin change interrupts.
257
258 // Enable Timer4 overflow event interrupt.
259 TIMSK4 |= (1 << TOIE4);
260
261 // Enable interrupts globally and let motor driver take over.
262 sei();
263}
264
271void loop()
272{
273 if (motorFlags.remote == TRUE)
274 {
275 // send data to SCPI parser only when you receive data:
276 if (Serial.available() > 0)
277 {
278 incoming_byte = Serial.read();
279 SCPI_Input(&scpi_context, &incoming_byte, 1);
280 }
281 }
283 {
286 }
287}
288
294static void FlagsInit(void)
295{
296 // Initialize motorFlags with default values.
303
304 // Initialize faultFlags with default values. Set motorStopped to FALSE at
305 // startup. This will make sure that the motor is not started if it is not
306 // really stopped. If it is stopped, this variable will quickly be updated.
314}
315
327
335static void PLLInit(void)
336{
337 // Configure PLL Frequency Control Register to output 48MHz for USB Module and
338 // 64MHz for the High-Speed Clock Timer with a base speed of 96MHz for PLL
339 // Output Frequency.
340
341 PLLFRQ = (0 << PINMUX) | (1 << PLLUSB) | PLL_POSTSCALER_DIV_1_5 | (1 << PDIV3) | (0 << PDIV2) | (1 << PDIV1) | (0 << PDIV0);
342
343 // Enable PLL.
344 PLLCSR = (1 << PINDIV) | (1 << PLLE);
345
346 // Wait until PLOCK bit is set, indicating PLL is locked and stable.
347 while ((PLLCSR & (1 << PLOCK)) == 0)
348 {
349 // Wait for PLL lock
350 ;
351 }
352}
353
361static void PortsInit(void)
362{
363#if (EMULATE_HALL == TRUE)
364 // Configure and set hall sensor pins for motor emulation
365 PORTB &= ~((1 << H1_PIN) | (1 << H2_PIN) | (1 << H3_PIN));
366 PORTB |= (0x07 & pgm_read_byte_near(&expectedHallSequenceForward[1]));
367 // Set hall sensor pins as outputs.
368 DDRB |= (1 << H1_PIN) | (1 << H2_PIN) | (1 << H3_PIN);
369#endif
370
371#if ((HALL_PULLUP_ENABLE == TRUE) && (EMULATE_HALL != TRUE))
372 // Configure and set hall sensor pins as input with pull-ups enabled
373 PORTB |= (1 << H1_PIN) | (1 << H2_PIN) | (1 << H3_PIN);
374#endif
375
376 // Configure and set pins FAULT_PIN_3, FAULT_PIN_2, and FAULT_PIN_1 as outputs
377 PORTB &= ~((1 << FAULT_PIN_3) | (1 << FAULT_PIN_2));
378 DDRB |= (1 << FAULT_PIN_3) | (1 << FAULT_PIN_2);
379 PORTD &= ~(1 << FAULT_PIN_1);
380 DDRD |= (1 << FAULT_PIN_1);
381
382 // If remote mode, set enable and direction pin as output to allow software
383 // triggered interrupts
384 if (motorFlags.remote == TRUE)
385 {
386 PORTD &= ~((1 << ENABLE_PIN) | (1 << DIRECTION_COMMAND_PIN));
387 DDRD |= (1 << ENABLE_PIN) | (1 << DIRECTION_COMMAND_PIN);
388 }
389}
390
405void TimersInit(void)
406{
407 // Set Timer1 accordingly.
408 TCCR1A = (1 << WGM11) | (0 << WGM10);
409 TCCR1B = (0 << WGM13) | (1 << WGM12);
410 TIMSK1 = (1 << TOIE1);
411
412 // Start Timer1.
413 TCCR1B |= TIM1_CLOCK_DIV_64;
414
415#if (EMULATE_HALL == TRUE)
416 // Set Timer3 accordingly.
417 TCCR3A = (1 << WGM31) | (1 << WGM30);
418 TCCR3B = (1 << WGM33) | (1 << WGM32);
419 TIMSK3 = (1 << TOIE3);
420
421 // Set top value of Timer/counter3.
422 OCR3AH = (uint8_t)(TIM3_TOP >> 8);
423 OCR3AL = (uint8_t)(0xff & TIM3_TOP);
424
425 // Start Timer3.
426 TCCR3B |= TIM1_CLOCK_DIV_8;
427#endif
428 // Set Timer4 in "PWM6 / Dual-slope" mode. Does not enable outputs yet.
429 TCCR4A = (0 << COM4A1) | (1 << COM4A0) | (0 << COM4B1) | (1 << COM4B0) | (1 << PWM4A) | (1 << PWM4B);
431 TCCR4C |= (0 << COM4D1) | (1 << COM4D0) | (1 << PWM4D);
432 TCCR4E = (1 << ENHC4);
433
434 // Set top value of Timer/counter4.
435 TC4H = (uint8_t)(motorConfigs.tim4Top >> 8);
436 OCR4C = (uint8_t)(0xff & motorConfigs.tim4Top);
437
438 // Set the dead time.
440
441 // Start Timer4.
443}
444
450static void PinChangeIntInit(void)
451{
452 // Initialize external interrupt on shutdown pin (INT0) and direction input
453 // (INT2) pin.
454 EICRA = (0 << ISC21) | (1 << ISC20) | (0 << ISC01) | (1 << ISC00);
455 EIMSK = (1 << INT2) | (1 << INT0);
456
457 // Initialize pin change interrupt on hall sensor inputs (PCINT1..3).
458 PCMSK0 = (1 << PCINT3) | (1 << PCINT2) | (1 << PCINT1);
459
460 // Enable pin change interrupt on ports with pin change signals
461 PCICR = (1 << PCIE0);
462}
463
481static void ADCInit(void)
482{
483 // Select initial AD conversion channel [0V for self-test].
484 ADMUX = (ADC_REFERENCE_VOLTAGE | (1 << ADLAR) | ADC_MUX_L_0V);
485 ADCSRB = ADC_MUX_H_0V;
486 _delay_ms(1);
487
488 // Enable ADC
489 ADCSRA = (1 << ADEN);
490
491 // Start ADC single conversion and discard first measurement.
492 uint16_t adc_reading = ADCSingleConversion();
493
494 // Start ADC single conversion to measure 0V, this time it is correct.
495 adc_reading = ADCSingleConversion();
496
497 // Check if ADC can measure 0V within 10mV.
498 if (adc_reading > 2)
499 {
500 FatalError((uint8_t)0b0000111);
501 }
502
503 // Select next AD conversion channel [1V1 for self-test].
504 ADMUX = (ADC_REFERENCE_VOLTAGE | (1 << ADLAR) | ADC_MUX_L_1V1);
505 ADCSRB = ADC_MUX_H_1V1;
506 _delay_ms(1);
507
508 // Start ADC single conversion to measure 1V1.
509 adc_reading = ADCSingleConversion();
510
511 // Check if ADC can measure 1.1V within 1% (1.09 to 1.1V).
512 if ((adc_reading < 223) || (adc_reading > 227))
513 {
514 FatalError((uint8_t)0b0000111);
515 }
516
517 // Select next AD conversion channel [BREF].
518 ADMUX = (ADC_REFERENCE_VOLTAGE | (1 << ADLAR) | ADC_MUX_L_BREF);
519 ADCSRB = ADC_MUX_H_BREF;
520
521 // Enable pull up resistor
522 PORTF |= (1 << PF0);
523
524 _delay_ms(1);
526
527 // Start ADC single conversion to measure BREF.
528 adc_reading = ADCSingleConversion();
529
530 // Wait to check if any board is connected. Should be anything other than
531 // 0x3ff if any board is connected assuming BREF of the board is not equal to
532 // IOREF.
533 while (adc_reading == 0x3ff)
534 {
536
537 // Start ADC single conversion to measure BREF.
538 adc_reading = ADCSingleConversion();
539 }
540
541 // Disable pull up resistor
542 PORTF &= ~(1 << PF0);
543
544 // Re-initialize ADC mux channel select.
545 ADMUX &= ~ADC_MUX_L_BITS;
546 ADMUX |= ADC_MUX_L_SPEED;
547 // Set trigger source to ADC_TRIGGER.
548 ADCSRB = ADC_MUX_H_SPEED | ADC_TRIGGER;
549
550 // Re-initialize ADC to work with interrupts.
551 ADCSRA = (1 << ADEN) | (1 << ADSC) | (1 << ADATE) | (1 << ADIF) | (1 << ADIE) | ADC_PRESCALER;
552}
553
561static uint16_t ADCSingleConversion(void)
562{
563 // Initialize ADC for one-time conversion.
564 ADCSRA |= (1 << ADSC);
565
566 // Wait for the conversion to complete.
567 while (ADCSRA & (1 << ADSC))
568 {
569 // Wait until the conversion is finished.
570 }
571
572 // Read the ADC result and combine ADCH and ADCL into a 16-bit value.
573 uint16_t value = (ADCL >> 6);
574 value |= 0x3ff & (ADCH << 2);
575
576 return value;
577}
578
594static void EnableUpdate(void)
595{
596 if ((PIND & (1 << ENABLE_PIN)) != 0)
597 {
599 }
600 else
601 {
603
604#if (TURN_OFF_MODE == TURN_OFF_MODE_COAST)
605 // Disable driver signals to let the motor coast.
610#endif
611
612#if (TURN_OFF_MODE == TURN_OFF_MODE_BRAKE)
613 // Set the motor in brake mode.
615 TimersSetModeBrake();
616#endif
617 }
618}
619
627static void RemoteUpdate(void)
628{
629 if ((PIND & (1 << REMOTE_PIN)) != 0)
630 {
632 }
633 else
634 {
636 }
637}
638
664static void SpeedController(void)
665{
666 if (motorFlags.enable == TRUE)
667 {
668#if (SPEED_CONTROL_METHOD == SPEED_CONTROL_CLOSED_LOOP)
669 // Calculate an increment set point from the analog speed input.
670 int16_t incrementSetpoint = ((int32_t)speedInput * SPEED_CONTROLLER_MAX_SPEED) / SPEED_CONTROLLER_MAX_INPUT;
671
672 // PID regulator with feed forward from speed input.
673 uint16_t outputValue;
674
675 outputValue = PIDController(incrementSetpoint, (motorConfigs.tim4Freq / (lastCommutationTicks * 3)) >> 1, &pidParameters);
676
677 if (outputValue > 255)
678 {
679 outputValue = 255;
680 }
681
682 speedOutput = outputValue;
683
684 // Without the delay PID does not reset when needed
685 _delay_us(1);
686#else
687 // Calculate the delta in speedInput
688 int16_t delta = speedInput - speedOutput;
689 // If delta exceeds the maximum allowed change, limit it and update
690 // speedOutput
691 if (delta > SPEED_CONTROLLER_MAX_DELTA)
692 {
694 }
695 else if (delta < -SPEED_CONTROLLER_MAX_DELTA)
696 {
698 }
699 else
700 {
702 }
703#endif
704 }
705 else
706 {
707 speedOutput = 0;
708 }
709}
710
728static void FatalError(uint8_t code)
729{
730 // Detach all interrupts
731 cli();
732
733 // Disable outputs
735
736 // Set faultFlags based on the provided error code
737 faultFlags.userFlag3 = (code & 0x01) != 0;
738 faultFlags.userFlag2 = (code & 0x02) != 0;
739 faultFlags.userFlag1 = (code & 0x04) != 0;
740 faultFlags.reverseDirection = (code & 0x08) != 0;
741 faultFlags.motorStopped = (code & 0x10) != 0;
742 faultFlags.overCurrent = (code & 0x20) != 0;
743 faultFlags.noHallConnections = (code & 0x40) != 0;
744
745 // loop forever
746 while (1)
747 {
749 _delay_ms(2);
750 }
751}
752
761static FORCE_INLINE void SetDuty(const uint16_t duty)
762{
763 TC4H = duty >> 8;
764 OCR4A = 0xFF & duty;
765}
766
780{
781 // Set PWM pins to input (High-Z) while changing modes.
783
784 // Sets up timers.
785 TCCR4A = (0 << COM4A1) | (1 << COM4A0) | (0 << COM4B1) | (1 << COM4B0) | (1 << PWM4A) | (1 << PWM4B);
786 TCCR4C |= (0 << COM4D1) | (1 << COM4D0) | (1 << PWM4D);
787 TCCR4D = (1 << WGM41) | (1 << WGM40);
788
789 // Set output duty cycle to zero for now.
790 SetDuty(0);
791
792 // Wait for the next PWM cycle to ensure that all outputs are updated.
794
796
797 // Change PWM pins to output again to allow PWM control.
799}
800
801#if (TURN_OFF_MODE == TURN_OFF_MODE_BRAKE)
820static FORCE_INLINE void TimersSetModeBrake(void)
821{
822 // Set PWM pins to input (High-Z) while changing modes.
824
825 // Sets up timers.
826 TCCR4A = (0 << COM4A1) | (1 << COM4A0) | (0 << COM4B1) | (1 << COM4B0) | (1 << PWM4A) | (1 << PWM4B);
827 TCCR4C |= (0 << COM4D1) | (1 << COM4D0) | (1 << PWM4D);
828 TCCR4D = (1 << WGM41) | (1 << WGM40);
829
830 // Set to 50% duty
831 SetDuty((uint16_t)511);
832
833 // PWM outputs on both high side and low side gates are turned enabled
834 // (complementary)
835 TCCR4E &= ~0b00111111;
837
838 // Wait for the next PWM cycle to ensure that all outputs are updated.
840
842
844}
845#endif
846
853{
854 // Clear Timer1 Capture event flag.
855 TIFR4 = (1 << TOV4);
856
857 // Wait for new Timer1 Capture event flag.
858 while (!(TIFR4 & (1 << TOV4)))
859 {
860 }
861}
862
874{
875 return (uint8_t)motorFlags.desiredDirection;
876}
877
894{
896}
897
908static FORCE_INLINE void BlockCommutate(const uint8_t direction, uint8_t hall)
909{
910 const uint8_t *tableAddress;
911
912 if (direction == DIRECTION_FORWARD)
913 {
914 tableAddress = blockCommutationTableForward;
915 }
916 else
917 {
918 tableAddress = blockCommutationTableReverse;
919 }
920 tableAddress += (hall * 4);
921
923 TCCR4E &= ~0b00111111;
924
926
927 PORTB |= (uint8_t)pgm_read_byte_near(tableAddress++);
928 PORTC |= (uint8_t)pgm_read_byte_near(tableAddress++);
929 PORTD |= (uint8_t)pgm_read_byte_near(tableAddress++);
930 TCCR4E |= (uint8_t)pgm_read_byte_near(tableAddress);
931
933}
934
946static FORCE_INLINE uint8_t GetHall(void)
947{
948 uint8_t hall;
949
950 hall = HALL_PIN & ((1 << H3_PIN) | (1 << H2_PIN) | (1 << H1_PIN));
951 hall >>= H1_PIN;
952
953 return hall;
954}
955
962{
963 if ((PIND & (1 << DIRECTION_COMMAND_PIN)) != 0)
964 {
966 }
967 else
968 {
970 }
971}
972
982static FORCE_INLINE void ActualDirectionUpdate(uint8_t lastHall, const uint8_t newHall)
983{
984 // Ensure that lastHall is within the bounds of the table. If not, set it to
985 // 0, which is also an illegal hall value but a legal table index.
986 if (lastHall > 6)
987 {
988 lastHall = 0;
989 }
990
991 if (pgm_read_byte_near(&expectedHallSequenceForward[lastHall]) == newHall)
992 {
994 }
995 else if (pgm_read_byte_near(&expectedHallSequenceReverse[lastHall]) == newHall)
996 {
998 }
999 else
1000 {
1002 }
1003}
1004
1011{
1013 {
1015 }
1016 else
1017 {
1019 }
1020}
1021
1029{
1030 DDRB |= PWM_PATTERN_PORTB;
1031 DDRC |= PWM_PATTERN_PORTC;
1032 DDRD |= PWM_PATTERN_PORTD;
1033}
1034
1042{
1043 DDRB &= ~PWM_PATTERN_PORTB;
1044 DDRC &= ~PWM_PATTERN_PORTC;
1045 DDRD &= ~PWM_PATTERN_PORTD;
1046}
1047
1055{
1056 PORTB &= ~PWM_PATTERN_PORTB;
1057 PORTC &= ~PWM_PATTERN_PORTC;
1058 PORTD &= ~PWM_PATTERN_PORTD;
1059}
1060
1077{
1079 {
1081 }
1082 else
1083 {
1085 lastCommutationTicks = 0xffff;
1086 uint8_t hall = GetHall();
1087 if ((hall == 0) || (hall == 0b111))
1088 {
1090 }
1092 {
1093 speedOutput = 0;
1094#if (SPEED_CONTROL_METHOD == SPEED_CONTROL_CLOSED_LOOP)
1095 PIDResetIntegrator(&pidParameters);
1096#endif
1099 }
1100#if (TURN_OFF_MODE == TURN_OFF_MODE_BRAKE)
1101 else if (motorFlags.enable == FALSE)
1102 {
1105 ClearPWMPorts();
1106 }
1107#endif
1108 }
1109}
1110
1115ISR(INT0_vect)
1116{
1117 EnableUpdate();
1118}
1119
1129ISR(PCINT0_vect)
1130{
1131 static uint8_t lastHall = 0xff;
1132 uint8_t hall;
1133
1134 hall = GetHall();
1135
1137 {
1139 }
1140
1141 // Update flags that depend on hall sensor value.
1142 ActualDirectionUpdate(lastHall, hall);
1144
1145 lastHall = hall;
1146
1147 // Reset commutation timer.
1149 commutationTicks = 0;
1150
1151 // Since the hall sensors are changing, the motor can not be stopped.
1154}
1155
1168ISR(INT2_vect)
1169{
1170 // Update desired direction flag.
1173 {
1174 }
1176 {
1177 };
1178
1179#if (TURN_OFF_MODE == TURN_OFF_MODE_COAST)
1180 // Disable driver signals to let motor coast. The motor will automatically
1181 // start once it stopped.
1184 ClearPWMPorts();
1186#endif
1187
1188#if (TURN_OFF_MODE == TURN_OFF_MODE_BRAKE)
1189 // Set motor in brake mode. The motor will automatically start once it is
1190 // stopped.
1192 TimersSetModeBrake(); // Automatically sets driveWaveform.
1193#endif
1194}
1195
1202ISR(TIMER4_OVF_vect)
1203{
1205 {
1206 uint16_t dutyCycle = ((uint32_t)speedOutput * motorConfigs.tim4Top) >> 7;
1207
1208 if (dutyCycle > (uint16_t)(motorConfigs.tim4Top << 1))
1209 {
1210 dutyCycle = (uint16_t)(motorConfigs.tim4Top << 1);
1211 }
1212
1213 SetDuty(dutyCycle);
1214 }
1215
1217
1218 {
1219 // Run the speed regulation loop with constant intervals.
1220 static uint8_t speedRegTicks = 0;
1221 speedRegTicks++;
1222 if (speedRegTicks >= SPEED_CONTROLLER_TIME_BASE)
1223 {
1225 speedRegTicks -= SPEED_CONTROLLER_TIME_BASE;
1226 }
1227 }
1228}
1229
1230#if (EMULATE_HALL == TRUE)
1246ISR(TIMER3_OVF_vect)
1247{
1248 if (motorFlags.enable == TRUE)
1249 {
1250 uint8_t hall = GetHall();
1251
1253 {
1254 PORTB = (PORTB & ~((1 << H1_PIN) | (1 << H2_PIN) | (1 << H3_PIN))) | ((0x07 & pgm_read_byte_near(&expectedHallSequenceForward[hall])) << H1_PIN);
1255 }
1256 else
1257 {
1258 PORTB = (PORTB & ~((1 << H1_PIN) | (1 << H2_PIN) | (1 << H3_PIN))) | ((0x07 & pgm_read_byte_near(&expectedHallSequenceReverse[hall])) << H1_PIN);
1259 }
1260 }
1261}
1262#endif
1263
1273ISR(TIMER1_OVF_vect)
1274{
1276}
1277
1292ISR(ADC_vect)
1293{
1294 switch ((ADMUX & ADC_MUX_L_BITS) | (ADCSRB & ADC_MUX_H_BITS))
1295 {
1297 // Handle ADC conversion result for speed measurement.
1299 {
1300 speedInput = ADCH;
1301 }
1302 ADMUX &= ~ADC_MUX_L_BITS;
1303 ADMUX |= ADC_MUX_L_CURRENT;
1304 ADCSRB &= ~ADC_MUX_H_BITS;
1305 ADCSRB |= ADC_MUX_H_CURRENT;
1306 break;
1308 // Handle ADC conversion result for current measurement.
1309 current = ADCL >> 6;
1310 current |= (ADCH << 2);
1311 ADMUX &= ~ADC_MUX_L_BITS;
1312 ADMUX |= ADC_MUX_L_GATEVREF;
1313 ADCSRB &= ~ADC_MUX_H_BITS;
1314 ADCSRB |= ADC_MUX_H_GATEVREF;
1315
1316 // Check for over current conditions and set fault flags.
1318 {
1319 FatalError((uint8_t)0b0100111);
1320 }
1322 {
1324 }
1325 else
1326 {
1328 }
1329 break;
1331 // Handle ADC conversion result for gate voltage reference measurement.
1332 gateVref = ADCL >> 6;
1333 gateVref |= (ADCH << 2);
1334 ADMUX &= ~ADC_MUX_L_BITS;
1335 ADMUX |= ADC_MUX_L_SPEED;
1336 ADCSRB &= ~ADC_MUX_H_BITS;
1337 ADCSRB |= ADC_MUX_H_SPEED;
1338 break;
1339 default:
1340 // This is probably an error and should be handled.
1341 FatalError((uint8_t)0b0000111);
1342 break;
1343 }
1344
1345 // Clear Timer/Counter0 overflow flag.
1346 TIFR0 = (1 << TOV0);
1347}
void SweepLEDsBlocking(void)
Sweeps through all LEDs individually with a delay.
Definition fault.cpp:144
void faultSequentialStateMachine(volatile faultflags_t *faultFlags, volatile motorflags_t *motorFlags)
Sequential State Machine for Handling Fault Flags.
Definition fault.cpp:181
Fault LED header file.
int16_t calculateEMA(uint16_t currentSample, uint16_t previousEMA, uint8_t alphaExponent)
Exponential Moving Average (EMA) calculation algorithm.
Definition filter.cpp:34
Filter header file.
#define ADC_MUX_H_1V1
High ADC channel selection bit (MUX5) - 1.1V (Vbandgap).
Definition main.h:898
#define ADC_MUX_H_0V
High ADC channel selection bit (MUX5) - 0V (GND).
Definition main.h:902
#define ADC_MUX_L_1V1
Lower ADC channel selection bits (MUX4:0) - 1.1V (Vbandgap).
Definition main.h:896
#define ADC_MUX_L_0V
Lower ADC channel selection bits (MUX4:0) - 0V (GND).
Definition main.h:900
#define ADC_MUX_H_BITS
High ADC channel selection bit (MUX5) mask.
Definition main.h:842
#define ADC_MUX_L_BITS
Lower ADC channel selection bits (MUX4:0) mask.
Definition main.h:840
#define TIM4_TOP(tim4Freq)
Definition main.h:1059
#define DEAD_TIME_HALF(deadTime)
This value specifies half the dead time in number of clock cycles. Divide by frequency to get duratio...
Definition main.h:1080
#define DT_PRESCALER_DIV_PATTERN(dtPrescaler)
Deadtime generator pre-scaler selection bits based on pre-scaler value.
Definition main.h:1070
#define TIM3_TOP
Calculated top value for Timer 3.
Definition main.h:1088
#define TIM4_PRESCALER_DIV_PATTERN(tim4Prescaler)
Timer 4 clock select bits based on pre-scaler value.
Definition main.h:1052
#define PLL_POSTSCALER_DIV_1_5
PLL Post-scaler - division factor 1.5.
Definition main.h:770
#define ADC_MUX_L_CURRENT
Lower analog channel selection bits (MUX4:0) for motor current measurement.
Definition main.h:599
#define H2_PIN
Pin where H2 is connected.
Definition main.h:587
#define WAVEFORM_BLOCK_COMMUTATION
Waveform constant for block commutation.
Definition main.h:643
#define ADC_MUX_H_GATEVREF
High analog channel selection bit (MUX5) for for motor gateVref measurement.
Definition main.h:605
#define DIRECTION_FORWARD
Forward direction flag value.
Definition main.h:575
#define WAVEFORM_UNDEFINED
Waveform status flag used for coasting.
Definition main.h:647
#define FAULT_PIN_2
Fault Pin 2.
Definition main.h:637
#define DIRECTION_COMMAND_PIN
Pin where direction command input is located.
Definition main.h:621
#define SPEED_INPUT_SOURCE_LOCAL
Speed input source - Local or speed input pin.
Definition main.h:629
#define ADC_MUX_L_BREF
Lower analog channel selection bits (MUX4:0) for motor bref measurement.
Definition main.h:607
#define FAST_ACCESS(register_address)
Assign a specific memory address to a variable for fast access.
Definition main.h:731
#define CHOOSE_DT_PRESCALER(deadTime)
Macro to choose Timer4 dead time pre-scaler based on the dead time.
Definition main.h:695
#define SPEED_CONTROLLER_MAX_INPUT
Maximum Speed Reference Input.
Definition main.h:674
#define DIRECTION_REVERSE
Reverse direction flag value.
Definition main.h:577
#define ADC_MUX_L_SPEED
Definition main.h:594
#define ENABLE_PIN
Enable input pin.
Definition main.h:623
#define ADC_MUX_H_CURRENT
High analog channel selection bit (MUX5) for for motor current measurement.
Definition main.h:601
#define PWM_PATTERN_PORTC
Bit pattern of PWM pins placed on PORTC (Phase B).
Definition main.h:560
#define ADC_TRIGGER
ADC trigger used in this application.
Definition main.h:617
#define HALL_PIN
PIN register for Hall sensor input.
Definition main.h:583
#define ADC_MUX_L_GATEVREF
Lower analog channel selection bits (MUX4:0) for motor gateVref measurement.
Definition main.h:603
#define ADC_MUX_H_BREF
High analog channel selection bit (MUX5) for for motor bref measurement.
Definition main.h:609
#define WAVEFORM_BRAKING
Waveform status flag for braking.
Definition main.h:645
#define TRUE
TRUE constant value, defined to be compatible with comparisons.
Definition main.h:537
#define FALSE
FALSE constant value.
Definition main.h:535
#define OC_ENABLE_PORTB
Definition main.h:565
#define CHOOSE_TIM4_PRESCALER(tim4Freq)
Macro to choose Timer4 pre-scaler.
Definition main.h:677
#define ADC_PRESCALER
ADC clock pre-scaler used in this application.
Definition main.h:613
#define REMOTE_PIN
Remote input pin.
Definition main.h:625
#define FORCE_INLINE
Macro for forcing inline expansion of functions.
Definition main.h:715
#define PWM_PATTERN_PORTB
Bit pattern of PWM pins placed on PORTB (Phase A).
Definition main.h:558
#define ADC_MUX_H_SPEED
Definition main.h:597
#define PWM_PATTERN_PORTD
Bit pattern of PWM pins placed on PORTD (Phase C).
Definition main.h:562
#define FAULT_PIN_3
Fault Pin 3.
Definition main.h:639
#define DIRECTION_UNKNOWN
Unknown direction flag value.
Definition main.h:579
#define H3_PIN
Pin where H3 is connected.
Definition main.h:589
#define H1_PIN
Pin where H1 is connected.
Definition main.h:585
#define OC_ENABLE_PORTC
Definition main.h:568
#define OC_ENABLE_PORTD
Definition main.h:571
#define ADC_REFERENCE_VOLTAGE
ADC voltage reference used in this application.
Definition main.h:615
#define FAULT_PIN_1
Fault Pin 1.
Definition main.h:635
#define TIM1_CLOCK_DIV_64
Timer1 clock - i/o clk with division factor 64.
Definition main.h:805
#define TIM1_CLOCK_DIV_8
Timer1 clock - i/o clk with division factor 8.
Definition main.h:803
#define PID_K_P
PID Controller Proportional Gain Constant (Only for Closed Loop)
Definition main.h:415
#define CURRENT_WARNING_THRESHOLD
Current Warning Threshold (Register Value)
Definition main.h:273
#define CURRENT_ERROR_THRESHOLD
Current Error Threshold (Register Value)
Definition main.h:312
#define TIM4_FREQ
Desired Switching Frequency for MOSFET Gate Signals.
Definition main.h:99
#define SPEED_CONTROLLER_MAX_DELTA
Speed Controller Maximum Delta (Applicable for Open Loop Control)
Definition main.h:375
#define PID_K_D
PID Controller Derivative Gain Constant (Only for Closed Loop)
Definition main.h:472
#define SPEED_CONTROLLER_MAX_SPEED
Speed Controller Maximum Speed.
Definition main.h:396
#define SPEED_CONTROLLER_TIME_BASE
Speed Controller Time Base.
Definition main.h:354
#define COMMUTATION_TICKS_STOPPED
Commutation Stopped Limit.
Definition main.h:188
#define PID_K_I
PID Controller Integral Gain Constant (Only for Closed Loop)
Definition main.h:434
#define DEAD_TIME
Dead Time Specification.
Definition main.h:128
Motor control header file.
static void BlockCommutate(const uint8_t direction, uint8_t hall)
Perform block commutation based on direction and hall sensor input.
Definition main.ino:908
static uint8_t GetActualDirection(void)
Retrieve the current motor direction.
Definition main.ino:893
static uint8_t GetHall(void)
Read the hall sensor inputs and decode the hall state.
Definition main.ino:946
static uint8_t GetDesiredDirection(void)
Retrieve the intended motor direction.
Definition main.ino:873
static void PortsInit(void)
Initialize I/O port directions and pull-up resistors.
Definition main.ino:361
static void TimersSetModeBlockCommutation(void)
Configures timers for block commutation.
Definition main.ino:779
static void TimersWaitForNextPWMCycle(void)
Wait for the start of the next PWM cycle.
Definition main.ino:852
static void ADCInit(void)
Initializes the ADC.
Definition main.ino:481
volatile motorflags_t motorFlags
Motor control flags placed in I/O space for fast access.
Definition main.ino:76
static void SpeedController(void)
Speed regulator loop.
Definition main.ino:664
static void DisablePWMOutputs(void)
Disable PWM output pins.
Definition main.ino:1041
volatile uint8_t speedInput
The most recent "speed" input measurement.
Definition main.ino:125
static void FatalError(uint8_t code)
Handle a fatal error and enter a fault state.
Definition main.ino:728
static void FlagsInit(void)
Initializes motorFlags and faultFlags.
Definition main.ino:294
volatile motorconfigs_t motorConfigs
Motor Configs.
Definition main.ino:90
static void PinChangeIntInit(void)
Initialize pin change interrupts.
Definition main.ino:450
void setup(void)
Main initialization function.
Definition main.ino:211
static void PLLInit(void)
Initialize PLL (Phase-Locked Loop)
Definition main.ino:335
static void ActualDirectionUpdate(uint8_t lastHall, const uint8_t newHall)
Update the global actual direction flag based on the two latest hall values.
Definition main.ino:982
volatile uint16_t current
Current measurement (Register Value).
Definition main.ino:161
static void ReverseRotationSignalUpdate(void)
Update the reverse rotation flag.
Definition main.ino:1010
volatile uint16_t commutationTicks
The number of 'ticks' between two hall sensor changes (counter).
Definition main.ino:105
static void CommutationTicksUpdate(void)
Update the 'tick' counter and check for a stopped motor.
Definition main.ino:1076
static void DesiredDirectionUpdate(void)
Updates global desired direction flag.
Definition main.ino:961
volatile uint8_t speedOutput
The most recent "speed" output from the speed controller.
Definition main.ino:132
volatile faultflags_t faultFlags
Fault flags placed in I/O space for fast access.
Definition main.ino:84
static void SetDuty(const uint16_t duty)
Set duty cycle for TIM4.
Definition main.ino:761
static void EnablePWMOutputs(void)
Enable PWM output pins.
Definition main.ino:1028
volatile uint16_t lastCommutationTicks
The number of 'ticks' between two hall sensor changes (store).
Definition main.ino:118
void TimersInit(void)
Initializes and synchronizes Timers.
Definition main.ino:405
static void EnableUpdate(void)
Check whether the enable pin is set and update flags accordingly.
Definition main.ino:594
static uint16_t ADCSingleConversion(void)
Perform a single ADC conversion.
Definition main.ino:561
static void ClearPWMPorts(void)
Clear PWM output ports.
Definition main.ino:1054
char incoming_byte
Buffer for incoming serial data.
Definition main.ino:199
static void ConfigsInit(void)
Initializes motorConfigs.
Definition main.ino:320
volatile uint16_t gateVref
Gate voltage measurement (Register Value)
Definition main.ino:190
static void RemoteUpdate(void)
Check whether the remote pin is set and update flags accordingly.
Definition main.ino:627
void loop()
Main Loop Function.
Definition main.ino:271
ISR(INT0_vect)
Enable interrupt service routine.
Definition main.ino:1115
void PIDInit(int16_t p_factor, int16_t i_factor, int16_t d_factor, pidData_t *pid)
Initialisation of PID controller parameters.
Definition pid.cpp:31
uint16_t PIDController(int16_t setPoint, int16_t processValue, pidData_t *pid_st)
PID control algorithm.
Definition pid.cpp:54
void PIDResetIntegrator(pidData_t *pid_st)
Resets the integrator in the PID regulator.
Definition pid.cpp:130
PID controller header file.
scpi_interface_t scpi_interface
SCPI interface structure.
Definition scpi.cpp:651
const scpi_command_t scpi_commands[]
Array of SCPI commands.
Definition scpi.cpp:504
scpi_error_t scpi_error_queue_data[4]
SCPI error queue data array.
Definition scpi.cpp:673
char scpi_input_buffer[64]
SCPI input buffer.
Definition scpi.cpp:665
scpi_t scpi_context
SCPI context structure.
Definition scpi.cpp:681
SCPI implementation header file.
#define SCPI_INPUT_BUFFER_LENGTH
Definition scpi.h:47
#define SCPI_IDN4
The software verion for the identification SCPI query.
Definition scpi.h:59
#define SCPI_IDN1
The manufacturer's name for the identification SCPI query.
Definition scpi.h:53
#define SCPI_IDN2
The device's model number for the identification SCPI query.
Definition scpi.h:55
#define SCPI_IDN3
The device's serial number for the identification SCPI query.
Definition scpi.h:57
#define SCPI_ERROR_QUEUE_SIZE
The SCPI error queue size or the maximum number of error retained in memory.
Definition scpi.h:50
Collection of all fault flags.
Definition main.h:999
uint8_t userFlag2
Is user flag 2 set?
Definition main.h:1013
uint8_t motorStopped
Is motor stopped?
Definition main.h:1005
uint8_t userFlag3
Is user flag 3 set?
Definition main.h:1015
uint8_t noHallConnections
Is there no hall connections?
Definition main.h:1009
uint8_t overCurrent
Has it tripped the over current limit?
Definition main.h:1007
uint8_t reverseDirection
Is motor spinning in an unexpected direction?
Definition main.h:1003
uint8_t userFlag1
Is user flag 1 set?
Definition main.h:1011
Collection of motor configurations.
Definition main.h:1024
uint16_t tim4Top
Corresponding TIM4 top value for TIM4 frequency.
Definition main.h:1028
uint8_t speedInputSource
SpeedInput source select (only for remote mode).
Definition main.h:1032
uint16_t tim4DeadTime
Corresponding dead time for TIM4 output.
Definition main.h:1030
uint32_t tim4Freq
TIM4 or gate switching frequency.
Definition main.h:1026
Collection of all motor control flags.
Definition main.h:979
uint8_t desiredDirection
The desired direction of rotation.
Definition main.h:989
uint8_t enable
Is the motor enabled?
Definition main.h:985
uint8_t actualDirection
The actual direction of rotation.
Definition main.h:987
uint8_t driveWaveform
The current waveform that should be produced.
Definition main.h:991
uint8_t remote
Is the remote enabled?
Definition main.h:983
uint8_t speedControllerRun
Should speed controller run?
Definition main.h:981
PID Status.
Definition pid.h:47
Motor Control Tables.
const uint8_t expectedHallSequenceReverse[7]
Table of Expected Hall Sensor Values in Reverse Direction.
Definition tables.h:163
const uint8_t expectedHallSequenceForward[7]
Table of Expected Hall Sensor Values in Forward Direction.
Definition tables.h:149
const uint8_t blockCommutationTableReverse[32]
Block Commutation Port Direction Masks for Reverse Driving.
Definition tables.h:128
const uint8_t blockCommutationTableForward[32]
Block Commutation Port Direction Masks for Forward Driving.
Definition tables.h:80