Guest User

Untitled

a guest
Jun 24th, 2020
153
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 18.75 KB | None | 0 0
  1. #include "ATmega8.h"
  2. #include <avr/interrupt.h>
  3.  
  4. // --------------------
  5. // This firmware implements servo-style position control on standard brushless motor
  6. // speed controllers of the sort used for radio control airplanes, quadcopters, etc.
  7. //
  8. // The basic speed controller hardware consists of a microcontroller and 6 transistors.
  9. // The transistors are in 3 pairs, which connect to the 3 motor wires. This allows
  10. // the microcontroller to connect each motor wire to battery + or battery -.
  11. // By cycling through a sequence of 6 transistor combinations, the motor is rotated one
  12. // electrical revolution. The number of electrical revolutions needed to complete
  13. // a full physical revolution of the rotor is equal to half the number of permanent
  14. // magnets on the rotor (the magnets alternate polarity, and one electrical revolution
  15. // moves forward one north-south pair).
  16. //
  17. // In order to accurately track the position, 3 hall effect sensors (e.g. U1881)
  18. // must be added to the motor to sense the position of the rotor magnets.
  19. // These sensors cycle through 6 states, which correspond to the 6 transistor states.
  20. // For most motor configurations, spacing the sensors equally around the motor
  21. // (120 physical degrees apart) will result in a valid configuration. One exception
  22. // is 9N12P (9 stator teeth, 12 rotor magnets), where the sensors must be placed at
  23. // 3 consecutive stator teeth.
  24. //
  25. // Once you have the sensor spacing correct, you may also need to shift them all forward
  26. // or back a little bit. Each active transistor pair will pull the rotor to a specific
  27. // position, and the sensors need to be positioned so their state transition points are
  28. // half way between these transistor positions. If the function DetectHallPhase fails to
  29. // detect 6 unique hall states, then the sensors aren't positioned quite right.
  30. //
  31. // Positioning is only done to the nearest hall sensor state, so the total number of steps
  32. // per physical revolution is 3 times the number of rotor magnets (6 transistor states per
  33. // north-south pair). So for example a 12N14P motor will have 42 steps per revolution.
  34. // --------------------
  35.  
  36.  
  37.  
  38. // Various ESC transistor mappings are taken from SimonK firmware https://github.com/sim-/tgy
  39.  
  40. #if 0 // DYS 40A speed controller, from dys_nfet.inc
  41. // Output wires on DYS 40A, viewed from transistor side.
  42. // When ApFET_PORT BIT(ApFET) is CLEAR, output A is positive. When AnFET_PORT BIT(AnFET) is SET, output A is ground. Else disconnected.
  43. //  ______
  44. // |B C A||
  45. // |[] []||
  46. // |[] []||
  47. #define F_CPU 16000000
  48. #define USE_ICP 1
  49. #define rcp_in 0 // RC pulse input
  50. #define rcp_in_port REG_PINB
  51. #define ApFET 4
  52. #define AnFET 5
  53. #define BpFET 3
  54. #define BnFET 7
  55. #define CpFET 2
  56. #define CnFET 1
  57. #define ApFET_port REG_PORTD
  58. #define AnFET_port REG_PORTD
  59. #define BpFET_port REG_PORTD
  60. #define BnFET_port REG_PORTD
  61. #define CpFET_port REG_PORTD
  62. #define CnFET_port REG_PORTB
  63.  
  64. #define INIT_PB (BIT(HallA) | BIT(HallB) | BIT(HallC)) // U1881 hall effect sensors need pull-up on their output pin
  65. #define DIR_PB  BIT(CnFET)
  66. #define INIT_PC (BIT(i2c_clk) | BIT(i2c_data))
  67. #define DIR_PC  0
  68. #define INIT_PD (BIT(ApFET) | BIT(BpFET) | BIT(CpFET) | BIT(txd))
  69. #define DIR_PD  (BIT(ApFET) | BIT(AnFET) | BIT(BpFET) | BIT(BnFET) | BIT(CpFET) | BIT(txd))
  70.  
  71. #define ApFET_off ApFET_port |=  BIT(ApFET)
  72. #define ApFET_on  ApFET_port &= ~BIT(ApFET)
  73. #define BpFET_off BpFET_port |=  BIT(BpFET)
  74. #define BpFET_on  BpFET_port &= ~BIT(BpFET)
  75. #define CpFET_off CpFET_port |=  BIT(CpFET)
  76. #define CpFET_on  CpFET_port &= ~BIT(CpFET)
  77.  
  78. #define AnFET_off AnFET_port &= ~BIT(AnFET)
  79. #define AnFET_on  AnFET_port |=  BIT(AnFET)
  80. #define BnFET_off BnFET_port &= ~BIT(BnFET)
  81. #define BnFET_on  BnFET_port |=  BIT(BnFET)
  82. #define CnFET_off CnFET_port &= ~BIT(CnFET)
  83. #define CnFET_on  CnFET_port |=  BIT(CnFET)
  84.  
  85. #elif 1 // HobbyKing 10A speed controller, from bs.inc
  86. // Output wires on HobbyKing 10A, viewed from transistor side.
  87. // When ApFET_PORT BIT(ApFET) is SET, output A is positive. When AnFET_PORT BIT(AnFET) is SET, output A is ground. Else disconnected.
  88. //  _____
  89. // |C B A|
  90. // |[] []|
  91. // |[] []|
  92. #define F_CPU 16000000
  93. #define USE_INT0 1
  94. #define rcp_in 2 // RC pulse input
  95. #define rcp_in_port REG_PIND
  96. #define ApFET 4
  97. #define AnFET 5
  98. #define BpFET 5
  99. #define BnFET 4
  100. #define CpFET 3
  101. #define CnFET 0
  102. #define ApFET_port REG_PORTD
  103. #define AnFET_port REG_PORTD
  104. #define BpFET_port REG_PORTC
  105. #define BnFET_port REG_PORTC
  106. #define CpFET_port REG_PORTC
  107. #define CnFET_port REG_PORTB
  108.  
  109. #define INIT_PB (BIT(HallA) | BIT(HallB) | BIT(HallC)) // U1881 hall effect sensors need pull-up on their output pin
  110. #define DIR_PB  BIT(CnFET)
  111. #define INIT_PC 0
  112. #define DIR_PC  (BIT(BpFET) | BIT(BnFET) | BIT(CpFET))
  113. #define INIT_PD 0
  114. #define DIR_PD  (BIT(ApFET) | BIT(AnFET))
  115.  
  116. #define ApFET_off ApFET_port &= ~BIT(ApFET)
  117. #define ApFET_on  ApFET_port |=  BIT(ApFET)
  118. #define BpFET_off BpFET_port &= ~BIT(BpFET)
  119. #define BpFET_on  BpFET_port |=  BIT(BpFET)
  120. #define CpFET_off CpFET_port &= ~BIT(CpFET)
  121. #define CpFET_on  CpFET_port |=  BIT(CpFET)
  122.  
  123. #define AnFET_off AnFET_port &= ~BIT(AnFET)
  124. #define AnFET_on  AnFET_port |=  BIT(AnFET)
  125. #define BnFET_off BnFET_port &= ~BIT(BnFET)
  126. #define BnFET_on  BnFET_port |=  BIT(BnFET)
  127. #define CnFET_off CnFET_port &= ~BIT(CnFET)
  128. #define CnFET_on  CnFET_port |=  BIT(CnFET)
  129.  
  130. #else
  131. #error "No target speed controller specified"
  132. #endif
  133.  
  134. // PORTB pins that the hall sensors are connected to
  135. #define HallA 3
  136. #define HallB 4
  137. #define HallC 5
  138.  
  139. // Values for pwmState
  140. #define PWM_FREEWHEEL 0
  141. #define PWM_AnBp 1
  142. #define PWM_AnCp 2
  143. #define PWM_BnCp 3
  144. #define PWM_BnAp 4
  145. #define PWM_CnAp 5
  146. #define PWM_CnBp 6
  147. #define PWM_BRAKE 8
  148. #define PWM_OFF_DUTY BIT07 // Toggle on and off for active and inactive part of duty cycle
  149.  
  150. // Radio control input pulse is approximately 1000 to 2000 microseconds. But timer ticks once
  151. // every 4 microseconds so the range between min and max fits in 8 bits for fast scaling.
  152. #define RC_PULSE_MIN 250
  153. #define RC_PULSE_MAX 500
  154.  
  155. // Special signal to save current position before turning off
  156. #define RC_PULSE_SAVE 64
  157.  
  158. // EEPROM addresses for variables to be saved
  159. #define EEPROM_CUR_POS 2
  160. #define EEPROM_MAX_POS 4
  161. #define EEPROM_HALL_STATE_TO_PWM_STATE_POS 16
  162.  
  163. #define MAX_POWER 64
  164. #define SOFT_STOP_DISTANCE 100 // Slow down when less than this many commutations from target position
  165. #define DEADBAND 4 // Don't bother moving if already this close to targetPos
  166.  
  167. #define SPEED_RANGE_NUM 4
  168. // 0: Very low speed, starting and stopping
  169. // 1: More than 2ms per commutation
  170. // 2: Between 1ms and 2ms per commutation
  171. // 3: Less than 1ms per commutation
  172.  
  173. static const u8 maxPower[SPEED_RANGE_NUM] = { 16, 32, 48, 64 }; // Limiting PWM duty based on motor speed is a rough method of current limiting.
  174.  
  175. // As the motor rotates forward, hall state cycles through 6 values (001b,011b,010b,110b,100b,101b) or in decimal (1,3,2,6,4,5).
  176. // Turning backward will step through that sequence in the opposite direction.
  177. // The next and prev state tables map from the current state to the next or previous in that sequence.
  178. static const u8 nextHallState[8] = { 0, 3, 6, 2, 5, 1, 4, 0 };
  179. static const u8 prevHallState[8] = { 0, 5, 3, 1, 6, 4, 2, 0 };
  180.  
  181. // This table says which hall state corresponds to which PWM state (e.g. if you want the motor to rotate to hall state 3,
  182. // then set PWM state to hallStateToPWMState[3]). The values depend on the particular motor and sensor arrangement.
  183. // The function DetectHallPhase will automatically detect the correct values by moving the motor to each position and
  184. // then reading the sensor state.
  185. u8 hallStateToPWMState[8] = {0};
  186.  
  187. // By the user physically moving the servo output shaft to the desired extremes while in calibration mode, the total
  188. // number of motor commutations between the two positions can be counted, and used to track the current position without
  189. // a feedback potentiometer. However, this method does require re-calibrating every time the power is turned off, or
  190. // saving the current position to EEPROM and assuming the servo shaft hasn't been moved while the power was off.
  191. s16 curPos = 0; // In commutations, range 0 to maxPos
  192. s8 curDir = 0; // Direction the motor is currently spinning, +1 or -1, or 0 if not moving.
  193. s16 maxPos = 100; // In commutations. Can be negative. Initial value here is fairly irrelevant since it's normally calibrated and then loaded from EEPROM.
  194. s16 targetPos = 0; // In commutations, calculated from the radio control PPM input value.
  195. u8 speedRange = 0; // Based on time between last two sensor state changes
  196. u8 hallState = 0; // Bit0 = hall sensor A, bit1 = hall sensor B, bit2 = hall sensor C.
  197. u8 jitteringToStart = 0; // This is set true if PWM state is set to turn the opposite direction from the target, when struggling to get the rotor started under load.
  198. volatile u16 rcPulseTime = 0xffff; // In milliseconds. Should always be <= RC_PULSE_MAX except at startup.
  199. volatile u8 pwmState = PWM_FREEWHEEL; // State of the motor transistors
  200. volatile u8 pwmDelay = MAX_POWER;
  201. volatile u8 hallTime = 0; // Number of timer2 overflows since last hall sensor state change
  202.  
  203. void EEPROMRead(u8 addr, u8 *dest, u8 size);
  204. void EEPROMWrite(u8 addr, const u8 *data, u8 size);
  205. void Update();
  206.  
  207. STIN void wait(u8 ticks)
  208. {
  209.     asm volatile(
  210.     "lsr %0\n"
  211.     "lsr %0\n"
  212.     "breq 2f\n"
  213.     "1: dec %0\n"
  214.     "nop\n"
  215.     "brne 1b\n"
  216.     "2:\n"
  217.     : "=r" (ticks) : "0" (ticks));
  218. }
  219. STIN void waitLong(u32 ticks) { while(ticks > 255){wait(255); ticks-=255;} wait((u8)ticks); }
  220.  
  221. #if USE_ICP
  222. #define RC_PULSE_IS_RISING_EDGE        REG_TCCR1B & TCCR1B_ICP_RISING_EDGE
  223. #define RC_PULSE_WAIT_FOR_RISING_EDGE  REG_TCCR1B |= TCCR1B_ICP_RISING_EDGE
  224. #define RC_PULSE_WAIT_FOR_FALLING_EDGE REG_TCCR1B &= ~TCCR1B_ICP_RISING_EDGE
  225. #define RC_PULSE_ACKNOWLEDGE_INTERRUPT REG_TIFR = TIMSK_INPUT_CAPTURE
  226. ISR(TIMER1_CAPT_vect) // This is the function name to go with the brackets below the #endif
  227.  
  228. #elif USE_INT0
  229. #define RC_PULSE_IS_RISING_EDGE        REG_MCUCR == MCUCR_INT0_RISING_EDGE
  230. #define RC_PULSE_WAIT_FOR_RISING_EDGE  REG_MCUCR = MCUCR_INT0_RISING_EDGE
  231. #define RC_PULSE_WAIT_FOR_FALLING_EDGE REG_MCUCR = MCUCR_INT0_FALLING_EDGE
  232. #define RC_PULSE_ACKNOWLEDGE_INTERRUPT REG_GIFR = GICR_INT0
  233. ISR(INT0_vect) // This is the function name to go with the brackets below the #endif
  234.  
  235. #else
  236. #error "No RC pulse input method specified."
  237. #endif
  238. {
  239.     if (RC_PULSE_IS_RISING_EDGE)
  240.     {
  241.         RC_PULSE_WAIT_FOR_FALLING_EDGE;
  242.         REG_TCNT1 = 0; // Start counting the duration of the pulse
  243.         REG_TIFR = TIMSK_OC1B; // Clear overflow flag
  244.     }
  245.     else
  246.     {
  247.         rcPulseTime = REG_TCNT1;
  248.         RC_PULSE_WAIT_FOR_RISING_EDGE;
  249.     }
  250.     RC_PULSE_ACKNOWLEDGE_INTERRUPT;
  251. }
  252.  
  253. ISR(TIMER0_OVF_vect) // Interrupt for PWM
  254. {
  255.     if (pwmDelay == MAX_POWER)
  256.         pwmState &= ~PWM_OFF_DUTY; // Max power is always on duty
  257.     else
  258.         pwmState ^= PWM_OFF_DUTY;
  259.  
  260.     switch(pwmState)
  261.     {
  262.     case PWM_AnBp: BnFET_off, CnFET_off; ApFET_off, CpFET_off; AnFET_on, BpFET_on; break;
  263.     case PWM_AnCp: BnFET_off, CnFET_off; ApFET_off, BpFET_off; AnFET_on, CpFET_on; break;
  264.     case PWM_BnCp: AnFET_off, CnFET_off; ApFET_off, BpFET_off; BnFET_on, CpFET_on; break;
  265.     case PWM_BnAp: AnFET_off, CnFET_off; BpFET_off, CpFET_off; BnFET_on, ApFET_on; break;
  266.     case PWM_CnAp: AnFET_off, BnFET_off; BpFET_off, CpFET_off; CnFET_on, ApFET_on; break;
  267.     case PWM_CnBp: AnFET_off, BnFET_off; ApFET_off, CpFET_off; CnFET_on, BpFET_on; break;
  268.     case PWM_BRAKE: ApFET_off, BpFET_off, CpFET_off, AnFET_on, BnFET_on, CnFET_on; break;
  269.     case PWM_FREEWHEEL:
  270.     // If freewheeling, or if PWM_OFF_DUTY flag is set, turn all transistors off.
  271.     default: AnFET_off, BnFET_off; CnFET_off, ApFET_off, BpFET_off, CpFET_off; break;
  272.     }
  273.  
  274.     REG_TCNT0 = (pwmState & PWM_OFF_DUTY) ? (u8)(pwmDelay - MAX_POWER) : (u8)-pwmDelay;
  275.     REG_TIFR = TIMSK_TM0_OVERFLOW;
  276. }
  277.  
  278. ISR(TIMER2_OVF_vect) // Interrupt for measuring motor speed
  279. {
  280.     if (hallTime != 0xff)
  281.         hallTime++;
  282.     REG_TIFR = TIMSK_TM2_OVERFLOW;
  283. }
  284.  
  285. void EEPROMRead(u8 addr, u8 *dest, u8 size)
  286. {
  287.     const u8 irq = REG_SREG & SREG_IRQ_ENABLE;
  288.     REG_SREG &= ~SREG_IRQ_ENABLE;
  289.     AnFET_off, BnFET_off; CnFET_off, ApFET_off, BpFET_off, CpFET_off;
  290.  
  291.     REG_EEAR_H = 0;
  292.     while(size--)
  293.     {
  294.         REG_EEAR_L = addr++;
  295.         REG_EECR = EECR_READ;
  296.         *dest++ = REG_EEDR;
  297.     }
  298.     REG_SREG |= irq;
  299. }
  300.  
  301. void EEPROMWrite(u8 addr, const u8 *data, u8 size)
  302. {
  303.     const u8 irq = REG_SREG & SREG_IRQ_ENABLE;
  304.     REG_SREG &= ~SREG_IRQ_ENABLE;
  305.     AnFET_off, BnFET_off; CnFET_off, ApFET_off, BpFET_off, CpFET_off;
  306.  
  307.     REG_EEAR_H = 0;
  308.     while(size--)
  309.     {
  310.         REG_EEAR_L = addr++;
  311.         REG_EEDR = *data++;
  312.         REG_EECR |= EECR_WRITE_ENABLE;
  313.         REG_EECR |= EECR_WRITE;
  314.         while(REG_EECR & EECR_WRITE) {}
  315.     }
  316.     REG_SREG |= irq;
  317. }
  318.  
  319. void beep(u32 period)
  320. {
  321.     u8 cycles = 30;
  322.  
  323.     REG_SREG &= ~SREG_IRQ_ENABLE;
  324.     AnFET_off, BnFET_off; CnFET_off, ApFET_off, BpFET_off, CpFET_off;
  325.  
  326.     while(--cycles)
  327.     {
  328.         BnFET_on;
  329.         CpFET_on;
  330.         waitLong(1000);
  331.         CpFET_off;
  332.         ApFET_on;
  333.         waitLong(1000);
  334.         ApFET_off;
  335.         BnFET_off;
  336.         waitLong(period - 2000);
  337.     }
  338.  
  339.     REG_SREG |= SREG_IRQ_ENABLE;
  340. }
  341.  
  342.  
  343. // Call this function to automatically detect which hall state corresponds to which PWM state.
  344. // For each PWM state, transistors are pulsed to pull the rotor into position, and then the hall state is read.
  345. //
  346. // The first and last entries of hallStateToPWMState are unused and should be 0 (because there should never be
  347. // a time when all hall sensors are turned off or all turned on).
  348. // The rest should have values 1 to 6 in some order, with no duplicates.
  349. // Valid output should look something like 0, 6, 2, 1, 4, 5, 3, 0
  350. // The numbers correspond to the PWM_AnBp, PWM_AnCp, etc. #defines
  351. //
  352. // Appropriate power level depends on the motor, battery, and any load on the output.
  353. // Too low and the rotor won't move, too high and transistors may overheat or cause power brownout.
  354. // Start low and if the table is incomplete, raise it and try again.
  355. void DetectHallPhase(u8 power)
  356. {
  357.     u8 i;
  358.     for (i = 1; i <= 6; i++)
  359.     {
  360.         pwmDelay = power >> 2; pwmState = i; waitLong(300000);
  361.         pwmDelay = power >> 1; waitLong(300000);
  362.         pwmDelay = power;      waitLong(300000);
  363.         pwmDelay = power >> 1; waitLong(300000);
  364.         hallStateToPWMState[(REG_PINB >> 3) & 7] = i;
  365.     }
  366.     pwmState = PWM_FREEWHEEL;
  367.     pwmDelay = MAX_POWER;
  368. }
  369.  
  370. int main(void)
  371. {
  372.     REG_SREG = 0;
  373.     REG_DDRB = DIR_PB;
  374.     REG_PORTB = INIT_PB;
  375.     REG_DDRC = DIR_PC;
  376.     REG_PORTC = INIT_PC;
  377.     REG_DDRD = DIR_PD;
  378.     REG_PORTD = INIT_PD;
  379.  
  380.     // Timer for PWM. Interrupt in REG_TIMSK is enabled further below.
  381.     REG_TCCR0 = TCCR0_CLOCK_8;
  382.  
  383.     // Timer for measuring motor speed
  384.     REG_TCCR2 = TCCR2_CLOCK_8;
  385.  
  386.     // Timer and interrupt for radio control PPM input
  387.     #if (F_CPU != 16000000)
  388.     #error "Due to lazy programmer, conversion of timer ticks to RC pulse time only works if CPU freq is 16MHz"
  389.     #endif
  390.     REG_OCR1B = RC_PULSE_MAX;
  391.     #if USE_ICP
  392.     REG_TCCR1B = TCCR0_CLOCK_64 | TCCR1B_ICP_RISING_EDGE | TCCR1B_ICP_NOISE_CANCEL;
  393.     REG_TIMSK = TIMSK_INPUT_CAPTURE | TIMSK_TM0_OVERFLOW | TIMSK_TM2_OVERFLOW;
  394.     #elif USE_INT0
  395.     REG_TCCR1B = TCCR0_CLOCK_64;
  396.     REG_TIMSK = TIMSK_TM0_OVERFLOW | TIMSK_TM2_OVERFLOW;
  397.     REG_MCUCR = MCUCR_INT0_RISING_EDGE;
  398.     REG_GICR = GICR_INT0;
  399.     #endif
  400.  
  401.     REG_SREG |= SREG_IRQ_ENABLE;
  402.  
  403.     while(rcPulseTime == 0xffff) {} // Wait for first RC pulse input
  404.  
  405.     beep(100000);
  406.     waitLong(2000000);
  407.  
  408.     hallState = (REG_PINB >> 3) & 7;
  409.  
  410.     // High input on startup triggers calibration mode, with initial position defining max position.
  411.     if (rcPulseTime > RC_PULSE_MAX - ((RC_PULSE_MAX - RC_PULSE_MIN) >> 2))
  412.     {
  413.         // Remain in calibration mode until user gives low input.
  414.         while(rcPulseTime > RC_PULSE_MIN + ((RC_PULSE_MAX - RC_PULSE_MIN) >> 2))
  415.         {
  416.             // As the user physically rotates the servo arm to the desired min position,
  417.             // maxPos is stepped in the opposite direction.
  418.             const u8 lastHallState = hallState;
  419.             hallState = (REG_PINB >> 3) & 7;
  420.             if (hallState == nextHallState[lastHallState])
  421.                 maxPos--;
  422.             else if (hallState == prevHallState[lastHallState])
  423.                 maxPos++;
  424.         }
  425.  
  426.         DetectHallPhase(48);
  427.  
  428.         EEPROMWrite(EEPROM_CUR_POS, (const u8*)&curPos, sizeof(curPos));
  429.         EEPROMWrite(EEPROM_MAX_POS, (const u8*)&maxPos, sizeof(maxPos));
  430.         EEPROMWrite(EEPROM_HALL_STATE_TO_PWM_STATE_POS, hallStateToPWMState, sizeof(hallStateToPWMState));
  431.     }
  432.     else
  433.     {
  434.         EEPROMRead(EEPROM_CUR_POS, (u8*)&curPos, sizeof(curPos));
  435.         EEPROMRead(EEPROM_MAX_POS, (u8*)&maxPos, sizeof(maxPos));
  436.         EEPROMRead(EEPROM_HALL_STATE_TO_PWM_STATE_POS, hallStateToPWMState, sizeof(hallStateToPWMState));
  437.         targetPos = curPos;
  438.     }
  439.  
  440.     beep(50000);
  441.     waitLong(2000000);
  442.     while(1)
  443.         Update();
  444. }
  445.  
  446. void Update()
  447. {
  448.     // rcPulseTime and hallTime are copied because they could be changed by interrupts
  449.     const u8 lastHallTime = hallTime;
  450.     const u8 newHallState = (REG_PINB >> 3) & 7;
  451.     const s16 lastRCPulseTime = rcPulseTime;
  452.  
  453.     // Update RC pulse input
  454.     if (lastRCPulseTime >= RC_PULSE_MIN)
  455.         targetPos = maxPos * ((u8)(lastRCPulseTime - RC_PULSE_MIN)) >> 8;
  456.     else if (lastRCPulseTime == RC_PULSE_SAVE)
  457.         EEPROMWrite(EEPROM_CUR_POS, (const u8*)&curPos, sizeof(curPos));
  458.  
  459.     // Update hall sensor state
  460.     if (newHallState == 0 || newHallState == 7)
  461.     {
  462.         // Invalid state
  463.     }
  464.     else if (newHallState != hallState)
  465.     {
  466.         // Note: hallTime ticks once every 128 microseconds
  467.  
  468.         if (curDir == 0 || ABS(curPos - targetPos) < SOFT_STOP_DISTANCE)
  469.             speedRange = 0;
  470.         else if (lastHallTime > (2048 >> 7)) speedRange = 1; // Greater than 2ms per commutation but not starting/stopping
  471.         else if (lastHallTime > (1024 >> 7)) speedRange = 2; // 1ms to 2ms per commutation
  472.         else speedRange = 3; // Less than 1ms per commutation
  473.  
  474.         if (newHallState == nextHallState[hallState])
  475.             curDir = +1;
  476.         else if (newHallState == prevHallState[hallState])
  477.             curDir = -1;
  478.         else if (newHallState == nextHallState[nextHallState[hallState]])
  479.             curDir = +2; // Missed a commutation, but probably ok
  480.         else if (newHallState == prevHallState[prevHallState[hallState]])
  481.             curDir = -2; // Missed a commutation, but probably ok
  482.         else    // Missed multiple commutations. Give error beep.
  483.             beep(75000);
  484.  
  485.         hallState = newHallState;
  486.         curPos += curDir;
  487.         hallTime = 0; // Start counting time until next sensor state change
  488.         jitteringToStart = 0;
  489.     }
  490.     else if (hallTime == 0xff)
  491.     {
  492.         // Not moving
  493.         curDir = 0;
  494.         speedRange = 0;
  495.         hallTime = 0;
  496.         if (ABS(curPos - targetPos) > DEADBAND)
  497.             jitteringToStart ^= 1;
  498.     }
  499.  
  500.     // Update PWM state
  501.     if (ABS(curPos - targetPos) < DEADBAND)// || (curPos < targetPos && curDir < 0) || (curPos > targetPos && curDir > 0))
  502.     {
  503.         // Brake if at target position or moving in the wrong direction
  504.         speedRange = 0;
  505.         pwmState = PWM_BRAKE;
  506.         pwmDelay = MAX_POWER;
  507.         hallTime = 0;
  508.     }
  509.     else
  510.     {
  511.         REG_SREG &= ~SREG_IRQ_ENABLE;
  512.         pwmState = (pwmState & PWM_OFF_DUTY) |
  513.             hallStateToPWMState[(curPos < targetPos) ^ jitteringToStart ?
  514.                 nextHallState[hallState] : prevHallState[hallState]];
  515.         pwmDelay = maxPower[speedRange];
  516.         REG_SREG |= SREG_IRQ_ENABLE;
  517.     }
  518. }
Add Comment
Please, Sign In to add comment