PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : ATmega8 mit TWI-Interrupts, was mache ich falsch?



mefiX
26.08.2008, 12:25
Hallo Zusammen,

ich habe eine Schaltung aufgebaut, in der ein ATmega8 über I2C mit einem SRF02 Ultraschallmodul redet. Ich benutze im Code die I2C-Master Implementierung von peter fleury.

Ich hatte jetzt schon öfter den Effekt, dass die Kommunikation im i2c_readAck() einfriert, was vermutlich darauf zurückzuführen ist, dass vom Slave (SRF02) keine Antwort zurück kommt.

Ich wollte nun also versuchen, das Ganze interrupt-basiert anzugehen. Leider bekomme ich es nicht mal auf die Reihe, einen Interrupt für Aktivitäten auf dem I2C-Bus zu aktivieren. Ich habe folgenden Code:


#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include "delay.h"
#include "lcd.h"
#include "i2cmaster.h"

#ifndef SIGNAL
#include <avr/signal.h>
#endif /* SIGNAL */

ISR (TWI_vect)
{
PORTB &= ~(1 << PB0);
delayms(500);
PORTB |= (1 << PB0);
}

unsigned int read_cm(unsigned char address)
{
unsigned char lowbyte,highbyte;
unsigned int distance;

i2c_start_wait(address+I2C_WRITE);

while (i2c_write(0));
while (i2c_write(81));
i2c_stop();

i2c_start_wait(address+I2C_WRITE);
while (i2c_write(2));
i2c_stop();

delayms(65);

i2c_start_wait(address+I2C_READ);
highbyte = i2c_readAck();
lowbyte = i2c_readNak();
distance = (highbyte<<8)+lowbyte;
i2c_stop();
if(distance > 150) {
PORTC = 0x00;
}
return distance;
}

int main(void)
{
...
i2c_init();
...
TWCR |= (1<<TWIE) | (1<<TWINT);
sei();

for ( ;; ) {
dist = read_cm(SRF02_ADDRESS);
if (dist >= HEIGHT) {
fill_percent = 0;
} else {
fill_percent = 100 - ((dist * 100) / HEIGHT);
}
delayms(3000);
}
}


Was mache ich beim Aktivieren des Interrupts falsch? Es passiert einfach nichts ...

Wie ist das eigentlich, muss ich als Implementierung nun twimaster.c oder i2cmaster.S verwenden?

AVR-GCC Version 4.3.0

Gruss,
mefiX

sternst
26.08.2008, 13:01
Was mache ich beim Aktivieren des Interrupts falsch? Es passiert einfach nichts ...

Ich sehe weder, dass du i2c_init aufrufst, noch dass du TWBR selber setzt.


Wie ist das eigentlich, muss ich als Implementierung nun twimaster.c oder i2cmaster.S verwenden?

i2cmaster.S ist Software-I2C, twimaster.c ist Hardware-I2C, und du möchtest offensichtlich Hardware-I2C haben.

Wenn du den TWI-Interrupt benutzen willst, musst du dich von der Fleury-Lib aber sowieso verabschieden. Die macht nämlich Polling, und "mischen" wird nichts werden.

mefiX
26.08.2008, 13:10
Hallo,

danke für die schnelle Antwort!

ich habe den Code zur besseren Lesbarkeit hier im Thread beschnitten, i2c_init() rufe ich direkt zu Beginn von main() auf, das passt also.

Aber TWBR habe ich mir bisher noch nciht angesehen, allerdings habe ich eben gesehen, dass genau das in i2c_init() gesetzt wird. Zunächst mit 0 initialisiert, danach wird dort die Taktrate in Abhängigkeit von F_CPU gesetzt.

Ok, dann lag ich bisher auch mit twimaster.c richtig, danke.

Gibt es eine Alternative zur polling-basierten Lib von Peter Fleury?
Wäre es eine alternative, das Auslesen des SRF02 nebenläufig zu machen? Ich habe da eine minimalistische Thread-Lib für AVRs im Netz entdeckt?

Gruss,
mefiX

sternst
26.08.2008, 13:15
i2c_start_wait überschreibt deine eigene TWCR-Einstellung wieder.
Wie gesagt, für Interrupt-Betrieb musst du dich komplett von der Fleury-Lib verabschieden.

mefiX
26.08.2008, 16:08
ich hab mir jetzt einfach nen timer-interrupt gebastelt, der nach beendigung der read()-routine zurückgesetzt wird. wenn ein gewisses timeout erreicht wurde wird das programm neu initialisiert, ist ein workaround, aber für meine zwecke ok.

danke für die antworten!