Commit cabbedf7 authored by Diedrich Wolter's avatar Diedrich Wolter
Browse files

erste fassung

parent fc4a7388
# Hey Emacs, this is a -*- makefile -*-
############################################################################
### ###
### Adapt these to your project! ###
### ###
### CLOCK : system clock used (2Mhz is how our XMega starts up) ###
### correct value is important for USART serial communication ###
### and _delay_ms() delay utility function (UL is short for ###
### 'unsigned long' to make GCC choose a large enough int type) ###
### ###
### TARGET: name of the program (this is the file your main() goes in!) ###
### ###
### SRC : all your source files (.c) ###
### ###
### AVRDUDE_PORT : serial device of the board's serial-USB bridge ###
############################################################################
CLOCK = 32000000UL
TARGET = main
SRC = $(TARGET).c twi.c usart.c
AVRDUDE_PORT = /dev/cu.usbmodem14141
### make targets:
###
### make ---> same as 'make build'
### make build ---> compiles sources, builds TARGET
### make program ---> builds and uploades to board (in bootloader mode!)
############################################################################
OPT = 3
FORMAT = ihex
MCU = atxmega128a1
# Name of this Makefile (used for "make depend").
MAKEFILE = Makefile
# Debugging format.
# Native formats for AVR-GCC's -g are stabs [default], or dwarf-2.
# AVR (extended) COFF requires stabs, plus an avr-objcopy run.
DEBUG = stabs
# Compiler flag to set the C Standard level.
# c89 - "ANSI" C
# gnu89 - c89 plus GCC extensions
# c99 - ISO C99 standard (not yet fully implemented)
# gnu99 - c99 plus GCC extensions
CSTANDARD = -std=gnu99
# Place -D or -U options here
CDEFS =
# Place -I options here
CINCS =
CDEBUG = -g$(DEBUG)
CWARN = -Wall -Wstrict-prototypes
CTUNING = -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
#CEXTRA = -Wa,-adhlns=$(<:.c=.lst)
CFLAGS = $(CDEBUG) $(CDEFS) $(CINCS) -O$(OPT) $(CWARN) $(CSTANDARD) $(CEXTRA)
#ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs
#Additional libraries.
# Minimalistic printf version
PRINTF_LIB_MIN = -Wl,-u,vfprintf -lprintf_min
# Floating point printf version (requires MATH_LIB = -lm below)
PRINTF_LIB_FLOAT = -Wl,-u,vfprintf -lprintf_flt
PRINTF_LIB =
# Minimalistic scanf version
SCANF_LIB_MIN = -Wl,-u,vfscanf -lscanf_min
# Floating point + %[ scanf version (requires MATH_LIB = -lm below)
SCANF_LIB_FLOAT = -Wl,-u,vfscanf -lscanf_flt
SCANF_LIB =
MATH_LIB = -lm
# External memory options
# 64 KB of external RAM, starting after internal RAM (ATmega128!),
# used for variables (.data/.bss) and heap (malloc()).
#EXTMEMOPTS = -Wl,--section-start,.data=0x801100,--defsym=__heap_end=0x80ffff
# 64 KB of external RAM, starting after internal RAM (ATmega128!),
# only used for heap (malloc()).
#EXTMEMOPTS = -Wl,--defsym=__heap_start=0x801100,--defsym=__heap_end=0x80ffff
EXTMEMOPTS =
#LDMAP = $(LDFLAGS) -Wl,-Map=$(TARGET).map,--cref
LDFLAGS = $(EXTMEMOPTS) $(LDMAP) # $(PRINTF_LIB_MIN) $(SCANF_LIB_MIN)
# $(MATH_LIB)
# Programming support using avrdude. Settings and variables.
AVRDUDE_PROGRAMMER = avr109
AVRDUDE_XTRA_FLAGS = -b 57600 -e
AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex
#AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep
# Uncomment the following if you want avrdude's erase cycle counter.
# Note that this counter needs to be initialized first using -Yn,
# see avrdude manual.
#AVRDUDE_ERASE_COUNTER = -y
# Uncomment the following if you do /not/ wish a verification to be
# performed after programming the device.
#AVRDUDE_NO_VERIFY = -V
# Increase verbosity level. Please use this when submitting bug
# reports about avrdude. See <http://savannah.nongnu.org/projects/avrdude>
# to submit bug reports.
AVRDUDE_VERBOSE = -v -v -v
AVRDUDE_BASIC = -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER)
AVRDUDE_FLAGS = $(AVRDUDE_BASIC) $(AVRDUDE_NO_VERIFY) $(AVRDUDE_VERBOSE) $(AVRDUDE_ERASE_COUNTER) $(AVRDUDE_XTRA_FLAGS)
# system clock
CC = avr-gcc -DF_CPU=$(CLOCK)
OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
SIZE = avr-size
NM = avr-nm
AVRDUDE = avrdude
REMOVE = rm -f
MV = mv -f
# Define all object files.
OBJ = $(SRC:.c=.o)
# Define all listing files.
LST = $(SRC:.c=.lst)
# Combine all necessary flags and optional flags.
# Add target processor to flags.
ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS)
ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)
# Default target.
all: build
build: elf hex eep
elf: $(TARGET).elf
hex: $(TARGET).hex
eep: $(TARGET).eep
lss: $(TARGET).lss
sym: $(TARGET).sym
# Program the device.
program: $(TARGET).hex #$(TARGET).eep
$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) #$(AVRDUDE_WRITE_EEPROM)
# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB.
COFFCONVERT=$(OBJCOPY) --debugging \
--change-section-address .data-0x800000 \
--change-section-address .bss-0x800000 \
--change-section-address .noinit-0x800000 \
--change-section-address .eeprom-0x810000
coff: $(TARGET).elf
$(COFFCONVERT) -O coff-avr $(TARGET).elf $(TARGET).cof
extcoff: $(TARGET).elf
$(COFFCONVERT) -O coff-ext-avr $(TARGET).elf $(TARGET).cof
.SUFFIXES: .elf .hex .eep .lss .sym
.elf.hex:
$(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@
.elf.eep:
-$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \
--change-section-lma .eeprom=0 -O $(FORMAT) $< $@
# Create extended listing file from ELF output file.
.elf.lss:
$(OBJDUMP) -h -S $< > $@
# Create a symbol table from ELF output file.
.elf.sym:
$(NM) -n $< > $@
# Link: create ELF output file from object files.
$(TARGET).elf: $(OBJ)
$(CC) $(ALL_CFLAGS) $(OBJ) --output $@ $(LDFLAGS)
# Compile: create object files from C source files.
.c.o:
$(CC) -c $(ALL_CFLAGS) $< -o $@
# Compile: create assembler files from C source files.
.c.s:
$(CC) -S $(ALL_CFLAGS) $< -o $@
# Assemble: create object files from assembler source files.
.S.o:
$(CC) -c $(ALL_ASFLAGS) $< -o $@
# Target: clean project.
clean:
$(REMOVE) $(TARGET).hex $(TARGET).eep $(TARGET).cof $(TARGET).elf \
$(TARGET).map $(TARGET).sym $(TARGET).lss \
$(OBJ) $(LST) $(SRC:.c=.s) $(SRC:.c=.d)
depend:
if grep '^# DO NOT DELETE' $(MAKEFILE) >/dev/null; \
then \
sed -e '/^# DO NOT DELETE/,$$d' $(MAKEFILE) > \
$(MAKEFILE).$$$$ && \
$(MV) $(MAKEFILE).$$$$ $(MAKEFILE); \
fi
echo '# DO NOT DELETE THIS LINE -- make depend depends on it.' \
>> $(MAKEFILE); \
$(CC) -M -mmcu=$(MCU) $(CDEFS) $(CINCS) $(SRC) >> $(MAKEFILE)
.PHONY: all build elf hex eep lss sym program coff extcoff clean depend
/*
*
*
*/
#include "system.h"
#include <avr/sleep.h> // Strom sparen mit Sleep
#include "twi.h"
#include "usart.h"
/* globale Variablen */
TWI_Master_t twiMaster; // TWI master module
volatile uint8_t readData = false;
volatile unsigned int timerLow = 0, timerHigh = 0; // Zeitstempel der letzten Messung
/* sendet ein Byte an ein I2C-Gerät (typischerweise die Nummer
* eines Registers) und liest 2 Bytes also einen 16-Bit-Wert zurück.
* Anstelle der 2 Bytes dürfen bis zu TWIM_READ_BUFFER_SIZE == 8
* angefordert werden.
*
* i2cAddr : Adresses des Chips auf dem I2C-Bus
* reg : Register des Chips zum Auslesen (die Zahl wird als Byte gesendet)
* deadtime: maximale Wartezeit in µs bis zum Eintreffen der Bytes
* (Übertragungsgeschwindigkeit beachten: bei 400kHz Bustakt benötigt
* die Übertragung von 16 Bits mindestens 40µs)
* RÜckgabe: die gelesenen 16 Bit in der Reihenfolge High-/Lowbyte zusammengesetzt
*/
int readI2C(uint8_t i2cAddr, uint8_t reg, unsigned int deadtime)
{
unsigned int wait = deadtime;
if (!TWI_MasterWriteRead(&twiMaster, i2cAddr, &reg, 1, 2)) { // 1 Byte schreiben, 2 empfangen
usart_putDec(&USART_data, reg);
usart_puts_P(&USART_data, ": I2C read error\n");
}
while (twiMaster.status != TWIM_STATUS_READY) { // warten, bis Übertragung abgeschlossen
wait--;
if (wait==0) {
usart_putDec(&USART_data, reg);
usart_puts_P(&USART_data, " I2C read failed\n");
return 0; // Wartezeit überschritten
}
_delay_us(1);
}
return (twiMaster.readData[0]<<8) | twiMaster.readData[1];
}
/* analog zu readI2C: schreibt in ein Register einen Wert */
void writeI2C(uint8_t i2cAddr, uint8_t reg, uint8_t value, unsigned int deadtime)
{
unsigned char data[2];
unsigned int wait = deadtime;
data[0] = reg;
data[1] = value;
if (!TWI_MasterWriteRead(&twiMaster, i2cAddr, data, 2, 0)) { // 1 Byte schreiben, 2 empfangen
usart_putDec(&USART_data, reg);
usart_puts_P(&USART_data, ": I2C write error\n");
}
while (twiMaster.status != TWIM_STATUS_READY) { // warten, bis Übertragung abgeschlossen
wait--;
if (wait==0) {
usart_putDec(&USART_data, reg);
usart_puts_P(&USART_data, " I2C write failed\n");
return; // Wartezeit überschritten
}
_delay_us(1);
}
}
int __attribute__((OS_main)) main( void )
{
/* Clock auf 32Mhz einstellen damit die I2C schnell genug bedient werden kann */
OSC.PLLCTRL = OSC_PLLSRC_RC2M_gc | 16;
OSC.CTRL |= OSC_PLLEN_bm | OSC_RC2MEN_bm | OSC_RC32KEN_bm;;
while (!(OSC.STATUS & OSC_PLLRDY_bm));
DFLLRC2M.CTRL = DFLL_ENABLE_bm ;
CCP = CCP_IOREG_gc;
CLK.CTRL = CLK_SCLKSEL_PLL_gc;
/* Timer D0 als 100kHz-Zähler initialisieren und Event generieren */
TCD0.PER = 319; // 32Mhz / 320 = 100kHz
TCD0.CNT = 0;
TCD0.CTRLA = TC_CLKSEL_DIV1_gc;
EVSYS.CH0MUX = EVSYS_CHMUX_TCD0_OVF_gc;
/* Timer C0 zählt mit 100khZ */
TCC0.PER = 65535;
TCC0.CNT = 0;
TCC0.CTRLA = TC_CLKSEL_EVCH0_gc; // Events auf Kanal #0 zählen (100khz-Überlauf von TCD0)
EVSYS.CH1MUX = EVSYS_CHMUX_TCC0_OVF_gc;
/* Timer C1 zählt Überläufe von Timer C0 */
TCC1.PER = 65535;
TCC1.CNT = 0;
TCC1.CTRLA = TC_CLKSEL_EVCH1_gc; // Events auf Kanal #1 zählen (Überlauf von TCC0)
/* Art des Schlafzustandes: nur CPU-Kern schläft, Peripherie bleibt aktiv */
set_sleep_mode(SLEEP_MODE_IDLE);
/* Schnittstellen initialisieren */
usart_init(); // serielle Schnittstelle zum PC initialisieren
//TWI_MasterInit(&twiMaster, &TWIF, TWI_MASTER_INTLVL_HI_gc, TWI_BAUD(F_CPU, 2000000)); // I2C mit 1Mhz Busgeschwindigkeit initialisieren
// Wenn die Taktrate höher gewählt wird als der XMega kann, dann kommt eine hässliche Warnung
// im GCC, dass eine zu große Konstante in unsigned gewandelt wird. Vorsicht, das heißt nämlich
// dass es ein negativer Skalierungsfaktor ist/war... :-(
/* IRQ #0 auf Port F konfigurieren */
PORTF.DIRCLR = 1<<3; // Portpin 03 als Eingang
PORTF.INT0MASK = 1<<3;
PORTF.INTCTRL = PORT_INT0LVL_LO_gc;
PORTF.PIN3CTRL = PORT_ISC_RISING_gc;
/* LEDs als Statusinfo */
LEDPORT.OUT = 0xff; // alle LEDs aus
LEDPORT.DIR = 0xff; // LEDs als Ausgabe an Port E
/* alle Interrupts freigeben */
PMIC.CTRL |= PMIC_LOLVLEX_bm | PMIC_MEDLVLEX_bm | PMIC_HILVLEX_bm;
sei();
/* BMA-150 konfigurieren */
//writeI2C(0x38, 0x14, ((readI2C(0x38, 0x14, 40000)>>8) & 0b11100000), 4000);
//writeI2C(0x38, 0x15, 0xa0, 4000);
//writeI2C(0x38, 0x0b, 0b00000000, 4000);
int printCount = 1000; // 3000 Daten pro Sekunde, 25Hz Filter: alle 120 Werte reichen als Samplingfrequenz
unsigned char startReg = 0x02;
int deadtime;
int x_acc = 0;
int y_acc = 0;
int z_acc = 0;
readData = true; // 1x auslesen veranlassen, damit das Interrupt-Bit zurückgesetzt wird...
while(true) {
if(readData) {
readData = false;
/* 7 Bytes ab Adresse 2 lesen */
deadtime = 400;
if (!TWI_MasterWriteRead(&twiMaster, 0x38, &startReg, 1, 7)) {
usart_puts_P(&USART_data, "I2C RW error\n");
}
while ((twiMaster.status != TWIM_STATUS_READY) & deadtime) {
deadtime--;
delay_us(1);
}
printCount--;
if (printCount==0) {
printCount = 1000;
if (deadtime) {
usart_putDec(&USART_data,timerHigh);
usart_putc(&USART_data, ' ');
usart_putDec(&USART_data,timerLow);
usart_putc(&USART_data, ':');
int temp =-300 + 5*twiMaster.readData[6]; // Temperatur in 1/10 Grad
/* umsortieren der Bytes, um einen Integer von 16 Bit zu erhalten */
/* durch <<6 und casten auf int wird das Vorzeichenbit richt übernommen */
/* danach wird vorzeichenbehaftet wieder nach rechts geschoben. */
x_acc = ((int)((twiMaster.readData[1]<<2) | (twiMaster.readData[0]>>6))<<6)>>6;
y_acc = ((int)((twiMaster.readData[3]<<2) | (twiMaster.readData[2]>>6))<<6)>>6;
z_acc = ((int)((twiMaster.readData[5]<<2) | (twiMaster.readData[4]>>6))<<6)>>6;
usart_putDec(&USART_data,x_acc);
usart_putc(&USART_data, ' ');
usart_putDec(&USART_data,y_acc);
usart_putc(&USART_data, ' ');
usart_putDec(&USART_data,z_acc);
usart_putc(&USART_data, ' ');
usart_putDec(&USART_data,temp);
usart_putc(&USART_data, '\n');
/* Led-Anzeige 'Wasserwaage' */
uint8_t disp; // Led-Muster
if (y_acc > 128) {
disp = 8;
} else if (y_acc > 0){
disp = 4;
} else if (y_acc < -128) {
disp = 1;
} else {
disp = 2;
}
if (x_acc < 0) {
disp <<= 4;
}
if (abs(x_acc)<64) {
disp |= disp<<4 | disp>>4;
}
LEDPORT.OUT = ~disp; // LEDs sind Low-aktiv
}
}
} else {
sleep_enable();
sleep_cpu();
}
}
}
ISR(TWIF_TWIM_vect)
{
TWI_MasterInterruptHandler(&twiMaster); // ist in twic.c definiert
}
/* IRQ vom BMA-150 */
ISR(PORTF_INT0_vect){
timerLow = TCC0.CNT; // Zeitstempel auslesen
timerHigh = TCC1.CNT;
readData = true; // Auslesen der Messwerte veranlassen
}
/*
* Ghost Car
*
* Anschlüsse:
* ===========
* PC0 : IR-LED
* PC7 : IR-LED TXD1
* PC6 : IR-Empfänger (invertiert), RXD1
* PD1 : Motor-Transistor OC0B
*/
#include "system.h"
#include <avr/sleep.h> // Strom sparen mit Sleep
#include "usart.h"
#define PWMMAX 8191
int __attribute__((OS_main)) main( void )
{
unsigned int speed = 0;
/* Clock auf 32Mhz einstellen damit die I2C schnell genug bedient werden kann */
OSC.PLLCTRL = OSC_PLLSRC_RC2M_gc | 16;
OSC.CTRL |= OSC_PLLEN_bm | OSC_RC2MEN_bm | OSC_RC32KEN_bm;;
while (!(OSC.STATUS & OSC_PLLRDY_bm));
DFLLRC2M.CTRL = DFLL_ENABLE_bm ;
CCP = CCP_IOREG_gc;
CLK.CTRL = CLK_SCLKSEL_PLL_gc;
/* Schnittstellen initialisieren */
usart_init(); // serielle Schnittstelle zum PC initialisieren
/* IR-Sender ausschalten */
// Pin 0 führt 37khz
PORTC.PIN0CTRL = PORT_OPC_WIREDANDPULL_gc;
PORTC.PIN7CTRL = PORT_OPC_WIREDANDPULL_gc;
PORTC.OUTCLR = 0x80;
PORTC.DIRSET = 0x81;
/* PWM für Motor einschalten */
PORTD.OUTCLR = 2;
PORTD.DIR = 2; // D0 als Ausgang
TCD0.PER = PWMMAX; // bei DIV4 macht das 125Hz
TCD0.CCB = speed; // Dutycycle A
TCD0.CTRLA = TC_CLKSEL_DIV4_gc;
TCD0.CTRLB = 0x23; // PWM single slope (x3) auf Kanal A (2x)
/* IR-Sender 37 kHz */
TCD1.CTRLA = TC_CLKSEL_DIV1_gc;
TCD1.PER = 865;
TCD1.INTCTRLA = 1;
/* IR-Empfänger als Eingang schalten */
PORTC.DIRCLR = 64;
PORTC.PIN6CTRL = PORT_OPC_PULLUP_gc;
/* LEDs als Statusinfo */
LEDPORT.OUT = 0xff; // alle LEDs aus
LEDPORT.DIR = 0xff; // LEDs als Ausgabe an Port E
/* alle Interrupts freigeben */
PMIC.CTRL |= PMIC_LOLVLEX_bm | PMIC_MEDLVLEX_bm | PMIC_HILVLEX_bm;
sei();
usart_puts_P(&USART_data, "\nLos geht's!\n");
uint8_t spdCnt = 0;
unsigned int speeds[] = {0, 3000, 6000, 8191};
while (1) {
LEDPORT.OUT = (PORTC.IN & 64) ? 0 : 0xff;
if (USART_RXBufferData_Available(&USART_data)) {
char c = usart_getc(&USART_data);
switch (c) {
case '+': // schneller
speed = (speed <= PWMMAX-100) ? speed+100 : PWMMAX;
break;
case '-': // langsamer
speed = (speed >= 100) ? speed-100 : 0;
break;
case '0': // stop
speed = 0;
break;
case '1': // volle fahrt!
speed = PWMMAX;
break;
case 'i': // IR ein/aus
PORTC.OUTTGL = 0x80;
break;
default:
usart_puts_P(&USART_data, "\nKommando unbekannt!\n");
usart_putDec(&USART_data,c);
break;
}
TCD0.CCB = speed;
usart_puts_P(&USART_data, "\nGeschwindigkeit: ");
usart_putDec(&USART_data, speed);
/*
LEDPORT.OUTSET = 0xff;
for (unsigned int i = 0; i<7; i++) {
if ((256<<i) < speed) {
LEDPORT.OUTCLR = 1<<i;
}
}
*/
} else {
if (PORTC.IN & 64) {
spdCnt = (spdCnt + 1) & 3;
TCD0.CCB = speeds[spdCnt];
delay_ms(500);
}
}
}
}
ISR(TCD1_OVF_vect) {
PORTC.OUTTGL = 1;
}
#ifndef SYSTEM_H
#define SYSTEM_H
#ifndef F_CPU
#error F_CPU undefined!
#endif
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
/*! \brief This macro will protect the following code from interrupts. */
#define AVR_ENTER_CRITICAL_REGION( ) uint8_t volatile saved_sreg = SREG; \
cli();
/*! \brief This macro must always be used in conjunction with AVR_ENTER_CRITICAL_REGION
* so the interrupts are enabled again.
*/
#define AVR_LEAVE_CRITICAL_REGION( ) SREG = saved_sreg;
/*! \brief Define the delay_us macro for GCC. */
#define delay_us( us ) (_delay_us( us ))
#define delay_ms( us ) (_delay_ms( us ))
#define INLINE static inline
/*! \brief Define the no operation macro. */
#define nop() do { __asm__ __volatile__ ("nop"); } while (0)
#define MAIN_TASK_PROLOGUE int
#define MAIN_TASK_EPILOGUE() return -1;
#define SHORTENUM __attribute__ ((packed))
#define LEDPORT PORTE
#endif
/* This file has been prepared for Doxygen automatic documentation generation.*/
/*! \file *********************************************************************
*
* \brief
* XMEGA TWI master driver source file.
*
* This file contains the function implementations the XMEGA master TWI
* driver.
*
* The driver is not intended for size and/or speed critical code, since
* most functions are just a few lines of code, and the function call
* overhead would decrease code performance. The driver is intended for
* rapid prototyping and documentation purposes for getting started with
* the XMEGA TWI master module.
*
* For size and/or speed critical code, it is recommended to copy the
* function contents directly into your application instead of making
* a function call.
*
* Several functions use the following construct: