Hallo zusammen,
nach einigen Problemen mit der CAN_API von LPC würde ich euch gern paar
Fragen stellen, in der Hoffnung, für ein besseres Verständnis
meinerseits zu sorgen.
1) Man kann per "LPC_CCAN_API->config_rxmsgobj" konfigurieren, welche
IDs angenommen und in ein Buffer geschrieben werden. Mit Hilfe der Maske
lässt sich der ID-Bereich eingrenzen (z.B. nur ID mit 0x100 empfangen).
Ist es soweit richtig?
2) Falls eine Nachricht mit der anzunehmenden ID empfangen wird, wird
ein callback (CAN_RX) aufgerufen. Dieser hat, gemäß Datenblatt, die Form
void CAN_receive(uint8_t msg_obj_num). Was soll ich mir unter dieser
Objektnummer verstehen? Und vorallem ist sie doch gar nicht im CAN-Frame
vorhanden, oder?
3) Ähnliche Frage, bezogen auf die msg_obj_num, jedoch nun beim Senden,
also "LPC_CCAN_API->can_transmit". Ich würde gern ein Array per CAN
versenden, größer als der CAN-Ram im Mikrocontroller. Also übergebe ich
über Zeiger und eine Schleife taktweise 8 Bytes pro
"can_transmit"-Befehl. Diese Objekte haben alle dieselbe obj_num - das
Endgerät bekommt nur 16 Bytes. Ändere ich für jedes Paket die obj_num,
werden diese verschickt. Da ich aber nur eine uint8_z obj_num-Variable
habe, stehe ich vor dem Problem, wie ich das Array bei dieser Begrenzung
nun verschicke?
Beispielcode:
1
msg_obj.msgobj = 1;
2
msg_obj.mode_id = 0x100;
3
msg_obj.mask = 0x0;
4
msg_obj.dlc = 8;
5
6
for(i=0; i<64; i++){
7
for(j=0; j<8; j++){
8
msg_obj.data[j] = *eepromBuffer;
9
eepBuff++;
10
}
11
LPC_CCAN_API->can_transmit(&msg_obj);
12
}
Theoretisch schiebe ich immer 8Bytes durch den CAN-Bus. Praktisch aber
nicht :D
LPC-Anfänger schrieb:> 2) Falls eine Nachricht mit der anzunehmenden ID empfangen wird, wird> ein callback (CAN_RX) aufgerufen. Dieser hat, gemäß Datenblatt, die Form> void CAN_receive(uint8_t msg_obj_num). Was soll ich mir unter dieser> Objektnummer verstehen? Und vorallem ist sie doch gar nicht im CAN-Frame> vorhanden, oder?
Die msg_obj_num ist die Nummer des Message Objekts. Welch Überraschung.
Es gibt z.B. bei den LPC15xx 32 solcher message objects. In diesem
message object liegen alle Informationen zum CAN-Frame (ID, Länge usw.).
Das was du da vorhast geht gar nicht. Mit can_transmit(&msg_obj) wird
nur der Sendebuffer im CAN-Treiber gefüllt. Die Funktion wartet nicht
darauf dass die Message auch versendet wurde. Entweder man zieht sich
die komplette Beschreibung der CAN Register rein um nachzusehen ob die
Message versendet wurde oder muss den CAN_tx und CAN_error Handler so
implementieren, dass man die nächste Message erst sendet wenn die
aktuelle auch übertragen wurde.
@temp:
Ich setze ein Flag im void CAN_tx(uint8_t msg_obj_num) und überprüfe, ob
es gesetzt wird, bevor ich die nächste 8-Byte-Message in den Buffer
schreibe. Aber danke, dass du mich darauf hingewiesen hast, mir ist
nämlich aufgefallen, dass der Callback Handler die CAN_tx() gar nicht
ausführt??
Außerdem lese ich in der UM10398.pdf auf Seite 324 etwas von einer
Funktion namens void config_txmsgobj(CAN_MSG_OBJ * msg_obj)... Die ist
jedoch gar nicht im CAN-API vorhanden (vgl. S.322)?
Fragen über Fragen...
Mit anderen Worten: Sobald ich ein delay nach jeder 8-Byte-Message
setze, funktioniert die Übertragung 100%. Allerdings wird eben der
CAN_tx() über den Callback Handler nicht aufgerufen, sobald eine
Nachricht tatsächlich verschickt wurde.
//Testnachricht versenden, um das txFlag im CAN_tx zu setzen
40
// sonst deadlock
41
msg_obj.msgobj = 0;
42
msg_obj.mode_id = 0x345;
43
msg_obj.mask = 0x0;
44
msg_obj.dlc = 4;
45
msg_obj.data[0] = 'T'; // 0x54
46
msg_obj.data[1] = 'E'; // 0x45
47
msg_obj.data[2] = 'S'; // 0x53
48
msg_obj.data[3] = 'T'; // 0x54
49
LPC_CCAN_API->can_transmit(&msg_obj);
50
51
if(txFlag==2){
52
txFlag = 0;
53
for(i=0; i<8; i++){
54
55
msg_obj.msgobj = 5;
56
msg_obj.mode_id = 0x400;
57
msg_obj.mask = 0x0;
58
msg_obj.dlc = 8;
59
60
msg_obj.data[i] = eeprom[i+0xF0];
61
62
}
63
LPC_CCAN_API->can_transmit(&msg_obj);
64
}
65
66
67
while (1) {
68
__WFI(); /* Go to Sleep */
69
}
70
71
72
return 0;
73
}
Wenn ich die Bedingung if(rxFlag==2) im Code belasse, wird der
eeprom[i+0xF0]-Inhalt nicht per beim Teilnehmer ankommen. Setze ich die
Bedingung außer Kraft, muss ich ein delay zwischen den beiden
Nachrichten einfügen.
LPC-Anfänger schrieb:> Allerdings wird eben der> CAN_tx() über den Callback Handler nicht aufgerufen, sobald eine> Nachricht tatsächlich verschickt wurde.
Schon mal eine breakpoint auf die Funktion gesetzt?
LPC-Anfänger schrieb:> Genau, das txFlag ist als volatile uint8_t deklariert.
Aber nicht in deinem geposteten Code. Dein Fehler liegt im nicht
geposteten Code. Und ohne den vollständigen Code kann dir keiner helfen.
Ich habe jetzt einfach mal angenommen, dass ich einen Fehler mit der
CAN-API mache und nicht mit dem restlichen Teil...
Dann hierbei noch der Kopf mit den includes:
Ich habe jetzt schon gut 2 Jahre nix mehr mit den LPC11Cxx gemacht.
Irgendwas fehlt da.
Wo ist eigentlich deine CAN_IRQHandler()? Das kann doch so eigentlich
gar nicht lauffähig sein. Oder wegen WEAK in einer Endlosschleife oder
so landen.
LPC-Anfänger schrieb:> Wenn ich die Bedingung if(rxFlag==2) im Code belasse, wird der> eeprom[i+0xF0]-Inhalt nicht per beim Teilnehmer ankommen. Setze ich die> Bedingung außer Kraft, muss ich ein delay zwischen den beiden> Nachrichten einfügen.
Logisch. Wenn rxFlag wegen nicht ausgeführter isr nicht == 2 wird...
Naja, es fehlt in dem Sinne was, da der Rest in der Board-Bibliothek
ist. Die habe ich aber nicht angefasst, da sie 1:1 auf dem Datenblatt
basiert.
Dort ist auch der CCAN Interrupt Handler drin, der auf CAN_tx() leitet:
1
/**
2
* @brief CCAN Interrupt Handler
3
* @return Nothing
4
* @note The CCAN interrupt handler must be provided by the user application.
5
* It's function is to call the isr() API located in the ROM
6
*/
7
void CAN_IRQHandler(void) {
8
LPC_CCAN_API->isr();
9
}
Dort findet auch die Clockkonfiguration etc. statt, aber meine ersten
Programme haben damit gut funktioniert und ich konnte den Clock auch auf
einen Ausgangspin weiterleiten und auf einem Oszi anschauen - also
sollte das nicht das Problem sein.
Was mir aber auffällt, und das könnte dir, als Fortgeschrittenerem,
etwas sagen:
- Ich habe jetzt mal mit dem MCUXpresso das "Release Build" erstellt
- Dann Breakpoints gesetzt und Debug gestartet
- In dieser Reihenfolge spingt das Ding zum txFlag und setzt ihn auch
auf 2 und ich sehe auf dem CAN-Monitor den nächsten Wert. Sobald ich den
Debug-Mode verlasse und das Programm auf den LPC flashe, bleibt alles
beim Alten. (Außerdem habe ich komischerweise im Release Build keinen
automatischen Reset mehr, muss nach dem Flashvorgang die Platine manuell
resetten)...
[QUOTE]
Logisch. Wenn rxFlag wegen nicht ausgeführter isr nicht == 2 wird...
[/QUOTE]
Nein, was ich meine ist, wenn ich zwischen den Nachrichten eine
Zeitverzögerung aufbaue (und die if-Bedingung lösche), dann geht es auch
ohne den CAN_rx(). Also funktioniert der CAN-Bus und es wirklich "nur"
das Problem des Nicht-Wartens auf das Versenden der vorherigen
Message...
Gut, also aktueller Stand:
Das Programm funktioniert im DebugMode komplett. Sobald ich den Debugger
ausschalte und das ReleaseBuild flashe, wird die Schleife um i nicht
mehr bis inkl. 32 ausgeführt, sondern lediglich bis 11. Komischerweise
stand im debugMode auch beim i und j "Value optimized out".
Das hat mich gewundert und ich habe die Optimierung komplett
ausgeschaltet. Nun werden auch i, j dargestellt - allerdings nach wie
vor, die Schleife wird nur im debugMode komplett durchlaufen...
Edit: Die Schleife zählt nicht bis 11, sondern durch - allerdings werden
zwischendurch immer noch CAN-Messages übersprungen. Und das obwohl
eigentlich auf das Setzen des txFlags gewartet werden muss...