main.c File Reference


Detailed Description

Motor control implementation.

This file contains the full implementation of the motor control, except the PID-controller.

Application note:
AVR449: Sinusoidal driving of three-phase permanent motor using ATtiny261/461/861.
Documentation
For comprehensive code documentation, supported compilers, compiler settings and supported devices see readme.html
Author:
Atmel Corporation: http://www.atmel.com
Support email: avr@atmel.com
$Name$
Revision
2571
$RCSfile$
Date
2007-10-08 15:53:50 +0200 (ma, 08 okt 2007)

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.


Function Documentation

static void ActualDirectionUpdate ( uint8_t  lastHall,
const uint8_t  newHall 
) [static]

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.

Parameters:
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.

Parameters:
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 }

static void BlockCommutate ( const uint8_t  direction,
const uint8_t  hall 
) [static]

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.

Note:
Do not use this function while the timers are configured for sine wave driving.
Parameters:
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.

Parameters:
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.

Note:
The direction input is not read at this time. A separate pin change interrupt is responsible for reading the input.
Return values:
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.

Note:
It is possible to change the physical placement of hall sensor inputs, but the recommended configuration is the one used in this example, since it requires very little code to decode the hall values.
Returns:
The decoded hall sensor value.
Return values:
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.

Returns:
The motor synchronized flag.
Return values:
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 }

static unsigned int MultiplyUS15x8 ( const uint16_t  m15,
const uint8_t  m8 
) [static]

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.

Parameters:
m15 15 bit unsigned value (0x0000-0x7fff)
m8 8 bit unsigned value (0x00-0xff)
Returns:
15 most significant bits of m15 * m8 (m15 * m8 / 256)

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.

Note:
There is no checking of the advanceCommutation input parameter, but this should not be set to a value above 40 to avoid overflow in the sine table index.
Parameters:
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:

static uint16_t SineTableIncrementCalculate ( const uint16_t  ticks  )  [static]

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.

Parameters:
ticks The number of ticks in one electrical revolution.
Returns:
The step size in 8.8 format to be used for sine table iteration.

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:


Variable Documentation

__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().

__no_init __regvar volatile uint16_t amplitude

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

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.

Definition at line 47 of file main.c.


Generated on Wed Oct 10 15:31:44 2007 for AVR449 by  doxygen 1.5.2