This file contains the full implementation of the motor control, except the PID-controller.
Definition in file main.c.
#include <ioavr.h>
#include <inavr.h>
#include "stdint.h"
#include "PMSM.h"
#include "PMSMtables.h"
Include dependency graph for main.c:

Go to the source code of this file.
Functions | |
| static void | ActualDirectionUpdate (uint8_t lastHall, const uint8_t newHall) |
| Updates global actual direction flag based on the two latest hall values. | |
| __interrupt void | ADCCompleteISR (void) |
| AD conversion complete interrupt service routine. | |
| static void | ADCInit (void) |
| Initializes the ADC. | |
| static void | AdjustSineTableIndex (const uint16_t increment) |
| Adjusts the sine table index according to the current increment. | |
| static void | BlockCommutate (const uint8_t direction, uint8_t hall) |
| Performs block commutation according to running direction and hall sensor input. | |
| static void | BlockCommutationSetDuty (const uint8_t duty) |
| Sets duty cycle for block commutation. | |
| static void | CheckEmergencyShutdown (void) |
| Checks whether emergency shutdown is set at startup. | |
| static void | CommutationTicksUpdate (void) |
| Updates the 'tick' counter and checks for stopped motor. | |
| static void | DesiredDirectionUpdate (void) |
| Updates global desired direction flag. | |
| __interrupt void | DirectionInputChangeISR (void) |
| Direction input change interrupt service routine. | |
| static void | DisablePWMOutputs (void) |
| Disables PWM output pins. | |
| __interrupt void | EmergencyInterruptISR (void) |
| Emergency shut-off interrupt service routine. | |
| static void | EnablePWMOutputs (void) |
| Enables PWM output pins. | |
| static uint8_t | GetActualDirection (void) |
| Returns the actual direction of the motor. | |
| static uint8_t | GetDesiredDirection (void) |
| Returns the desired direction. | |
| static uint8_t | GetHall (void) |
| Reads the hall sensor inputs. | |
| __interrupt void | HallChangeISR (void) |
| Hall sensor change interrupt service routine. | |
| static void | InsertDeadband (const uint8_t compareValue, uint8_t *compareHighPtr, uint8_t *compareLowPtr) |
| Returns the high and low values with deadband for a given compare value. | |
| static uint8_t | IsMotorSynchronized (void) |
| Returns the motor synchronized flag. | |
| void | main (void) |
| Main function / initialization. | |
| static void | MotorSynchronizedUpdate (void) |
| Updates the global motor synchronized flag. | |
| static void | PinChangeIntInit (void) |
| Initialize pin change interrupts. | |
| static void | PortsInit (void) |
| Initializes I/O port directions and pull-up resistors. | |
| static void | ReverseRotationSignalUpdate (void) |
| Updates the reverse rotation signal output pin value. | |
| static void | SetAdvanceCommutation (const uint8_t advanceCommutation) |
| Sets the lead angle. | |
| static uint16_t | SineTableIncrementCalculate (const uint16_t ticks) |
| Calculates the increment for sine table iteration. | |
| static void | SpeedController (void) |
| Speed regulator loop. | |
| static void | TachoOutputUpdate (const uint8_t hall) |
| Updates the tacho output pin signal. | |
| __interrupt void | Timer1CaptureISR (void) |
| Timer1 Capture Evente interrupt service routine. | |
| static void | TimersInit (void) |
| Initializes and synchronizes Timers. | |
| static void | TimersSetModeBlockCommutation (void) |
| Configures timers for block commutation. | |
| static void | TimersSetModeBrake (void) |
| Configures timers for braking and starts braking. | |
| static void | TimersSetModeSinusoidal (void) |
| Configures timers for sine wave generation. | |
| static void | TimersWaitForNextPWMCycle (void) |
| Waits for the start of the next PWM cycle. | |
Variables | |
| __no_init __regvar volatile uint8_t | advanceCommutationSteps |
| The lead angle or advance commutation angle. | |
| __no_init __regvar volatile uint8_t | amplitude |
| The amplitude of the generated sine waves. | |
| __no_init __regvar volatile uint16_t | commutationTicks |
| The number of 'ticks' between two hall sensor changes. | |
| volatile uint8_t | current |
| Current measurement. | |
| __no_init __regvar volatile uint16_t | sineTableIncrement |
| Increment used for sine table iteration. | |
| __no_init __regvar volatile uint16_t | sineTableIndex |
| Index into sine table. | |
| __no_init __regvar volatile uint8_t | sineTableNextSectorStart |
| Index to the end of the current commutation sector. | |
| volatile uint8_t | SpeedControllerRun = FALSE |
| Speed controller run flag. | |
| volatile uint8_t | speedInput |
| The most recent speed input measurement. | |
| __io volatile PMSMflags_t fastFlags | x1e |
| Motor control flags placed in I/O space for fast access. | |
|
||||||||||||
|
Updates global actual direction flag based on the two latest hall values. Calling this function with the last two hall sensor values as parameters triggers an update of the global actualDirection flag.
Definition at line 594 of file main.c. References PMSMflags::actualDirection, DIRECTION_FORWARD, DIRECTION_REVERSE, DIRECTION_UNKNOWN, expectedHallSequenceForward, expectedHallSequenceReverse, FALSE, and PMSMflags::motorSynchronized. Referenced by HallChangeISR(). 00595 { 00596 //Make sure that lastHall is within bounds of table. If not, set to 0, which is 00597 //also an illegal hall value, but legal table index. 00598 if (lastHall > 6) 00599 { 00600 lastHall = 0; 00601 } 00602 if (expectedHallSequenceForward[lastHall] == newHall) 00603 { 00604 fastFlags.actualDirection = DIRECTION_FORWARD; 00605 } 00606 else if (expectedHallSequenceReverse[lastHall] == newHall) 00607 { 00608 fastFlags.actualDirection = DIRECTION_REVERSE; 00609 } 00610 else 00611 { 00612 PMSMflags_t tempFlags = fastFlags; 00613 tempFlags.actualDirection = DIRECTION_UNKNOWN; 00614 tempFlags.motorSynchronized = FALSE; 00615 fastFlags = tempFlags; 00616 } 00617 }
|
|
|
AD conversion complete interrupt service routine. This interrupt service routine is automatically executed every time an AD conversion is finished and the converted result is available in the ADC data register. The switch/case construct makes sure the converted value is stored in the variable corresponding to the selected channel and changes the channel for the next ADC measurement. More ADC measurements can be added to the cycle by extending the switch/ case construct. Only the 8 most significant bits of the ADC result are used. Definition at line 1122 of file main.c. References ADMUX_CURRENT, ADMUX_SPEED_REF, current, and speedInput. 01123 { 01124 switch (ADMUX) 01125 { 01126 case ADMUX_SPEED_REF: 01127 speedInput = ADCH; 01128 ADMUX = ADMUX_CURRENT; 01129 break; 01130 case ADMUX_CURRENT: 01131 current = ADCH; 01132 ADMUX = ADMUX_SPEED_REF; 01133 break; 01134 default: 01135 //This is probably an error and should be handled. 01136 break; 01137 } 01138 01139 //Clear Timer/counter0 overflow flag. 01140 TIFR0 = (1 << TOV0); 01141 }
|
|
|
Initializes the ADC. This function initializes the ADC for speed reference measurements. The ADC will operate in free-running mode, and reading is done in the ADC complete interrupt service routine. Definition at line 266 of file main.c. References ADC_PRESCALER, and ADMUX_SPEED_REF. Referenced by main(). 00267 { 00268 //Select initial AD conversion channel. 00269 ADMUX = ADMUX_SPEED_REF; 00270 00271 //Initialize ADC. 00272 ADCSRA = (1 << ADEN) | (1 << ADSC) | (1 << ADATE) | (1 << ADIF) | (1 << ADIE) | ADC_PRESCALER; 00273 00274 //Set trigger source to Timer/Counter0 overflow. 00275 ADCSRB = (1 << ADTS2) | (0 << ADTS1) | (0 << ADTS0); 00276 }
|
|
|
Adjusts the sine table index according to the current increment. This function increases the sine table index with the given increment The index is then adjusted to be within the table length.
Definition at line 713 of file main.c. References SINE_TABLE_LENGTH, sineTableIndex, and sineTableNextSectorStart. Referenced by Timer1CaptureISR(). 00714 { 00715 sineTableIndex += increment; 00716 00717 // If the table index is out of bounds, wrap the index around the table end 00718 // to continue from the beginning. Also wrap the next sector start index. 00719 if ((sineTableIndex >> 8) >= SINE_TABLE_LENGTH) 00720 { 00721 sineTableIndex -= (SINE_TABLE_LENGTH << 8); 00722 sineTableNextSectorStart -= SINE_TABLE_LENGTH; 00723 } 00724 00725 //Make copy of sineNextSectorStart to specify order of volatile access. 00726 uint8_t nextSectorStart = sineTableNextSectorStart; 00727 if ((sineTableIndex >> 8) > nextSectorStart) 00728 { 00729 sineTableIndex = (nextSectorStart << 8); 00730 } 00731 }
|
|
||||||||||||
|
Performs block commutation according to running direction and hall sensor input. This function performs a block commutation according to the specified running direction and hall sensor input.
Definition at line 520 of file main.c. References blockCommutationTableForward, blockCommutationTableReverse, DIRECTION_FORWARD, and DisablePWMOutputs(). Referenced by CommutationTicksUpdate(), and HallChangeISR(). 00521 { 00522 uint8_t const __flash *pattern; 00523 00524 if (direction == DIRECTION_FORWARD) 00525 { 00526 pattern = blockCommutationTableForward; 00527 } 00528 else 00529 { 00530 pattern = blockCommutationTableReverse; 00531 } 00532 pattern += (hall * 2); 00533 00534 DisablePWMOutputs(); 00535 DDRB |= *pattern++; 00536 DDRD |= *pattern; 00537 }
Here is the call graph for this function: ![]() |
|
|
Sets duty cycle for block commutation. This function sets duty cycle when block commutation is used. Never call this function when sine wave generation is used.
Definition at line 461 of file main.c. Referenced by Timer1CaptureISR(), and TimersSetModeBlockCommutation(). 00462 { 00463 // Set all compare registers to new duty cycle value. 00464 OCR0A = OCR0B = OCR1AL = OCR1BL = OCR2A = OCR2B = duty; 00465 }
|
|
|
Checks whether emergency shutdown is set at startup. This function checks whether emergency shut-off signal is set at startup and takes action accordingly. This function is only needed at startup, since pin change interrupts are enabled for these signals.
Definition at line 290 of file main.c. References EMERGENCY_SHUTDOWN_PIN. Referenced by main(). 00291 { 00292 if ( (PINB & (1 << EMERGENCY_SHUTDOWN_PIN)) != 0) 00293 { 00294 //Insert code here to handle emercency shutdown signal at startup. 00295 } 00296 }
|
|
|
Updates the 'tick' counter and checks for stopped motor. This function should be run at every PWM timer overflow to ensure that all 'ticks' are counted. It increases the 'tick' counter until it reaches the maximum tick limit that corresponds to what is considered a stopped or stalled motor. In that case, the global motor stopped flag is set. Definition at line 816 of file main.c. References BlockCommutate(), COMMUTATION_TICKS_STOPPED, commutationTicks, FALSE, GetDesiredDirection(), GetHall(), PID_Reset_Integrator(), TimersSetModeBlockCommutation(), TRUE, and WAVEFORM_BLOCK_COMMUTATION. Referenced by Timer1CaptureISR(). 00817 { 00818 if (commutationTicks < COMMUTATION_TICKS_STOPPED) 00819 { 00820 commutationTicks++; 00821 } 00822 else 00823 { 00824 fastFlags.motorStopped = TRUE; 00825 fastFlags.motorSynchronized = FALSE; 00826 if (fastFlags.driveWaveform != WAVEFORM_BLOCK_COMMUTATION) 00827 { 00828 TimersSetModeBlockCommutation(); 00829 BlockCommutate(GetDesiredDirection(), GetHall()); 00830 00831 #if (SPEED_CONTROL_METHOD == SPEED_CONTROL_CLOSED_LOOP) 00832 PID_Reset_Integrator(&pidParameters); 00833 #endif 00834 } 00835 } 00836 }
Here is the call graph for this function: ![]() |
|
|
Updates global desired direction flag. Running this function triggers a reading of the direction input pin. The desiredDirection flag is set accordingly. Definition at line 572 of file main.c. References DIRECTION_COMMAND_PIN, DIRECTION_FORWARD, and DIRECTION_REVERSE. Referenced by DirectionInputChangeISR(), and main(). 00573 { 00574 if ( (PIND & (1 << DIRECTION_COMMAND_PIN)) != 0 ) 00575 { 00576 fastFlags.desiredDirection = DIRECTION_REVERSE; 00577 } 00578 else 00579 { 00580 fastFlags.desiredDirection = DIRECTION_FORWARD; 00581 } 00582 }
|
|
|
Direction input change interrupt service routine. This ISR is called every time the direction input pin changes state. The desired direction flag is updated accordingly. The motor control then goes into a state where it needs a stopped motor or a synchronization before any driving of the motor is performed. Definition at line 999 of file main.c. References DesiredDirectionUpdate(), DisablePWMOutputs(), FALSE, TimersSetModeBrake(), and WAVEFORM_UNDEFINED. 01000 { 01001 //Update desired direction flag. 01002 DesiredDirectionUpdate(); 01003 01004 #if (TURN_MODE == TURN_MODE_COAST) 01005 //Disable driver signals to let motor coast. The motor will automatically 01006 //start once it is synchronized or stopped. 01007 DisablePWMOutputs(); 01008 fastFlags.motorSynchronized = FALSE; 01009 fastFlags.motorStopped = FALSE; 01010 fastFlags.driveWaveform = WAVEFORM_UNDEFINED; 01011 #endif 01012 01013 #if (TURN_MODE == TURN_MODE_BRAKE) 01014 //Set motor in brake mode. The motor will automatically start once it is 01015 //synchronized or stopped. 01016 fastFlags.motorSynchronized = FALSE; 01017 fastFlags.motorStopped = FALSE; 01018 TimersSetModeBrake(); // Automatically sets driveWaveform. 01019 #endif 01020 }
Here is the call graph for this function: ![]() |
|
|
Disables PWM output pins. This function disables PWM outputs by setting the port dierction for all PWM pins as inputs, thus overriding the PWM. The PWM configuration itself is not altered in any way by running this function. Definition at line 800 of file main.c. References PWM_PATTERN_PORTB, and PWM_PATTERN_PORTD. Referenced by BlockCommutate(), DirectionInputChangeISR(), EmergencyInterruptISR(), TimersSetModeBlockCommutation(), TimersSetModeBrake(), and TimersSetModeSinusoidal(). 00801 { 00802 DDRB &= ~PWM_PATTERN_PORTB; 00803 DDRD &= ~PWM_PATTERN_PORTD; 00804 }
|
|
|
Emergency shut-off interrupt service routine. This ISR is triggered if the emergency shutdown input changes state.
Definition at line 901 of file main.c. References DisablePWMOutputs(). 00902 { 00903 DisablePWMOutputs(); 00904 for (;;) 00905 { 00906 00907 } 00908 }
Here is the call graph for this function: ![]() |
|
|
Enables PWM output pins. This function enables PWM outputs by setting the port direction for all PWM pins as output. The PWM configuration itself is not altered in any way by running this function. Definition at line 786 of file main.c. References PWM_PATTERN_PORTB, and PWM_PATTERN_PORTD. Referenced by TimersSetModeBlockCommutation(), TimersSetModeBrake(), and TimersSetModeSinusoidal(). 00787 { 00788 DDRB |= PWM_PATTERN_PORTB; 00789 DDRD |= PWM_PATTERN_PORTD; 00790 }
|
|
|
Returns the actual direction of the motor. This function returns the actual direction of the motor.
Definition at line 502 of file main.c. Referenced by ReverseRotationSignalUpdate().
|
|
|
Returns the desired direction. This function returns the current desired direction.
Definition at line 479 of file main.c. Referenced by CommutationTicksUpdate(), HallChangeISR(), ReverseRotationSignalUpdate(), and Timer1CaptureISR(). 00480 { 00481 return (uint8_t)fastFlags.desiredDirection; 00482 }
|
|
|
Reads the hall sensor inputs. This function reads the hall sensor inputs and converts it to a number from 1 to 6 by combining the hall sensors as bits: H3|H2|H1.
Definition at line 556 of file main.c. References H1_PIN, H2_PIN, and H3_PIN. Referenced by CommutationTicksUpdate(), and HallChangeISR(). 00557 { 00558 uint8_t hall; 00559 00560 hall = PINC & ((1 << H3_PIN) | (1 << H2_PIN) | (1 << H1_PIN)); 00561 hall >>= H1_PIN; 00562 return hall; 00563 }
|
|
|
Hall sensor change interrupt service routine. This interrupt service routine is called every time any of the hall sensors change. The sine table index is updated to reflect the position indicated by the hall sensors. A new increment is calculated, based on the time since last hall sensor change. The Tacho output signal is updated. The actual direction is updated. The reverse rotation output signal is updated. The motor stopped flag is set to false, since the motor is obviously not stopped when there is a hall change. Definition at line 930 of file main.c. References ActualDirectionUpdate(), advanceCommutationSteps, BlockCommutate(), commutationTicks, CSOffsetsForward, CSOffsetsReverse, DIRECTION_FORWARD, FALSE, GetDesiredDirection(), GetHall(), IsMotorSynchronized(), MotorSynchronizedUpdate(), ReverseRotationSignalUpdate(), sineTableIncrement, SineTableIncrementCalculate(), sineTableIndex, sineTableNextSectorStart, TABLE_ELEMENTS_PER_COMMUTATION_SECTOR, TachoOutputUpdate(), TimersSetModeSinusoidal(), WAVEFORM_BLOCK_COMMUTATION, and WAVEFORM_SINUSOIDAL. 00931 { 00932 static uint8_t lastHall = 0xff; 00933 uint8_t hall; 00934 00935 hall = GetHall(); 00936 00937 MotorSynchronizedUpdate(); 00938 uint8_t synch = IsMotorSynchronized(); 00939 if ((fastFlags.driveWaveform != WAVEFORM_SINUSOIDAL) && (synch)) 00940 { 00941 TimersSetModeSinusoidal(); 00942 } 00943 00944 //If sinusoidal driving is used, synchronize sine wave generation to the 00945 //current hall sensor value. Advance commutation is also 00946 //added in the process. 00947 if (fastFlags.driveWaveform == WAVEFORM_SINUSOIDAL) 00948 { 00949 uint16_t tempIndex; 00950 if (GetDesiredDirection() == DIRECTION_FORWARD) 00951 { 00952 tempIndex = (CSOffsetsForward[hall] + advanceCommutationSteps) << 8; 00953 } 00954 else 00955 { 00956 tempIndex = (CSOffsetsReverse[hall] + advanceCommutationSteps) << 8; 00957 } 00958 sineTableIndex = tempIndex; 00959 00960 //Adjust next sector start index. It might be set to a value larger than 00961 //SINE_TABLE_LENGTH at this point. This is adjusted in AdjustSineTableIndex 00962 //and should not be done here, as it will cause problems when advance 00963 //commutation is used. 00964 sineTableNextSectorStart = (tempIndex >> 8) + TABLE_ELEMENTS_PER_COMMUTATION_SECTOR; 00965 } 00966 00967 //If block commutation is used. Commutate according to hall signal. 00968 else if (fastFlags.driveWaveform == WAVEFORM_BLOCK_COMMUTATION) 00969 { 00970 BlockCommutate(GetDesiredDirection(), hall); 00971 } 00972 00973 //Update internal and external signals that depend on hall sensor value. 00974 TachoOutputUpdate(hall); 00975 ActualDirectionUpdate(lastHall, hall); 00976 ReverseRotationSignalUpdate(); 00977 00978 lastHall = hall; 00979 00980 //Calculate new increment for sine wave generation and reset commutation 00981 //timer. 00982 sineTableIncrement = SineTableIncrementCalculate(commutationTicks); 00983 commutationTicks = 0; 00984 00985 //Since the hall sensors are changing, the motor can not be stopped. 00986 fastFlags.motorStopped = FALSE; 00987 }
Here is the call graph for this function: ![]() |
|
||||||||||||||||
|
Returns the high and low values with deadband for a given compare value. This function takes as argument a desired compare value and inserts a symmetric deadband. The compare values for high and low side with deadband are returned through the two supplied pointers. The constant DEAD_TIME_HALF is used as deadband, and the resulting deadtime will be DEAD_TIME_HALF clock cycles times 2.
Definition at line 661 of file main.c. References DEAD_TIME_HALF. Referenced by Timer1CaptureISR(). 00662 { 00663 if (compareValue <= DEAD_TIME_HALF) 00664 { 00665 *compareHighPtr = 0x00; 00666 *compareLowPtr = compareValue; 00667 } 00668 else if (compareValue >= (0xff - DEAD_TIME_HALF)) 00669 { 00670 *compareHighPtr = 0xff - (2 * DEAD_TIME_HALF); 00671 *compareLowPtr = 0xff; 00672 } 00673 else 00674 { 00675 *compareHighPtr = compareValue - DEAD_TIME_HALF; 00676 *compareLowPtr = compareValue + DEAD_TIME_HALF; 00677 } 00678 }
|
|
|
Returns the motor synchronized flag. This function returns the motor synchronized flag.
Definition at line 882 of file main.c. Referenced by HallChangeISR(). 00883 { 00884 return (uint8_t)(fastFlags.motorSynchronized); 00885 }
|
|
|
Main function / initialization. The main function initializes all subsystems needed for motor control and enables interrupts, which kicks off the fully interrupt-driven motor control. The main function goes into an eternal loop where it does nothing. Definition at line 135 of file main.c. References PMSMflags::actualDirection, ADCInit(), CheckEmergencyShutdown(), PMSMflags::desiredDirection, DesiredDirectionUpdate(), DIRECTION_UNKNOWN, PMSMflags::driveWaveform, FALSE, PMSMflags::motorStopped, PMSMflags::motorSynchronized, PID_Init(), PID_K_D, PID_K_I, PID_K_P, PinChangeIntInit(), PortsInit(), SetAdvanceCommutation(), SpeedController(), SpeedControllerRun, TimersInit(), and WAVEFORM_UNDEFINED. 00136 { 00137 //Initialize peripherals. 00138 PortsInit(); 00139 TimersInit(); 00140 PinChangeIntInit(); 00141 ADCInit(); 00142 00143 SetAdvanceCommutation(0); 00144 00145 #if (SPEED_CONTROL_METHOD == SPEED_CONTROL_CLOSED_LOOP) 00146 PID_Init(PID_K_P, PID_K_I, PID_K_D, &pidParameters); 00147 #endif 00148 00149 //Do not start until everything is ready. 00150 CheckEmergencyShutdown(); 00151 00152 //Initialize fastflags. Use temporary variable to avoid several accesses to 00153 //volatile variable. 00154 { 00155 PMSMflags_t fastFlagsInitial; 00156 00157 // Set motorStopped to FALSE at startup. This will make sure that the motor 00158 // is not started if it is not really stopped. If it is stopped, this variable 00159 // will quickly be updated. 00160 fastFlagsInitial.motorStopped = FALSE; 00161 00162 // Set motorSyncronized to FALSE at startup. This will prevent the motor from being 00163 // driven until the motor is in synch or stopped. 00164 fastFlagsInitial.motorSynchronized = FALSE; 00165 fastFlagsInitial.actualDirection = DIRECTION_UNKNOWN; 00166 fastFlagsInitial.desiredDirection = 0; 00167 fastFlagsInitial.driveWaveform = WAVEFORM_UNDEFINED; 00168 00169 fastFlags = fastFlagsInitial; 00170 } 00171 00172 DesiredDirectionUpdate(); 00173 00174 // Enable Timer1 capture event interrupt. 00175 TIMSK1 |= (1 << ICIE1); 00176 00177 //Enable interrupts globally and let motor driver take over. 00178 __enable_interrupt(); 00179 for(;;) 00180 { 00181 if (SpeedControllerRun) 00182 { 00183 SpeedController(); 00184 SpeedControllerRun = FALSE; 00185 } 00186 } 00187 }
Here is the call graph for this function: ![]() |
|
|
Updates the global motor synchronized flag. This function updates the global motor synchronized flag. The motor control is considered to be synchronized with the motor when it is not stopped and the driver has detected a direction of rotation that corresponds to the desired direction a predefined number of times. Definition at line 847 of file main.c. References PMSMflags::actualDirection, PMSMflags::desiredDirection, FALSE, PMSMflags::motorStopped, PMSMflags::motorSynchronized, SYNCHRONIZATION_COUNT, and TRUE. Referenced by HallChangeISR(). 00848 { 00849 static uint8_t synchCount = 0; 00850 00851 PMSMflags_t tempFlags; 00852 00853 tempFlags = fastFlags; 00854 00855 if ((tempFlags.desiredDirection == tempFlags.actualDirection) && 00856 (tempFlags.motorStopped == FALSE) && (tempFlags.motorSynchronized == FALSE)) 00857 { 00858 synchCount++; 00859 if (synchCount >= SYNCHRONIZATION_COUNT) 00860 { 00861 fastFlags.motorSynchronized = TRUE; 00862 } 00863 } 00864 else 00865 { 00866 fastFlags.motorSynchronized = FALSE; 00867 synchCount = 0; 00868 } 00869 }
|
|
|
Initialize pin change interrupts. This function initializes pin change interrupt on hall sensor input pins input, emergency shutdown input and motor direction control input. Definition at line 244 of file main.c. Referenced by main(). 00245 { 00246 // Initialize pin change interrupt on emergency shutdown pin. 00247 PCMSK0 = (1 << PCINT5); 00248 00249 // Initialize pin change interrupt on hall sensor inputs. 00250 PCMSK1 = (1 << PCINT10) | (1 << PCINT9) | (1 << PCINT8); 00251 00252 // Initialize pin change interrupt on direction input pin. 00253 PCMSK2 = (1 << PCINT18); 00254 00255 // Enable pin change interrupt on ports with pin change signals 00256 PCICR = (1 << PCIE2) | (1 << PCIE1) | (1 << PCIE0); 00257 }
|
|
|
Initializes I/O port directions and pull-up resistors. This function initializes all I/O ports with correct direction and pull-up resistors, if needed. Definition at line 195 of file main.c. References DIRECTION_COMMAND_PIN, H1_PIN, H2_PIN, H3_PIN, REV_ROTATION_PIN, and TACHO_OUTPUT_PIN. Referenced by main(). 00196 { 00197 #if (HALL_PULLUP_ENABLE == TRUE) 00198 // Set hall sensor pins as input, pullups enabled. 00199 PORTC = (1 << H1_PIN) | (1 << H2_PIN) | (1 << H3_PIN); 00200 #endif 00201 00202 // PORTD outputs 00203 DDRD = (1 << REV_ROTATION_PIN) | (1 << TACHO_OUTPUT_PIN); 00204 00205 //Enable pull-up on direction signal. 00206 PORTD |= (1 << DIRECTION_COMMAND_PIN); 00207 }
|
|
|
Updates the reverse rotation signal output pin value. Running this function compares the actual and desired direction flags to decide if the motor is running in the opposite direction of what is requested. The Reverse rotation pin will be set to high when the motor is running in the opposite direction and low when the motor is running in the correct direction.
Definition at line 633 of file main.c. References GetActualDirection(), GetDesiredDirection(), and REV_ROTATION_PIN. Referenced by HallChangeISR(). 00634 { 00635 #if (REVERSE_ROTATION_SIGNAL_ENABLE) 00636 if (GetActualDirection() == GetDesiredDirection()) 00637 { 00638 PORTD &= ~(1 << REV_ROTATION_PIN); 00639 } 00640 else 00641 { 00642 PORTD |= (1 << REV_ROTATION_PIN); 00643 } 00644 #endif 00645 }
Here is the call graph for this function: ![]() |
|
|
Sets the lead angle. This function sets the advance commutation angle to be used during sine wave operation. An increase of one equals 1.875 degrees.
Definition at line 746 of file main.c. References advanceCommutationSteps. Referenced by main(). 00747 { 00748 advanceCommutationSteps = advanceCommutation; 00749 }
|
|
|
Calculates the increment for sine table iteration. This function calculates the increment to be used for sine table iteration, based on the number of 'ticks' between two consecutive hall changes. Since a divide is needed, which is not supported in hardware on the AVR, the divide is done through a lookup table for values below 256 (when the motor is running fastest).
Definition at line 695 of file main.c. References divisionTable, and SINE_TABLE_LENGTH. Referenced by HallChangeISR(). 00696 { 00697 if (ticks < 256) 00698 { 00699 return divisionTable[(uint8_t)ticks]; 00700 } 00701 return (uint16_t)(((SINE_TABLE_LENGTH / 6) << 8) / ticks); 00702 }
|
|
|
Speed regulator loop. This function is called every SPEED_REGULATOR_TIME_BASE ticks. In this implementation, a simple PID controller loop is called, but this function could be replaced by any speed (or other regulator). Definition at line 305 of file main.c. References amplitude, PID_Controller(), sineTableIncrement, SPEED_CONTROLLER_MAX_INCREMENT, SPEED_CONTROLLER_MAX_INPUT, and speedInput. Referenced by main(). 00306 { 00307 #if (SPEED_CONTROL_METHOD == SPEED_CONTROL_CLOSED_LOOP) 00308 00309 //Calculate an increment setpoint from the analog speed input. 00310 int16_t incrementSetpoint = ((uint32_t)speedInput * SPEED_CONTROLLER_MAX_INCREMENT) / SPEED_CONTROLLER_MAX_INPUT; 00311 00312 //PID regulator with feed forward from speed input. 00313 int32_t outputValue; 00314 outputValue = (uint32_t)speedInput; 00315 outputValue += PID_Controller(incrementSetpoint, (int16_t)sineTableIncrement, &pidParameters); 00316 00317 if (outputValue < 0) 00318 { 00319 outputValue = 0; 00320 } 00321 else if (outputValue > 255) 00322 { 00323 outputValue = 255; 00324 } 00325 00326 amplitude = outputValue; 00327 #else 00328 amplitude = speedInput; 00329 #endif 00330 }
Here is the call graph for this function: ![]() |
|
|
Updates the tacho output pin signal. This function uses the current hall sensor value to determine the tacho output signal. The "algorithm" used is based on the fact that this signal should have a 0 value when the combined hall sensor inputs are a power of 2. The expression (hall & (hall - 1) computes to 0 for all values of 'hall' that is a power of 2. This can be used to produce the correct output signal.
Definition at line 764 of file main.c. References TACHO_OUTPUT_PIN. Referenced by HallChangeISR(). 00765 { 00766 #if (TACHO_OUTPUT_ENABLED) 00767 if ( (hall & (uint8_t)(hall - 1)) != 0 ) 00768 { 00769 PORTD &= ~(1 << TACHO_OUTPUT_PIN); 00770 } 00771 else 00772 { 00773 PORTD |= (1 << TACHO_OUTPUT_PIN); 00774 } 00775 #endif 00776 }
|
|
|
Timer1 Capture Evente interrupt service routine. This interrupt service routine is run everytime the up-down counting timer0 reaches TOP (0xff). New sinusoidal output values are calculated and the timers are updated to reflect the new values. Definition at line 1030 of file main.c. References AdjustSineTableIndex(), amplitude, BLOCK_COMMUTATION_DUTY_MULTIPLIER, BlockCommutationSetDuty(), CommutationTicksUpdate(), DIRECTION_FORWARD, GetDesiredDirection(), InsertDeadband(), sineTable, sineTableIncrement, sineTableIndex, SPEED_CONTROLLER_TIME_BASE, SpeedControllerRun, TRUE, WAVEFORM_BLOCK_COMMUTATION, and WAVEFORM_SINUSOIDAL. 01031 { 01032 if (fastFlags.driveWaveform == WAVEFORM_SINUSOIDAL) 01033 { 01034 uint8_t tempU, tempV, tempW; 01035 { 01036 uint8_t const __flash * sineTablePtr = sineTable; 01037 01038 AdjustSineTableIndex(sineTableIncrement); 01039 01040 //Add sine table offset to pointer. Must be multiplied by 3, since one 01041 //value for each phase is stored in the table. 01042 sineTablePtr += (sineTableIndex >> 8) * 3; 01043 01044 tempU = *sineTablePtr++; 01045 if (GetDesiredDirection() == DIRECTION_FORWARD) 01046 { 01047 tempV = *sineTablePtr++; 01048 tempW = *sineTablePtr; 01049 } 01050 else 01051 { 01052 tempW = *sineTablePtr++; 01053 tempV = *sineTablePtr; 01054 } 01055 } 01056 01057 //Scale sine modulation values to the current amplitude. 01058 tempU = ((uint16_t)(amplitude * tempU) >> 8); 01059 tempV = ((uint16_t)(amplitude * tempV) >> 8); 01060 tempW = ((uint16_t)(amplitude * tempW) >> 8); 01061 01062 { 01063 uint8_t compareHigh, compareLow; 01064 01065 01066 InsertDeadband(tempU, &compareHigh, &compareLow); 01067 OCR0A = compareHigh; 01068 OCR0B = compareLow; 01069 01070 InsertDeadband(tempV, &compareHigh, &compareLow); 01071 OCR1AL = compareHigh; 01072 OCR1BL = compareLow; 01073 01074 InsertDeadband(tempW, &compareHigh, &compareLow); 01075 OCR2A = compareHigh; 01076 OCR2B = compareLow; 01077 } 01078 } 01079 else if (fastFlags.driveWaveform == WAVEFORM_BLOCK_COMMUTATION) 01080 { 01081 uint16_t blockCommutationDuty = amplitude * BLOCK_COMMUTATION_DUTY_MULTIPLIER; 01082 01083 if (blockCommutationDuty > 255) 01084 { 01085 blockCommutationDuty = 255; 01086 } 01087 01088 BlockCommutationSetDuty((uint8_t)blockCommutationDuty); 01089 } 01090 01091 CommutationTicksUpdate(); 01092 01093 { 01094 //Run the speed regulation loop with constant intervals. 01095 static uint8_t speedRegTicks = 0; 01096 speedRegTicks++; 01097 if (speedRegTicks >= SPEED_CONTROLLER_TIME_BASE) 01098 { 01099 SpeedControllerRun = TRUE; 01100 speedRegTicks -= SPEED_CONTROLLER_TIME_BASE; 01101 } 01102 } 01103 }
Here is the call graph for this function: ![]() |
|
|
Initializes and synchronizes Timers. This function sets the correct prescaler and starts all three timers. The timers are synchronized to ensure that all PWM signals are aligned. Definition at line 216 of file main.c. Referenced by main(). 00217 { 00218 //Set all timers in "Phase correct mode". Do not enable outputs yet. 00219 TCCR0A = (1 << WGM00); 00220 TCCR1A = (1 << WGM11); 00221 TCCR2A = (1 << WGM20); 00222 00223 //Set top value of Timer/counter1. 00224 ICR1 = 0xff; 00225 00226 //Synchronize timers 00227 TCNT0 = 0; 00228 TCNT1 = 2; 00229 TCNT2 = 4; 00230 00231 // Start all 3 timers. 00232 TCCR0B = (0 << CS01) | (1 << CS00); 00233 TCCR1B = (1 << WGM13) | (0 << CS11) | (1 << CS10); 00234 TCCR2B = (0 << CS21) | (1 << CS20); 00235 }
|
|
|
Configures timers for block commutation. This function is called every time block commutation is needed. PWM outputs are safely disabled while configuration registers are changed to avoid unintended driving or shoot- through. Definition at line 373 of file main.c. References BlockCommutationSetDuty(), DisablePWMOutputs(), EnablePWMOutputs(), TimersWaitForNextPWMCycle(), and WAVEFORM_BLOCK_COMMUTATION. Referenced by CommutationTicksUpdate(). 00374 { 00375 //Set PWM pins to input (Hi-Z) while changing modes. 00376 DisablePWMOutputs(); 00377 00378 //Sets both outputs of all 3 timers in "clear on up-counting, set on down-counting" mode. 00379 TCCR0A = (1 << COM0A1) | (0 << COM0A0) | (1 << COM0B1) | (0 << COM0B0) | (1 << WGM00); 00380 TCCR1A = (1 << COM1A1) | (0 << COM1A0) | (1 << COM1B1) | (0 << COM1B0) | (1 << WGM11); 00381 TCCR2A = (1 << COM2A1) | (0 << COM2A0) | (1 << COM2B1) | (0 << COM2B0) | (1 << WGM20); 00382 00383 //Set output duty cycle to zero for now. 00384 BlockCommutationSetDuty(0); 00385 00386 //Wait for next PWM cycle to ensure that all outputs are updated. 00387 TimersWaitForNextPWMCycle(); 00388 00389 fastFlags.driveWaveform = WAVEFORM_BLOCK_COMMUTATION; 00390 00391 //Change PWM pins to output again to allow PWM control. 00392 EnablePWMOutputs(); 00393 }
Here is the call graph for this function: ![]() |
|
|
Configures timers for braking and starts braking. This function configures the timers for braking and starts braking. Please note that braking when turning can produce too much heat for the drivers to handle. Use with care! Definition at line 404 of file main.c. References DisablePWMOutputs(), EnablePWMOutputs(), TimersWaitForNextPWMCycle(), and WAVEFORM_BRAKING. Referenced by DirectionInputChangeISR(). 00405 { 00406 //Set PWM pins to input (Hi-Z) while changing modes. 00407 DisablePWMOutputs(); 00408 00409 //Sets both outputs of all 3 timers in "clear on up-counting, set on down-counting" mode. 00410 TCCR0A = (1 << COM0A1) | (0 << COM0A0) | (1 << COM0B1) | (0 << COM0B0) | (1 << WGM00); 00411 TCCR1A = (1 << COM1A1) | (0 << COM1A0) | (1 << COM1B1) | (0 << COM1B0) | (1 << WGM11); 00412 TCCR2A = (1 << COM2A1) | (0 << COM2A0) | (1 << COM2B1) | (0 << COM2B0) | (1 << WGM20); 00413 00414 // High side 00415 OCR0A = OCR1A = OCR2A = 0x00; 00416 00417 // Low side 00418 OCR0B = OCR1B = OCR2B = 0xff; 00419 00420 //Wait for next PWM cycle to ensure that all outputs are updated. 00421 TimersWaitForNextPWMCycle(); 00422 00423 fastFlags.driveWaveform = WAVEFORM_BRAKING; 00424 00425 EnablePWMOutputs(); 00426 }
Here is the call graph for this function: ![]() |
|
|
Configures timers for sine wave generation. This function is called every time sine wave generation is needed. PWM outputs are safely disabled while configuration registers are changed to avoid unintended driving or shoot- through. Definition at line 341 of file main.c. References DisablePWMOutputs(), EnablePWMOutputs(), TimersWaitForNextPWMCycle(), and WAVEFORM_SINUSOIDAL. Referenced by HallChangeISR(). 00342 { 00343 //Set PWM pins to input (Hi-Z) while changing modes. 00344 DisablePWMOutputs(); 00345 00346 //Sets all 3 timers in inverted pair mode. 00347 TCCR0A = (1 << COM0A1) | (0 << COM0A0) | (1 << COM0B1) | (1 << COM0B0) | (1 << WGM00); 00348 TCCR1A = (1 << COM1A1) | (0 << COM1A0) | (1 << COM1B1) | (1 << COM1B0) | (1 << WGM11); 00349 TCCR2A = (1 << COM2A1) | (0 << COM2A0) | (1 << COM2B1) | (1 << COM2B0) | (1 << WGM20); 00350 00351 //Make sure all outputs are turned off before PWM outputs are enabled. 00352 OCR0A = OCR1AL = OCR2A = 0; 00353 OCR0B = OCR1BL = OCR2B = 0xff; 00354 00355 //Wait for next PWM cycle to ensure that all outputs are updated. 00356 TimersWaitForNextPWMCycle(); 00357 00358 fastFlags.driveWaveform = WAVEFORM_SINUSOIDAL; 00359 00360 //Change PWM pins to output again to allow PWM control. 00361 EnablePWMOutputs(); 00362 }
Here is the call graph for this function: ![]() |
|
|
Waits for the start of the next PWM cycle. Waits for the start of the next PWM cycle. Can be used to make sure that a shoot-through does not occur in the transition between two output waveform generation modes. Definition at line 437 of file main.c. Referenced by TimersSetModeBlockCommutation(), TimersSetModeBrake(), and TimersSetModeSinusoidal(). 00438 { 00439 //Clear Timer1 Capture event flag. 00440 TIFR1 = (1 << ICF1); 00441 00442 //Wait for new Timer1 Capture event flag. 00443 while ( !(TIFR1 & (1 << ICF1)) ) 00444 { 00445 00446 } 00447 }
|
|
|
The lead angle or advance commutation angle. This variable specifies a shift in the sine table that will generate advance commutaiton. For a 192 element sine table, an increase of one in advanceCommutationSteps will result in 1.875 degrees lead angle. Definition at line 89 of file main.c. Referenced by HallChangeISR(), and SetAdvanceCommutation(). |
|
|
The amplitude of the generated sine waves. This variable controls the amplitude of the generated sine waves. The range is 0-255. Definition at line 79 of file main.c. Referenced by SpeedController(), and Timer1CaptureISR(). |
|
|
The number of 'ticks' between two hall sensor changes. This variable is used to count the number of 'ticks' between each hall sensor change. One 'tick' is one PWM period, 510 CPU clock cycles. This is used to calculate sine table increment. The speed of the motor is inversely proportional to this value. Definition at line 71 of file main.c. Referenced by CommutationTicksUpdate(), and HallChangeISR(). |
|
|
Current measurement. The most recent current measurement is stored in this variable. It is not used for any purpose in this implementation, but the measurement is updated. Definition at line 109 of file main.c. Referenced by ADCCompleteISR(). |
|
|
Increment used for sine table iteration. This variable holds the increment used for sine table iteration. It is stored in an 8.8 fixed point format. Definition at line 52 of file main.c. Referenced by HallChangeISR(), SpeedController(), and Timer1CaptureISR(). |
|
|
Index into sine table. This variable is used as an index into the sine table. It is stored in a 8.8 fixed point format, so it can be directly incremented by sineTableIncrement. Only the high byte is used as table index. Definition at line 61 of file main.c. Referenced by AdjustSineTableIndex(), HallChangeISR(), and Timer1CaptureISR(). |
|
|
Index to the end of the current commutation sector. This variable holds the index where the next commutation sector starts, including the advance commutation angle. It is used to prevent the output from going further until the hall sensors changes. Definition at line 100 of file main.c. Referenced by AdjustSineTableIndex(), and HallChangeISR(). |
|
|
Speed controller run flag. This variable is set to TRUE every time the speed controller should be run. Definition at line 119 of file main.c. Referenced by main(), and Timer1CaptureISR(). |
|
|
The most recent speed input measurement.
Definition at line 113 of file main.c. Referenced by ADCCompleteISR(), and SpeedController(). |
|
|
Motor control flags placed in I/O space for fast access. This variable contains all the flags used for motor control. It is placed in GPIOR0 register, which allows usage of several fast bit manipulation/branch instructions. |
1.4.4