blmc/main.c

235 lines
6.0 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. *
***************************************************************************/
/*
* Status LED_GN LED_RT
* No Error, Motor off ON -
* No Error, Motor spinup FAST -
* No Error, Motor running SLOW -
* Current Limit F/S ON
* i2c Timeout ON ON
* Undervoltage OFF SLOW
* Overcurrent (Hard Limit) OFF FAST
* SELFTEST failed FAST FAST (not implemented yet)
* EEPROM invalid SLOW SLOW
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include "main.h"
#include "blmc.h"
#include "eeprom.h"
#define LED_OFF 0x00
#define LED_SLOW 0x01
#define LED_FAST 0x10
#define LED_ON 0x11
extern struct blmc_ blmc;
static uint8_t led[2];
ISR(TIMER1_COMPB_vect)
{
static uint8_t rpm_cnt = 0;
static uint8_t adc_chan = SENSE_CURRENT;
/* Come back in 20ms */
OCR1B = TCNT1 + 20000;
/* commutations during last 20ms */
uint16_t diff = blmc.rpm_tmp - blmc.rpm_tmp_old;
blmc.rpm_tmp_old = blmc.rpm_tmp;
if ((blmc.flags & FLAG_RUN_MASK) == (FLAG_PWM_NORMAL | FLAG_COM_NORMAL)) {
/* too few commutations while running -> do a spinup */
if (diff < 0x08) {
blmc.flags &= ~(FLAG_RUN_MASK);
blmc.flags |= FLAG_PWM_SPINUP | FLAG_COM_SPINUP;
}
#if 0
/* no i2c cmd in the last 20ms */
if (!(blmc.flags & FLAG_I2C_ACTIVE)) {
/* already in i2c timeout, turn off motor */
if (blmc.flags & FLAG_I2C_TIMEOUT)
blmc.pwm = 0;
blmc.flags |= FLAG_I2C_TIMEOUT;
} else {
blmc.flags &= ~FLAG_I2C_TIMEOUT;
}
#endif
blmc.flags &= ~FLAG_I2C_ACTIVE;
}
/* set pwm again (adjust current limit) */
setpwm(blmc.pwm);
/* calc rpm every second */
rpm_cnt++;
if (rpm_cnt == 50) {
rpm_cnt = 0;
blmc.rpm = blmc.rpm_tmp;
blmc.rpm_tmp = 0;
}
/* trigger adc by hand when not running */
if (!(blmc.flags & FLAG_COM_NORMAL)) {
trigger_adc(adc_chan);
if (adc_chan == SENSE_CURRENT)
adc_chan = SENSE_VOLTAGE;
else
adc_chan = SENSE_CURRENT;
}
/* led blink timer */
static uint8_t led_timer = 0;
led_timer = (led_timer +1) & 0x1F;
/* green LED */
if (((led[0] == LED_SLOW) && (led_timer & 0x10)) ||
(led[0] == LED_FAST && (led_timer & 0x04)) ||
(led[0] == LED_ON)) {
PORTB |= LED_GN;
} else {
PORTB &= ~LED_GN;
}
/* red LED */
if (((led[1] == LED_SLOW) && !(led_timer & 0x10)) ||
(led[1] == LED_FAST && !(led_timer & 0x04)) ||
(led[1] == LED_ON)) {
PORTB |= LED_RT;
} else {
PORTB &= ~LED_RT;
}
}
/*
* For newer devices (mega88) the watchdog timer remains active even after a
* system reset. So disable it as soon as possible.
* automagically called on startup
*/
void get_mcusr(void) __attribute__((naked, section(".init3")));
void get_mcusr(void)
{
MCUSR = 0;
WDTCSR = (1<<WDCE) | (0<<WDE);
}
int main(void)
{
DDRB = PHASE_A_EN | PHASE_A_PWM | LED_RT | LED_GN;
DDRD = PHASE_B_EN | PHASE_B_PWM | PHASE_C_EN | PHASE_C_PWM;
PORTB = 0x00;
PORTD = 0x00;
/* timer0: running with F_CPU, 8bit Phase Correct PWM (16kHz) */
TCCR0A = (1<<WGM00);
TCCR0B = (1<<CS00);
/* timer1: running with F_CPU/8 */
TCCR1B = (1<<CS11) | (1<<ICNC1);
/* timer2: running with F_CPU, 8bit Phase Correct PWM (16kHz) */
TCCR2A = (1<<WGM20);
TCCR2B = (1<<CS20);
/* sync PWM timers */
GTCCR = (1<<TSM) | (1<<PSRASY) | (1<<PSRSYNC);
TCNT0 = 0x00;
TCNT2 = 0x00;
GTCCR = (0<<TSM);
/* enable Timer1 OVF Interrupt */
TIMSK1 = (1<<OCIE1B);
/* Enable Analog Comparator Multiplexer */
ADCSRB |= (1<<ACME);
ACSR |= (1<<ACIC);
/* I2C Init: keep Address from bootloader, Auto ACKs with Interrupts */
TWCR = (1<<TWEA) | (1<<TWEN) | (1<<TWIE);
blmc.flags = 0x00;
if (read_parameters())
blmc.flags |= FLAG_INVALID_EEPROM;
set_sleep_mode(SLEEP_MODE_IDLE);
sei();
while (1) {
uint8_t ledX[2] = { 0x00, 0x00 };
/* get motor status: spinup, running or off */
if (blmc.flags & FLAG_RUN_MASK) {
if (blmc.flags & (FLAG_COM_SPINUP | FLAG_PWM_SPINUP))
ledX[0] = LED_FAST;
else
ledX[0] = LED_SLOW;
} else {
ledX[0] = LED_ON;
}
/* soft errors (current limit, i2c timeout) */
if (blmc.flags & FLAG_SOFTERR_MASK)
ledX[1] = LED_ON;
/* hard errors */
if (blmc.flags & FLAG_HARDERR_MASK) {
if (blmc.flags & FLAG_CURRENT_LIMIT) {
ledX[0] = LED_OFF;
ledX[1] = LED_FAST;
} else if (blmc.flags & FLAG_UNDERVOLTAGE) {
ledX[0] = LED_OFF;
ledX[1] = LED_SLOW;
} else if (blmc.flags & FLAG_SELFTEST_FAILED) {
ledX[0] = LED_FAST;
ledX[1] = LED_FAST;
} else if (blmc.flags & FLAG_INVALID_EEPROM) {
ledX[0] = LED_SLOW;
ledX[1] = LED_SLOW;
}
}
if (!(blmc.flags & (FLAG_SOFTERR_MASK | FLAG_HARDERR_MASK)))
ledX[1] = LED_OFF;
led[0] = ledX[0];
led[1] = ledX[1];
/* do a spinup from main loop (blocking for > 200ms) */
if (blmc.flags & FLAG_COM_SPINUP)
spinup();
sleep_mode();
};
return 0;
}