PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Controller hängt sich auf(verm. bei twi übertragung)mega644



hosti
11.10.2009, 11:54
Guten Tag,
ich habe seit längerm ein Problem.
Und zwar frage ich ein digitales Steuerkreuz ab.
Links/Rechts = auswahl des Servos (1 -18 )
Hoch/Runter = Wert um 5 verändern und über twi senden.
Diese Eingaben zeige ich auf einem Display an.

Leider hängt sich der Controller irgendwan beim senden des Werts über I2C auf.
Das hat aber funktioniert, und erst seit ich über eingabe/ausgabe via Steuerkreuz und display interagiere funktioniert das nicht mehr.

Ich habe es soweit eingegrenzt das ich mir eigentlich sicher bin, das es an der Busübertragung liegt.

So sieht der Code des Atmega644 aus(dieser sendet):
Main.c


#define F_CPU 16000000UL //CPU Tackt

#include <avr/io.h> // I/O Port definitions
#include <avr/interrupt.h> // Interrupt macros
#include <util/twi.h>
#include <util/delay.h>
#include "lcd.h"
#include "funktionen.h"




/*----------------------------------------------------------------------------------------*/
//MAIN AUFRUF
/*----------------------------------------------------------------------------------------*/

int main(void)
{

DDRA |= (1<<PORTA0);
PORTA |= (1<<PORTA0);

//Init Ports Steuerkreuz (Eingänge)
DDRD &= ~((1<<PORTD4) | (1<<PORTD5) | (1<<PORTD6) | (1<<PORTD7));
//Pullup aktivieren
PORTD |= (1<<PORTD4) | (1<<PORTD5) | (1<<PORTD6) | (1<<PORTD7) ;
//D7 Rechts
//D6 Links
//D5 Runter
//D4 Hoch
twi_init();

servo1 = 125;
servo2 = 125;
servo3 = 125;
servo4 = 125;
servo5 = 125;
servo6 = 125;
servo7 = 125;
servo8 = 125;
servo9 = 125;
servo10 = 125;
servo11 = 125;
servo12 = 125;
servo13 = 125;
servo14 = 125;
servo15 = 125;
servo16 = 125;
servo17 = 125;
servo18 = 125;


servochance = 1;


//screenup();


while(1)
{

if(tast(&PIND, PORTD7))
{
if(servochance<18)
servochance++;
else
servochance = 1;
dispz(servochance, servochance);

}

if(tast(&PIND, PORTD6))
{
if(servochance>1)
servochance--;
else
servochance = 18;
dispz(servochance, servochance);
}

if(tast(&PIND, PORTD4))
{
switch(servochance)
{
case 1:
if(servo1<250)
{
servo1= servo1+5;
twi_servo(SLAVE_ADRESSE1, servo1, servo2, servo3);
dispz(servochance, servo1);
}
break;
/*
case 2:
if(servo2<250)
{
servo2= servo2+5;
twi_servo(SLAVE_ADRESSE1, servo1, servo2, servo3);
dispz(servochance, servo2);
}
break;

case 3:
if(servo3<250)
{
servo3= servo3+5;
twi_servo(SLAVE_ADRESSE1, servo1, servo2, servo3);
dispz(servochance, servo3);
}
break;

case 4:
if(servo4<250)
{
servo4= servo4+5;
twi_servo(SLAVE_ADRESSE2, servo4, servo5, servo6);
dispz(servochance, servo4);
}
break;

case 5:
if(servo5<250)
{
servo5= servo5+5;
twi_servo(SLAVE_ADRESSE2, servo4, servo5, servo6);
dispz(servochance, servo5);
}
break;

case 6:
if(servo6<250)
{
servo6= servo6+5;
twi_servo(SLAVE_ADRESSE2, servo4, servo5, servo6);
dispz(servochance, servo6);
}
break;

case 7:
if(servo7<250)
{
servo7= servo7+5;;
twi_servo(SLAVE_ADRESSE3, servo7, servo8, servo9);
dispz(servochance, servo7);
}
break;

case 8:
if(servo8<250)
{
servo8= servo8+5;
twi_servo(SLAVE_ADRESSE3, servo7, servo8, servo9);
dispz(servochance, servo8);
}
break;

case 9:
if(servo9<250)
{
servo9= servo9+5;
twi_servo(SLAVE_ADRESSE3, servo7, servo8, servo9);
dispz(servochance, servo9);
}
break;

case 10:
if(servo10<250)
{
servo10= servo10+5;
twi_servo(SLAVE_ADRESSE4, servo10, servo11, servo12);
dispz(servochance, servo10);
}
break;

case 11:
if(servo11<250)
{
servo11= servo11+5;
twi_servo(SLAVE_ADRESSE4, servo10, servo11, servo12);
dispz(servochance, servo11);
}
break;

case 12:
if(servo12<250)
{
servo12= servo12+5;
twi_servo(SLAVE_ADRESSE4, servo10, servo11, servo12);
dispz(servochance, servo12);
}
break;

case 13:
if(servo13<250)
{
servo13= servo13+5;
twi_servo(SLAVE_ADRESSE5, servo13, servo14, servo15);
dispz(servochance, servo13);
}
break;

case 14:
if(servo14<250)
{
servo14= servo14+5;
twi_servo(SLAVE_ADRESSE5, servo13, servo14, servo15);
dispz(servochance, servo14);
}
break;

case 15:
if(servo15<250)
{
servo15= servo15+5;
twi_servo(SLAVE_ADRESSE5, servo13, servo14, servo15);
dispz(servochance, servo15);
}
break;

case 16:
if(servo16<250)
{
servo16= servo16+5;
twi_servo(SLAVE_ADRESSE6, servo16, servo17, servo18);
dispz(servochance, servo16);
}
break;

case 17:
if(servo17<250)
{
servo17= servo17+5;
twi_servo(SLAVE_ADRESSE6, servo16, servo17, servo18);
dispz(servochance, servo17);
}
break;

case 18:
if(servo18<250)
{
servo18= servo18+5;
twi_servo(SLAVE_ADRESSE6, servo16, servo17, servo18);
dispz(servochance, servo18);
}
break;*/

}

}

if(tast(&PIND, PORTD5))
{
switch(servochance)
{
case 1:
if(servo1>1)
{
servo1= servo1-5;
twi_servo(SLAVE_ADRESSE1, servo1, servo2, servo3);
dispz(servochance, servo1);
}
break;
/*
case 2:
if(servo2>1)
{
servo2= servo2-5;
twi_servo(SLAVE_ADRESSE1, servo1, servo2, servo3);
dispz(servochance, servo2);
}
break;

case 3:
if(servo3>1)
{
servo3= servo3-5;
twi_servo(SLAVE_ADRESSE1, servo1, servo2, servo3);
dispz(servochance, servo3);
}
break;

case 4:
if(servo4>1)
{
servo4= servo4-5;
twi_servo(SLAVE_ADRESSE2, servo4, servo5, servo6);
dispz(servochance, servo4);
}
break;

case 5:
if(servo5>1)
{
servo5= servo5-5;
twi_servo(SLAVE_ADRESSE2, servo4, servo5, servo6);
dispz(servochance, servo5);
}
break;

case 6:
if(servo6>1)
{
servo6= servo6-5;
twi_servo(SLAVE_ADRESSE2, servo4, servo5, servo6);
dispz(servochance, servo6);
}
break;

case 7:
if(servo7>1)
{
servo7= servo7-5;
twi_servo(SLAVE_ADRESSE3, servo7, servo8, servo9);
dispz(servochance, servo7);
}
break;

case 8:
if(servo8>1)
{
servo8= servo8-5;
twi_servo(SLAVE_ADRESSE3, servo7, servo8, servo9);
dispz(servochance, servo8);
}
break;

case 9:
if(servo9>1)
{
servo9= servo9-5;
twi_servo(SLAVE_ADRESSE3, servo7, servo8, servo9);
dispz(servochance, servo9);
}
break;

case 10:
if(servo10>1)
{
servo10= servo10-5;
twi_servo(SLAVE_ADRESSE4, servo10, servo11, servo12);
dispz(servochance, servo10);
}
break;

case 11:
if(servo11>1)
{
servo11= servo11-5;
twi_servo(SLAVE_ADRESSE4, servo10, servo11, servo12);
dispz(servochance, servo11);
}
break;

case 12:
if(servo12>1)
{
servo12= servo12-5;
twi_servo(SLAVE_ADRESSE4, servo10, servo11, servo12);
dispz(servochance, servo12);
}
break;

case 13:
if(servo13>1)
{
servo13= servo13-5;
twi_servo(SLAVE_ADRESSE5, servo13, servo14, servo15);
dispz(servochance, servo13);
}
break;

case 14:
if(servo14>1)
{
servo14= servo14-5;
twi_servo(SLAVE_ADRESSE5, servo13, servo14, servo15);
dispz(servochance, servo14);
}
break;

case 15:
if(servo15>1)
{
servo15= servo15-5;
twi_servo(SLAVE_ADRESSE5, servo13, servo14, servo15);
dispz(servochance, servo15);
}
break;

case 16:
if(servo16>1)
{
servo16= servo16-5;
twi_servo(SLAVE_ADRESSE6, servo16, servo17, servo18);
dispz(servochance, servo16);
}
break;

case 17:
if(servo17>1)
{
servo17= servo17-5;
twi_servo(SLAVE_ADRESSE6, servo16, servo17, servo18);
dispz(servochance, servo17);
}
break;

case 18:
if(servo18>1)
{
servo18= servo18-5;
twi_servo(SLAVE_ADRESSE6, servo16, servo17, servo18);
dispz(servochance, servo18);
}
break;*/

}


}




}

}


funktionen.c

unsigned char twi_servo(unsigned char slave_adr, unsigned char servo1,unsigned char servo2,unsigned char servo3)
{
if(!(twi_start(slave_adr+0)))
{
twi_senden(0x00);
_delay_ms(10);

twi_senden(servo1);
_delay_ms(10);

twi_senden(servo2);
_delay_ms(10);

twi_senden(servo3);
_delay_ms(10);

twi_stop();
return 1;
}
return 0;
}

void twi_init(void)
{
DDRC &= !((1<<DD0) | (DD1));
PORTC = (1<<DD0) | (1<<DD1);
TWSR = 0x00; //Prescaler
TWBR = 12; //TWI 400khz

//Hintergrundbeleuchtung on
PORTA |= (1<<PORTA0);
//Initialisieren des Displays, Cursor off
lcd_init(LCD_DISP_ON);
//Display löschen, Cursor i Zeile, 1 Spalte
lcd_clrscr();
//Cursor auf 1 Zeile, 3 Buchstaben
lcd_gotoxy(0,0);
//String ausgeben
lcd_puts("I2C ");
//Cursor auf 2 Zeile, 3 Buchstaben
lcd_gotoxy (0, 1);
//String ausgeben
lcd_puts("Initialisieren");
//~3s warten
_delay_ms(1000);
//Display off
lcd_init(LCD_DISP_OFF);
//Hintergrundbeleuchtung off
PORTA &= ~(1<<PORTA0);
}

unsigned char twi_start(unsigned char adresse)
{
uint8_t twst;


TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN); //TWI aktivieren und Start condition auslösen
while(!(TWCR & (1<<TWINT))); //Warten auf Start condition
twst = TW_STATUS & 0xF8;
//if((TWSR & 0xF8) != 0x08);
if ((twst != TW_START) && (twst != TW_REP_START))return 1;

TWDR = adresse; //Adresse mit Schreibbit(xxxxxxx0) in Register
TWCR = (1<<TWINT) | (1<<TWEN); //senden
//if((TWSR & 0xF8) != 0x18);
while(!(TWCR & (1<<TWINT))); //warten auf ACK oder NACK
twst = TW_STATUS & 0xF8;
if ((twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK)) return 1;
return 0;

}

unsigned char twi_rep_start(unsigned char adresse)
{
return twi_start(adresse);
}

unsigned char twi_senden(unsigned char daten)
{
uint8_t twst;

TWDR = daten; //Byte in Datenregister laden
TWCR = (1<<TWINT) | (1<<TWEN); //senden
while (!(TWCR & (1<<TWINT))); //warten auf ACK oder NACK
twst = TW_STATUS & 0xF8;
if(twst != TW_MT_DATA_ACK) return 1;
return 0;

}

unsigned char twi_lesenAck(void)
{
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);
while(!(TWCR & (1<<TWINT)));
return TWDR;
}

unsigned char twi_lesenNak(void)
{
TWCR = (1<<TWINT) | (1<<TWEN);
while(!(TWCR & (1<<TWINT)));
return TWDR;
}

void twi_stop(void)
{
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
while(TWCR & (1<<TWSTO));
}


/*----------------------------------------------------------------------------------------*/
//Display ausgaben
/*----------------------------------------------------------------------------------------*/


void dispz(const char zahl1, const char zahl2)
{

char text1[17];
char text2[17];

itoa(zahl1, text1, 10);
itoa(zahl2, text2, 10);


//Initialisieren des Displays, Cursor off
lcd_init(LCD_DISP_ON);
//Display löschen, Cursor i Zeile, 1 Spalte
lcd_clrscr();
//Cursor auf 1 Zeile, 3 Buchstaben
lcd_gotoxy(0,0);
//String ausgeben
lcd_puts(text1);
//Cursor auf 2 Zeile, 3 Buchstaben
lcd_gotoxy (0, 1);
//String ausgeben
lcd_puts(text2);
_delay_ms(50);
}

int tast(volatile uint8_t *port, uint8_t pin)
{
if(!(*port & (1<<pin)))
{
_delay_ms(100);
if(!(*port & (1<<pin)))
{
_delay_ms(100);
return 1;
}
}
return 0;
}


und der code des Slaves, wobei ich denke das müsste passen:


#include <avr/io.h> //I/O Port definitions
#include <avr/interrupt.h> //Interrupt macros
#include <util/twi.h> //TWI STATUS

#define F_CPU 16000000UL //CPU Tackt

/*----------------------------------------------------------------------------------------*/
//TWI
/*----------------------------------------------------------------------------------------*/
#define SLAVE_ADRESSE 0x60 //Slaveadresse
#define buffer_size 5 //TWI_empfangsbuffer grösse
//ACK nach empfangenen Daten senden/erwarten
#define TWCR_ACK TWCR = (1<<TWEN) | (1<<TWIE) | (1<<TWINT) | (1<<TWEA) | (0<<TWSTA) | (0<<TWSTO) | (0<<TWWC)
//NACK nach empfangenen Daten senden/erwarten
#define TWCR_NACK TWCR =(1<<TWEN) | (1<<TWIE) | (1<<TWINT) | (0<<TWEA) | (0<<TWSTA) | (0<<TWSTO) | (0<<TWWC)
//wechseln zu nicht adressiertem Slavemodus
#define TWCR_RESET TWCR = (1<<TWEN) | (1<<TWIE) | (1<<TWINT) | (1<<TWEA) | (0<<TWSTA) | (0<<TWSTO) | (0<<TWWC)

uint8_t adresse; //Slaveadresse
volatile uint8_t buffer_adr; //Speicherposition
volatile uint8_t rxbuffer[buffer_size] = {1,1,1,1,1}; //TWI_empfangsbuffer
volatile uint8_t txbuffer[buffer_size] = {1,1,1,1,1}; //TWI_sendenbuffer


/*----------------------------------------------------------------------------------------*/
//PWM
/*----------------------------------------------------------------------------------------*/

//1000 = 1ms(links), 1500 = 1,5ms(mitte), 2000 = 2ms(rechts)
volatile int schulter= 1500;
volatile int huefte = 1500;
volatile int knie = 1500;

void twi_slave(uint8_t adresse); //TWI_Init funktion
void pwm_init(int schulter, int huefte, int knie); //PWM_init Funktion
void pwm_chance(int schulter, int huefte, int knie);//Anpassen der PWM grössen

/*----------------------------------------------------------------------------------------*/
//MAIN AUFRUF
/*----------------------------------------------------------------------------------------*/

int main(void)
{
adresse = SLAVE_ADRESSE; //Slave 1
DDRB = 0xFF; //B... AUSGANG
PORTB &= ~((1<<PORTB1) | (1<<PORTB2) | (1<<PORTB3)); //B.. Low
sei(); //Globale Interupts zulassen
pwm_init(schulter, huefte, knie); //PWM initialisieren
twi_slave(adresse); //TWI initialisieren


while(1)
{



}

}

ISR(TWI_vect) //TWI Interupt (Ausgelöst bei Bus Ereignis)
{
uint8_t daten = 0;

switch(TW_STATUS) //TWI-Statusregister prüfen und agieren
{

case TW_SR_SLA_ACK: //0x60, Slave Receiver wurde adressiert

TWCR_ACK;
buffer_adr = 0xFF;
break;

case TW_SR_DATA_ACK: //0x80, Slave Receiver Daten empfangen

daten = TWDR; //Daten auslesen

if (buffer_adr == 0xFF)
{
if(daten<=buffer_size)
{
buffer_adr = daten;
}
else
{
buffer_adr=0;
}

TWCR_ACK;
}
else
{
rxbuffer[buffer_adr] = daten;
buffer_adr++;

//Zuweisen der neuen PWM werte
schulter = ((rxbuffer[0]*4)+1000);
huefte = ((rxbuffer[1]*4)+1000);
knie = ((rxbuffer[2]*4)+1000);

pwm_chance(schulter, huefte, knie); //PWM grössen anpassen

if (buffer_adr<(buffer_size-1))
{
TWCR_ACK;
}
else
{
TWCR_NACK;
}
}




break;

case TW_ST_DATA_ACK: //0xB8, Slave Transmitter Daten angefordert

if(buffer_adr == 0xFF)
{
buffer_adr = 0;
}
TWDR = txbuffer[buffer_adr];
buffer_adr++;

if(buffer_adr<(buffer_size-1))
{
TWCR_ACK;
}
else
{
TWCR_NACK;
}
break;


case TW_SR_STOP:

default:
TWCR_RESET;

break;

//Ende
}




}

Ich hoffe das reicht an Code, es fehlen Teile wie Headerfiles und funktionen die nichts mit dem Problem zu tun haben.
Ein Grossteil ist bewusst auskommentiert um den Fehler näher einzugrenzen.

Nochmal um das Problem näher zu umschreiben:
Das auswählen des Servos klappt super, auch das erhöhen des Wert wen ich die Twiübertragung ausklammere.
Ist diese aber drin funktioniert es, aber meisst nur kurz. Sprich 1 -3 Werte können übertragen werden dann hängt sich der Atmega644 auf.
Manchmal sind es auch mehrere Übertragungen. Dies aber eher selten.
Mir gehen echt die Ideen aus.

Besten dank fürs lesen und jeglichen Tipp

Jaecko
11.10.2009, 12:01
Sicher, dass das an den Ausgaben liegt?
Ich hätte eher die _delay_ms() in der Funktion twi_servo() in Verdacht. Solange eine TWI-Übertragung aktiv ist (d.h. zwischen Start und Stop), ist ein Delay schlecht.
Wenn schon ein Delay sein muss, dann würd ich jeden Befehl extra mit Start und Stop einschliessen.

hosti
11.10.2009, 12:16
Diese Vermutung hatte ich auch schon, hat sogar eine Verbesserung gebracht... war aber auch nicht die Ursache für das Problem.

Aufhängen tut er sich immernoch, aber danke für den Tip

Marten83
12.10.2009, 10:58
Hallo Hosti,

hast du dir schonmal überlegt ob die Übertragung interruptgesteuert sinnvoll wäre?
Bei Atmel gibt es eine APPNote (AVR315) worin das schon alles vorhanden ist.
Muss man nur noch geringfügig (je nach dem) anpassen.

MfG, Maren83

yaro
12.10.2009, 23:05
Hallo Hosti,

Hast du schonmal geguckt, wo genau (in der TWI-Funktion) der Controller immer abstürzt? Du hast doch ein Display zur Verfügung, lass dir einfach mal nach jedem Befehl ausgeben, ob er richtig ausgeführt wurde. Wahrscheinlich bleibt er in irgendeiner Schleife hängen, dann wäre es sinvoll zu wissen, in welcher.

Wenn du diese Schleife gefunden hast, dann guck, welche Parameter dazu führen, dass das Programm nicht aus ihr rauskommt.

Gut wäre auch noch zu gucken, was beim Slave ankommt, was aber wahrscheinlich eher weniger möglich ist.... vieleicht hast du am Slave aber trotzdem noch einige Pins frei und kannst sie mit einem Multimeter nachmessen, um eventuelle informationen aus dem Controller zu bekommen.

Bin gespannt, was bei rauskommt.

Gruß, Yaro

hosti
13.10.2009, 19:50
Hm, ich wollt mir die Sache nochmals ansehen.
Doch leider ist der Fehler weg, es hat einfach wieder funktioniert.
Einmal ist er heute abend aufgetaucht. Dann war schon wieder ruhe. :-k
Ist für mich völlig unverständlich, auf Hardware fehler habe ich zwar schon geprüft und nichts gefunden. Dennoch werde ich da nochmals dahinter. müsste ja verm. eine Problematik im Bereich der Busleitunge bestehen.

@Marten, nein, darüber habe ich noch nicht nachgedacht. Was für Vorteile hat das?

Danke schonmal für eure Bemühungen, ich hoffe einen einfachen Hardwarefehler zu finden

darwin.nuernberg
13.10.2009, 20:10
Hast Du berücksichtigt, dass dein TWI Kabel nicht all zu lange sein darf (Störeinstrahlung) das könnte des zeitweise Störverhalten erklären
Hast du die 10k PullUp Widerstände zu SCR und SDA berücksichtigt?