Forum: Mikrocontroller und Digitale Elektronik Komisches Verhalten bei AVR i2c


von xvzf (Gast)


Lesenswert?

Hallo,

Ich entwickel momentan eine Steuerungssoftware für einen Quadrocopter.

Der Quellcode ist hier zu finden und ist noch nicht komplett: 
https://github.com/xvzf/Infinity

Als ich heute Mittag seit langem die Software wieder auf den Copter 
aufgespielt habe, hatte ich ein merkwürdiges Problem festgestellt, das 
vorher nicht aufgetreten ist:
(Anbei, ich rede von dieser Datei: 
https://github.com/xvzf/Infinity/blob/testing/src_avr/sensors.cpp)

Folgender "Fehler" tritt auf:
Ich kann in der Funktion update_all der Klasse __sensors
entweder
1
update_data_itg3600();
oder
1
update_data_adxl345();
aufrufen, wenn ich beides Aufrufe, scheint mein Programm sich an dieser 
Stelle aufzuhängen.

Hat jemand
a) Eine Möglichkeit woran dies liegen könnte oder
b) Eine Idee wie ich das ganze Debuggen kann, ich habe nur einen Polulu 
PGM03A zur Verfügung, den ich für AVRs nutze, außerdem noch einen 
BusPirate, wobei ich JTAG nicht verwenden kann, da ich diese Pins des 
µCs bereits anders belegt habe.


Das einzige was ich geändert habe (was diese Datei betrifft) ist, dass 
ich die Konfiguration in eine lokale config.h verlegt habe.
Außerdem bin ich auf GCC 4.9 umgestiegen, da mein Linux eine Rolling 
Release Distribution ist, und GCC 4.8 nach einem Update vergebens nach 
einem Shared Object gesucht hat. Beide Compilerer habe ich selbst 
übersetzt. Dies ist das erste mal dass ich mit GCC 4.9 arbeite, vorher 
wie gesagt, 4.8.3.


Gerne kann auch ein Pull-request gemacht werden.


LG,
Matthias

von xvzf (Gast)


Lesenswert?

Ach ja, wenn jemand einen älteren GCC zufällig installiert hat, wäre 
freundlich einfach
1
 ./ibs.sh build
 aufzurufen und das HEX File hier hochzuladen.

LG

von xvzf (Gast)


Lesenswert?

niemand? :(

von Karl H. (kbuchegg)


Lesenswert?

xvzf schrieb:

> aufrufen, wenn ich beides Aufrufe, scheint mein Programm sich an dieser
> Stelle aufzuhängen.


... und das hast du wie verifiziert?

Wenn alle Stricke reissen:

Am Anfang von update_data_itg3600 eine LED einschalten. Am Ende der 
Funktion selbe LED wieder ausschalten.

Am Anfang der Funktion update_data_adxl345 eine andere LED 
einschalten. Am Ende dieser Funktion dieselbe LED wieder ausschalten.


Wenn alles reibungslos funktioniert, dann müssen beide LED vor sich 
hinleuchten. Leuchtet nur eine, dann hängt dein Programm in der anderen 
Funktion irgendwo.

Aber ausser, dass deine 'Last' in Form von Speicherverbrauch zu groß ist 
oder du dir irgendwo den Stack zerschossen hast, wüsste ich keinen 
Grund, warum das passieren sollte. Also verifizier erst mal, ob dein 
Programm tatsächlich abstürzt oder ob du nicht einfach nur einen 
Logikfehler hast, wonach der Aufruf der 2.ten Funktion die Effekte bzw. 
Berechnungen der 1.ten Funktion ungültig macht, so dass du nur einfach 
nicht das Ergebnis siehst, welches du erwarten würdest.


> Das einzige was ich geändert habe (was diese Datei betrifft) ist,
> dass ich die Konfiguration in eine lokale config.h verlegt habe.

Dann mach die Änderung probehalber mal rückgängig.


PS: dein Klassenaufbau ist etwas merkwürdig.
Du hast eine Sensorklasse, aber die scheint darüber Bescheid zu wissen, 
wie alle Sensoren im Detail funktionieren. So ist eine Klassenhierarchie 
nicht wirklich gedacht. Das sollte so funktionieren, dass es eine 
allgemeine Sensorklasse gibt, in der all das enthalten ist, was alle 
Sensoren (egal welcher Typ) gemeinsam haben.
Ein spezieller Sensor, zb ein itg3200 leitet sich dann als spezieller 
Sensor davon her
1
class itg3200 : public sensor
2
{
3
   ....
4
};

und enthält dann die Spezialisierung für diesen einen speziellen 
Sensortyp. Dein Quadrocopter enthält dann nicht einfach nur ein 
unspezifisches Sensor Objekt, das irgendwie magisch weiß, dass es bei 
einem UpdateAll nacheinander alle Spezialfunktionen aufrufen muss.
Dein Quadrocopter enthält dann eben 3 spezialisierte Objekte, das eine 
eine Instanz von der itg3200 Klasse, das andere ist eine Instanz der 
adxl345 Klasse und das dritte ist eine Instanz der mpu6050 Klasse.

D.h. dein main (bzw. dein QUadrocopter Objekt) enthält 3 Objekte
1
#include <avr/io.h>
2
#include <util/delay.h>
3
#include <avr/interrupt.h>
4
#include <string.h>
5
#include <itg3200.h>
6
#include <adxl345.h>
7
#include <mpu6050.h>
8
9
itg3200 theIth3200Object;
10
adxl345 theAdxl345Object;
11
mpu6050 theMpu6050Object;
12
13
int main(void)
14
{  
15
  init_quadcopter();
16
  main_quadcopter();
17
18
  while(1)
19
    ;  
20
21
  return 0;
22
}
23
24
/* 100Hz update intervall */
25
ISR(TIMER0_COMPA_vect) {
26
  theIth3200Object.Update();
27
  theAdxl345Object.Update();
28
  theMpu6050Object.Update();
29
}

Wahrscheinlich wäre es auch vernünftig eine 'Quadro' Klasse einzufügen, 
welches als zusammenführendes Element aller Bordsysteme fungiert, in dem 
der mechanische Aufbau deines Quadrocopters beschrieben ist und in dem 
dann die Sensor-übergreifende Logik des Zusammenführens aller Messwerte 
gemacht wird.
D.h. so ein Quadrocopter Objekt enthält alle Sensoren, die dann nicht 
mehr einfach so in der Gegend rumkugeln wie im Falle von globalen 
Objekten. Ich geb aber zu, dass das hier ein wenig überdeigned 
erscheinen mag, da man ja das komplette Programm als 'den Quadrocopter' 
auffassen kann.

Man könnte sich auch ein Sensor-Subsystem des Qudrocopters vorstellen, 
in welchem alle Sensoren verwaltet werden. Durchaus denkbar. Aber bitte 
nicht so, dass du die Logiken, die speziell für einen bestimmten Sensor 
notwendig sind, alle in der Sensor Klasse beheimatet sind. Auf lange 
Sicht ist es viel einfacher, jeden SensorTyp in eine eigene Klasse 
auszulagern und die Verwaltungsebene besitzt dann eben genau 1 (oder 
mehrere) Objekte dieses Typs. Das macht dann auch das ergänzen von 
anderen Sensoren bzw. das Austauschen eines Sensors gegen einen anderen 
(von der gleichen Kategrie: also ein andere Beschleunigungssensor) um 
vieles einfacher, wenn du all das für diesen IC notwendige Spezialwissen 
in einer Klasse sammelst.
Genau das ist ja die große Stärke in der objektorientieren 
Programmierung: das sie dir ermöglicht Funktionalität so stark zu 
kapseln, dass du die Details hinter der Klasse verstecken kannst ohne 
dass sich der Aufrufer um diese Details kümmern muss. Das 
Sensorssubsystem bzw. der Quadrocopter muss sich nicht darum kümmern, 
wie und mit welchen Befehlen man die MPU initialisiert. Das weiß die MPU 
Klasse schon selber.

von xvzf (Gast)


Lesenswert?

Hallo,

Habe eben das Problem durch Testen ermittelt:
Ich habe die I2C Frequenz auf 400 Khz erhöt, wenn ich den ITG3200 und 
den ADXL Update, dann muss ein _delay_us(5) zwischen beide Aufrufe, 
ansonsten scheint das I2C Segment des Atmega nicht mehr mitspielen zu 
wollen. (Es lebe der Buspirate!). Jetzt geht es!

Zu den Klassen:
Das habe ich bewusst so geregelt, ich wollte die Sensordaten 
zusammenfassen bzw. die Ergebnisse der Sensoren.
Natürlich - ich könnte für jeden Sensor eine Klasse schreiben, ich kann 
das ganze aber auch simpler mit defines regeln.
Das ganze ist so gelöst, dass es eine Klasse
IMU gibt, die die public Elemente der Klasse sensors erbt, somit kann 
ich direkt auf alle Sensordaten zugreifen und habe den Code von Sensor 
Abfragen und IMU getrennt.

Da ich wohl nicht mehr sehr lange bei den AVRs bleiben werde, sondern 
einen CORTEX M3 verwenden möchte, vereinfacht das das Portieren.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.