00001
00028 #include <ioavr.h>
00029 #include <inavr.h>
00030 #include "stdint.h"
00031 #include "PMSM.h"
00032 #include "PMSMtables.h"
00033
00034 #if (SPEED_CONTROL_METHOD == SPEED_CONTROL_CLOSED_LOOP)
00035 #include "pid.h"
00036 #endif
00037
00044 __io volatile PMSMflags_t fastFlags @0x1e;
00045
00046
00052 __no_init __regvar volatile uint16_t sineTableIncrement @14;
00053
00054
00061 __no_init __regvar volatile uint16_t sineTableIndex @12;
00062
00063
00071 __no_init __regvar volatile uint16_t commutationTicks @10;
00072
00073
00079 __no_init __regvar volatile uint8_t amplitude @9;
00080
00081
00089 __no_init __regvar volatile uint8_t advanceCommutationSteps @8;
00090
00091
00100 __no_init __regvar volatile uint8_t sineTableNextSectorStart @7;
00101
00102
00109 volatile uint8_t current;
00110
00111
00113 volatile uint8_t speedInput;
00114
00119 volatile uint8_t SpeedControllerRun = FALSE;
00120
00121
00122 #if (SPEED_CONTROL_METHOD == SPEED_CONTROL_CLOSED_LOOP)
00123
00124 pidData_t pidParameters;
00125 #endif
00126
00127
00135 void main(void)
00136 {
00137
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
00150 CheckEmergencyShutdown();
00151
00152
00153
00154 {
00155 PMSMflags_t fastFlagsInitial;
00156
00157
00158
00159
00160 fastFlagsInitial.motorStopped = FALSE;
00161
00162
00163
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
00175 TIMSK1 |= (1 << ICIE1);
00176
00177
00178 __enable_interrupt();
00179 for(;;)
00180 {
00181 if (SpeedControllerRun)
00182 {
00183 SpeedController();
00184 SpeedControllerRun = FALSE;
00185 }
00186 }
00187 }
00188
00189
00195 static void PortsInit(void)
00196 {
00197 #if (HALL_PULLUP_ENABLE == TRUE)
00198
00199 PORTC = (1 << H1_PIN) | (1 << H2_PIN) | (1 << H3_PIN);
00200 #endif
00201
00202
00203 DDRD = (1 << REV_ROTATION_PIN) | (1 << TACHO_OUTPUT_PIN);
00204
00205
00206 PORTD |= (1 << DIRECTION_COMMAND_PIN);
00207 }
00208
00209
00216 static void TimersInit(void)
00217 {
00218
00219 TCCR0A = (1 << WGM00);
00220 TCCR1A = (1 << WGM11);
00221 TCCR2A = (1 << WGM20);
00222
00223
00224 ICR1 = 0xff;
00225
00226
00227 TCNT0 = 0;
00228 TCNT1 = 2;
00229 TCNT2 = 4;
00230
00231
00232 TCCR0B = (0 << CS01) | (1 << CS00);
00233 TCCR1B = (1 << WGM13) | (0 << CS11) | (1 << CS10);
00234 TCCR2B = (0 << CS21) | (1 << CS20);
00235 }
00236
00237
00244 static void PinChangeIntInit(void)
00245 {
00246
00247 PCMSK0 = (1 << PCINT5);
00248
00249
00250 PCMSK1 = (1 << PCINT10) | (1 << PCINT9) | (1 << PCINT8);
00251
00252
00253 PCMSK2 = (1 << PCINT18);
00254
00255
00256 PCICR = (1 << PCIE2) | (1 << PCIE1) | (1 << PCIE0);
00257 }
00258
00259
00266 static void ADCInit(void)
00267 {
00268
00269 ADMUX = ADMUX_SPEED_REF;
00270
00271
00272 ADCSRA = (1 << ADEN) | (1 << ADSC) | (1 << ADATE) | (1 << ADIF) | (1 << ADIE) | ADC_PRESCALER;
00273
00274
00275 ADCSRB = (1 << ADTS2) | (0 << ADTS1) | (0 << ADTS0);
00276 }
00277
00278
00290 static void CheckEmergencyShutdown(void)
00291 {
00292 if ( (PINB & (1 << EMERGENCY_SHUTDOWN_PIN)) != 0)
00293 {
00294
00295 }
00296 }
00297
00298
00305 static void SpeedController(void)
00306 {
00307 #if (SPEED_CONTROL_METHOD == SPEED_CONTROL_CLOSED_LOOP)
00308
00309
00310 int16_t incrementSetpoint = ((uint32_t)speedInput * SPEED_CONTROLLER_MAX_INCREMENT) / SPEED_CONTROLLER_MAX_INPUT;
00311
00312
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 }
00331
00332
00340 #pragma inline=forced
00341 static void TimersSetModeSinusoidal(void)
00342 {
00343
00344 DisablePWMOutputs();
00345
00346
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
00352 OCR0A = OCR1AL = OCR2A = 0;
00353 OCR0B = OCR1BL = OCR2B = 0xff;
00354
00355
00356 TimersWaitForNextPWMCycle();
00357
00358 fastFlags.driveWaveform = WAVEFORM_SINUSOIDAL;
00359
00360
00361 EnablePWMOutputs();
00362 }
00363
00364
00372 #pragma inline=forced
00373 static void TimersSetModeBlockCommutation(void)
00374 {
00375
00376 DisablePWMOutputs();
00377
00378
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
00384 BlockCommutationSetDuty(0);
00385
00386
00387 TimersWaitForNextPWMCycle();
00388
00389 fastFlags.driveWaveform = WAVEFORM_BLOCK_COMMUTATION;
00390
00391
00392 EnablePWMOutputs();
00393 }
00394
00395
00402 #if (TURN_MODE == TURN_MODE_BRAKE)
00403 #pragma inline=forced
00404 static void TimersSetModeBrake(void)
00405 {
00406
00407 DisablePWMOutputs();
00408
00409
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
00415 OCR0A = OCR1A = OCR2A = 0x00;
00416
00417
00418 OCR0B = OCR1B = OCR2B = 0xff;
00419
00420
00421 TimersWaitForNextPWMCycle();
00422
00423 fastFlags.driveWaveform = WAVEFORM_BRAKING;
00424
00425 EnablePWMOutputs();
00426 }
00427 #endif
00428
00429
00436 #pragma inline=forced
00437 static void TimersWaitForNextPWMCycle(void)
00438 {
00439
00440 TIFR1 = (1 << ICF1);
00441
00442
00443 while ( !(TIFR1 & (1 << ICF1)) )
00444 {
00445
00446 }
00447 }
00448
00449
00460 #pragma inline=forced
00461 static void BlockCommutationSetDuty(const uint8_t duty)
00462 {
00463
00464 OCR0A = OCR0B = OCR1AL = OCR1BL = OCR2A = OCR2B = duty;
00465 }
00466
00467
00478 #pragma inline=forced
00479 static uint8_t GetDesiredDirection(void)
00480 {
00481 return (uint8_t)fastFlags.desiredDirection;
00482 }
00483
00484
00501 #pragma inline=forced
00502 static uint8_t GetActualDirection(void)
00503 {
00504 return fastFlags.actualDirection;
00505 }
00506
00507
00519 #pragma inline=forced
00520 static void BlockCommutate(const uint8_t direction, uint8_t hall)
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 }
00538
00539
00555 #pragma inline=forced
00556 static uint8_t GetHall(void)
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 }
00564
00565
00571 #pragma inline=forced
00572 static void DesiredDirectionUpdate(void)
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 }
00583
00584
00593 #pragma inline=forced
00594 static void ActualDirectionUpdate(uint8_t lastHall, const uint8_t newHall)
00595 {
00596
00597
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 }
00618
00619
00632 #pragma inline=forced
00633 static void ReverseRotationSignalUpdate(void)
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 }
00646
00647
00660 #pragma inline=forced
00661 static void InsertDeadband(const uint8_t compareValue, uint8_t * compareHighPtr, uint8_t * compareLowPtr)
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 }
00679
00680
00694 #pragma inline = forced
00695 static uint16_t SineTableIncrementCalculate(const uint16_t ticks)
00696 {
00697 if (ticks < 256)
00698 {
00699 return divisionTable[(uint8_t)ticks];
00700 }
00701 return (uint16_t)(((SINE_TABLE_LENGTH / 6) << 8) / ticks);
00702 }
00703
00704
00712 #pragma inline=forced
00713 static void AdjustSineTableIndex(const uint16_t increment)
00714 {
00715 sineTableIndex += increment;
00716
00717
00718
00719 if ((sineTableIndex >> 8) >= SINE_TABLE_LENGTH)
00720 {
00721 sineTableIndex -= (SINE_TABLE_LENGTH << 8);
00722 sineTableNextSectorStart -= SINE_TABLE_LENGTH;
00723 }
00724
00725
00726 uint8_t nextSectorStart = sineTableNextSectorStart;
00727 if ((sineTableIndex >> 8) > nextSectorStart)
00728 {
00729 sineTableIndex = (nextSectorStart << 8);
00730 }
00731 }
00732
00733
00745 #pragma inline=forced
00746 static void SetAdvanceCommutation(const uint8_t advanceCommutation)
00747 {
00748 advanceCommutationSteps = advanceCommutation;
00749 }
00750
00751
00763 #pragma inline=forced
00764 static void TachoOutputUpdate(const uint8_t hall)
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 }
00777
00778
00785 #pragma inline=forced
00786 static void EnablePWMOutputs(void)
00787 {
00788 DDRB |= PWM_PATTERN_PORTB;
00789 DDRD |= PWM_PATTERN_PORTD;
00790 }
00791
00792
00799 #pragma inline=forced
00800 static void DisablePWMOutputs(void)
00801 {
00802 DDRB &= ~PWM_PATTERN_PORTB;
00803 DDRD &= ~PWM_PATTERN_PORTD;
00804 }
00805
00806
00815 #pragma inline=forced
00816 static void CommutationTicksUpdate(void)
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 }
00837
00838
00846 #pragma inline=forced
00847 static void MotorSynchronizedUpdate(void)
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 }
00870
00871
00881 #pragma inline=forced
00882 static uint8_t IsMotorSynchronized(void)
00883 {
00884 return (uint8_t)(fastFlags.motorSynchronized);
00885 }
00886
00887
00900 #pragma vector=PCINT0_vect
00901 __interrupt void EmergencyInterruptISR(void)
00902 {
00903 DisablePWMOutputs();
00904 for (;;)
00905 {
00906
00907 }
00908 }
00909
00910
00929 #pragma vector=PCINT1_vect
00930 __interrupt void HallChangeISR(void)
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
00945
00946
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
00961
00962
00963
00964 sineTableNextSectorStart = (tempIndex >> 8) + TABLE_ELEMENTS_PER_COMMUTATION_SECTOR;
00965 }
00966
00967
00968 else if (fastFlags.driveWaveform == WAVEFORM_BLOCK_COMMUTATION)
00969 {
00970 BlockCommutate(GetDesiredDirection(), hall);
00971 }
00972
00973
00974 TachoOutputUpdate(hall);
00975 ActualDirectionUpdate(lastHall, hall);
00976 ReverseRotationSignalUpdate();
00977
00978 lastHall = hall;
00979
00980
00981
00982 sineTableIncrement = SineTableIncrementCalculate(commutationTicks);
00983 commutationTicks = 0;
00984
00985
00986 fastFlags.motorStopped = FALSE;
00987 }
00988
00989
00998 #pragma vector=PCINT2_vect
00999 __interrupt void DirectionInputChangeISR(void)
01000 {
01001
01002 DesiredDirectionUpdate();
01003
01004 #if (TURN_MODE == TURN_MODE_COAST)
01005
01006
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
01015
01016 fastFlags.motorSynchronized = FALSE;
01017 fastFlags.motorStopped = FALSE;
01018 TimersSetModeBrake();
01019 #endif
01020 }
01021
01022
01029 #pragma vector=TIMER1_CAPT_vect
01030 __interrupt void Timer1CaptureISR(void)
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
01041
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
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
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 }
01104
01105
01121 #pragma vector=ADC_vect
01122 __interrupt void ADCCompleteISR(void)
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
01136 break;
01137 }
01138
01139
01140 TIFR0 = (1 << TOV0);
01141 }