227 lines
5.2 KiB
C
227 lines
5.2 KiB
C
/***************************************************************************
|
|
* 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"
|
|
|
|
struct blmc_ blmc;
|
|
|
|
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++;
|
|
}
|
|
|
|
void spinup(void)
|
|
{
|
|
uint16_t time = 1000;
|
|
while (time > 50) {
|
|
next_phase();
|
|
|
|
uint16_t i;
|
|
for (i = 0; i < time; i++)
|
|
_delay_us(25);
|
|
|
|
time -= (time / 24 +1);
|
|
}
|
|
|
|
blmc.flags = FLAG_PWM_SPINUP | FLAG_COM_NORMAL;
|
|
next_phase();
|
|
|
|
for (time = 0; time < 10; time++)
|
|
_delay_ms(20);
|
|
|
|
blmc.flags = FLAG_PWM_NORMAL | FLAG_COM_NORMAL;
|
|
}
|
|
|
|
void setpwm(uint8_t pwm)
|
|
{
|
|
|
|
if (pwm >= 8) {
|
|
if (blmc.pwm == 0)
|
|
blmc.flags = FLAG_PWM_SPINUP | FLAG_COM_SPINUP;
|
|
|
|
blmc.pwm = pwm;
|
|
|
|
} else {
|
|
blmc.flags = 0x00;
|
|
blmc.pwm = 0;
|
|
}
|
|
|
|
if (blmc.flags & FLAG_PWM_SPINUP)
|
|
pwm = 0x0f;
|
|
else
|
|
pwm = blmc.pwm;
|
|
|
|
if (blmc.current > 120)
|
|
blmc.pwm_limit++;
|
|
|
|
else if (blmc.pwm_limit > 0)
|
|
blmc.pwm_limit--;
|
|
|
|
if (blmc.pwm_limit > pwm)
|
|
blmc.pwm_limit = pwm;
|
|
|
|
pwm -= blmc.pwm_limit;
|
|
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);
|
|
|
|
sei();
|
|
|
|
if (channel == SENSE_CURRENT) {
|
|
current_tmp += value;
|
|
current_cnt++;
|
|
if (current_cnt == 6) {
|
|
blmc.current = current_tmp;
|
|
current_tmp = 0;
|
|
current_cnt = 0;
|
|
}
|
|
// TODO: ueberstrom-abschaltung
|
|
|
|
} else {
|
|
voltage_tmp += value;
|
|
voltage_cnt++;
|
|
if (voltage_cnt == 6) {
|
|
blmc.voltage = voltage_tmp;
|
|
voltage_tmp = 0;
|
|
voltage_cnt = 0;
|
|
}
|
|
// TODO: unterspannungs-abschaltung
|
|
}
|
|
}
|