Main Page | Data Structures | File List | Data Fields | Globals | Related Pages

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:
AVR447: Sinusoidal driving of three-phase permanent motor using ATmega48/88/168
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
RELEASE_1_0
Revision
1.8
RCSfile
main.c,v
Date
2006/03/27 07:20:51

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.


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

__interrupt void ADCCompleteISR void   ) 
 

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 }

static void ADCInit void   )  [static]
 

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 }

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

static void BlockCommutate const uint8_t  direction,
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 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:

static void BlockCommutationSetDuty const uint8_t  duty  )  [static]
 

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.

Note:
The duty cycle is not in percent, but a value from 0-255. Duty cycle in percent can be calculated as duty * 100 / 255.
Parameters:
duty New duty cycle. Range is 0-255.

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 }

static void CheckEmergencyShutdown void   )  [static]
 

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.

Note:
In this version, nothing is done in these situations.
Todo:
Write code to handle a situation where either emergency shut-off set at startup.

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 }

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

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

__interrupt void DirectionInputChangeISR void   ) 
 

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:

static void DisablePWMOutputs void   )  [static]
 

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 }

__interrupt void EmergencyInterruptISR void   ) 
 

Emergency shut-off interrupt service routine.

This ISR is triggered if the emergency shutdown input changes state.

Note:
In the current implementation, the motor driver outputs are simply disabled and the program goes into an eternal loop on any change at this input. Custom code should be made here that handles such situation in a more intelligent way, adapted to the motor and driver stage.
Todo:
Change how emergency shut-off is handled.

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:

static void EnablePWMOutputs void   )  [static]
 

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 }

static uint8_t GetActualDirection void   )  [static]
 

Returns the actual direction of the motor.

This function returns the actual direction of the motor.

Note:
Two hall changes in the same direction is needed before this function returns the correct direction of rotation.
Returns:
The desired direction.
Return values:
DIRECTION_FORWARD Motor is running forward
DIRECTION_REVERSE Motor is running in reverse
DIRECTION_UNKNOWN The current direction of the motor can not be determined (may be stopped or turning), or the hall sensors output incorrect values.

Definition at line 502 of file main.c.

Referenced by ReverseRotationSignalUpdate().

00503 {
00504   return fastFlags.actualDirection;
00505 }

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 479 of file main.c.

Referenced by CommutationTicksUpdate(), HallChangeISR(), ReverseRotationSignalUpdate(), and Timer1CaptureISR().

00480 {
00481   return (uint8_t)fastFlags.desiredDirection;
00482 }

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

__interrupt void HallChangeISR void   ) 
 

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:

static void InsertDeadband const uint8_t  compareValue,
uint8_t compareHighPtr,
uint8_t compareLowPtr
[static]
 

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.

Parameters:
compareValue desired compare value
compareHighPtr Pointer used to return high side compare value with dead band.
compareLowPtr Pointer used to return low side compare value with dead band.

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 }

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 882 of file main.c.

Referenced by HallChangeISR().

00883 {
00884   return (uint8_t)(fastFlags.motorSynchronized);
00885 }

void main void   ) 
 

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:

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

static void PinChangeIntInit void   )  [static]
 

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 }

static void PortsInit void   )  [static]
 

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 }

static void ReverseRotationSignalUpdate void   )  [static]
 

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.

Note:
This function does not update actual and desired direction flags. The result of this function will therefore represent the time at which these variables were updated.

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:

static void SetAdvanceCommutation const uint8_t  advanceCommutation  )  [static]
 

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.

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 746 of file main.c.

References advanceCommutationSteps.

Referenced by main().

00747 {
00748   advanceCommutationSteps = advanceCommutation;
00749 }

static uint16_t SineTableIncrementCalculate const uint16_t  ticks  )  [static]
 

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

Parameters:
ticks The number of ticks between two consecutive hall changes.
Returns:
The increment in 8.8 format to be used for sine table iteration.

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 }

static void SpeedController void   )  [static]
 

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:

static void TachoOutputUpdate const uint8_t  hall  )  [static]
 

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.

Parameters:
hall The current hall sensor value.

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 }

__interrupt void Timer1CaptureISR void   ) 
 

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:

static void TimersInit void   )  [static]
 

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 }

static void TimersSetModeBlockCommutation void   )  [static]
 

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:

static void TimersSetModeBrake void   )  [static]
 

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:

static void TimersSetModeSinusoidal void   )  [static]
 

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:

static void TimersWaitForNextPWMCycle void   )  [static]
 

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 }


Variable Documentation

__no_init __regvar volatile uint8_t advanceCommutationSteps
 

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

__no_init __regvar volatile uint8_t amplitude
 

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

__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 71 of file main.c.

Referenced by CommutationTicksUpdate(), and HallChangeISR().

volatile uint8_t current
 

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

__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 52 of file main.c.

Referenced by HallChangeISR(), SpeedController(), and Timer1CaptureISR().

__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 61 of file main.c.

Referenced by AdjustSineTableIndex(), HallChangeISR(), and Timer1CaptureISR().

__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 100 of file main.c.

Referenced by AdjustSineTableIndex(), and HallChangeISR().

volatile uint8_t SpeedControllerRun = FALSE
 

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

volatile uint8_t speedInput
 

The most recent speed input measurement.

Definition at line 113 of file main.c.

Referenced by ADCCompleteISR(), and SpeedController().

__io volatile PMSMflags_t fastFlags x1e
 

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 44 of file main.c.


Generated on Mon Mar 27 09:31:31 2006 for AVR447: Sine wave driving of three phase motor by  doxygen 1.4.4