Forum: Mikrocontroller und Digitale Elektronik [LPC] Fragen zum CAN-Bus und der CAN_API


von LPC-Anfänger (Gast)


Lesenswert?

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

von LPC-Anfänger (Gast)


Lesenswert?

Edit: Die Zeigerinkrementierung muss natürlich

[CODE
eepromBuffer++;
[/CODE]

heißen.

von Lutz (Gast)


Lesenswert?

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.).

von temp (Gast)


Lesenswert?

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.
1
// Callback function prototypes 
2
void CAN_rx(uint8_t msg_obj_num);
3
void CAN_tx(uint8_t msg_obj_num);
4
void CAN_error(uint32_t error_info);
5
6
// Publish CAN Callback Functions 
7
CAN_CALLBACKS callbacks = {
8
   CAN_rx,
9
   CAN_tx,
10
   CAN_error,
11
   NULL,
12
   NULL,
13
   NULL,
14
   NULL,
15
   NULL,
16
};

von LPC-Anfänger (Gast)


Lesenswert?

@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...

von LPC-Anfänger (Gast)


Lesenswert?

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.

von temp (Gast)


Lesenswert?

Am besten du zeigst uns mal deinen Code, dann können wir eventuell 
helfen. Mein Kaffeesatzt ist zu schimmlig um da was drin lesen zu 
können...

von LPC-Anfänger (Gast)


Lesenswert?

Naja, das habe ich im Grunde schon, aber jetzt nochmal der gesamte 
Testcode:
1
/*  CAN transmit callback */
2
void CAN_tx(uint8_t msg_obj_num) {
3
4
  // Flag setzen, die nächste Nachricht kann in den Buffer
5
  txFlag = 2;
6
7
}
8
9
int main(void)
10
{
11
  uint8_t i, j;
12
13
14
  uint32_t CanApiClkInitTable[2];
15
  /* Publish CAN Callback Functions */
16
  CCAN_CALLBACKS_T callbacks = {
17
    CAN_rx,
18
    CAN_tx,
19
    CAN_error,
20
    NULL,
21
    NULL,
22
    NULL,
23
    NULL,
24
    NULL,
25
  };
26
27
  SystemCoreClockUpdate();
28
  Board_Init();
29
  baudrateCalculate(TEST_CCAN_BAUD_RATE, CanApiClkInitTable);
30
31
  LPC_CCAN_API->init_can(&CanApiClkInitTable[0], TRUE);
32
  /* Configure the CAN callback functions */
33
  LPC_CCAN_API->config_calb(&callbacks);
34
  /* Enable the CAN Interrupt */
35
  NVIC_EnableIRQ(CAN_IRQn);
36
37
38
39
  //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.

von LPC-Anfänger (Gast)


Angehängte Dateien:

Lesenswert?

An die RAM-Reservierung für die CAN-API ist ebenfalls, und hoffentlich 
richtig, gedacht.

Die Baudrate ist mit
1
#define TEST_CCAN_BAUD_RATE 500000

definiert, aber auch schon mit 100000 probiert gehabt, ohne Erfolg.

von Lutz (Gast)


Lesenswert?

Wo ist denn da txFlag definiert (als volatile)???

von Lutz (Gast)


Lesenswert?

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?

von LPC-Anfänger (Gast)


Lesenswert?

Genau, das txFlag ist als volatile uint8_t deklariert.

Breakpoint half nicht sonderlich,, weil Routine gar nicht aufgerufen 
wurde...

von Lutz (Gast)


Lesenswert?

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.

von LPC-Anfänger (Gast)


Lesenswert?

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:
1
#include <stdlib.h>
2
#include <string.h>
3
#include "board.h"
4
5
/*****************************************************************************
6
 * Private types/enumerations/variables
7
 ****************************************************************************/
8
9
#define TEST_CCAN_BAUD_RATE 500000
10
#define I2C_EEPROM_SIZE    0xFF
11
12
CCAN_MSG_OBJ_T msg_obj;
13
CCAN_MSG_OBJ_T msg_test_obj;
14
15
16
volatile uint8_t txFlag = 0;
17
18
static uint8_t eeprom[I2C_EEPROM_SIZE+1];

von Lutz (Gast)


Lesenswert?

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...

von LPC-Anfänger (Gast)


Lesenswert?

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)...

von LPC-Anfänger (Gast)


Lesenswert?

[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...

von LPC-Anfänger (Gast)


Lesenswert?

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...
1
  for(i=0; i<32; i++)
2
  {  while(txFlag!=2){}
3
    if(txFlag==2)
4
    {  for(j=0; j<8; j++)
5
      {
6
        msg_obj.msgobj = 5;
7
        msg_obj.mode_id = 0x346;
8
        msg_obj.dlc = 8;
9
10
        msg_obj.data[j] = dumpEEPROM[j+8*i];
11
      }
12
      LPC_CCAN_API->can_transmit(&msg_obj);
13
      txFlag = 0;
14
    }
15
  }

von LPC-Anfänger (Gast)


Lesenswert?

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...

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.