|
|
- /***************************************************************************
- * Copyright (C) 09/2007 by Olaf Rempel *
- * razzor@kopf-tisch.de *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; version 2 of the License, *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the *
- * Free Software Foundation, Inc., *
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
- ***************************************************************************/
- #include <avr/io.h>
- #include <avr/interrupt.h>
-
- #include "main.h"
- #include "blmc.h"
- #include "eeprom.h"
-
- extern struct ee_param params;
- struct blmc_ blmc;
-
- /* Analog Comparator Channel */
- static uint8_t next_sense;
-
- void trigger_adc(uint8_t channel)
- {
- /* Disable Analog Comperator */
- ACSR &= ~(1<<ACIE);
-
- /* set channel (Internal reference, 2.56V) */
- ADMUX = (1<<REFS1) | (1<<REFS0) | channel;
-
- /* turn on ADC with interrupts, start conversion with 1/32 of F_CPU */
- ADCSRA = (1<<ADEN) | (1<<ADSC) | (1<<ADIE) | (1<<ADIF)| (1<<ADPS2) | (1<<ADPS0);
- }
-
- void next_phase(void)
- {
- static uint8_t phase;
- static uint8_t phase_adc;
-
- /* Disable Analog Comperator */
- ACSR &= ~(1<<ACIE);
-
- TCNT1 = 0x00;
- TCNT2 = 0x00;
-
- switch (phase) {
- case 0: PORTD = (PORTD & ~PHASE_L_MASK) | PHASE_B_L;
- TCCR1A = (TCCR1A & ~(1<<COM1B1)) | (1<<COM1A1);
- TCCR2 &= ~(1<<COM21);
- ACSR = (1<<ACIS1);
- next_sense = SENSE_C;
- break;
-
- case 1: PORTD = (PORTD & ~PHASE_L_MASK) | PHASE_B_L;
- TCCR1A &= ~((1<<COM1A1) | (1<<COM1B1));
- TCCR2 |= (1<<COM21);
- ACSR = (1<<ACIS1) | (1<<ACIS0);
- next_sense = SENSE_A;
- break;
-
- case 2: PORTD = (PORTD & ~PHASE_L_MASK) | PHASE_A_L;
- TCCR1A &= ~((1<<COM1A1) | (1<<COM1B1));
- TCCR2 |= (1<<COM21);
- ACSR = (1<<ACIS1);
- next_sense = SENSE_B;
- break;
-
- case 3: PORTD = (PORTD & ~PHASE_L_MASK) | PHASE_A_L;
- TCCR1A = (TCCR1A & ~(1<<COM1A1)) | (1<<COM1B1);
- TCCR2 &= ~(1<<COM21);
- ACSR = (1<<ACIS1) | (1<<ACIS0);
- next_sense = SENSE_C;
- break;
-
- case 4: PORTD = (PORTD & ~PHASE_L_MASK) | PHASE_C_L;
- TCCR1A = (TCCR1A & ~(1<<COM1A1)) | (1<<COM1B1);
- TCCR2 &= ~(1<<COM21);
- ACSR = (1<<ACIS1);
- next_sense = SENSE_A;
- break;
-
- case 5: PORTD = (PORTD & ~PHASE_L_MASK) | PHASE_C_L;
- TCCR1A = (TCCR1A & ~(1<<COM1B1)) | (1<<COM1A1);
- TCCR2 &= ~(1<<COM21);
- ACSR = (1<<ACIS1) | (1<<ACIS0);
- next_sense = SENSE_B;
- break;
- }
-
- if (phase == (phase_adc & 0x0F)) {
- if (phase_adc & 0x10)
- trigger_adc(SENSE_VOLTAGE);
- else
- trigger_adc(SENSE_CURRENT);
-
- phase_adc--;
- if (phase_adc == 0xff)
- phase_adc = 0x15;
-
- else if (phase_adc == 0x0f)
- phase_adc = 0x05;
-
- } else {
- /* restore channel */
- ADMUX = next_sense;
-
- /* enable Analog Comparator with Interrupts */
- if (blmc.flags & FLAG_COM_NORMAL)
- ACSR |= (1<<ACIE) | (1<<ACI);
- }
-
- phase++;
- if (phase == 6)
- phase = 0;
-
- blmc.rpm_tmp++;
- }
-
- /*
- * starts motor, must not run from interrupt
- */
- void spinup(void)
- {
- /* see util/delay.h for details.. */
- uint16_t tick = (((uint16_t)(F_CPU / 3e6)) << 8) * (params.spinup_tick & 0x3F);
-
- uint16_t time = params.spinup_ticks;
- while (time > 50) {
- next_phase();
-
- uint16_t i;
- for (i = 0; i < time; i++)
- _delay_loop_1(tick >> 8);
-
- time -= (time / params.spinup_step +1);
- }
-
- /* manual spinup complete, analog comperator takes control */
- blmc.flags &= ~(FLAG_RUN_MASK);
- blmc.flags |= FLAG_PWM_SPINUP | FLAG_COM_NORMAL;
- next_phase();
-
- for (time = 0; time < params.spinup_wait; time++)
- _delay_ms(20);
-
- /* switch to desired pwm value */
- blmc.flags &= ~(FLAG_RUN_MASK);
- blmc.flags |= FLAG_PWM_NORMAL | FLAG_COM_NORMAL;
- }
-
- /*
- * sets new pwm value
- * called from i2c-slave (set new value) and from timer (recalc current limit)
- */
- void setpwm(uint8_t pwm)
- {
- /* run motor *only* if there are no hard errors */
- if (pwm >= params.pwm_min && !(blmc.flags & FLAG_HARDERR_MASK)) {
- /* do a spinup */
- if (blmc.pwm == 0) {
- blmc.flags &= ~(FLAG_RUN_MASK);
- blmc.flags |= FLAG_PWM_SPINUP | FLAG_COM_SPINUP;
- }
-
- } else {
- blmc.flags &= ~FLAG_RUN_MASK;
- pwm = 0;
- }
-
- /* save pwm value */
- blmc.pwm = pwm;
-
- /* do spinup with small pwm */
- if (blmc.flags & FLAG_PWM_SPINUP)
- pwm = params.spinup_pwm;
-
- /* raise current-limit, set flag */
- if (blmc.current > params.current_limit) {
- blmc.flags |= FLAG_CURRENT_LIMIT;
- blmc.pwm_limit++;
-
- /* lower current-limit */
- } else if (blmc.pwm_limit > 0) {
- blmc.pwm_limit--;
-
- } else if (blmc.pwm_limit == 0) {
- blmc.flags &= ~FLAG_CURRENT_LIMIT;
- }
-
- /* prevent overflow */
- if (blmc.pwm_limit > pwm)
- blmc.pwm_limit = pwm;
-
- /* set new value */
- pwm -= blmc.pwm_limit;
-
- /* limit pwm */
- if (pwm > params.pwm_max)
- pwm = params.pwm_max;
-
- OCR1A = pwm;
- OCR1B = pwm;
- OCR2 = pwm;
- }
-
- ISR(ANA_COMP_vect)
- {
- next_phase();
- }
-
- ISR(ADC_vect)
- {
- static uint16_t current_tmp, voltage_tmp;
- static uint8_t current_cnt, voltage_cnt;
-
- uint8_t channel = ADMUX & 0x0F;
- uint16_t value = ADCW;
-
- /* restore channel */
- ADMUX = next_sense;
-
- /* turn off ADC, disable interrupt */
- ADCSRA = 0x00;
-
- /* enable Analog Comparator with Interrupts */
- if (blmc.flags & FLAG_COM_NORMAL)
- ACSR |= (1<<ACIE) | (1<<ACI);
-
- if (channel == SENSE_CURRENT) {
- current_tmp += value;
- current_cnt++;
- if (current_cnt == 6) {
- blmc.current = current_tmp;
- current_tmp = 0;
- current_cnt = 0;
- }
-
- if (value > params.current_max)
- blmc.flags |= FLAG_OVERCURRENT;
-
- } else {
- voltage_tmp += value;
- voltage_cnt++;
- if (voltage_cnt == 6) {
- blmc.voltage = voltage_tmp;
- voltage_tmp = 0;
- voltage_cnt = 0;
-
- if (blmc.voltage < params.voltage_min)
- blmc.flags |= FLAG_UNDERVOLTAGE;
- }
- }
- }
|