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 "PMSM_tables.h"
#include "TinyX61_macros.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. | |
| static void | ADCInit (void) |
| Sets up the ADC for speed reference input on PA7. | |
| static void | AdjustSineTableIndex (const uint16_t increment) |
| Adjusts the sine table index according to the current increment. | |
| static void | BlockCommutate (const uint8_t direction, const uint8_t hall) |
| Performs block commutation according to running direction and hall sensor input. | |
| static void | BlockCommutationSetDuty (const uint16_t compareValue) |
| Sets the duty cycle when operating in block commutation mode. | |
| static void | CommutationTicksUpdate (void) |
| Updates the 'tick' counter and checks for stopped motor. | |
| static void | DesiredDirectionUpdate (void) |
| Updates global desired direction flag. | |
| static void | DisablePWMOutputs (void) |
| Disable PWM outputs by setting the port direction to input. | |
| static void | EnablePWMOutputs (void) |
| Enable PWM outputs by setting the port direction to output. | |
| __interrupt void | FaultProtectionISR () |
| Hardware fault protection interrupt. | |
| static uint8_t | GetDesiredDirection (void) |
| Returns the desired direction. | |
| static uint8_t | GetHall (void) |
| Reads the hall sensor inputs. | |
| __interrupt void | HallChangeISR () |
| Updates the PWM outputs according to the current position and amplitude.Hall sensor change interrupt service routine. | |
| static uint8_t | IsMotorSynchronized (void) |
| Returns the motor synchronized flag. | |
| void | main (void) |
| static void | MotorSynchronizedUpdate (void) |
| Updates the global motor synchronized flag. | |
| static unsigned int | MultiplyUS15x8 (const uint16_t m15, const uint8_t m8) |
| Fast unsigned multiply of a 15 bit number with an 8 bit number with 15 bit result. | |
| static void | PinChangeInit (void) |
| Initialize Pin change interrupt for hall sensors. | |
| static void | PLLInit (void) |
| Initialize PLL. | |
| static void | PortsInit (void) |
| Initialize port pin directions and internal pull-ups. | |
| static void | PWMInit (void) |
| Initialize PWM on Timer/counter1. | |
| static void | SetAdvanceCommutation (const uint8_t advanceCommutation) |
| Sets the advance commutation. | |
| static void | SineOutputUpdate (void) |
| Get the sine table value from the small sine table.Updates the PWM outputs according to the current position and amplitude. | |
| static uint16_t | SineTableIncrementCalculate (const uint16_t ticks) |
| Calculates step size for sine table iteration. | |
| static void | SpeedController (uint16_t speedReference) |
| Speed controller loop. | |
| __interrupt void | Timer1OverflowISR () |
| Timer/counter1 overflow interrupt service routine. | |
| static void | TimerSetModeBlockCommutation (void) |
| Configures Timer/counter1 in block commutation mode. | |
| static void | TimerSetModeBrake (void) |
| Configures Timer/Counter1 in braking mode. | |
| static void | TimerSetModeSinusoidal (void) |
| Configures Timer/Counter1 in Sinusoidal mode. | |
Variables | |
| __no_init __regvar volatile uint8_t | advanceCommutationSteps |
| The advance commutation angle. | |
| __no_init __regvar volatile uint16_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. | |
| __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. | |
| __no_init __regvar volatile uint8_t | speedControllerTimer |
| Time in ticks until the speed controller loop should be executed. | |
| volatile __io PMSMflags_t fastFlags | x0a |
| 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.
| lastHall | The last hall value. | |
| newHall | The current hall value. |
Definition at line 521 of file main.c.
References PMSMflags::actualDirection, DIRECTION_FORWARD, DIRECTION_REVERSE, DIRECTION_UNKNOWN, expectedHallSequenceForward, expectedHallSequenceReverse, FALSE, and PMSMflags::motorSynchronized.
Referenced by HallChangeISR().
00522 { 00523 //Make sure that lastHall is within bounds of table. If not, set to an 00524 //illegal hall value, but legal table index. 00525 if (lastHall > 7) 00526 { 00527 lastHall = 0; 00528 } 00529 if (expectedHallSequenceForward[lastHall] == newHall) 00530 { 00531 fastFlags.actualDirection = DIRECTION_FORWARD; 00532 } 00533 else if (expectedHallSequenceReverse[lastHall] == newHall) 00534 { 00535 fastFlags.actualDirection = DIRECTION_REVERSE; 00536 } 00537 else 00538 { 00539 PMSMflags_t tempFlags = fastFlags; 00540 tempFlags.actualDirection = DIRECTION_UNKNOWN; 00541 tempFlags.motorSynchronized = FALSE; 00542 fastFlags = tempFlags; 00543 } 00544 }
| static void ADCInit | ( | void | ) | [static] |
Sets up the ADC for speed reference input on PA7.
This function initializes the ADC for speed reference measurements. The ADC will operate in single conversion mode.
Definition at line 239 of file main.c.
Referenced by main().
00240 { 00241 //Use PA7 as ADC input, 2.56V internal voltage reference without bypass capacitor. 00242 ADMUX = (1 << REFS1) | (0 << MUX4) | (0 << MUX3) | (1 << MUX2) | (1 << MUX1) | (0 << MUX0); 00243 00244 ADCSRA = (1 << ADEN) | //Enable the ADC. 00245 (1 << ADSC) | //Start the first converssion. 00246 (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // Prescaler CK/128. 00247 ADCSRB = (1 << REFS2); //2.56V internal reference. 00248 }
| static void AdjustSineTableIndex | ( | const uint16_t | increment | ) | [static] |
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.
| increment | The increment (in 8.8 format) added to the sine table index. |
Definition at line 572 of file main.c.
References SINE_TABLE_LENGTH, sineTableIndex, and sineTableNextSectorStart.
Referenced by Timer1OverflowISR().
00573 { 00574 sineTableIndex += increment; 00575 00576 // If the table index is out of bounds, wrap the index around the table end 00577 // to continue from the beginning. Also wrap the next sector start index. 00578 if ((sineTableIndex >> 8) >= SINE_TABLE_LENGTH) 00579 { 00580 sineTableIndex -= (SINE_TABLE_LENGTH << 8); 00581 sineTableNextSectorStart -= SINE_TABLE_LENGTH; 00582 } 00583 00584 //Make copy of sineNextSectorStart to specify order of volatile access. 00585 uint8_t nextSectorStart = sineTableNextSectorStart; 00586 if ((sineTableIndex >> 8) > nextSectorStart) 00587 { 00588 sineTableIndex = (nextSectorStart << 8); 00589 } 00590 }
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.
| direction | Direction of rotation. | |
| hall | Hall sensor value at the same form as returned by GetHall(). |
Definition at line 454 of file main.c.
References blockCommutationTableForward, blockCommutationTableReverse, and DIRECTION_FORWARD.
Referenced by CommutationTicksUpdate(), and HallChangeISR().
00455 { 00456 if (direction == DIRECTION_FORWARD) 00457 { 00458 TCCR1E = blockCommutationTableForward[hall]; 00459 } 00460 else 00461 { 00462 TCCR1E = blockCommutationTableReverse[hall]; 00463 } 00464 }
| static void BlockCommutationSetDuty | ( | const uint16_t | compareValue | ) | [static] |
Sets the duty cycle when operating in block commutation mode.
Calling this function sets the duty cycle when operating in block commutation mode (PWM6 mode). Do not use this function when Timer/counter1 is not operated in PWM6 mode.
Note that the argument specifies the output compare value, not the duty cycle in percent. The duty cycle in percent can be calculated as duty = (compareValue / PWM_TOP_VALUE) * 100.
| compareValue | Ouput compare value. |
Definition at line 419 of file main.c.
References TC1_PWM6_SET_DUTY_CYCLE.
Referenced by Timer1OverflowISR(), and TimerSetModeBlockCommutation().
00420 { 00421 TC1_PWM6_SET_DUTY_CYCLE(compareValue); 00422 }
| static void CommutationTicksUpdate | ( | void | ) | [static] |
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 642 of file main.c.
References BlockCommutate(), COMMUTATION_TICKS_STOPPED, commutationTicks, FALSE, GetDesiredDirection(), GetHall(), pid_Reset_Integrator(), sineTableIncrement, TimerSetModeBlockCommutation(), TRUE, and WAVEFORM_BLOCK_COMMUTATION.
Referenced by Timer1OverflowISR().
00643 { 00644 if (commutationTicks < COMMUTATION_TICKS_STOPPED) 00645 { 00646 commutationTicks++; 00647 } 00648 else 00649 { 00650 fastFlags.motorStopped = TRUE; 00651 fastFlags.motorSynchronized = FALSE; 00652 sineTableIncrement = 0; 00653 if (fastFlags.driveWaveform != WAVEFORM_BLOCK_COMMUTATION) 00654 { 00655 TimerSetModeBlockCommutation(); 00656 BlockCommutate(GetDesiredDirection(), GetHall()); 00657 00658 #if (SPEED_CONTROL_METHOD == SPEED_CONTROL_CLOSED_LOOP) 00659 pid_Reset_Integrator(&pidParameters); 00660 #endif 00661 } 00662 } 00663 }
Here is the call graph for this function:

| static void DesiredDirectionUpdate | ( | void | ) | [static] |
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 499 of file main.c.
References DIRECTION_FORWARD, DIRECTION_PIN, and DIRECTION_REVERSE.
Referenced by main(), and Timer1OverflowISR().
00500 { 00501 if ( (PINA & (1 << DIRECTION_PIN)) != 0 ) 00502 { 00503 fastFlags.desiredDirection = DIRECTION_REVERSE; 00504 } 00505 else 00506 { 00507 fastFlags.desiredDirection = DIRECTION_FORWARD; 00508 } 00509 }
| static void DisablePWMOutputs | ( | void | ) | [static] |
Disable PWM outputs by setting the port direction to input.
Disables PWM outputs by setting the port direction to input for the PWM pins.
Definition at line 627 of file main.c.
References PWM_PIN_MASK_PORTB.
Referenced by Timer1OverflowISR(), TimerSetModeBlockCommutation(), TimerSetModeBrake(), and TimerSetModeSinusoidal().
00628 { 00629 DDRB &= (~PWM_PIN_MASK_PORTB); 00630 }
| static void EnablePWMOutputs | ( | void | ) | [static] |
Enable PWM outputs by setting the port direction to output.
Enables PWM outputs by setting the port direction to output for the PWM pins.
Definition at line 616 of file main.c.
References PWM_PIN_MASK_PORTB.
Referenced by TimerSetModeBlockCommutation(), TimerSetModeBrake(), and TimerSetModeSinusoidal().
00617 { 00618 DDRB |= PWM_PIN_MASK_PORTB; 00619 }
| __interrupt void FaultProtectionISR | ( | ) |
Hardware fault protection interrupt.
This ISR will be run every time the hardware fault protection disables the PWM outputs. The required action to this event will be different from application to application. Here, a delay is inserted, before the PWM outputs are once again enabled.
Definition at line 1028 of file main.c.
References pid_Reset_Integrator().
01029 { 01030 __delay_cycles(10000000); 01031 TCCR1D |= (1 << FPEN1); 01032 #if (SPEED_CONTROL_METHOD == SPEED_CONTROL_CLOSED_LOOP) 01033 pid_Reset_Integrator(&pidParameters); 01034 #endif 01035 }
Here is the call graph for this function:

| static uint8_t GetDesiredDirection | ( | void | ) | [static] |
Returns the desired direction.
This function returns the current desired direction.
| DIRECTION_FORWARD | Forward direction is requested. | |
| DIRECTION_REVERSE | Reverse direction is requested. |
Definition at line 436 of file main.c.
Referenced by CommutationTicksUpdate(), HallChangeISR(), and SineOutputUpdate().
00437 { 00438 return (uint8_t)fastFlags.desiredDirection; 00439 }
| static uint8_t GetHall | ( | void | ) | [static] |
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.
| 0 | Illegal hall state. Possible hardware error. | |
| 1-6 | Legal hall sensor values. | |
| 7 | Illegal hall state. Possible hardware error. |
Definition at line 483 of file main.c.
References H1_PIN, H2_PIN, and H3_PIN.
Referenced by CommutationTicksUpdate(), and HallChangeISR().
00484 { 00485 uint8_t hall; 00486 00487 hall = (PINA) & ((1 << H3_PIN) | (1 << H2_PIN) | (1 << H1_PIN)); 00488 hall >>= H1_PIN; 00489 return hall; 00490 }
| __interrupt void HallChangeISR | ( | ) |
Updates the PWM outputs according to the current position and amplitude.Hall sensor change interrupt service routine.
This ISR is run every time one of the hall sensor inputs changes value. The responsibilities of this ISR are:
Definition at line 887 of file main.c.
References ActualDirectionUpdate(), advanceCommutationSteps, BlockCommutate(), commutationTicks, CSOffsetsForward, CSOffsetsReverse, DIRECTION_FORWARD, FALSE, GetDesiredDirection(), GetHall(), IsMotorSynchronized(), MotorSynchronizedUpdate(), sineTableIncrement, SineTableIncrementCalculate(), sineTableIndex, sineTableNextSectorStart, TABLE_ELEMENTS_PER_COMMUTATION_SECTOR, TimerSetModeSinusoidal(), WAVEFORM_BLOCK_COMMUTATION, and WAVEFORM_SINUSOIDAL.
00888 { 00889 static uint8_t lastHall = 0xff; 00890 uint8_t hall; 00891 00892 hall = GetHall(); 00893 00894 //Make sure that the hall sensors really changed. 00895 if (hall == lastHall) 00896 { 00897 return; 00898 } 00899 00900 MotorSynchronizedUpdate(); 00901 uint8_t synch = IsMotorSynchronized(); 00902 if ((fastFlags.driveWaveform != WAVEFORM_SINUSOIDAL) && (synch)) 00903 { 00904 TimerSetModeSinusoidal(); 00905 } 00906 00907 //If sinusoidal driving is used, synchronize sine wave generation to the 00908 //current hall sensor value. Advance commutation (lead angle) is also 00909 //added in the process. 00910 if (fastFlags.driveWaveform == WAVEFORM_SINUSOIDAL) 00911 { 00912 uint16_t tempIndex; 00913 if (GetDesiredDirection() == DIRECTION_FORWARD) 00914 { 00915 tempIndex = (CSOffsetsForward[hall] + advanceCommutationSteps) << 8; 00916 } 00917 else 00918 { 00919 tempIndex = (CSOffsetsReverse[hall] + advanceCommutationSteps) << 8; 00920 } 00921 sineTableIndex = tempIndex; 00922 00923 //Adjust next sector start index. It might be set to a value larger than 00924 //SINE_TABLE_LENGTH at this point. This is adjusted in AdjustSineTableIndex 00925 //and should not be done here, as it will cause problems when advance 00926 //commutation is used. 00927 sineTableNextSectorStart = (tempIndex >> 8) + TABLE_ELEMENTS_PER_COMMUTATION_SECTOR; 00928 00929 } 00930 //If block commutation is used. Commutate according to hall signal. 00931 else if (fastFlags.driveWaveform == WAVEFORM_BLOCK_COMMUTATION) 00932 { 00933 BlockCommutate(GetDesiredDirection(), hall); 00934 } 00935 00936 //Update the actual direction flag. 00937 ActualDirectionUpdate(lastHall, hall); 00938 00939 lastHall = hall; 00940 00941 00942 //Calculate new step size for sine wave generation and reset commutation 00943 //timer. 00944 sineTableIncrement = SineTableIncrementCalculate(commutationTicks); 00945 commutationTicks = 0; 00946 00947 //Since the hall sensors are changing, the motor can not be stopped. 00948 fastFlags.motorStopped = FALSE; 00949 }
Here is the call graph for this function:

| static uint8_t IsMotorSynchronized | ( | void | ) | [static] |
Returns the motor synchronized flag.
This function returns the motor synchronized flag.
| TRUE | Motor control is synchronized with motor. | |
| FALSE | Motor control is not yet synchronized with motor. |
Definition at line 708 of file main.c.
Referenced by HallChangeISR().
00709 { 00710 return (uint8_t)(fastFlags.motorSynchronized); 00711 }
| void main | ( | void | ) |
Definition at line 120 of file main.c.
References PMSMflags::actualDirection, ADCInit(), PMSMflags::desiredDirection, DesiredDirectionUpdate(), DIRECTION_UNKNOWN, PMSMflags::driveWaveform, FALSE, PMSMflags::motorStopped, PMSMflags::motorSynchronized, pid_Init(), PID_K_D, PID_K_I, PID_K_P, PinChangeInit(), PLLInit(), PortsInit(), PWMInit(), SetAdvanceCommutation(), SPEED_CONTROLLER_TIME_BASE, SpeedController(), speedControllerTimer, and WAVEFORM_UNDEFINED.
00121 { 00122 PortsInit(); 00123 PLLInit(); 00124 PWMInit(); 00125 PinChangeInit(); 00126 ADCInit(); 00127 00128 #if (SPEED_CONTROL_METHOD == SPEED_CONTROL_CLOSED_LOOP) 00129 pid_Init(PID_K_P, PID_K_I, PID_K_D, &pidParameters); 00130 #endif 00131 00132 speedControllerTimer= SPEED_CONTROLLER_TIME_BASE; 00133 SetAdvanceCommutation(0); 00134 00135 //Initialize fastflags. Use temporary variable to avoid several accesses to 00136 //volatile variable. 00137 { 00138 PMSMflags_t fastFlagsInitial; 00139 00140 // Set motorStopped to FALSE at startup. This will make sure that the motor 00141 // is not started if it is not really stopped. If it is stopped, this variable 00142 // will quickly be updated. 00143 fastFlagsInitial.motorStopped = FALSE; 00144 00145 // Set motorSyncronized to FALSE at startup. This will prevent the motor from being 00146 // driven until the motor is in synch or stopped. 00147 fastFlagsInitial.motorSynchronized = FALSE; 00148 fastFlagsInitial.actualDirection = DIRECTION_UNKNOWN; 00149 fastFlagsInitial.desiredDirection = 0; 00150 fastFlagsInitial.driveWaveform = WAVEFORM_UNDEFINED; 00151 00152 fastFlags = fastFlagsInitial; 00153 } 00154 00155 DesiredDirectionUpdate(); 00156 00157 //Enable Timer/counter1 overflow. 00158 TIMSK |= (1 << TOV1); 00159 00160 //Enable interrupts globally and let motor driver take over. 00161 __enable_interrupt(); 00162 00163 for (;;) 00164 { 00165 uint16_t speedReference; 00166 00167 if ( !(ADCSRA & (1 << ADSC)) ) 00168 { 00169 speedReference = ADC; 00170 ADCSRA |= (1 << ADSC); 00171 } 00172 00173 if (speedControllerTimer == 0) 00174 { 00175 speedControllerTimer = SPEED_CONTROLLER_TIME_BASE; 00176 SpeedController(speedReference); 00177 } 00178 } 00179 }
Here is the call graph for this function:

| static void MotorSynchronizedUpdate | ( | void | ) | [static] |
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 674 of file main.c.
References PMSMflags::actualDirection, PMSMflags::desiredDirection, FALSE, PMSMflags::motorStopped, PMSMflags::motorSynchronized, SYNCHRONIZATION_COUNT, and TRUE.
Referenced by HallChangeISR().
00675 { 00676 static uint8_t synchCount = 0; 00677 00678 PMSMflags_t tempFlags; 00679 00680 tempFlags = fastFlags; 00681 00682 if ((tempFlags.desiredDirection == tempFlags.actualDirection) && 00683 (tempFlags.motorStopped == FALSE) && (tempFlags.motorSynchronized == FALSE)) 00684 { 00685 synchCount++; 00686 if (synchCount >= SYNCHRONIZATION_COUNT) 00687 { 00688 fastFlags.motorSynchronized = TRUE; 00689 } 00690 } 00691 else 00692 { 00693 synchCount = 0; 00694 } 00695 }
Fast unsigned multiply of a 15 bit number with an 8 bit number with 15 bit result.
This function performs a fast unsigned multiply of a 15 bit number with an 8 bit number. The lower byte of the result is discarded in the process, returning the 15 most significant bytes as result. The function has a fixed execution time of 50 CPU clock cycles.
| m15 | 15 bit unsigned value (0x0000-0x7fff) | |
| m8 | 8 bit unsigned value (0x00-0xff) |
Definition at line 1051 of file main.c.
Referenced by SineOutputUpdate().
01052 { 01053 unsigned int result = 0x0000; 01054 01055 if (m8 & (1 << 0)) 01056 { 01057 result += m15; 01058 } 01059 result >>= 1; 01060 01061 if (m8 & (1 << 1)) 01062 { 01063 result += m15; 01064 } 01065 result >>= 1; 01066 if (m8 & (1 << 2)) 01067 { 01068 result += m15; 01069 } 01070 result >>= 1; 01071 01072 if (m8 & (1 << 3)) 01073 { 01074 result += m15; 01075 } 01076 result >>= 1; 01077 01078 if (m8 & (1 << 4)) 01079 { 01080 result += m15; 01081 } 01082 result >>= 1; 01083 01084 if (m8 & (1 << 5)) 01085 { 01086 result += m15; 01087 } 01088 result >>= 1; 01089 if (m8 & (1 << 6)) 01090 { 01091 result += m15; 01092 } 01093 result >>= 1; 01094 01095 if (m8 & (1 << 7)) 01096 { 01097 result += m15; 01098 } 01099 result >>= 1; 01100 01101 return result; 01102 }
| static void PinChangeInit | ( | void | ) | [static] |
Initialize Pin change interrupt for hall sensors.
Initializes the pin change interrupt for hall sensors.
Definition at line 255 of file main.c.
Referenced by main().
00256 { 00257 //Initialize hall change interrupt 00258 PCMSK0 = (1 << PCINT2) | (1 << PCINT1) | (1 << PCINT0); 00259 //Clear all other pin change interrupts. 00260 PCMSK1 = 0x00; 00261 00262 // 00263 GIMSK |= (1 << PCIE1); 00264 00265 //Force the pin change interrupt to be triggered. 00266 DDRA |= ((1 << PA2) | (1 << PA1) | (1 << PA0)); 00267 DDRA &= ~((1 << PA2) | (1 << PA1) | (1 << PA0)); 00268 }
| static void PLLInit | ( | void | ) | [static] |
Initialize PLL.
Waits for PLL lock and enables the PLL. This function does not enable the PLL clock. This should be done by setting the CKSEL fuses to 0001. Otherwise, the application will hang here forever.
Definition at line 203 of file main.c.
Referenced by main().
00204 { 00205 //Wait for PLL lock 00206 while ( !(PLLCSR & (1 << PLOCK)) ) 00207 { 00208 00209 } 00210 PLLCSR = (1 << PCKE); 00211 }
| static void PortsInit | ( | void | ) | [static] |
Initialize port pin directions and internal pull-ups.
Initializes port pin directions and internal pull-ups if needed.
Definition at line 187 of file main.c.
References H1_PIN, H2_PIN, and H3_PIN.
Referenced by main().
00188 { 00189 #if (HALL_PULL_UP_ENABLE) 00190 PORTA = (1 << H1_PIN) | (1 << H2_PIN) | (1 << H3_PIN); 00191 #endif 00192 00193 DDRA = (1 << PA4); 00194 }
| static void PWMInit | ( | void | ) | [static] |
Initialize PWM on Timer/counter1.
Initializes PWM on Timer/counter1.
Definition at line 218 of file main.c.
References DEAD_TIME, PWM1X, PWM_INVERT_OUTPUT, PWM_TOP_VALUE, and TC1_WRITE_10_BIT_REGISTER.
Referenced by main().
00219 { 00220 //Start TCNT1 with prescaler 1. 00221 TCCR1B = (PWM_INVERT_OUTPUT << PWM1X) | (1 << CS10); 00222 00223 //Enable fault protection input on INT0 pin, falling edge. 00224 TCCR1D = (1 << FPIE1) | (1 << FPEN1) | (0 << FPES1); 00225 00226 //Set dead-time. 00227 DT1 = (DEAD_TIME << 4) | (DEAD_TIME); 00228 00229 //Set PWM top value. 00230 TC1_WRITE_10_BIT_REGISTER(OCR1C, PWM_TOP_VALUE); 00231 }
| static void SetAdvanceCommutation | ( | const uint8_t | advanceCommutation | ) | [static] |
Sets the advance commutation.
This function sets the advance commutation to be used during sine wave operation. An increase of one equals 1.875 degrees.
| advanceCommutation | The advance commutation. (1 equals 1.875 degrees) |
Definition at line 605 of file main.c.
References advanceCommutationSteps.
Referenced by main().
00606 { 00607 advanceCommutationSteps = advanceCommutation; 00608 }
| static void SineOutputUpdate | ( | void | ) | [static] |
Get the sine table value from the small sine table.Updates the PWM outputs according to the current position and amplitude.
This functon uses the current position and amplitude setting to update the PWM outputs. This version uses the large sine table (3 * 192 elements).
Definition at line 749 of file main.c.
References amplitude, COMPARE_REGISTER_PHASE_U, COMPARE_REGISTER_PHASE_V, COMPARE_REGISTER_PHASE_W, DIRECTION_FORWARD, GetDesiredDirection(), MultiplyUS15x8(), sineTable, sineTableIndex, and TC1_WRITE_10_BIT_REGISTER.
Referenced by Timer1OverflowISR().
00750 { 00751 uint8_t const __flash * sineTablePtr = sineTable; 00752 uint16_t temp; 00753 00754 //Add sine table offset to pointer. Must be multiplied by 3, since one 00755 //value for each phase is stored in the table. 00756 //sineTablePtr += (uint8_t)(sineTableIndex >> 8) * 3; 00757 { 00758 uint8_t tempIndex = (uint8_t)(sineTableIndex >> 8); 00759 sineTablePtr += tempIndex; 00760 sineTablePtr += tempIndex; 00761 sineTablePtr += tempIndex; 00762 } 00763 00764 //Calculate output duty cycles. Since one phase is always zero, the scaling 00765 //is only performed on the two non-zero phases, saving one multiply. 00766 00767 //Calculate U phase output duty cycle. 00768 temp = *sineTablePtr++; 00769 if (temp != 0) 00770 { 00771 temp = MultiplyUS15x8(amplitude, temp); 00772 } 00773 TC1_WRITE_10_BIT_REGISTER(COMPARE_REGISTER_PHASE_U, temp); 00774 00775 //Calculate U + 240 degree phase output duty cycle. 00776 temp = *sineTablePtr++; 00777 if (temp != 0) 00778 { 00779 temp = MultiplyUS15x8(amplitude, temp); 00780 } 00781 if (GetDesiredDirection() == DIRECTION_FORWARD) 00782 { 00783 TC1_WRITE_10_BIT_REGISTER(COMPARE_REGISTER_PHASE_V, temp); 00784 } 00785 else 00786 { 00787 TC1_WRITE_10_BIT_REGISTER(COMPARE_REGISTER_PHASE_W, temp); 00788 } 00789 00790 //Calculate U + 120 degree phase output duty cycle. 00791 temp = *sineTablePtr++; 00792 if (temp != 0) 00793 { 00794 temp = MultiplyUS15x8(amplitude, temp); 00795 } 00796 if (GetDesiredDirection() == DIRECTION_FORWARD) 00797 { 00798 TC1_WRITE_10_BIT_REGISTER(COMPARE_REGISTER_PHASE_W, temp); 00799 } 00800 else 00801 { 00802 TC1_WRITE_10_BIT_REGISTER(COMPARE_REGISTER_PHASE_V, temp); 00803 } 00804 }
Here is the call graph for this function:

Calculates step size for sine table iteration.
This function calculates the step size to be used for sine table iteration, based on the number of 'ticks' used for each electrical revolution.
| ticks | The number of ticks in one electrical revolution. |
Definition at line 558 of file main.c.
References SINE_TABLE_LENGTH.
Referenced by HallChangeISR().
00559 { 00560 return (uint16_t)(((SINE_TABLE_LENGTH / 6) << 8) / ticks); 00561 }
| static void SpeedController | ( | uint16_t | speedReference | ) | [static] |
Speed controller loop.
This function is called every SPEED_CONTROLLER_TIME_BASE ticks. In this implementation, a simple PID controller loop is called, but this function could be replaced by any speed (or other) controller.
Definition at line 277 of file main.c.
References amplitude, pid_Controller(), PWM_TOP_VALUE, sineTableIncrement, SPEED_CONTROLLER_MAX_INCREMENT, and SPEED_CONTROLLER_MAX_INPUT.
Referenced by main().
00278 { 00279 #if (SPEED_CONTROL_METHOD == SPEED_CONTROL_CLOSED_LOOP) 00280 00281 //Calculate an increment setpoint from the analog speed input. 00282 int16_t incrementSetpoint = ((uint32_t)speedReference * SPEED_CONTROLLER_MAX_INCREMENT) / SPEED_CONTROLLER_MAX_INPUT; 00283 00284 //PID controller with feed forward from speed input. 00285 int32_t outputValue; 00286 outputValue = (uint32_t)speedReference; 00287 outputValue += pid_Controller(incrementSetpoint, (int16_t)sineTableIncrement, &pidParameters); 00288 00289 if (outputValue < 0) 00290 { 00291 outputValue = 0; 00292 } 00293 else if (outputValue > PWM_TOP_VALUE) 00294 { 00295 outputValue = PWM_TOP_VALUE; 00296 } 00297 __disable_interrupt(); 00298 amplitude = outputValue; 00299 __enable_interrupt(); 00300 #else 00301 __disable_interrupt(); 00302 amplitude = speedReference; 00303 __enable_interrupt(); 00304 #endif 00305 }
Here is the call graph for this function:

| __interrupt void Timer1OverflowISR | ( | ) |
Timer/counter1 overflow interrupt service routine.
This ISR is run every time Timer/counter1 overflows. This is the same moment as the double buffered PWM outputs are updated.
The responsibilities of this ISR are:
Definition at line 964 of file main.c.
References AdjustSineTableIndex(), amplitude, BLOCK_COMMUTATION_DUTY_MULTIPLIER, BlockCommutationSetDuty(), CommutationTicksUpdate(), DesiredDirectionUpdate(), DIRECTION_UNKNOWN, DisablePWMOutputs(), FALSE, PWM_TOP_VALUE, SineOutputUpdate(), sineTableIncrement, speedControllerTimer, TimerSetModeBrake(), WAVEFORM_BLOCK_COMMUTATION, WAVEFORM_SINUSOIDAL, and WAVEFORM_UNDEFINED.
00965 { 00966 PORTA |= (1 << PA4); 00967 if (fastFlags.driveWaveform == WAVEFORM_SINUSOIDAL) 00968 { 00969 AdjustSineTableIndex(sineTableIncrement); 00970 SineOutputUpdate(); 00971 } 00972 else if (fastFlags.driveWaveform == WAVEFORM_BLOCK_COMMUTATION) 00973 { 00974 uint16_t blockCommutationDuty = amplitude * BLOCK_COMMUTATION_DUTY_MULTIPLIER; 00975 00976 if (blockCommutationDuty > PWM_TOP_VALUE) 00977 { 00978 blockCommutationDuty = PWM_TOP_VALUE; 00979 } 00980 BlockCommutationSetDuty(blockCommutationDuty); 00981 } 00982 00983 //Update desired direction flag. 00984 DesiredDirectionUpdate(); 00985 00986 static uint8_t lastDesiredDirection = 0xff; 00987 if ( (fastFlags.desiredDirection != lastDesiredDirection)) 00988 { 00989 #if (TURN_MODE == TURN_MODE_COAST) 00990 //Disable driver signals to let motor coast. The motor will automatically 00991 //start once it is synchronized or stopped. 00992 DisablePWMOutputs(); 00993 fastFlags.motorSynchronized = FALSE; 00994 fastFlags.driveWaveform = WAVEFORM_UNDEFINED; 00995 #endif 00996 00997 #if (TURN_MODE == TURN_MODE_BRAKE) 00998 //Set motor in brake mode. The motor will automatically start once it is 00999 //synchronized or stopped. 01000 fastFlags.motorSynchronized = FALSE; 01001 if (fastFlags.actualDirection != DIRECTION_UNKNOWN) 01002 { 01003 TimerSetModeBrake(); // Automatically sets driveWaveform. 01004 } 01005 #endif 01006 01007 lastDesiredDirection = fastFlags.desiredDirection; 01008 } 01009 01010 CommutationTicksUpdate(); 01011 01012 if (speedControllerTimer > 0) 01013 { 01014 speedControllerTimer--; 01015 } 01016 PORTA &= ~(1 << PA4); 01017 }
Here is the call graph for this function:

| static void TimerSetModeBlockCommutation | ( | void | ) | [static] |
Configures Timer/counter1 in block commutation mode.
This function configures Timer/counter1 in block commutation mode in a safe way by disabling all output before any configuration bits are changed. After running this function, Timer/counter1 will be in dual slop PWM6 mode. Commutations can be performed by running 'BlockCommutate'. The duty cycle can be adjusted by calling 'BlockCommutationSetDuty'.
Definition at line 352 of file main.c.
References BlockCommutationSetDuty(), DisablePWMOutputs(), EnablePWMOutputs(), and WAVEFORM_BLOCK_COMMUTATION.
Referenced by CommutationTicksUpdate().
00353 { 00354 //Set PWM pins to input (Hi-Z) while changing modes. 00355 DisablePWMOutputs(); 00356 00357 //Set Timer/counter1 in dual slope PWM6 mode, clear on upcounting, set on downcounting (non-inverting). 00358 TCCR1A = (1 << COM1A1) | (0 << COM1A0) | (1 << COM1B1) | (0 << COM1B0) | (1 << PWM1A) | (1 << PWM1B); 00359 TCCR1C = (1 << COM1A1S) | (0 << COM1A0S) | (1 << COM1B1S) | (0 << COM1B0S) | (1 << COM1D1) | (0 << COM1D0) | (1 << PWM1D); 00360 TCCR1D |= (1 << WGM11) | (1 << WGM10); 00361 00362 TCCR1E = 0x00; 00363 00364 //Set output duty cycle to 0. 00365 BlockCommutationSetDuty(0x0000); 00366 00367 fastFlags.driveWaveform = WAVEFORM_BLOCK_COMMUTATION; 00368 00369 //Change PWM pins to output again to allow PWM control. 00370 EnablePWMOutputs(); 00371 }
Here is the call graph for this function:

| static void TimerSetModeBrake | ( | void | ) | [static] |
Configures Timer/Counter1 in braking mode.
This function configures Timer/counter1 in sinusoidal mode in a safe way way by disabling all output before any configuration bits are changed. After running this function, Timer/counter1 will be in phase and frequency correct mode with a duty cycle of 0 on all three phases, resulting in low side braking.
Definition at line 384 of file main.c.
References DisablePWMOutputs(), EnablePWMOutputs(), TC1_SET_ALL_COMPARE_VALUES, and WAVEFORM_BRAKING.
Referenced by Timer1OverflowISR().
00385 { 00386 //Set PWM pins to input (Hi-Z) while changing modes. 00387 DisablePWMOutputs(); 00388 00389 //Set Timer/counter1 in phase and frequency correct mode. 00390 TCCR1A = (0 << COM1A1) | (1 << COM1A0) | (0 << COM1B1) | (1 << COM1B0) | (1 << PWM1A) | (1 << PWM1B); 00391 TCCR1C = (0 << COM1A1S) | (1 << COM1A0S) | (0 << COM1B1S) | (1 << COM1B0S) | (0 << COM1D1) | (1 << COM1D0) | (1 << PWM1D); 00392 TCCR1D &= ~((1 << WGM11) | (1 << WGM10)); 00393 TCCR1D |= (0 << WGM11) | (1 << WGM10); 00394 00395 //All output duty cycles at 0 creates a braking force. (Low side braking) 00396 TC1_SET_ALL_COMPARE_VALUES(0x0000); 00397 00398 fastFlags.driveWaveform = WAVEFORM_BRAKING; 00399 00400 //Change PWM pins to output again to allow PWM control. 00401 EnablePWMOutputs(); 00402 }
Here is the call graph for this function:

| static void TimerSetModeSinusoidal | ( | void | ) | [static] |
Configures Timer/Counter1 in Sinusoidal mode.
This function configures Timer/counter1 in sinusoidal mode in a safe way way by disabling all output before any configuration bits are changed. After running this function, Timer/counter1 will be in phase and frequency correct mode used for sine wave generation.
Definition at line 316 of file main.c.
References DisablePWMOutputs(), EnablePWMOutputs(), TC1_SET_ALL_COMPARE_VALUES, and WAVEFORM_SINUSOIDAL.
Referenced by HallChangeISR().
00317 { 00318 //Set PWM pins to input (Hi-Z) while changing modes. 00319 DisablePWMOutputs(); 00320 00321 //Set Timer/counter1 in phase and frequency correct mode. 00322 TCCR1A = (0 << COM1A1) | (1 << COM1A0) | (0 << COM1B1) | (1 << COM1B0) | (1 << PWM1A) | (1 << PWM1B); 00323 TCCR1C = (0 << COM1A1S) | (1 << COM1A0S) | (0 << COM1B1S) | (1 << COM1B0S) | (0 << COM1D1) | (1 << COM1D0) | (1 << PWM1D); 00324 TCCR1D &= ~((1 << WGM11) | (1 << WGM10)); 00325 TCCR1D |= (0 << WGM11) | (1 << WGM10); 00326 00327 TC1_SET_ALL_COMPARE_VALUES(0x0000); 00328 00329 fastFlags.driveWaveform = WAVEFORM_SINUSOIDAL; 00330 00331 //Wait for the PWM cycle to complete. 00332 TIFR = TIFR; 00333 while ( ! (TIFR & (1 << TOV1)) ) 00334 { 00335 00336 } 00337 00338 //Change PWM pins to output again to allow PWM control. 00339 EnablePWMOutputs(); 00340 }
Here is the call graph for this function:

| __no_init __regvar volatile uint8_t advanceCommutationSteps |
The advance commutation angle.
This variable specifies a shift in the sine table that will generate a lead angle. For a 192 element sine table, an increase of one in advanceCommutationSteps will result in 1.875 degrees lead angle.
Definition at line 92 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-0x03ff.
Definition at line 82 of file main.c.
Referenced by SineOutputUpdate(), SpeedController(), and Timer1OverflowISR().
| __no_init __regvar volatile uint16_t commutationTicks |
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 74 of file main.c.
Referenced by CommutationTicksUpdate(), and HallChangeISR().
| __no_init __regvar volatile uint16_t sineTableIncrement |
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 55 of file main.c.
Referenced by CommutationTicksUpdate(), HallChangeISR(), SpeedController(), and Timer1OverflowISR().
| __no_init __regvar volatile uint16_t sineTableIndex |
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 64 of file main.c.
Referenced by AdjustSineTableIndex(), HallChangeISR(), and SineOutputUpdate().
| __no_init __regvar volatile uint8_t sineTableNextSectorStart |
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 103 of file main.c.
Referenced by AdjustSineTableIndex(), and HallChangeISR().
| __no_init __regvar volatile uint8_t speedControllerTimer |
Time in ticks until the speed controller loop should be executed.
This variable holds the number of ticks until the speed controller should be executed.
Definition at line 111 of file main.c.
Referenced by main(), and Timer1OverflowISR().
| volatile __io PMSMflags_t fastFlags x0a |
1.5.2