Forum: Mikrocontroller und Digitale Elektronik CAn Empfang beim LPC1768


von Tom (Gast)


Lesenswert?

Hallo alle zusammen,
ich würde gerne mit meinem LPC1768 Daten empfangen und auswerten auf dem 
CAN1, ich habe mich dazu durch das Datenblatt gearbeitet und mir das 
Beispielprogramm von NXP vorgenommen.
Leider ist mir schleierhaft was ich in meinem Hauptprogramm alles 
einstellen muss, ich hoffe hier das das jemand mal gemacht und dieser 
jemand kann mir helfen =)
Ich hab meine Schaltung an CANoe angeschlossen und sehe auch, dass die 
beiden miteinander kommunizieren sprich keine Errors, nun würde ich 
gerne eine Nachricht mit einem speziellen Identifier senden und diese 
dann auch empfangen, weiß nur nicht genau wie ich das machen soll.

Für hilfe bin ich sehr dankbar =)

Hier einmal der Code der can.c Datei auf welcher mein Programm basieren 
soll
1
/*****************************************************************************
2
 *  can.c:  CAN module API file for NXP LPC17xx Family Microprocessors
3
 *
4
 *   Copyright(C) 2009, NXP Semiconductor
5
 *   All rights reserved.
6
 *
7
 *   History
8
 *   2009.05.27  ver 1.00    Prelimnary version, first Release
9
 *   13.10.2010  ver 1.1     Änderung bezüglich CAN2
10
*****************************************************************************/
11
#include "lpc17xx.h"
12
#include "type.h"
13
#include "can.h"
14
15
/* Receive Queue: one queue for each CAN port */
16
extern CAN_MSG MsgBuf_RX1;
17
extern volatile uint32_t CAN1RxDone;
18
volatile uint32_t CANStatus;
19
uint32_t CAN1RxCount = 0;
20
uint32_t CAN1ErrCount = 0;
21
22
/******************************************************************************
23
** Function name:    CAN_ISR_Rx1
24
**
25
** Descriptions:    CAN Rx1 interrupt handler
26
**
27
** parameters:      None
28
** Returned value:    None
29
** 
30
******************************************************************************/
31
void CAN_ISR_Rx1( void )
32
{
33
  uint32_t * pDest;
34
35
  /* initialize destination pointer  */
36
  pDest = (uint32_t *)&MsgBuf_RX1;
37
  *pDest = LPC_CAN1->RFS;  /* Frame  */
38
39
  pDest++;
40
  *pDest = LPC_CAN1->RID; /* ID  */
41
  
42
43
  pDest++;
44
  *pDest = LPC_CAN1->RDA; /* Data A */
45
46
47
  pDest++;
48
  *pDest = LPC_CAN1->RDB; /* Data B  */
49
50
  
51
  CAN1RxDone = TRUE;
52
  LPC_CAN1->CMR = 0x04; /* release receive buffer */
53
  return;
54
}
55
56
/*****************************************************************************
57
** Function name:    CAN_Handler
58
**
59
** Descriptions:    CAN interrupt handler
60
**
61
** parameters:      None
62
** Returned value:    None
63
** 
64
*****************************************************************************/
65
void CAN_IRQHandler(void)  
66
{    
67
68
  CANStatus = LPC_CANCR->CANRxSR;
69
  if ( CANStatus & (1 << 8) )
70
  {
71
  CAN1RxCount++;
72
  CAN_ISR_Rx1();
73
  }
74
75
  if ( LPC_CAN1->GSR & (1 << 6 ) )
76
  {
77
  /* The error count includes both TX and RX */
78
  CAN1ErrCount = LPC_CAN1->GSR >> 16;
79
  }
80
  return;
81
}
82
83
/******************************************************************************
84
** Function name:    CAN_Init
85
**
86
** Descriptions:    Initialize CAN, install CAN interrupt handler
87
**
88
** parameters:      bitrate
89
** Returned value:    true or false, false if initialization failed.
90
** 
91
******************************************************************************/
92
uint32_t CAN_Init( uint32_t can_btr )
93
{
94
  CAN1RxDone = FALSE;
95
96
  LPC_SC->PCONP |= ((1<<13)|(1<<14));  /* Enable CAN1 and CAN2 clock */
97
98
  LPC_PINCON->PINSEL0 &= ~0x0000000F;  /* CAN1 is p0.0 and p0.1  */
99
  LPC_PINCON->PINSEL0 |= 0x00000005;  
100
101
  LPC_CAN1->MOD = 1;    /* Reset CAN */
102
  LPC_CAN1->IER = 0;    /* Disable Receive Interrupt */
103
  LPC_CAN1->GSR = 0;    /* Reset error counter when CANxMOD is in reset  */
104
105
  LPC_CAN1->BTR = can_btr;
106
  LPC_CAN1->MOD = 0x0;  /* CAN in normal operation mode */
107
108
  LPC_CAN1->IER = 0x01; /* Enable receive interrupts */
109
  return( TRUE );
110
}
111
112
/******************************************************************************
113
** Function name:    CAN_SetACCF_Lookup
114
**
115
** Descriptions:    Initialize CAN, install CAN interrupt handler
116
**
117
** parameters:      bitrate
118
** Returned value:    true or false, false if initialization failed.
119
** 
120
******************************************************************************/
121
void CAN_SetACCF_Lookup( void )
122
{
123
  uint32_t address = 0;
124
  uint32_t i;
125
  uint32_t ID_high, ID_low;
126
127
  /* Set explicit standard Frame */ 
128
  LPC_CANAF->SFF_sa = address;
129
  for ( i = 0; i < ACCF_IDEN_NUM; i += 2 )
130
  {
131
  ID_low = (i << 29) | (EXP_STD_ID << 16);
132
  ID_high = ((i+1) << 13) | (EXP_STD_ID << 0);
133
  *((volatile uint32_t *)(LPC_CANAF_RAM_BASE + address)) = ID_low | ID_high;
134
  address += 4; 
135
  }
136
    
137
  /* Set group standard Frame */
138
  LPC_CANAF->SFF_GRP_sa = address;
139
  for ( i = 0; i < ACCF_IDEN_NUM; i += 2 )
140
  {
141
  ID_low = (i << 29) | (GRP_STD_ID << 16);
142
  ID_high = ((i+1) << 13) | (GRP_STD_ID << 0);
143
  *((volatile uint32_t *)(LPC_CANAF_RAM_BASE + address)) = ID_low | ID_high;
144
  address += 4; 
145
  }
146
 
147
  /* Set explicit extended Frame */ 
148
  LPC_CANAF->EFF_sa = address;
149
  for ( i = 0; i < ACCF_IDEN_NUM; i++  )
150
  {
151
  ID_low = (i << 29) | (EXP_EXT_ID << 0);
152
  *((volatile uint32_t *)(LPC_CANAF_RAM_BASE + address)) = ID_low;
153
  address += 4; 
154
  }
155
156
  /* Set group extended Frame */
157
  LPC_CANAF->EFF_GRP_sa = address;
158
  for ( i = 0; i < ACCF_IDEN_NUM; i++  )
159
  {
160
  ID_low = (i << 29) | (GRP_EXT_ID << 0);
161
  *((volatile uint32_t *)(LPC_CANAF_RAM_BASE + address)) = ID_low;
162
  address += 4; 
163
  }
164
   
165
  /* Set End of Table */
166
  LPC_CANAF->ENDofTable = address;
167
  return;
168
}
169
170
/******************************************************************************
171
** Function name:    CAN_SetACCF
172
**
173
** Descriptions:    Set acceptance filter and SRAM associated with  
174
**
175
** parameters:      ACMF mode
176
** Returned value:    None
177
**
178
** 
179
******************************************************************************/
180
void CAN_SetACCF( uint32_t ACCFMode )
181
{
182
  switch ( ACCFMode )
183
  {
184
  case ACCF_OFF:
185
    LPC_CANAF->AFMR = ACCFMode;
186
    LPC_CAN1->MOD = LPC_CAN2->MOD = 1;  // Reset CAN
187
    LPC_CAN1->IER = LPC_CAN2->IER = 0;  // Disable Receive Interrupt
188
    LPC_CAN1->GSR = LPC_CAN2->GSR = 0;  // Reset error counter when CANxMOD is in reset
189
  break;
190
191
  case ACCF_BYPASS:
192
    LPC_CANAF->AFMR = ACCFMode;
193
  break;
194
195
  case ACCF_ON:
196
  case ACCF_FULLCAN:
197
    LPC_CANAF->AFMR = ACCF_OFF;
198
    CAN_SetACCF_Lookup();
199
    LPC_CANAF->AFMR = ACCFMode;
200
  break;
201
202
  default:
203
  break;
204
  }
205
  return;
206
}
207
208
/******************************************************************************
209
** Function name:    CAN1_SendMessage
210
**
211
** Descriptions:    Send message block to CAN1  
212
**
213
** parameters:      pointer to the CAN message
214
** Returned value:    true or false, if message buffer is available,
215
**            message can be sent successfully, return TRUE,
216
**            otherwise, return FALSE.
217
** 
218
******************************************************************************/
219
uint32_t CAN1_SendMessage( CAN_MSG *pTxBuf )
220
{
221
  uint32_t CANStatus;
222
223
  CANStatus = LPC_CAN1->SR;
224
  if ( CANStatus & 0x00000004 )
225
  {
226
  LPC_CAN1->TFI1 = pTxBuf->Frame & 0xC00F0000;
227
  LPC_CAN1->TID1 = pTxBuf->MsgID;
228
  LPC_CAN1->TDA1 = pTxBuf->DataA;
229
  LPC_CAN1->TDB1 = pTxBuf->DataB;
230
  LPC_CAN1->CMR = 0x21;
231
  return ( TRUE );
232
  }
233
  else if ( CANStatus & 0x00000400 )
234
  {
235
  LPC_CAN1->TFI2 = pTxBuf->Frame & 0xC00F0000;
236
  LPC_CAN1->TID2 = pTxBuf->MsgID;
237
  LPC_CAN1->TDA2 = pTxBuf->DataA;
238
  LPC_CAN1->TDB2 = pTxBuf->DataB;
239
  LPC_CAN1->CMR = 0x41;
240
  return ( TRUE );
241
  }
242
  else if ( CANStatus & 0x00040000 )
243
  {  
244
  LPC_CAN1->TFI3 = pTxBuf->Frame & 0xC00F0000;
245
  LPC_CAN1->TID3 = pTxBuf->MsgID;
246
  LPC_CAN1->TDA3 = pTxBuf->DataA;
247
  LPC_CAN1->TDB3 = pTxBuf->DataB;
248
  LPC_CAN1->CMR = 0x81;
249
  return ( TRUE );
250
  }
251
  return ( FALSE );
252
}
253
254
/******************************************************************************
255
**                            End Of File
256
******************************************************************************/
257
258
259
und hier mein main Programm wobei ich weiß das dieses mit Sicherheit so nicht korrekt ist aber deshalb brauch ich ja eure Hilfe =)
260
261
[c]
262
263
/******************************Header Dateien einbinden***********************************/
264
#include "lpc17xx.h"
265
#include "type.h"
266
#include "can.h"
267
268
CAN_MSG MsgBuf_TX1, MsgBuf_TX2; /* TX and RX Buffers for CAN message */
269
CAN_MSG MsgBuf_RX1, MsgBuf_RX2; /* TX and RX Buffers for CAN message */
270
271
volatile uint32_t CAN1RxDone = FALSE, CAN2RxDone = FALSE;
272
273
274
/*****************************************************************************
275
** Function name:    main
276
**
277
** Descriptions:    main routine for CAN module test
278
**
279
** parameters:      None
280
** Returned value:    int
281
** 
282
*****************************************************************************/
283
int main( void )
284
{
285
286
  SystemInit();
287
  INOUT_Def();
288
 
289
  /* Please note, the bit timing is based on the setting of the 
290
  PCLK, if different PCLK is used, please read can.h carefully 
291
  and set your CAN bit timing accordingly. */  
292
  //CAN_Init( BITRATE100K24MHZ );
293
  CAN_Init(BITRATE500K15MHZ);  
294
  NVIC_EnableIRQ(CAN_IRQn);
295
  CAN_SetACCF(ACCF_BYPASS);
296
  CAN_SetACCF_Lookup();
297
  while(1)
298
  {
299
300
    if(!(LPC_CAN1->RID & 0x23))
301
    {
302
      LPC_GPIO2->FIOPIN &= ~(0x000000FF);
303
    }
304
    
305
  }
306
307
}
[/c]

von Lutz (Gast)


Lesenswert?

Mit einem Cortex M3, und dazu auch noch CAN, hast Du Dir natürlich für 
den Anfang auch gleich einen richtigen Hammer zum Üben ausgesucht.
Mit FIOPIN kannst Du einen Port lesen, aber nicht schreiben.
Und das if da drüber tut wahrscheinlich auch nicht das, was Du denkst. 
Schreibe den Inhalt des Tests einfach mal binär auf einen Zettel und 
schau, ob es das ist, was Du meinst.

Was ist denn CANoe, SystemInit() und INOUT_Def()? In der Lib finde ich 
die auf die Schnelle nicht.

Und wenn Du da schon irgendwie eine errorfreie Kommunkation mit 
hinbekommen hast, brauchst Du doch eigentlich nur im Datenblatt und der 
Lib nachschauen, wo die Filter definiert werden und diesen Teil an Deine 
Bedürfnisse anpassen.

Wie gesagt: CM3 und dazu CAN ist schon ein Hammer; ich lese mich da 
selbst gerade erst ein. Da ist soviel zu bedenken; Takte, 
Initialisierungen etc. Mit der Lib habe ich mich allerdings noch gar 
nicht beschäftigt. Vielleicht nimmt die einem ja allerhand ab, kann 
sein.

von Erwin R. (er-tronik)


Lesenswert?

Ich finde es traurig, wenn Leute hier antworten, die selber nicht genau 
über das Thema Bescheid wissen. Mit FIOPIN kann sehr wohl gelesen wie 
auch geschrieben werden. Aber das wird in der Regel bei diesen 
Controllern nicht gemacht, sondern es werden die Befehle FIOSET und 
FIOCLR zum geziehlten Setzen und Löschen von IO-Pins genutzt.

Da ich mich gerade in den letzten Wochen die CAN-Communikation mit dem 
LPC1766 beschäftigt hatte, kann ich nur sagen, so schlimm ist das Ganze 
gar nicht. Der große Unterschied gegenüber vielen anderen 
CAN-Controllern ist hier der Harware-Filter, den man aber für die ersten 
Experimente gar nicht braucht. Aber wichtig, unbedingt den Filter auf 
ACCF_BYPASS setzen, sonst empfängt das Teil nämlich gar nichts.

Das Senden eines CAN-Paketes ist doch ganz einfach, du brauchst nur eine 
Struktur, die du mit allen wichtigen Daten füllst und dann einfach 
absendest:
1
CAN_MSG TxBuf;
2
int rc;
3
4
TxBuf.Frame = (8 << 16)   ; 8 Bytes,  | (1 << 31) bei 29 Bit ID
5
TxBuf.MsgId = 0x789       ; oder 29 Bit ID
6
TxBuf.DataA = 0x01234567
7
TxBuf.DataB = 0x89ABCDEF
8
9
rc = CAN1_SendMessage(&TxBuf);

Das wars. Alles andere sollte so klappen, wie in deinem Listing.
Wichtig ist natürlich noch, daß die Bitratenwerte mit der Taktfrequenz 
deines Controllers übereinstimmen.


Erwin

von Tom (Gast)


Lesenswert?

Vielen dank für die netten antworten =)
Das mit FIOSET und FIOCLR werd ich mir zu Herzen nehmen danke, hatte das 
bisher mit FIOPIN gemacht aber wenn es anders üblicher ist werd ich das 
umändern =)

Ich habe gestern noch ein bisschen rumprobiert und habe mir die 
LookupTable angesehen. Ich kann in CANoe sehen, dass ich bereits daten 
senden kann nur geht es mir ja noch um das Empfangen.

ich poste jetzt zur besseren strukturierung nocheinmal den Code der 
LookupTable aus der can.c
1
void CAN_SetACCF_Lookup( void )
2
{
3
  uint32_t address = 0;
4
  uint32_t i;
5
  uint32_t ID_high, ID_low;
6
7
  /* Set explicit standard Frame */ 
8
  LPC_CANAF->SFF_sa = address;
9
  for ( i = 0; i < ACCF_IDEN_NUM; i += 2 )
10
  {
11
  ID_low = (i << 29) | (EXP_STD_ID << 16);
12
  ID_high = ((i+1) << 13) | (EXP_STD_ID << 0);
13
  *((volatile uint32_t *)(LPC_CANAF_RAM_BASE + address)) = ID_low | ID_high;
14
  address += 4; 
15
  }
16
    
17
  /* Set group standard Frame */
18
  LPC_CANAF->SFF_GRP_sa = address;
19
  for ( i = 0; i < ACCF_IDEN_NUM; i += 2 )
20
  {
21
  ID_low = (i << 29) | (GRP_STD_ID << 16);
22
  ID_high = ((i+1) << 13) | (GRP_STD_ID << 0);
23
  *((volatile uint32_t *)(LPC_CANAF_RAM_BASE + address)) = ID_low | ID_high;
24
  address += 4; 
25
  }
26
 
27
  /* Set explicit extended Frame */ 
28
  LPC_CANAF->EFF_sa = address;
29
  for ( i = 0; i < ACCF_IDEN_NUM; i++  )
30
  {
31
  ID_low = (i << 29) | (EXP_EXT_ID << 0);
32
  *((volatile uint32_t *)(LPC_CANAF_RAM_BASE + address)) = ID_low;
33
  address += 4; 
34
  }
35
36
  /* Set group extended Frame */
37
  LPC_CANAF->EFF_GRP_sa = address;
38
  for ( i = 0; i < ACCF_IDEN_NUM; i++  )
39
  {
40
  ID_low = (i << 29) | (GRP_EXT_ID << 0);
41
  *((volatile uint32_t *)(LPC_CANAF_RAM_BASE + address)) = ID_low;
42
  address += 4; 
43
  }
44
   
45
  /* Set End of Table */
46
  LPC_CANAF->ENDofTable = address;
47
  return;
48
}

und zwar ist mein Problem das i addiert wird im laufe der Beschreibung. 
Die Table dient ja dazu bestimmte Identifier für den Controller bekannt 
zu machen so dass er diese durchlässt.
Ich habe nun mit dem explicit standard Frame getestet und hier ist es 
so, dass die Bits der verschiedenen Identifier so geschoben werden, dass 
es eine 32-Bit struktur gibt mit dem SCC (kennzeichnet den Controller). 
Laut dem Code kennzeichnet das i also den Cotnroller dies ist beim 
Eintritt 2 durch das verschieben kennzeichnet  es dann CAN2 jedoch für 
den lower Teil der Bitfolge wird i erhöht und spricht meiner meinung 
nach nun einen anderen Controller an oder?
Wenn ich nun eine Nachricht sende, so kommt diese auch durch jedoch nur 
mit dem upper Identifier, woran liegt das?

Vielen dank ich hoffe ihr habt das so alles verstanden wenn nicht dann 
erklär ich es einfach nochmal anders =)

von Erwin R. (er-tronik)


Lesenswert?

Das mit den Filtern ist schon so eine Sache, da bin ich auch noch nicht 
komplett durch. Für meinen Anwendungszweck funktioniert das jedenfalls 
schon wie im Folgenden beschrieben.
Für meinen Anwendungszweck muß ich die OBD-Adressen für CAN-11bit und 
CAN-29bit ausfiltern. Bereiche, die nicht gebraucht werden, müssen 
einfach mit dem aktuellen Wert von adr initialisiert werden.

1
static void CAN_SetFilter(void)
2
{
3
  u32 adr = 0;
4
5
  CANAF->AFMR = ACCF_OFF;              // Acceptance Filter OFF
6
  
7
  CANAF->SFF_sa = adr;
8
  CANAF->SFF_GRP_sa = adr; 
9
    // === Diesen Bereich auslassen, wenn keine 11-Bit Filter gebraucht werden
10
    *((vu32 *)(CANAF_RAM_BASE + adr)) = ((u16)Id11_lo << 16) | (u16)Id11_hi;
11
    adr += 4;
12
    //=============================================================
13
  CANAF->EFF_sa = adr;
14
  CANAF->EFF_GRP_sa = adr;
15
    // === Diesen Bereich auslassen, wenn keine 29-Bit Filter gebraucht werden
16
    *((vu32 *)(CANAF_RAM_BASE + adr)) = Id29_lo;
17
    adr += 4;
18
    *((vu32 *)(CANAF_RAM_BASE + adr)) = Id29_hi;
19
    adr += 4;
20
    //=============================================================
21
  CANAF->ENDofTable = adr;
22
  
23
  CANAF->AFMR = ACCF_ON;               // Acceptance Filter ON
24
}
25
26
27
void CAN_Init(void) 
28
{
29
  //....
30
  Id11_lo = 0x7E0;
31
  Id11_hi = 0x7EF;
32
  Id29_lo = 0x18DAF100; 
33
  Id29_hi = 0x18DAF1FF;
34
  CAN_SetFilter();
35
  //....
36
}

von Tom (Gast)


Lesenswert?

alles klar jetzt funktioniert es bei mir auch die for schleife vor dem 
ganzen ist absolut unnötig gewesen und jetzt kann ich auch mehrere 
Identifier zulassen.
Vielen dank für die super Hilfe =)

von Lutz (Gast)


Lesenswert?

Tom schrieb:
> Vielen dank für die super Hilfe =)

Kein Problem, hab' ich doch gerne gemacht.

Duck und weg ...

von Hoschi (Gast)


Lesenswert?

Erwin Reuss schrieb:
> Ich finde es traurig, wenn Leute hier antworten, die selber nicht _genau_
> über das Thema Bescheid wissen.

Erwin Reuss schrieb:
> Das mit den Filtern ist schon so eine Sache, da bin ich auch noch nicht
> komplett durch.

Ach so ...

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.