AVR based brushless motor controller
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

263 lines
6.3 KiB

  1. /***************************************************************************
  2. * Copyright (C) 09/2007 by Olaf Rempel *
  3. * razzor@kopf-tisch.de *
  4. * *
  5. * This program is free software; you can redistribute it and/or modify *
  6. * it under the terms of the GNU General Public License as published by *
  7. * the Free Software Foundation; version 2 of the License, *
  8. * *
  9. * This program is distributed in the hope that it will be useful, *
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  12. * GNU General Public License for more details. *
  13. * *
  14. * You should have received a copy of the GNU General Public License *
  15. * along with this program; if not, write to the *
  16. * Free Software Foundation, Inc., *
  17. * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
  18. ***************************************************************************/
  19. #include <avr/io.h>
  20. #include <avr/interrupt.h>
  21. #include "main.h"
  22. #include "blmc.h"
  23. #include "eeprom.h"
  24. extern struct ee_param params;
  25. struct blmc_ blmc;
  26. /* Analog Comparator Channel */
  27. static uint8_t next_sense;
  28. void trigger_adc(uint8_t channel)
  29. {
  30. /* Disable Analog Comperator */
  31. ACSR &= ~(1<<ACIE);
  32. /* set channel (Internal reference, 2.56V) */
  33. ADMUX = (1<<REFS1) | (1<<REFS0) | channel;
  34. /* turn on ADC with interrupts, start conversion with 1/32 of F_CPU */
  35. ADCSRA = (1<<ADEN) | (1<<ADSC) | (1<<ADIE) | (1<<ADIF)| (1<<ADPS2) | (1<<ADPS0);
  36. }
  37. void next_phase(void)
  38. {
  39. static uint8_t phase;
  40. static uint8_t phase_adc;
  41. /* Disable Analog Comperator */
  42. ACSR &= ~(1<<ACIE);
  43. TCNT1 = 0x00;
  44. TCNT2 = 0x00;
  45. switch (phase) {
  46. case 0: PORTD = (PORTD & ~PHASE_L_MASK) | PHASE_B_L;
  47. TCCR1A = (TCCR1A & ~(1<<COM1B1)) | (1<<COM1A1);
  48. TCCR2 &= ~(1<<COM21);
  49. ACSR = (1<<ACIS1);
  50. next_sense = SENSE_C;
  51. break;
  52. case 1: PORTD = (PORTD & ~PHASE_L_MASK) | PHASE_B_L;
  53. TCCR1A &= ~((1<<COM1A1) | (1<<COM1B1));
  54. TCCR2 |= (1<<COM21);
  55. ACSR = (1<<ACIS1) | (1<<ACIS0);
  56. next_sense = SENSE_A;
  57. break;
  58. case 2: PORTD = (PORTD & ~PHASE_L_MASK) | PHASE_A_L;
  59. TCCR1A &= ~((1<<COM1A1) | (1<<COM1B1));
  60. TCCR2 |= (1<<COM21);
  61. ACSR = (1<<ACIS1);
  62. next_sense = SENSE_B;
  63. break;
  64. case 3: PORTD = (PORTD & ~PHASE_L_MASK) | PHASE_A_L;
  65. TCCR1A = (TCCR1A & ~(1<<COM1A1)) | (1<<COM1B1);
  66. TCCR2 &= ~(1<<COM21);
  67. ACSR = (1<<ACIS1) | (1<<ACIS0);
  68. next_sense = SENSE_C;
  69. break;
  70. case 4: PORTD = (PORTD & ~PHASE_L_MASK) | PHASE_C_L;
  71. TCCR1A = (TCCR1A & ~(1<<COM1A1)) | (1<<COM1B1);
  72. TCCR2 &= ~(1<<COM21);
  73. ACSR = (1<<ACIS1);
  74. next_sense = SENSE_A;
  75. break;
  76. case 5: PORTD = (PORTD & ~PHASE_L_MASK) | PHASE_C_L;
  77. TCCR1A = (TCCR1A & ~(1<<COM1B1)) | (1<<COM1A1);
  78. TCCR2 &= ~(1<<COM21);
  79. ACSR = (1<<ACIS1) | (1<<ACIS0);
  80. next_sense = SENSE_B;
  81. break;
  82. }
  83. if (phase == (phase_adc & 0x0F)) {
  84. if (phase_adc & 0x10)
  85. trigger_adc(SENSE_VOLTAGE);
  86. else
  87. trigger_adc(SENSE_CURRENT);
  88. phase_adc--;
  89. if (phase_adc == 0xff)
  90. phase_adc = 0x15;
  91. else if (phase_adc == 0x0f)
  92. phase_adc = 0x05;
  93. } else {
  94. /* restore channel */
  95. ADMUX = next_sense;
  96. /* enable Analog Comparator with Interrupts */
  97. if (blmc.flags & FLAG_COM_NORMAL)
  98. ACSR |= (1<<ACIE) | (1<<ACI);
  99. }
  100. phase++;
  101. if (phase == 6)
  102. phase = 0;
  103. blmc.rpm_tmp++;
  104. }
  105. /*
  106. * starts motor, must not run from interrupt
  107. */
  108. void spinup(void)
  109. {
  110. /* see util/delay.h for details.. */
  111. uint16_t tick = (((uint16_t)(F_CPU / 3e6)) << 8) * (params.spinup_tick & 0x3F);
  112. uint16_t time = params.spinup_ticks;
  113. while (time > 50) {
  114. next_phase();
  115. uint16_t i;
  116. for (i = 0; i < time; i++)
  117. _delay_loop_1(tick >> 8);
  118. time -= (time / params.spinup_step +1);
  119. }
  120. /* manual spinup complete, analog comperator takes control */
  121. blmc.flags &= ~(FLAG_RUN_MASK);
  122. blmc.flags |= FLAG_PWM_SPINUP | FLAG_COM_NORMAL;
  123. next_phase();
  124. for (time = 0; time < params.spinup_wait; time++)
  125. _delay_ms(20);
  126. /* switch to desired pwm value */
  127. blmc.flags &= ~(FLAG_RUN_MASK);
  128. blmc.flags |= FLAG_PWM_NORMAL | FLAG_COM_NORMAL;
  129. }
  130. /*
  131. * sets new pwm value
  132. * called from i2c-slave (set new value) and from timer (recalc current limit)
  133. */
  134. void setpwm(uint8_t pwm)
  135. {
  136. /* run motor *only* if there are no hard errors */
  137. if (pwm >= params.pwm_min && !(blmc.flags & FLAG_HARDERR_MASK)) {
  138. /* do a spinup */
  139. if (blmc.pwm == 0) {
  140. blmc.flags &= ~(FLAG_RUN_MASK);
  141. blmc.flags |= FLAG_PWM_SPINUP | FLAG_COM_SPINUP;
  142. }
  143. } else {
  144. blmc.flags &= ~FLAG_RUN_MASK;
  145. pwm = 0;
  146. }
  147. /* save pwm value */
  148. blmc.pwm = pwm;
  149. /* do spinup with small pwm */
  150. if (blmc.flags & FLAG_PWM_SPINUP)
  151. pwm = params.spinup_pwm;
  152. /* raise current-limit, set flag */
  153. if (blmc.current > params.current_limit) {
  154. blmc.flags |= FLAG_CURRENT_LIMIT;
  155. blmc.pwm_limit++;
  156. /* lower current-limit */
  157. } else if (blmc.pwm_limit > 0) {
  158. blmc.pwm_limit--;
  159. } else if (blmc.pwm_limit == 0) {
  160. blmc.flags &= ~FLAG_CURRENT_LIMIT;
  161. }
  162. /* prevent overflow */
  163. if (blmc.pwm_limit > pwm)
  164. blmc.pwm_limit = pwm;
  165. /* set new value */
  166. pwm -= blmc.pwm_limit;
  167. /* limit pwm */
  168. if (pwm > params.pwm_max)
  169. pwm = params.pwm_max;
  170. OCR1A = pwm;
  171. OCR1B = pwm;
  172. OCR2 = pwm;
  173. }
  174. ISR(ANA_COMP_vect)
  175. {
  176. next_phase();
  177. }
  178. ISR(ADC_vect)
  179. {
  180. static uint16_t current_tmp, voltage_tmp;
  181. static uint8_t current_cnt, voltage_cnt;
  182. uint8_t channel = ADMUX & 0x0F;
  183. uint16_t value = ADCW;
  184. /* restore channel */
  185. ADMUX = next_sense;
  186. /* turn off ADC, disable interrupt */
  187. ADCSRA = 0x00;
  188. /* enable Analog Comparator with Interrupts */
  189. if (blmc.flags & FLAG_COM_NORMAL)
  190. ACSR |= (1<<ACIE) | (1<<ACI);
  191. if (channel == SENSE_CURRENT) {
  192. current_tmp += value;
  193. current_cnt++;
  194. if (current_cnt == 6) {
  195. blmc.current = current_tmp;
  196. current_tmp = 0;
  197. current_cnt = 0;
  198. }
  199. if (value > params.current_max)
  200. blmc.flags |= FLAG_OVERCURRENT;
  201. } else {
  202. voltage_tmp += value;
  203. voltage_cnt++;
  204. if (voltage_cnt == 6) {
  205. blmc.voltage = voltage_tmp;
  206. voltage_tmp = 0;
  207. voltage_cnt = 0;
  208. if (blmc.voltage < params.voltage_min)
  209. blmc.flags |= FLAG_UNDERVOLTAGE;
  210. }
  211. }
  212. }