Browse Source

init

tags/v1.0
Olaf Rempel 13 years ago
commit
eea082635e
7 changed files with 599 additions and 0 deletions
  1. +6
    -0
      .gitignore
  2. +64
    -0
      Makefile
  3. +226
    -0
      blmc.c
  4. +47
    -0
      blmc.h
  5. +130
    -0
      i2c-slave.c
  6. +114
    -0
      main.c
  7. +12
    -0
      main.h

+ 6
- 0
.gitignore View File

@@ -0,0 +1,6 @@
*.o
*.elf
*.bin
*.hex
*.lst
*.map

+ 64
- 0
Makefile View File

@@ -0,0 +1,64 @@
PRG = bl_test
OBJ = blmc.o i2c-slave.o main.o
MCU_TARGET = atmega8
OPTIMIZE = -Os

DEFS =
LIBS =

# You should not have to change anything below here.

CC = avr-gcc

# Override is only needed by avr-lib build system.

override CFLAGS = -g -Wall $(OPTIMIZE) -mmcu=$(MCU_TARGET) $(DEFS)
override LDFLAGS = -Wl,-Map,$(PRG).map

OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
SIZE = avr-size

all: $(PRG).elf lst text eeprom
$(SIZE) -x -A $(PRG).elf

$(PRG).elf: $(OBJ)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)

clean:
rm -rf *.o *.lst *.map $(PRG).elf *.hex *.bin

lst: $(PRG).lst

%.lst: %.elf
$(OBJDUMP) -h -S $< > $@

# Rules for building the .text rom images

text: hex bin

hex: $(PRG).hex
bin: $(PRG).bin

%.hex: %.elf
$(OBJCOPY) -j .text -j .data -O ihex $< $@

%.bin: %.elf
$(OBJCOPY) -j .text -j .data -O binary $< $@

# Rules for building the .eeprom rom images

eeprom: ehex ebin

ehex: $(PRG)_eeprom.hex
ebin: $(PRG)_eeprom.bin

%_eeprom.hex: %.elf
$(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@

%_eeprom.bin: %.elf
$(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O binary $< $@

install: text
uisp -dprog=avr910 -dserial=/dev/ttyS0 -dspeed=115200 -dpart=M8 --erase --upload if=$(PRG).hex
# avrdude -p m8 -c butterfly -b 19200 -P /dev/ttyUSB0 -u -e -V -U flash:w:$(PRG).hex

+ 226
- 0
blmc.c View File

@@ -0,0 +1,226 @@
/***************************************************************************
* 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
}
}

+ 47
- 0
blmc.h View File

@@ -0,0 +1,47 @@
#ifndef _BLMC_H_
#define _BLMC_H_

#include <avr/io.h>

#define PHASE_A_H (1<<PORTB1)
#define PHASE_B_H (1<<PORTB2)
#define PHASE_C_H (1<<PORTB3)
#define PHASE_H_MASK (PHASE_A_H | PHASE_B_H | PHASE_C_H)

#define PHASE_A_L (1<<PORTD4)
#define PHASE_B_L (1<<PORTD3)
#define PHASE_C_L (1<<PORTD2)
#define PHASE_L_MASK (PHASE_A_L | PHASE_B_L | PHASE_C_L)

#define SENSE_A 0
#define SENSE_B 1
#define SENSE_C 2

#define SENSE_VOLTAGE 3
#define SENSE_CURRENT 6

#define FLAG_PWM_SPINUP 0x01
#define FLAG_PWM_NORMAL 0x02

#define FLAG_COM_SPINUP 0x10
#define FLAG_COM_NORMAL 0x20

struct blmc_ {
uint8_t flags;

uint8_t pwm; // pwm setpoint
uint8_t pwm_limit; // increased by current-limit

uint16_t rpm;
uint16_t rpm_tmp;
uint16_t rpm_tmp2;

uint16_t current;
uint16_t voltage;
};

void trigger_adc(uint8_t channel);
void setpwm(uint8_t pwm);
void spinup(void);

#endif

+ 130
- 0
i2c-slave.c View File

@@ -0,0 +1,130 @@
/***************************************************************************
* 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 <avr/wdt.h>

#include "main.h"
#include "blmc.h"

extern struct blmc_ blmc;

#define CMD_NONE 0x00
#define CMD_SETPWM 0x10
#define CMD_GETSTAT 0x20
#define CMD_REBOOT 0x80

ISR(TWI_vect)
{
static uint8_t cmd = CMD_NONE;

switch (TWSR & 0xF8) {
/* SLA + W received, ACK returned -> receive Data and ACK */
case 0x60:
cmd = CMD_NONE;
TWCR |= (1<<TWINT) | (1<<TWEA);
break;

/* prev. SLA + W, data received, ACK returned -> receive Data and ACK */
case 0x80:
switch (cmd & 0xF0) {
/* First bytes -> Command */
case CMD_NONE:
cmd = TWDR;
break;

/* set pwm */
case CMD_SETPWM:
setpwm(TWDR);
cmd = CMD_NONE;
break;

/* set parameters */
case CMD_REBOOT:
if (TWDR == 0x42)
wdt_enable(WDTO_15MS);
cmd = CMD_NONE;
break;

/* rest invalid */
default:
cmd = CMD_NONE;
break;
}

TWCR |= (1<<TWINT);
break;

/* SLA+R received, ACK returned -> send data */
case 0xA8:
/* prev. SLA+R, data sent, ACK returned -> send data */
case 0xB8:
switch (cmd & 0xF0) {
/* get Current */
case CMD_GETSTAT:
switch (cmd++ & 0x0F) {
case 0: TWDR = blmc.pwm - blmc.pwm_limit;
break;

case 1: TWDR = blmc.pwm;
break;

case 2: TWDR = (blmc.rpm >> 8);
break;

case 3: TWDR = (blmc.rpm & 0xFF);
break;

case 4: TWDR = (blmc.current >> 8);
break;

case 5: TWDR = (blmc.current & 0xFF);
break;

case 6: TWDR = (blmc.voltage >> 8);
break;

case 7: TWDR = (blmc.voltage & 0xFF);
cmd = CMD_NONE;
break;
}
break;

/* rest invalid */
default:
cmd = CMD_NONE;
break;
}

TWCR |= (1<<TWINT);
break;

/* STOP or repeated START */
case 0xA0:
/* Data transmitted, NACK returned */
case 0xC0:
TWCR |= (1<<TWINT) | (1<<TWEA);
break;

/* Illegal state -> reset Hardware */
case 0xF8:
TWCR |= (1<<TWINT) | (1<<TWSTO) | (1<<TWEA);
break;
}
}

+ 114
- 0
main.c View File

@@ -0,0 +1,114 @@
/***************************************************************************
* 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. *
***************************************************************************/
/*
* Application:
* LED_GN blinking -> motor stop
* LED_GN on -> motor running
* LED_GN on & LED_RT blinking -> pwm soft limit
* LED_GN off & LED_RT blinking -> current to high / undervoltage
*
* startup:
* - selftest
*
* cmdloop:
* - set motor (pwm)
* - get status (motor speed, voltage, current)
* - reboot (with cookie)
*/

#include <avr/io.h>
#include <avr/interrupt.h>

#include "main.h"
#include "blmc.h"

extern struct blmc_ blmc;

ISR(TIMER0_OVF_vect)
{
static uint8_t timer0_cnt = 0;
static uint8_t adc_chan = SENSE_CURRENT;

/* Come back in 20ms */
TCNT0 = 0xFF - 156;

/* current-limiting */
setpwm(blmc.pwm);

uint16_t diff = blmc.rpm_tmp - blmc.rpm_tmp2;
blmc.rpm_tmp2 = blmc.rpm_tmp;

/* too low rpm while running -> do a spinup */
if (diff < 0x8 && blmc.flags == (FLAG_PWM_NORMAL | FLAG_COM_NORMAL))
blmc.flags = FLAG_PWM_SPINUP | FLAG_COM_SPINUP;

timer0_cnt++;
if (timer0_cnt == 50) {
timer0_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;
}
}

int main(void)
{
DDRB = PHASE_H_MASK | LED_RT | LED_GN;
DDRD = PHASE_L_MASK;

PORTB = LED_GN;
PORTD = 0x00;

/* timer0: running with F_CPU/1024 */
TCCR0 = (1<<CS02) | (1<<CS00);

/* timer1: running with F_CPU, 8bit Fast PWM (32kHz) */
TCCR1B = (1<<CS10);// | (1<<WGM12);
TCCR1A = (1<<WGM10);

/* timer2: running with F_CPU, 8bit Fast PWM (32kHz) */
TCCR2 = (1<<WGM20) | (1<<CS20);// | (1<<WGM21);

/* enable Timer0 OVF Interrupt */
TIMSK = (1<<TOIE0); // | (1<<OCIE2); // | (1<<TOIE2)

/* Enable Analog Comparator Multiplexer */
SFIOR |= (1<<ACME);

/* I2C Init: keep Address from bootloader, Auto ACKs with Interrupts */
TWCR = (1<<TWEA) | (1<<TWEN) | (1<<TWIE);

sei();

while (1) {
if (blmc.flags & FLAG_COM_SPINUP)
spinup();
};

return 0;
}

+ 12
- 0
main.h View File

@@ -0,0 +1,12 @@
#ifndef _MAIN_H_
#define _MAIN_H_

#include <avr/io.h>

#define F_CPU 8000000
#include <util/delay.h>

#define LED_RT (1<<PORTB4)
#define LED_GN (1<<PORTB5)

#endif

Loading…
Cancel
Save