Motor Driver Evaluation Kit NEVB-MTR1-t01-1.1.0
Firmware for NEVB-MTR1-KIT1 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.*/
29
30// Include motor control related headers
31#include "config.h"
32#include "tables.h"
33#include "fault.h"
34#include "filter.h"
35#include "scpi.h"
36
37// Include PID control algorithm if closed-loop speed control is enabled
38#if (SPEED_CONTROL_METHOD == SPEED_CONTROL_CLOSED_LOOP)
39#include "pid.h"
40#endif
41
51
61
67
81volatile uint16_t commutationTicks = 0;
94volatile uint16_t lastCommutationTicks = 0xffff;
95
101volatile uint8_t speedInput = 0;
102
108volatile uint8_t speedOutput = 0;
109
137volatile uint16_t ibus = 0;
138
167volatile int16_t iphaseU = 0;
196volatile int16_t iphaseV = 0;
197
226volatile int16_t iphaseW = 0;
227
255volatile uint16_t vbusVref = 0;
256
257#if (SPEED_CONTROL_METHOD == SPEED_CONTROL_CLOSED_LOOP)
259pidData_t pidParameters;
260#endif
261
267void setup(void)
268{
269 // Load motor configs
270 ConfigsInit();
271
272 // Initialize flags.
273 FlagsInit();
274
275 // Check if remote mode requested.
276 RemoteUpdate();
277
278 // Initialize peripherals.
279 PortsInit(); // depends on motorFlags.remote
280 ADCInit(); // include self-test + loop until board detected must be before TimersInit
281 PLLInit();
282 TimersInit();
283
284#if (SPEED_CONTROL_METHOD == SPEED_CONTROL_CLOSED_LOOP)
285 PIDInit(PID_K_P, PID_K_I, PID_K_D, &pidParameters);
286#endif
287
288 if (motorFlags.remote == TRUE)
289 {
290 // Start serial interface with 115200 bauds.
291 Serial.begin(115200);
292 // while (!Serial); // wait for serial to finish initializing
293
294 // Initialise SCPI subsystem if remote mode.
295 ScpiInit();
296 }
297 else
298 {
299 // Update direction before enable flag.
301 // Do not update enable flag until everything is ready.
302 EnableUpdate();
303 }
304
305 // Set up pin change interrupts.
307
308 // Enable Timer4 overflow event interrupt.
309 TIMSK4 |= (1 << TOIE4);
310
311 // Enable interrupts globally and let motor driver take over.
312 sei();
313}
314
321void loop()
322{
323 if (motorFlags.remote == TRUE)
324 {
325 ScpiInput(Serial);
326 }
327 if (motorFlags.speedControllerRun)
328 {
330 motorFlags.speedControllerRun = FALSE;
331 }
332}
333
339static void FlagsInit(void)
340{
341 // Initialize motorFlags with default values.
342 motorFlags.speedControllerRun = FALSE;
343 motorFlags.remote = FALSE;
344 motorFlags.enable = FALSE;
345 motorFlags.actualDirection = DIRECTION_UNKNOWN;
346 motorFlags.desiredDirection = DIRECTION_FORWARD;
347 motorFlags.driveWaveform = WAVEFORM_UNDEFINED;
348 motorFlags.fatalFault = FALSE;
349
350 // Initialize faultFlags with default values. Set motorStopped to FALSE at
351 // startup. This will make sure that the motor is not started if it is not
352 // really stopped. If it is stopped, this variable will quickly be updated.
353 faultFlags.motorStopped = FALSE;
354 faultFlags.reverseDirection = FALSE;
355 faultFlags.overCurrent = FALSE;
356 faultFlags.noHallConnections = FALSE;
357 faultFlags.userFlag1 = FALSE;
358 faultFlags.userFlag2 = FALSE;
359 faultFlags.userFlag3 = FALSE;
360}
361
366static void ConfigsInit(void)
367{
368 motorConfigs.tim4Freq = (uint32_t)F_MOSFET;
369 motorConfigs.tim4Top = (uint16_t)TIM4_TOP(motorConfigs.tim4Freq);
370 motorConfigs.tim4DeadTime = (uint16_t)DEAD_TIME;
371 motorConfigs.speedInputSource = (uint8_t)SPEED_INPUT_SOURCE_LOCAL;
372}
373
381static void PLLInit(void)
382{
383 // Configure PLL Frequency Control Register to output 48MHz for USB Module and
384 // 64MHz for the High-Speed Clock Timer with a base speed of 96MHz for PLL
385 // Output Frequency.
386
387 PLLFRQ = (0 << PINMUX) | (1 << PLLUSB) | PLL_POSTSCALER_DIV_1_5 | (1 << PDIV3) | (0 << PDIV2) | (1 << PDIV1) | (0 << PDIV0);
388
389 // Enable PLL.
390 PLLCSR = (1 << PINDIV) | (1 << PLLE);
391
392 // Wait until PLOCK bit is set, indicating PLL is locked and stable.
393 while ((PLLCSR & (1 << PLOCK)) == 0)
394 {
395 // Wait for PLL lock
396 ;
397 }
398}
399
407static void PortsInit(void)
408{
409#if (EMULATE_HALL == TRUE)
410 // Configure and set hall sensor pins for motor emulation
411 PORTB &= ~((1 << H1_PIN) | (1 << H2_PIN) | (1 << H3_PIN));
412 PORTB |= (0x07 & pgm_read_byte_near(&expectedHallSequenceForward[1]));
413 // Set hall sensor pins as outputs.
414 DDRB |= (1 << H1_PIN) | (1 << H2_PIN) | (1 << H3_PIN);
415#endif
416
417#if ((HALL_PULLUP_ENABLE == TRUE) && (EMULATE_HALL != TRUE))
418 // Configure and set hall sensor pins as input with pull-ups enabled
419 PORTB |= (1 << H1_PIN) | (1 << H2_PIN) | (1 << H3_PIN);
420#endif
421
422 // Configure and set pins FAULT_PIN_3, FAULT_PIN_2, and FAULT_PIN_1 as outputs
423 PORTB &= ~((1 << FAULT_PIN_3) | (1 << FAULT_PIN_2));
424 DDRB |= (1 << FAULT_PIN_3) | (1 << FAULT_PIN_2);
425 PORTD &= ~(1 << FAULT_PIN_1);
426 DDRD |= (1 << FAULT_PIN_1);
427
428 // If remote mode, set enable and direction pin as output to allow software
429 // triggered interrupts
430 if (motorFlags.remote == TRUE)
431 {
432 PORTD &= ~((1 << ENABLE_PIN) | (1 << DIRECTION_COMMAND_PIN));
433 DDRD |= (1 << ENABLE_PIN) | (1 << DIRECTION_COMMAND_PIN);
434 }
435}
436
455void TimersInit(void)
456{
457 // Set Timer1 accordingly.
458 TCCR1A = (1 << WGM11) | (0 << WGM10);
459 TCCR1B = (0 << WGM13) | (1 << WGM12);
460 TIMSK1 = (1 << TOIE1);
461
462 // Start Timer1.
463 TCCR1B |= TIM1_CLOCK_DIV_64;
464
465#if (EMULATE_HALL == TRUE)
466 // Set Timer3 accordingly.
467 TCCR3A = (1 << WGM31) | (1 << WGM30);
468 TCCR3B = (1 << WGM33) | (1 << WGM32);
469 TIMSK3 = (1 << TOIE3);
470
471 // Set top value of Timer/counter3.
472 OCR3AH = (uint8_t)(TIM3_TOP >> 8);
473 OCR3AL = (uint8_t)(0xff & TIM3_TOP);
474
475 // Start Timer3.
476 TCCR3B |= TIM1_CLOCK_DIV_8;
477#endif
478 // Set Timer4 in "PWM6 / Dual-slope" mode. Does not enable outputs yet.
479 TCCR4A = (0 << COM4A1) | (1 << COM4A0) | (0 << COM4B1) | (1 << COM4B0) | (1 << PWM4A) | (1 << PWM4B);
481 TCCR4C |= (0 << COM4D1) | (1 << COM4D0) | (1 << PWM4D);
482 TCCR4E = (1 << ENHC4);
483
484 // Set top value of Timer/counter4.
485 TC4H = (uint8_t)(motorConfigs.tim4Top >> 8);
486 OCR4C = (uint8_t)(0xff & motorConfigs.tim4Top);
487
488 // Set the dead time.
489 DT4 = (DEAD_TIME_HALF(motorConfigs.tim4DeadTime) << 4) | DEAD_TIME_HALF(motorConfigs.tim4DeadTime);
490
491 // Start Timer4.
493}
494
500static void PinChangeIntInit(void)
501{
502 // Initialize external interrupt on shutdown pin (INT0) and direction input
503 // (INT2) pin.
504 EICRA = (0 << ISC21) | (1 << ISC20) | (0 << ISC01) | (1 << ISC00);
505 EIMSK = (1 << INT2) | (1 << INT0);
506
507 // Initialize pin change interrupt on hall sensor inputs (PCINT1..3).
508 PCMSK0 = (1 << PCINT3) | (1 << PCINT2) | (1 << PCINT1);
509
510 // Enable pin change interrupt on ports with pin change signals
511 PCICR = (1 << PCIE0);
512}
513
536static void ADCInit(void)
537{
538#if (WAIT_FOR_BOARD == TRUE)
539 // Select initial AD conversion channel [IBUS] to check if board is connected.
540 ADMUX = (ADC_REFERENCE_VOLTAGE | (1 << ADLAR) | ADC_MUX_L_IBUS);
541 ADCSRB = ADC_MUX_H_IBUS;
542 _delay_ms(1);
543
544 // Enable ADC
545 ADCSRA = (1 << ADEN);
546
547 // Start ADC single conversion and discard first measurement.
548 uint16_t adc_reading = ADCSingleConversion();
549
550 // Enable pull up resistor
551 PORTF |= (1 << IBUS_PIN);
552
553 _delay_ms(10);
555
556 // Start ADC single conversion to measure BREF.
557 adc_reading = ADCSingleConversion();
558
559 // Wait to check if any board is connected. Should be less than
560 // 0x3C0 if the inverter board is connected
561 while (adc_reading > 0x3C0)
562 {
564
565 // Start ADC single conversion to measure BREF.
566 adc_reading = ADCSingleConversion();
567
568 _delay_ms(10);
569 }
570
571 // Disable pull up resistor
572 PORTF &= ~(1 << IBUS_PIN);
573
574 _delay_ms(10);
575
576#else
577 // Select AD reference voltage and left adjust result.
578 ADMUX = (ADC_REFERENCE_VOLTAGE | (1 << ADLAR));
579
581#endif
582
583 // Re-initialize ADC mux channel select.
584 ADMUX &= ~ADC_MUX_L_BITS;
585 ADMUX |= ADC_MUX_L_SPEED;
586 // Set trigger source to ADC_TRIGGER.
587 ADCSRB = ADC_MUX_H_SPEED | ADC_TRIGGER;
588
589 // Re-initialize ADC to work with interrupts.
590 ADCSRA = (1 << ADEN) | (1 << ADSC) | (1 << ADATE) | (1 << ADIF) | (1 << ADIE) | ADC_PRESCALER;
591}
592
600static uint16_t ADCSingleConversion(void)
601{
602 // Initialize ADC for one-time conversion.
603 ADCSRA |= (1 << ADSC);
604
605 // Wait for the conversion to complete.
606 while (ADCSRA & (1 << ADSC))
607 {
608 // Wait until the conversion is finished.
609 }
610
611 // Read the ADC result and combine ADCH and ADCL into a 16-bit value.
612 uint16_t value = (ADCL >> 6);
613 value |= 0x3ff & (ADCH << 2);
614
615 return value;
616}
617
633static void EnableUpdate(void)
634{
635 if ((PIND & (1 << ENABLE_PIN)) != 0)
636 {
637 motorFlags.enable = TRUE;
638 }
639 else
640 {
641 DisableMotor();
642 }
643}
644
659static void DisableMotor(void)
660{
661 motorFlags.enable = FALSE;
663
664#if (TURN_OFF_MODE == TURN_OFF_MODE_COAST)
665 // Disable driver signals to let the motor coast.
666 motorFlags.driveWaveform = WAVEFORM_UNDEFINED;
669#endif
670}
671
679static void RemoteUpdate(void)
680{
681 if ((PIND & (1 << REMOTE_PIN)) != 0)
682 {
683 motorFlags.remote = TRUE;
684 }
685 else
686 {
687 motorFlags.remote = FALSE;
688 }
689}
690
716static void SpeedController(void)
717{
718 if (motorFlags.enable == TRUE)
719 {
720#if (SPEED_CONTROL_METHOD == SPEED_CONTROL_CLOSED_LOOP)
721 // Calculate an increment set point from the analog speed input.
722 int16_t incrementSetpoint = ((int32_t)speedInput * SPEED_CONTROLLER_MAX_SPEED) / SPEED_CONTROLLER_MAX_INPUT;
723
724 // PID regulator with feed forward from speed input.
725 uint16_t outputValue;
726
727 outputValue = PIDController(incrementSetpoint, (motorConfigs.tim4Freq / (lastCommutationTicks * 3)) >> 1, &pidParameters);
728
729 if (outputValue > 255)
730 {
731 outputValue = 255;
732 }
733
734 speedOutput = outputValue;
735
736 // Without the delay PID does not reset when needed
737 _delay_us(1);
738#else
739 // Calculate the delta in speedInput
740 int16_t delta = speedInput - speedOutput;
741 // If delta exceeds the maximum allowed change, limit it and update
742 // speedOutput
743 if (delta > SPEED_CONTROLLER_MAX_DELTA)
744 {
746 }
747 else if (delta < -SPEED_CONTROLLER_MAX_DELTA)
748 {
750 }
751 else
752 {
754 }
755#endif
756 }
757 else
758 {
759 if (speedOutput > 0)
760 {
762 {
764 }
765 else
766 {
767 speedOutput = 0;
768 }
769 }
770 }
771}
772
781static void FatalError()
782{
783 // Stop the motor.
784 DisableMotor();
785
786 // Once this is set no more faults will be registered creating a snapshot
787 // of the failure point.
788 motorFlags.fatalFault = TRUE;
789}
790
799static FORCE_INLINE void SetDuty(const uint16_t duty)
800{
801 TC4H = duty >> 8;
802 OCR4A = 0xFF & duty;
803}
804
818{
819 // Set PWM pins to input (High-Z) while changing modes.
821
822 // Sets up timers.
823 TCCR4A = (0 << COM4A1) | (1 << COM4A0) | (0 << COM4B1) | (1 << COM4B0) | (1 << PWM4A) | (1 << PWM4B);
824 TCCR4C |= (0 << COM4D1) | (1 << COM4D0) | (1 << PWM4D);
825 TCCR4D = (1 << WGM41) | (1 << WGM40);
826
827 // Set output duty cycle to zero for now.
828 SetDuty(0);
829
830 // Wait for the next PWM cycle to ensure that all outputs are updated.
832
834
835 // Change PWM pins to output again to allow PWM control.
837}
838
845{
846 // Clear Timer1 Capture event flag.
847 TIFR4 = (1 << TOV4);
848
849 // Wait for new Timer1 Capture event flag.
850 while (!(TIFR4 & (1 << TOV4)))
851 {
852 }
853}
854
865static FORCE_INLINE void BlockCommutate(const uint8_t direction, uint8_t hall)
866{
867 const uint8_t *tableAddress;
868
869 if (direction == DIRECTION_FORWARD)
870 {
871 tableAddress = blockCommutationTableForward;
872 }
873 else
874 {
875 tableAddress = blockCommutationTableReverse;
876 }
877 tableAddress += (hall * 4);
878
880 TCCR4E &= ~0b00111111;
881
883
884 PORTB |= (uint8_t)pgm_read_byte_near(tableAddress++);
885 PORTC |= (uint8_t)pgm_read_byte_near(tableAddress++);
886 PORTD |= (uint8_t)pgm_read_byte_near(tableAddress++);
887 TCCR4E |= (uint8_t)pgm_read_byte_near(tableAddress);
888
890}
891
903static FORCE_INLINE uint8_t GetHall(void)
904{
905 uint8_t hall;
906
907 hall = HALL_PIN & ((1 << H3_PIN) | (1 << H2_PIN) | (1 << H1_PIN));
908 hall >>= H1_PIN;
909
910 return hall;
911}
912
919{
920 if (motorFlags.enable == TRUE)
921 {
922 return;
923 }
924 else if ((PIND & (1 << DIRECTION_COMMAND_PIN)) != 0)
925 {
926 motorFlags.desiredDirection = DIRECTION_REVERSE;
927 }
928 else
929 {
930 motorFlags.desiredDirection = DIRECTION_FORWARD;
931 }
932}
933
943static FORCE_INLINE void ActualDirectionUpdate(uint8_t lastHall, const uint8_t newHall)
944{
945 // Ensure that lastHall is within the bounds of the table. If not, set it to
946 // 0, which is also an illegal hall value but a legal table index.
947 if (lastHall > 6)
948 {
949 lastHall = 0;
950 }
951
952 if (pgm_read_byte_near(&expectedHallSequenceForward[lastHall]) == newHall)
953 {
954 motorFlags.actualDirection = DIRECTION_FORWARD;
955 }
956 else if (pgm_read_byte_near(&expectedHallSequenceReverse[lastHall]) == newHall)
957 {
958 motorFlags.actualDirection = DIRECTION_REVERSE;
959 }
960 else
961 {
962 motorFlags.actualDirection = DIRECTION_UNKNOWN;
963 }
964}
965
975{
976 if (motorFlags.actualDirection == motorFlags.desiredDirection)
977 {
978 faultFlags.reverseDirection = FALSE;
979 }
980 else
981 {
982 faultFlags.reverseDirection = TRUE;
983 }
984}
985
993{
994 DDRB |= PWM_PATTERN_PORTB;
995 DDRC |= PWM_PATTERN_PORTC;
996 DDRD |= PWM_PATTERN_PORTD;
997}
998
1006{
1007 DDRB &= ~PWM_PATTERN_PORTB;
1008 DDRC &= ~PWM_PATTERN_PORTC;
1009 DDRD &= ~PWM_PATTERN_PORTD;
1010}
1011
1019{
1020 PORTB &= ~PWM_PATTERN_PORTB;
1021 PORTC &= ~PWM_PATTERN_PORTC;
1022 PORTD &= ~PWM_PATTERN_PORTD;
1023}
1024
1041{
1042 // If the motor is not stopped, increment the tick counter.
1044 {
1046 }
1047 // If motor is stopped, set the stopped flag and clear the tick counter.
1048 else
1049 {
1050 // Set flags to notify that the motor is stopped.
1052 lastCommutationTicks = 0xffff;
1053
1054 // Get the current hall value.
1055 uint8_t hall = GetHall();
1056 if ((hall == 0) || (hall == 0b111))
1057 {
1059 }
1060
1061 // If the motor is in a fatal fault, motor is now stopped so loop forever.
1062 if (motorFlags.fatalFault == TRUE)
1063 {
1064 while (1)
1065 {
1067 _delay_ms(2);
1068 }
1069 }
1070 // If the motor is supposed to be enabled, and the drive method is not block commutation,
1071 // reset the speed output and set the drive waveform.
1072 else if (motorFlags.driveWaveform != WAVEFORM_BLOCK_COMMUTATION && motorFlags.enable == TRUE)
1073 {
1074 speedOutput = 0;
1075#if (SPEED_CONTROL_METHOD == SPEED_CONTROL_CLOSED_LOOP)
1076 PIDResetIntegrator(&pidParameters);
1077#endif
1079 BlockCommutate(motorFlags.desiredDirection, GetHall());
1080 }
1081 // If the motor is supposed to be stopped, (and it has stopped now) ...
1082 else if (motorFlags.enable == FALSE)
1083 {
1084#if (TURN_OFF_MODE == TURN_OFF_MODE_RAMP)
1085 // ... unset the drive waveform and disable PWM outputs.
1086 motorFlags.driveWaveform = WAVEFORM_UNDEFINED;
1088 ClearPWMPorts();
1089#endif
1090 // ... update the desired direction flag as this would not have been
1091 // updated if the direction was changed while the motor was running.
1093 }
1094 }
1095}
1096
1101ISR(INT0_vect)
1102{
1103 EnableUpdate();
1104}
1105
1115ISR(PCINT0_vect)
1116{
1117 static uint8_t lastHall = 0xff;
1118 uint8_t hall;
1119
1120 hall = GetHall();
1121
1122 if (motorFlags.driveWaveform == WAVEFORM_BLOCK_COMMUTATION)
1123 {
1124 BlockCommutate(motorFlags.desiredDirection, hall);
1125 }
1126
1127 // Update flags that depend on hall sensor value.
1128 ActualDirectionUpdate(lastHall, hall);
1130
1131 lastHall = hall;
1132
1133 // Reset commutation timer.
1135 commutationTicks = 0;
1136
1137 // Since the hall sensors are changing, the motor can not be stopped.
1138 // For fast access, SetFaultFlag() is not used to update this flag.
1139 // Instead, the flag is updated directly.
1140 faultFlags.motorStopped = FALSE;
1141 faultFlags.noHallConnections = FALSE;
1142}
1143
1156ISR(INT2_vect)
1157{
1158 // Update desired direction flag.
1160
1161 // Stop the motor.
1162 DisableMotor();
1163}
1164
1173ISR(TIMER4_OVF_vect)
1174{
1175 if (motorFlags.driveWaveform == WAVEFORM_BLOCK_COMMUTATION)
1176 {
1177 uint16_t dutyCycle = ((uint32_t)speedOutput * motorConfigs.tim4Top) >> 7;
1178
1179 if (dutyCycle > (uint16_t)(motorConfigs.tim4Top << 1))
1180 {
1181 dutyCycle = (uint16_t)(motorConfigs.tim4Top << 1);
1182 }
1183
1184 SetDuty(dutyCycle);
1185 }
1186
1188
1189 {
1190 // Run the speed regulation loop with constant intervals.
1191 static uint8_t speedRegTicks = 0;
1192 speedRegTicks++;
1193 if (speedRegTicks >= SPEED_CONTROLLER_TIME_BASE)
1194 {
1195 motorFlags.speedControllerRun = TRUE;
1196 speedRegTicks -= SPEED_CONTROLLER_TIME_BASE;
1197 }
1198 }
1199}
1200
1201#if (EMULATE_HALL == TRUE)
1217ISR(TIMER3_OVF_vect)
1218{
1219 if (motorFlags.enable == TRUE)
1220 {
1221 uint8_t hall = GetHall();
1222
1223 if (motorFlags.desiredDirection == DIRECTION_FORWARD)
1224 {
1225 PORTB = (PORTB & ~((1 << H1_PIN) | (1 << H2_PIN) | (1 << H3_PIN))) | ((0x07 & pgm_read_byte_near(&expectedHallSequenceForward[hall])) << H1_PIN);
1226 }
1227 else
1228 {
1229 PORTB = (PORTB & ~((1 << H1_PIN) | (1 << H2_PIN) | (1 << H3_PIN))) | ((0x07 & pgm_read_byte_near(&expectedHallSequenceReverse[hall])) << H1_PIN);
1230 }
1231 }
1232}
1233#endif
1234
1244ISR(TIMER1_OVF_vect)
1245{
1247}
1248
1263ISR(ADC_vect)
1264{
1265 switch ((ADMUX & ADC_MUX_L_BITS) | (ADCSRB & ADC_MUX_H_BITS))
1266 {
1268 // Handle ADC conversion result for speed measurement.
1269 if (motorConfigs.speedInputSource == SPEED_INPUT_SOURCE_LOCAL)
1270 {
1271 speedInput = ADCH;
1272 }
1273 ADMUX &= ~ADC_MUX_L_BITS;
1274 ADMUX |= ADC_MUX_L_IBUS;
1275 ADCSRB &= ~ADC_MUX_H_BITS;
1276 ADCSRB |= ADC_MUX_H_IBUS;
1277 break;
1279 // Handle ADC conversion result for current measurement.
1280 ibus = ADCL >> 6;
1281 ibus |= (ADCH << 2);
1282 ADMUX &= ~ADC_MUX_L_BITS;
1283 ADMUX |= ADC_MUX_L_IPHASE_U;
1284 ADCSRB &= ~ADC_MUX_H_BITS;
1285 ADCSRB |= ADC_MUX_H_IPHASE_U;
1286
1287#if (IBUS_FAULT_ENABLE == TRUE)
1288 // Debounce current error flags.
1289 static uint8_t currentErrorCount = 0;
1291 {
1292 if (currentErrorCount < 3)
1293 {
1294 currentErrorCount++;
1295 }
1296 else
1297 {
1302 FatalError();
1303 }
1304 }
1305 else
1306#endif
1308 {
1310#if (IBUS_FAULT_ENABLE == TRUE)
1311 currentErrorCount = 0;
1312#endif
1313 }
1314 else
1315 {
1317#if (IBUS_FAULT_ENABLE == TRUE)
1318 currentErrorCount = 0;
1319#endif
1320 }
1321 break;
1323 // Handle ADC conversion result for phase current measurement.
1324 iphaseU = ADCL >> 6;
1325 iphaseU |= (ADCH << 2);
1326 ADMUX &= ~ADC_MUX_L_BITS;
1327 ADMUX |= ADC_MUX_L_IPHASE_V;
1328 ADCSRB &= ~ADC_MUX_H_BITS;
1329 ADCSRB |= ADC_MUX_H_IPHASE_V;
1330 break;
1332 // Handle ADC conversion result for phase current measurement.
1333 iphaseV = ADCL >> 6;
1334 iphaseV |= (ADCH << 2);
1335 ADMUX &= ~ADC_MUX_L_BITS;
1336 ADMUX |= ADC_MUX_L_IPHASE_W;
1337 ADCSRB &= ~ADC_MUX_H_BITS;
1338 ADCSRB |= ADC_MUX_H_IPHASE_W;
1339 break;
1341 // Handle ADC conversion result for phase current measurement.
1342 iphaseW = ADCL >> 6;
1343 iphaseW |= (ADCH << 2);
1344 ADMUX &= ~ADC_MUX_L_BITS;
1345 ADMUX |= ADC_MUX_L_VBUSVREF;
1346 ADCSRB &= ~ADC_MUX_H_BITS;
1347 ADCSRB |= ADC_MUX_H_VBUSVREF;
1348 break;
1350 // Handle ADC conversion result for gate voltage reference measurement.
1351 vbusVref = ADCL >> 6;
1352 vbusVref |= (ADCH << 2);
1353 ADMUX &= ~ADC_MUX_L_BITS;
1354 ADMUX |= ADC_MUX_L_SPEED;
1355 ADCSRB &= ~ADC_MUX_H_BITS;
1356 ADCSRB |= ADC_MUX_H_SPEED;
1357 break;
1358 default:
1359 // This is probably an error and should be handled.
1363 FatalError();
1364 break;
1365 }
1366
1367 // Clear Timer/Counter0 overflow flag.
1368 TIFR0 = (1 << TOV0);
1369}
1370
1382static void SetFaultFlag(fault_flag_t flag, uint8_t value)
1383{
1384 if (motorFlags.fatalFault)
1385 {
1386 // Fatal fault active, cannot set any more flags.
1387 return;
1388 }
1389
1390 switch (flag)
1391 {
1392 case FAULT_RESERVED:
1393 faultFlags.reserved = value;
1394 break;
1396 faultFlags.reverseDirection = value;
1397 break;
1399 faultFlags.motorStopped = value;
1400 break;
1401 case FAULT_OVER_CURRENT:
1402 faultFlags.overCurrent = value;
1403 break;
1405 faultFlags.noHallConnections = value;
1406 break;
1407 case FAULT_USER_FLAG1:
1408 faultFlags.userFlag1 = value;
1409 break;
1410 case FAULT_USER_FLAG2:
1411 faultFlags.userFlag2 = value;
1412 break;
1413 case FAULT_USER_FLAG3:
1414 faultFlags.userFlag3 = value;
1415 break;
1416 default:
1417 return; // Invalid flag
1418 }
1419
1420 return; // Success
1421}
Motor config header file.
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:182
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_BITS
High ADC channel selection bit (MUX5) mask.
Definition config.h:973
#define ADC_MUX_L_BITS
Lower ADC channel selection bits (MUX4:0) mask.
Definition config.h:971
#define TIM4_TOP(tim4Freq)
Definition config.h:1216
#define DEAD_TIME_HALF(deadTime)
This value specifies half the dead time in number of clock cycles. Divide by frequency to get duratio...
Definition config.h:1237
#define DT_PRESCALER_DIV_PATTERN(dtPrescaler)
Deadtime generator pre-scaler selection bits based on pre-scaler value.
Definition config.h:1227
#define TIM3_TOP
Calculated top value for Timer 3.
Definition config.h:1245
#define TIM4_PRESCALER_DIV_PATTERN(tim4Prescaler)
Timer 4 clock select bits based on pre-scaler value.
Definition config.h:1209
#define PLL_POSTSCALER_DIV_1_5
PLL Post-scaler - division factor 1.5.
Definition config.h:901
#define H2_PIN
Pin where H2 is connected.
Definition config.h:711
#define WAVEFORM_BLOCK_COMMUTATION
Waveform constant for block commutation.
Definition config.h:777
#define ADC_MUX_L_IBUS
Lower analog channel selection bits (MUX4:0) for motor current measurement.
Definition config.h:723
#define DIRECTION_FORWARD
Forward direction flag value.
Definition config.h:699
#define ADC_MUX_H_IPHASE_V
High analog channel selection bit (MUX5) for for motor current measurement.
Definition config.h:733
#define ADC_MUX_H_VBUSVREF
High analog channel selection bit (MUX5) for for motor vbusVref measurement.
Definition config.h:741
#define WAVEFORM_UNDEFINED
Waveform status flag used for coasting.
Definition config.h:779
#define FAULT_PIN_2
Fault Pin 2.
Definition config.h:771
#define ADC_MUX_L_IPHASE_W
Lower analog channel selection bits (MUX4:0) for motor current measurement.
Definition config.h:735
#define DIRECTION_COMMAND_PIN
Pin where direction command input is located.
Definition config.h:753
#define SPEED_INPUT_SOURCE_LOCAL
Speed input source - Local or speed input pin.
Definition config.h:763
#define FAST_ACCESS(register_address)
Assign a specific memory address to a variable for fast access.
Definition config.h:862
#define CHOOSE_DT_PRESCALER(deadTime)
Macro to choose Timer4 dead time pre-scaler based on the dead time.
Definition config.h:826
#define ADC_MUX_L_VBUSVREF
Lower analog channel selection bits (MUX4:0) for motor vbusVref measurement.
Definition config.h:739
#define SPEED_CONTROLLER_MAX_INPUT
Maximum Speed Reference Input.
Definition config.h:805
#define DIRECTION_REVERSE
Reverse direction flag value.
Definition config.h:701
#define ADC_MUX_L_SPEED
Definition config.h:718
struct motorflags motorflags_t
Collection of all motor control flags.
#define ENABLE_PIN
Enable input pin.
Definition config.h:755
#define ADC_MUX_H_IPHASE_W
High analog channel selection bit (MUX5) for for motor current measurement.
Definition config.h:737
#define PWM_PATTERN_PORTC
Bit pattern of PWM pins placed on PORTC (Phase B).
Definition config.h:684
fault_flag_t
Enumeration of fault flags.
Definition config.h:1156
#define ADC_TRIGGER
ADC trigger used in this application.
Definition config.h:749
#define HALL_PIN
PIN register for Hall sensor input.
Definition config.h:707
struct motorconfigs motorconfigs_t
Collection of motor configurations.
#define ADC_MUX_L_IPHASE_V
Lower analog channel selection bits (MUX4:0) for motor current measurement.
Definition config.h:731
#define IBUS_PIN
IBUS ADC input pin (used to check if board is attached).
Definition config.h:759
#define ADC_MUX_H_IBUS
High analog channel selection bit (MUX5) for for motor current measurement.
Definition config.h:725
#define TRUE
TRUE constant value, defined to be compatible with comparisons.
Definition config.h:661
#define FALSE
FALSE constant value.
Definition config.h:659
#define CHOOSE_TIM4_PRESCALER(tim4Freq)
Macro to choose Timer4 pre-scaler.
Definition config.h:808
#define ADC_PRESCALER
ADC clock pre-scaler used in this application.
Definition config.h:745
#define REMOTE_PIN
Remote input pin.
Definition config.h:757
#define ADC_MUX_L_IPHASE_U
Lower analog channel selection bits (MUX4:0) for motor current measurement.
Definition config.h:727
#define FORCE_INLINE
Macro for forcing inline expansion of functions.
Definition config.h:846
#define PWM_PATTERN_PORTB
Bit pattern of PWM pins placed on PORTB (Phase A).
Definition config.h:682
#define ADC_MUX_H_SPEED
Definition config.h:721
#define PWM_PATTERN_PORTD
Bit pattern of PWM pins placed on PORTD (Phase C).
Definition config.h:686
#define FAULT_PIN_3
Fault Pin 3.
Definition config.h:773
#define DIRECTION_UNKNOWN
Unknown direction flag value.
Definition config.h:703
struct faultflags faultflags_t
Collection of all fault flags.
#define ADC_MUX_H_IPHASE_U
High analog channel selection bit (MUX5) for for motor current measurement.
Definition config.h:729
#define H3_PIN
Pin where H3 is connected.
Definition config.h:713
#define H1_PIN
Pin where H1 is connected.
Definition config.h:709
#define ADC_REFERENCE_VOLTAGE
ADC voltage reference used in this application.
Definition config.h:747
#define FAULT_PIN_1
Fault Pin 1.
Definition config.h:769
@ FAULT_OVER_CURRENT
Has it tripped the over current limit?
Definition config.h:1164
@ FAULT_USER_FLAG1
Is user flag 1 set?
Definition config.h:1168
@ FAULT_NO_HALL_CONNECTIONS
Is there no hall connections?
Definition config.h:1166
@ FAULT_USER_FLAG2
Is user flag 2 set?
Definition config.h:1170
@ FAULT_RESERVED
Reserved flag, always false.
Definition config.h:1158
@ FAULT_USER_FLAG3
Is user flag 3 set?
Definition config.h:1172
@ FAULT_REVERSE_DIRECTION
Is motor spinning in an unexpected direction?
Definition config.h:1160
@ FAULT_MOTOR_STOPPED
Is motor stopped?
Definition config.h:1162
#define TIM1_CLOCK_DIV_64
Timer1 clock - i/o clk with division factor 64.
Definition config.h:936
#define TIM1_CLOCK_DIV_8
Timer1 clock - i/o clk with division factor 8.
Definition config.h:934
#define IBUS_WARNING_THRESHOLD
Hi-side Current (IBUS) Warning Threshold (Register Value)
Definition config.h:367
#define PID_K_P
PID Controller Proportional Gain Constant (Only for Closed Loop)
Definition config.h:509
#define F_MOSFET
Desired Switching Frequency for MOSFET Gate Signals.
Definition config.h:157
#define IBUS_ERROR_THRESHOLD
Hi-side Current (IBUS) Error Threshold (Register Value)
Definition config.h:406
#define SPEED_CONTROLLER_MAX_DELTA
Speed Controller Maximum Delta (Applicable for Open Loop Control)
Definition config.h:469
#define PID_K_D
PID Controller Derivative Gain Constant (Only for Closed Loop)
Definition config.h:566
#define SPEED_CONTROLLER_MAX_SPEED
Speed Controller Maximum Speed.
Definition config.h:490
#define SPEED_CONTROLLER_TIME_BASE
Speed Controller Time Base.
Definition config.h:448
#define COMMUTATION_TICKS_STOPPED
Commutation Stopped Limit.
Definition config.h:246
#define PID_K_I
PID Controller Integral Gain Constant (Only for Closed Loop)
Definition config.h:528
#define DEAD_TIME
Dead Time Specification.
Definition config.h:186
static void BlockCommutate(const uint8_t direction, uint8_t hall)
Perform block commutation based on direction and hall sensor input.
Definition main.ino:865
static uint8_t GetHall(void)
Read the hall sensor inputs and decode the hall state.
Definition main.ino:903
static void PortsInit(void)
Initialize I/O port directions and pull-up resistors.
Definition main.ino:407
volatile uint16_t vbusVref
VBUS voltage measurement (Register Value)
Definition main.ino:255
static void TimersSetModeBlockCommutation(void)
Configures timers for block commutation.
Definition main.ino:817
static void TimersWaitForNextPWMCycle(void)
Wait for the start of the next PWM cycle.
Definition main.ino:844
static void ADCInit(void)
Initializes the ADC.
Definition main.ino:536
static void SetFaultFlag(fault_flag_t flag, uint8_t value)
Sets a fault flag value.
Definition main.ino:1382
volatile motorflags_t motorFlags
Motor control flags placed in I/O space for fast access.
Definition main.ino:50
static void SpeedController(void)
Speed regulator loop.
Definition main.ino:716
static void DisablePWMOutputs(void)
Disable PWM output pins.
Definition main.ino:1005
volatile uint8_t speedInput
The most recent "speed" input measurement.
Definition main.ino:101
static void FlagsInit(void)
Initializes motorFlags and faultFlags.
Definition main.ino:339
volatile uint16_t ibus
Hi-side Current (IBUS) measurement (Register Value).
Definition main.ino:137
volatile motorconfigs_t motorConfigs
Motor Configs.
Definition main.ino:66
static void PinChangeIntInit(void)
Initialize pin change interrupts.
Definition main.ino:500
void setup(void)
Main initialization function.
Definition main.ino:267
static void PLLInit(void)
Initialize PLL (Phase-Locked Loop)
Definition main.ino:381
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:943
static void ReverseRotationSignalUpdate(void)
Update the reverse rotation flag.
Definition main.ino:974
volatile uint16_t commutationTicks
The number of 'ticks' between two hall sensor changes (counter).
Definition main.ino:81
static void CommutationTicksUpdate(void)
Update the 'tick' counter and check for a stopped motor.
Definition main.ino:1040
static void DesiredDirectionUpdate(void)
Updates global desired direction flag.
Definition main.ino:918
volatile int16_t iphaseW
In-line Phase W current current measurement (Register Value).
Definition main.ino:226
volatile uint8_t speedOutput
The most recent "speed" output from the speed controller.
Definition main.ino:108
volatile faultflags_t faultFlags
Fault flags placed in I/O space for fast access.
Definition main.ino:60
static void SetDuty(const uint16_t duty)
Set duty cycle for TIM4.
Definition main.ino:799
static void EnablePWMOutputs(void)
Enable PWM output pins.
Definition main.ino:992
volatile uint16_t lastCommutationTicks
The number of 'ticks' between two hall sensor changes (store).
Definition main.ino:94
void TimersInit(void)
Initializes and synchronizes Timers.
Definition main.ino:455
static void EnableUpdate(void)
Check whether the enable pin is set and update flags accordingly.
Definition main.ino:633
static uint16_t ADCSingleConversion(void)
Perform a single ADC conversion.
Definition main.ino:600
static void ClearPWMPorts(void)
Clear PWM output ports.
Definition main.ino:1018
volatile int16_t iphaseU
In-line Phase U current current measurement (Register Value).
Definition main.ino:167
static void FatalError()
Handle a fatal error and enter a fault state.
Definition main.ino:781
static void ConfigsInit(void)
Initializes motorConfigs.
Definition main.ino:366
static void DisableMotor(void)
Disable motor.
Definition main.ino:659
volatile int16_t iphaseV
In-line Phase V current current measurement (Register Value).
Definition main.ino:196
static void RemoteUpdate(void)
Check whether the remote pin is set and update flags accordingly.
Definition main.ino:679
void loop()
Main Loop Function.
Definition main.ino:321
ISR(INT0_vect)
Enable interrupt service routine.
Definition main.ino:1101
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.
struct pidData pidData_t
PID Status.
void ScpiInput(Stream &interface)
Processes incoming data from a serial interface for SCPI commands.
Definition scpi.cpp:122
void ScpiInit(void)
Initializes the SCPI command parser and registers all supported commands.
Definition scpi.cpp:71
SCPI implementation header file.
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