PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Controller verhält sich merkwürdig



robodriver
12.07.2009, 21:03
Hey Jungs,

ich habe hier ein Problem was mich seit einigen Tagen ziemlich stark verwirrt.
Vielleicht hat jemand von euch Ideen von woher ein solches Problem kommen könnte.

Folgendes:
Ich habe einen ATMega88 Fuses sind auf externen Clock gestellt und der Chip hängt an einen 8MHz Quarz Oszillator.

Der Chip fungiert als Slave am I²C Bus. Der Master ist auch ein Atmel Controller (ATMega1280, aber der ist erstmal unwichtig).
Das Programm ist momentan noch recht einfach:




int main(void)
{
init();

__RESET_LED;
_delay_ms(100);
__SET_LED;
_delay_ms(100);
__RESET_LED;
_delay_ms(100);
__SET_LED;
_delay_ms(100);
__RESET_LED;
while(1);
}

void init(void)
{
//------------------------
//Ein/Ausgänge:
//------------------------
DDRD |= _BV(0) | _BV(3) | _BV(1) | _BV(6) | _BV(7); //Motoren rechts/links und LED
DDRB |= _BV(0);

PORTD |= _BV(6); //vor2
//PORTD |= _BV(7); //zurück2

PORTD |= _BV(0); //vor1
//PORTB |= _BV(0); //zurück1

//------------------------
//Timer/Counter:
//------------------------

DDRB |= _BV(3); //PWM-Pin als Output
DDRD |= _BV(3); //PWM-Pin als Output

ASSR=0;
TCCR2A |= (1<<WGM20); //PWM-Mode
TCCR2A |= (1<<COM2A1) | (1<<COM2B1); //Compare = Set
TCCR2B |= (1<<CS20); //Prescaler 64
TCNT2=0;
OCR2A = 0; //PWM-Wert
OCR2B = 0; //PWM-Wert

//I2C Initialisieren:
i2c_init_slave(MY_I2C_ADR);

TWAMR = 255;

sei();
}

int i2c_init_slave(char address)
{
TWSR = 0;
TWDR = 0xFF;
TWCR = 0b00000100;
TWAR = (address<<1);
TWCR = 0b01000101;

return 1;
}

SIGNAL (SIG_2WIRE_SERIAL)
{
uint8_t status = 0;
uint8_t data = 0;
//PORTD &= ~(1<<PD2);
data = TWDR;

status = TWSR;

if (status_is(0xA8) || status_is(0xB8))
{

if (twi_send_data[a])
{
TWDR = twi_send_data[a];
a++;
if(a>3)
a=0;
}else{
for(a=0;a<11;a++)
twi_send_data[a]=0;

a=0;
TWDR = 0;
}

//TWDR = mydata;
}

TWCR |= 0b10000000;

if (status_is(0x80))
{
if (data == '*')
{
twi_data_received = 1;
}else{

if (twi_pointer < 10)
twi_buffer[twi_pointer++] = data;
//else
//fehler();//FEHLER!!
}
}
}



So viel zum Code, nur so, falls jemand was darin sieht...

Nun zum Problem:
Wie man sieht, müsste der Controller beim Einschalten 2x die LED blinken.

Der Master Controller Startet regelmäßig den Bus mit der Slaveadresse, sendet 2 Bytes und stopt den Bus wieder.
Mehr passiert da momentan nicht.

So und nun treten bei mir immer 2 verschiedene Möglichkeiten auf:

1) Ich starte alles und die LED blinkt 2x. Wenn der MAster den Slave aufruft, wird der Interrupt am Slave nicht aufgerufen, die Daten nicht bestätigt und somit gibt es einen Fehler auf dem Bus.

2) Ich starte alles und die LED blinkt 1x. Wenn der Master dann den Slave aufruft, dann läuft der Datentransfer ohne jegliche Probleme, ACKs kommen zurück und alles.

Unterm strich heißt das also:
Wenn die LED anfangs so blinkt (2x) wie es im Code steht, dann geht der Bus nicht.
Und wenn die LED anfangs nur einmal blinkt, was laut Code überhaupt nicht sein kann, dann geht der Bus hervorragend.

Wann welche der Möglichkeiten auftritt habe ich noch nicht heraus gefunden. Immer nach dem Brennen tritt eine dieser beiden Möglickeiten ein. Und irgendwann später mal beim brennen mal wieder die andere.
Ich habe da noch keinerlei Muster erkannt wann was kommt und auch keinerlei Ahnung was da los ist.
Weil keine der beiden Möglichkeiten nach dem Code richtig läuft...

Bin für jeden Hinweis dankbar. Egal welcher Art. Denn ich habe für dieses Verhalten keinerlei Erklärung...

PS: Die Interruptroutine läuft 1:1 auf einem anderen Chip am selben Bus fehlerfrei.

cipher
13.07.2009, 11:53
Hi!

Hast Du den Bus richtig terminiert?

Ein anderes Problem könnt die Verwendung der Timer in Verbindung mit _delay_ms() sein. _delay_ms() bentuzt einen der Timer.

Btw: Meines Wissens ist SIGNAL veraltet und mal sollte statt dessen ISR verwenden (Vorsicht: Dann den Namen des Interrupt-Vektors angeben).
Versuch's mal damit. Ich bin mir nämlich jetzt nicht sicher, ob das einfach das gleiche unter neuem Namen ist, oder ob sich auch was im Hintergrund geändert hat.

Viele Grüße,

Markus

robodriver
13.07.2009, 12:17
Hey, also erstmal vielen Dank für deine Antwort.
Bin für jede Idee dankbar.
Hab mir das alles nochmal angesehen:

Also der Bus hat auf beiden Leitungen Pull-Up Widerstände mit 4,7k Ohm.
Und die Kommunikation zu dem anderen Slave am Bus läuft ja auch einwandfrei. Nur der eine Slave macht halt Maken...

Die Delay Routinen habe ich mir nochmal angesehen. Diese verwenden definitiv keine Timer:


void
_delay_ms(double __ms)
{
uint16_t __ticks;
double __tmp = ((F_CPU) / 4e3) * __ms;
if (__tmp < 1.0)
__ticks = 1;
else if (__tmp > 65535)
{
// __ticks = requested delay in 1/10 ms
__ticks = (uint16_t) (__ms * 10.0);
while(__ticks)
{
// wait 1/10 ms
_delay_loop_2(((F_CPU) / 4e3) / 10);
__ticks --;
}
return;
}
else
__ticks = (uint16_t)__tmp;
_delay_loop_2(__ticks);
}

void
_delay_loop_2(uint16_t __count)
{
__asm__ volatile (
"1: sbiw %0,1" "\n\t"
"brne 1b"
: "=w" (__count)
: "0" (__count)
);
}


Und die ganzen Interruptbezeichnungen sind auch alle auf die den entsprechenden Vektor definiert.
Alle Bezeichnungen führen also zum gleichen Ergebnis:



/* Two-wire Serial Interface */
#define TWI_vect _VECTOR(24)
#define SIG_TWI _VECTOR(24)
#define SIG_2WIRE_SERIAL _VECTOR(24)

robodriver
13.07.2009, 16:01
Hey, also ich wollte bescheid sagen, das wir das Problem gelöst haben.

Haben festgestellt, dass beim aufruf des Slaves nicht nur der Bus hängen bleibt, sondern der komplette Controller hängen bleibt.
Was darauf hinweist, dass die ISR ins leere springt.

Der Compiler hat zwar angezeigt, dass er das Programm für einen Mega88 kompiliert, aber hat es scheinbar nicht getan.
Haben nochmal ein neues Projekt erstellt, die Dateien wieder rein kopiert und siehe da funktioniert es nun wieder :)
*freu*

Trotzdem danke für eure Bemühungen bzw. Gedanken die ihr euch eventuell darüber gemacht hat.

Falls nochmal jemand ein solches Problem haben sollte, hat er hier die Lösung dafür...