00001
00028 #include <ioavr.h>
00029 #include <inavr.h>
00030 #include "stdint.h"
00031 #include "PMSM.h"
00032 #include "PMSM_tables.h"
00033 #include "TinyX61_macros.h"
00034
00035
00036 #if (SPEED_CONTROL_METHOD == SPEED_CONTROL_CLOSED_LOOP)
00037 #include "pid.h"
00038 #endif
00039
00040
00047 volatile __io PMSMflags_t fastFlags @0x0a;
00048
00049
00055 __no_init __regvar volatile uint16_t sineTableIncrement @14;
00056
00057
00064 __no_init __regvar volatile uint16_t sineTableIndex @12;
00065
00066
00074 __no_init __regvar volatile uint16_t commutationTicks @10;
00075
00076
00082 __no_init __regvar volatile uint16_t amplitude @8;
00083
00084
00092 __no_init __regvar volatile uint8_t advanceCommutationSteps @7;
00093
00094
00103 __no_init __regvar volatile uint8_t sineTableNextSectorStart @6;
00104
00105
00111 __no_init __regvar volatile uint8_t speedControllerTimer @5;
00112
00113
00114 #if (SPEED_CONTROL_METHOD == SPEED_CONTROL_CLOSED_LOOP)
00116 pidData_t pidParameters;
00117 #endif
00118
00119
00120 void main(void)
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
00136
00137 {
00138 PMSMflags_t fastFlagsInitial;
00139
00140
00141
00142
00143 fastFlagsInitial.motorStopped = FALSE;
00144
00145
00146
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
00158 TIMSK |= (1 << TOV1);
00159
00160
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 }
00180
00181
00182
00187 static void PortsInit(void)
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 }
00195
00196
00203 static void PLLInit(void)
00204 {
00205
00206 while ( !(PLLCSR & (1 << PLOCK)) )
00207 {
00208
00209 }
00210 PLLCSR = (1 << PCKE);
00211 }
00212
00213
00218 static void PWMInit(void)
00219 {
00220
00221 TCCR1B = (PWM_INVERT_OUTPUT << PWM1X) | (1 << CS10);
00222
00223
00224 TCCR1D = (1 << FPIE1) | (1 << FPEN1) | (0 << FPES1);
00225
00226
00227 DT1 = (DEAD_TIME << 4) | (DEAD_TIME);
00228
00229
00230 TC1_WRITE_10_BIT_REGISTER(OCR1C, PWM_TOP_VALUE);
00231 }
00232
00233
00239 static void ADCInit(void)
00240 {
00241
00242 ADMUX = (1 << REFS1) | (0 << MUX4) | (0 << MUX3) | (1 << MUX2) | (1 << MUX1) | (0 << MUX0);
00243
00244 ADCSRA = (1 << ADEN) |
00245 (1 << ADSC) |
00246 (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
00247 ADCSRB = (1 << REFS2);
00248 }
00249
00250
00255 static void PinChangeInit(void)
00256 {
00257
00258 PCMSK0 = (1 << PCINT2) | (1 << PCINT1) | (1 << PCINT0);
00259
00260 PCMSK1 = 0x00;
00261
00262
00263 GIMSK |= (1 << PCIE1);
00264
00265
00266 DDRA |= ((1 << PA2) | (1 << PA1) | (1 << PA0));
00267 DDRA &= ~((1 << PA2) | (1 << PA1) | (1 << PA0));
00268 }
00269
00270
00277 static void SpeedController(uint16_t speedReference)
00278 {
00279 #if (SPEED_CONTROL_METHOD == SPEED_CONTROL_CLOSED_LOOP)
00280
00281
00282 int16_t incrementSetpoint = ((uint32_t)speedReference * SPEED_CONTROLLER_MAX_INCREMENT) / SPEED_CONTROLLER_MAX_INPUT;
00283
00284
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 }
00306
00307
00315 #pragma inline = forced
00316 static void TimerSetModeSinusoidal(void)
00317 {
00318
00319 DisablePWMOutputs();
00320
00321
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
00332 TIFR = TIFR;
00333 while ( ! (TIFR & (1 << TOV1)) )
00334 {
00335
00336 }
00337
00338
00339 EnablePWMOutputs();
00340 }
00341
00342
00351 #pragma inline = forced
00352 static void TimerSetModeBlockCommutation(void)
00353 {
00354
00355 DisablePWMOutputs();
00356
00357
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
00365 BlockCommutationSetDuty(0x0000);
00366
00367 fastFlags.driveWaveform = WAVEFORM_BLOCK_COMMUTATION;
00368
00369
00370 EnablePWMOutputs();
00371 }
00372
00373
00382 #if (TURN_MODE == TURN_MODE_BRAKE)
00383 #pragma inline = forced
00384 static void TimerSetModeBrake(void)
00385 {
00386
00387 DisablePWMOutputs();
00388
00389
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
00396 TC1_SET_ALL_COMPARE_VALUES(0x0000);
00397
00398 fastFlags.driveWaveform = WAVEFORM_BRAKING;
00399
00400
00401 EnablePWMOutputs();
00402 }
00403 #endif
00404
00405
00418 #pragma inline = forced
00419 static void BlockCommutationSetDuty(const uint16_t compareValue)
00420 {
00421 TC1_PWM6_SET_DUTY_CYCLE(compareValue);
00422 }
00423
00424
00435 #pragma inline = forced
00436 static uint8_t GetDesiredDirection(void)
00437 {
00438 return (uint8_t)fastFlags.desiredDirection;
00439 }
00440
00441
00453 #pragma inline = forced
00454 static void BlockCommutate(const uint8_t direction, const uint8_t hall)
00455 {
00456 if (direction == DIRECTION_FORWARD)
00457 {
00458 TCCR1E = blockCommutationTableForward[hall];
00459 }
00460 else
00461 {
00462 TCCR1E = blockCommutationTableReverse[hall];
00463 }
00464 }
00465
00466
00482 #pragma inline = forced
00483 static uint8_t GetHall(void)
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 }
00491
00492
00498 #pragma inline = forced
00499 static void DesiredDirectionUpdate(void)
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 }
00510
00511
00520 #pragma inline = forced
00521 static void ActualDirectionUpdate(uint8_t lastHall, const uint8_t newHall)
00522 {
00523
00524
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 }
00545
00546
00557 #pragma inline = forced
00558 static uint16_t SineTableIncrementCalculate(const uint16_t ticks)
00559 {
00560 return (uint16_t)(((SINE_TABLE_LENGTH / 6) << 8) / ticks);
00561 }
00562
00563
00571 #pragma inline = forced
00572 static void AdjustSineTableIndex(const uint16_t increment)
00573 {
00574 sineTableIndex += increment;
00575
00576
00577
00578 if ((sineTableIndex >> 8) >= SINE_TABLE_LENGTH)
00579 {
00580 sineTableIndex -= (SINE_TABLE_LENGTH << 8);
00581 sineTableNextSectorStart -= SINE_TABLE_LENGTH;
00582 }
00583
00584
00585 uint8_t nextSectorStart = sineTableNextSectorStart;
00586 if ((sineTableIndex >> 8) > nextSectorStart)
00587 {
00588 sineTableIndex = (nextSectorStart << 8);
00589 }
00590 }
00591
00592
00604 #pragma inline = forced
00605 static void SetAdvanceCommutation(const uint8_t advanceCommutation)
00606 {
00607 advanceCommutationSteps = advanceCommutation;
00608 }
00609
00610
00615 #pragma inline = forced
00616 static void EnablePWMOutputs(void)
00617 {
00618 DDRB |= PWM_PIN_MASK_PORTB;
00619 }
00620
00621
00626 #pragma inline = forced
00627 static void DisablePWMOutputs(void)
00628 {
00629 DDRB &= (~PWM_PIN_MASK_PORTB);
00630 }
00631
00632
00641 #pragma inline = forced
00642 static void CommutationTicksUpdate(void)
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 }
00664
00665
00673 #pragma inline = forced
00674 static void MotorSynchronizedUpdate(void)
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 }
00696
00697
00707 #pragma inline = forced
00708 static uint8_t IsMotorSynchronized(void)
00709 {
00710 return (uint8_t)(fastFlags.motorSynchronized);
00711 }
00712
00713
00721 #if (SINE_TABLE_SIZE == SINE_TABLE_SIZE_SMALL)
00722 #pragma inline = forced
00723 uint8_t SineTableSmallGetValue(uint8_t index)
00724 {
00725
00726 if (index >= (SINE_TABLE_LENGTH * 2 / 3) )
00727 {
00728 return 0;
00729 }
00730
00731
00732 if (index >= (SINE_TABLE_LENGTH / 3) )
00733 {
00734 index = ((SINE_TABLE_LENGTH * 2 / 3) - 1) - index;
00735 }
00736
00737 return sineTable[index];
00738 }
00739 #endif
00740
00741
00747 #if (SINE_TABLE_SIZE == SINE_TABLE_SIZE_LARGE)
00748 #pragma inline = forced
00749 static void SineOutputUpdate(void)
00750 {
00751 uint8_t const __flash * sineTablePtr = sineTable;
00752 uint16_t temp;
00753
00754
00755
00756
00757 {
00758 uint8_t tempIndex = (uint8_t)(sineTableIndex >> 8);
00759 sineTablePtr += tempIndex;
00760 sineTablePtr += tempIndex;
00761 sineTablePtr += tempIndex;
00762 }
00763
00764
00765
00766
00767
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
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
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 }
00805 #endif
00806
00807
00813 #if (SINE_TABLE_SIZE == SINE_TABLE_SIZE_SMALL)
00814 #pragma inline = forced
00815 static void SineOutputUpdate(void)
00816 {
00817 uint16_t temp;
00818 uint8_t tempIndex;
00819
00820
00821 tempIndex = (uint8_t)(sineTableIndex >> 8);
00822
00823 temp = SineTableSmallGetValue(tempIndex);
00824 if (temp != 0)
00825 {
00826 temp = MultiplyUS15x8(amplitude, temp);
00827 }
00828 TC1_WRITE_10_BIT_REGISTER(COMPARE_REGISTER_PHASE_U, temp);
00829
00830
00831 tempIndex += (SINE_TABLE_LENGTH / 3);
00832 if (tempIndex >= SINE_TABLE_LENGTH)
00833 {
00834 tempIndex -= SINE_TABLE_LENGTH;
00835 }
00836
00837 temp = SineTableSmallGetValue(tempIndex);
00838 if (temp != 0)
00839 {
00840 temp = MultiplyUS15x8(amplitude, temp);
00841 }
00842 if (GetDesiredDirection() == DIRECTION_FORWARD)
00843 {
00844 TC1_WRITE_10_BIT_REGISTER(COMPARE_REGISTER_PHASE_W, temp);
00845 }
00846 else
00847 {
00848 TC1_WRITE_10_BIT_REGISTER(COMPARE_REGISTER_PHASE_V, temp);
00849 }
00850
00851
00852 tempIndex += (SINE_TABLE_LENGTH / 3);
00853 if (tempIndex >= SINE_TABLE_LENGTH)
00854 {
00855 tempIndex -= SINE_TABLE_LENGTH;
00856 }
00857
00858 temp = SineTableSmallGetValue(tempIndex);
00859 if (temp != 0)
00860 {
00861 temp = MultiplyUS15x8(amplitude, temp);
00862 }
00863 if (GetDesiredDirection() == DIRECTION_FORWARD)
00864 {
00865 TC1_WRITE_10_BIT_REGISTER(COMPARE_REGISTER_PHASE_V, temp);
00866 }
00867 else
00868 {
00869 TC1_WRITE_10_BIT_REGISTER(COMPARE_REGISTER_PHASE_W, temp);
00870 }
00871 }
00872 #endif
00873
00874
00886 #pragma vector = PCINT0_vect
00887 __interrupt void HallChangeISR()
00888 {
00889 static uint8_t lastHall = 0xff;
00890 uint8_t hall;
00891
00892 hall = GetHall();
00893
00894
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
00908
00909
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
00924
00925
00926
00927 sineTableNextSectorStart = (tempIndex >> 8) + TABLE_ELEMENTS_PER_COMMUTATION_SECTOR;
00928
00929 }
00930
00931 else if (fastFlags.driveWaveform == WAVEFORM_BLOCK_COMMUTATION)
00932 {
00933 BlockCommutate(GetDesiredDirection(), hall);
00934 }
00935
00936
00937 ActualDirectionUpdate(lastHall, hall);
00938
00939 lastHall = hall;
00940
00941
00942
00943
00944 sineTableIncrement = SineTableIncrementCalculate(commutationTicks);
00945 commutationTicks = 0;
00946
00947
00948 fastFlags.motorStopped = FALSE;
00949 }
00950
00951
00963 #pragma vector = TIM1_OVF_vect
00964 __interrupt void Timer1OverflowISR()
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
00984 DesiredDirectionUpdate();
00985
00986 static uint8_t lastDesiredDirection = 0xff;
00987 if ( (fastFlags.desiredDirection != lastDesiredDirection))
00988 {
00989 #if (TURN_MODE == TURN_MODE_COAST)
00990
00991
00992 DisablePWMOutputs();
00993 fastFlags.motorSynchronized = FALSE;
00994 fastFlags.driveWaveform = WAVEFORM_UNDEFINED;
00995 #endif
00996
00997 #if (TURN_MODE == TURN_MODE_BRAKE)
00998
00999
01000 fastFlags.motorSynchronized = FALSE;
01001 if (fastFlags.actualDirection != DIRECTION_UNKNOWN)
01002 {
01003 TimerSetModeBrake();
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 }
01018
01019
01027 #pragma vector = FAULT_PROTECTION
01028 __interrupt void FaultProtectionISR()
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 }
01036
01037
01050 #pragma inline = forced
01051 static unsigned int MultiplyUS15x8(const uint16_t m15, const uint8_t m8)
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 }
01103