PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : RP6: Probleme mit I2C und move



-schumi-
16.06.2012, 16:01
Hallo zusammen,

ich baue gerade eine Bibliothek für den Raspberry Pi, die ähnliche Funktionen wie die für das M32 bietet, um den RP6 steuern zu können.

Für die Base habe ich das I2C-Slave-Beispielprogramm genommen. Wenn ich jetzt mit dem Raspi über I2C z.B. den Befehl für MoveAtSpeed(30, 30) schicke, dann macht der Robby das auch ganz brav.

Die Move() und Rotate() Funktionen gehen dagegen nicht. Die Ketten fahren nur ganz kurz an bleiben dann wieder stehen.

Das hier ist meine move-Funktion:


void rp6rpi_move (char desired_speed, char dir, unsigned int distance)
{
char buffer[] = {0, CMD_MOVE, desired_speed, dir, (distance>>8)&0xFF, distance&0xFF};
rp6rpi_write(buffer);
}

Dazu gehört noch:

//Direction:
#define FWD 0
#define BWD 1
#define LEFT 2
#define RIGHT 3

Und aufrufen tu ich die hiermit:

int main()
{
rp6rpi_openConnection();
rp6rpi_move(60, FWD, 300);
rp6rpi_closeConnection();
return 0;
};

Warum funzt das nicht? Fehlt Irgend ein Watchdog zeuch oder sowas? Power On? Interrupt?

Viele Grüße
-schumi-

Dirk
16.06.2012, 16:28
Es kann daran liegen, dass die Bewegung noch andauert, während deine main mit deinem Gsamtprogramm schon abbricht.
Mach mal eine Endlosschleife vor return.
Du must auch auf den INT0 reagieren: Siehe task_checkINT0();

-schumi-
16.06.2012, 17:24
Also die Endlosschleife alleine reicht noch nicht..

Das mit dem tast_checkINT0() hab ich so verstanden:

Jedes mal wenn die Base die INT0-Leitung auf high setzt, möchte die dass der Master die ersten 3 Register (I2C_REG_STATUS1, I2C_REG_STATUS2, I2C_REG_MOTION_STATUS) ausliest?

Ist das richtig?

Und ist die INT0-Leitung mit Open-Collector-Ausgängen mit Pullups realisiert? (Damit jeder einen Interrupt auslösen kann. Währe wichtig zu wissen für den Pegelwandler)

Viele Grüße
-schumi-

Dirk
16.06.2012, 18:56
Nein, das ist ein normaler Portpin mit einem 10 kOhm PULLDOWN.

-schumi-
16.06.2012, 19:08
Und wenn jetzt die M32 einen Interrupt auslösen möchte? Gibts nen Datencrash und die Base bekommts nicht mit?!

Oder wird der Pin entweder auf Eingang (mit Pulldown = low) oder Ausgang high und niemals Ausgang low geschalten?

Dirk
16.06.2012, 20:37
Hardware:
Am XBUS (Pin 8 ) werden im ganzen RP6-System je ein Portpin der Platinen zusammen geführt:
Base -> PA4
M32 -> PD2
M128 -> PE5

D.h.: Natürlich kann es da zu Konflikten kommen.

Software:
Ein System (Base, M32 oder M128 ) kann nur als Ausgang den IRQ auslösen, die anderen Systeme müssen den Portpin auf Eingang schalten. Das System, was einen IRQ auslöst, ist ein I2C-Slave, denn der will ja dem Master sagen, dass Daten anliegen. Dazu zieht er den XBUS Pin 8 auf Highpegel. Im RP6Base-Slave-Programm passiert das in der Funktion signalInterrupt() und darin mit dem Makro extIntON. Umgekehrt wird der Interrupt gelöscht mit clearInterrupt() bzw. dem Makro extIntOFF.
Die Makros schalten einfach PA4.

Die M32 (oder deine Platine) als Master bekommt das Signal über einen Eingangspin und muss dann darauf reagieren (z.B. über den I2C-Bus Daten übernehmen...).

-schumi-
16.06.2012, 20:54
Der Hinweis wo ich das finde ist schon mal super - vielen herzlichen Dank dafür :)



/************************************************** ***************************/
// External Interrupt Output
// Can be used to notify Master Controllers
// about events when operating in Slave Mode.

/**
* Set external interrupt to high level
*/
void extIntON(void)
{
DDRA |= E_INT1;
PORTA |= E_INT1;
}

/**
* Set external interrupt to low level
*/
void extIntOFF(void)
{
PORTA &= ~E_INT1;
DDRA &= ~E_INT1;
}

D.h.
ON = Ausgang + high
OFF = Eingang + Kein Pullup
-> Kein Konflikt möglich

Wobei ich mich schon frage, ob es bein ON nicht besser währe erst auf High zu schalten und dann auf Ausgang und bei OFF erst auf Eingang und dann PullupAus. Sonst kann ja für einen sehr kurzen Augenblick doch eine "hartes" low an der Interrupt-Leitung geben.


So, jetzt muss ich erst mal überlegen wie ich das mit der Pegelwandlung mache... Vielleicht kann man das I2C-Prinzip ja umstülpen.

Viele Grüße
-schumi-

Dirk
16.06.2012, 21:14
So, jetzt muss ich erst mal überlegen wie ich das mit der Pegelwandlung mache...
Haben die GPIOs des Raspberry denn andere Pegel als +5V/Gnd?
Oder warum braucht es eine Pegelanpassung?

-schumi-
16.06.2012, 21:54
Jep, die haben 3V3, aber ich glaub ich machs so:




D1
3V3 ------+-----|>|------+------ 5V
| |
| | | R1
| | | 6k6 oder größer
| |
+--------------+
|
| | R2
| | 10k
|
--- GND




Hoffentlich erkennen die AVRs die 3.3V mit der Diode dazwischen auch noch als High. Naja, wird schon klappen. Hab noch irgendwo so Germaniumteile (uf=0V3) rumfliegen

-schumi-
26.06.2012, 16:22
Also so irgendwie wills immer noch nicht funktionieren...


Ich kann mit dem Raspberry Pi den Status von INT1 abfragen (mit Spannungsteiler von 5V auf 3V3)
Wenn ich z.B. einen Bumper drücke und somit INT1 auslöse kann ich INT1 auch folgendermaßen wieder löschen:



int main()
{
rp6rpi_init();
rp6rpi_openConnection();
rp6rpi_task_RP6RPISystem(); // Read all Registers
rp6rpi_closeConnection();
return 0;
}


Wenn ich den Rp6_Move-Befehl mit dem im ersten Beitrag gezeigten Code ausführe wird wie zu erwarten INT1 ausgelöst und der Move-Vorgang abgebrochen.



Jetzt hab ich den Code so umgeändert, dass immer wenn INT1 ausgelöst wird, die Register gelesen werden:


int main()
{
rp6rpi_init();
rp6rpi_openConnection();
rp6rpi_move(60, FWD, 300);
while(1)
{
if(rp6rpi_return_INT1())
rp6rpi_task_RP6RPISystem(); // Read Registers
}
rp6rpi_closeConnection();
return 0;
}

Wenn ich an INT1 messe bekomme ich 0V, d.h. der Interrupt wird auch zurückgesetzt.

Trotzdem bewegt sich der RP6 nur ein ganz kleines Stück vorwärts. WARUM? Was fehlt?


Viele Grüße
-schumi-