mcp2515.c


1
#include "config.h"
2
#include "mcp2515.h"
3
#include "spi.h"
4
5
mcp2515_rxb_t rxb0; //Adressen Buffer 0
6
mcp2515_rxb_t rxb1; //Adressen Buffer 1
7
8
/*******************************************************************************
9
*
10
* Name:  mcp2515_init
11
*
12
* Zweck: Initialisieren eines oder zweier MCP2515-CAN-Controller mit dem
13
*        ATMEGA48.
14
*
15
* Prototyp: void mcp2515_init(unsigned char mode, unsigned int iBitrate)
16
*
17
* Parameter:
18
*           unsigned char mode (E): 0 Beide Controller (1/2) werden
19
*                                     initialisiert
20
*
21
*                                   1 Controller 1 wird initialisiert
22
*
23
*           unsigned int iBitrate (E): Bitrate des Busses
24
*
25
* Funktionswert: -
26
*
27
* Hinweis: 
28
*         Implementierung nicht vollständig. Z.B. Bitrate muss noch per
29
*         Hand eingegeben werden
30
*
31
*******************************************************************************/
32
void mcp2515_init(unsigned char mode, unsigned int iBitrate)
33
{
34
   rxb0.idh = RXB0SIDH;
35
   rxb0.dlc = RXB0DLC;
36
   rxb0.d0  = RXB0D0;
37
38
   rxb1.idh = RXB1SIDH;
39
   rxb1.dlc = RXB1DLC;
40
   rxb1.d0  = RXB1D0;
41
42
   switch(mode)
43
   {
44
      case 0:
45
         //RESET
46
         mcp2515_reset(1);
47
48
         //Baudrate (100kbps) bei 16MHz
49
         mcp2515_write(1, CNF3,0x02);
50
         mcp2515_write(1, CNF2,0xA0);
51
         mcp2515_write(1, CNF1,0x03);
52
53
         //Interrups einstellen
54
         mcp2515_write(1, CANINTE, (1<<RX1IE)|(1<<RX0IE));
55
56
         //ID-Erkennung
57
         mcp2515_write(1, RXB0CTRL,0x20); //Nur Standard-IDs, RTR OFF, Rollover OFF, RXF0 ON
58
         mcp2515_write(1, RXF0SIDH,0xC6); //Filter High
59
         mcp2515_write(1, RXF0SIDL,0xA0); //Filter Low
60
         mcp2515_write(1, RXM0SIDH,0xFF); //FilterMask High
61
         mcp2515_write(1, RXM0SIDL,0xFF); //FilterMask Low
62
63
         //CAN-CTRL-Register (in NORMAL MODE versetzen)
64
         mcp2515_write(1, CANCTRL,0x08);
65
66
      case 1:
67
68
/////////////////////////////////////////////////////////////////////////////
69
// ES WIRD ERSTMAL NUR CONTROLLER 1 VERWENDET
70
/////////////////////////////////////////////////////////////////////////////
71
72
         //Hard-(PORT-Pin)-Reset NUR FÜR TESTZWECKE
73
         DDRC |= (1<<PC0);  
74
         PORTC &= ~(1<<PC0);
75
         _delay_ms(2);
76
         PORTC |= (1<<PC0);
77
78
         //Soft-Reset
79
         mcp2515_reset(0);
80
81
         //Baudrate (100kbps) bei 16 MHz
82
         mcp2515_write(0, CNF3,0x02);
83
         mcp2515_write(0, CNF2,0xA0);
84
         mcp2515_write(0, CNF1,0x07);
85
86
         //Interrups einstellen
87
         mcp2515_write(0, CANINTE, (1<<RX0IE)); //Nur Receive-Interrupt für Buffer 0
88
         
89
         //ID-Erkennung
90
         mcp2515_write(0, RXB0CTRL,0x20); //Nur Standard-IDs, RTR OFF, Rollover OFF, RXF0 ON
91
         mcp2515_write(0, RXF0SIDH,0xC6); //Filter High
92
         mcp2515_write(0, RXF0SIDL,0xA0); //Filter Low
93
         mcp2515_write(0, RXM0SIDH,0xFF); //FilterMask High
94
         mcp2515_write(0, RXM0SIDL,0xFF); //FilterMask Low
95
96
         break;
97
98
      default:
99
         break;
100
   }
101
}
102
103
104
/*******************************************************************************
105
*
106
* Name:  mcp2515_write
107
*
108
* Zweck: Schreibt Daten in ein MCP2515-Register.
109
*
110
* Prototyp: void mcp2515_write(unsigned char id, unsigned char cAdress,
111
*                              unsigned char cData)
112
*
113
* Parameter:
114
*           unsigned char id (E): MCP2515 wählen
115
*
116
*           unsigned char cAdress (E): MCP2515 Registeradresse
117
*
118
*           unsigned char cData (E): Zu sendende Daten
119
*
120
* Funktionswert: -
121
*
122
* Hinweis: -
123
*
124
*******************************************************************************/
125
void mcp2515_write(unsigned char id, unsigned char cAdress, unsigned char cData)
126
{
127
   //HELD SLAVESELECT LOW
128
   mcp2515_slave_select(id, 1);
129
130
   spi_write(id, SPI_WRITE);
131
   spi_write(id, cAdress);
132
   spi_write(id , cData);
133
   
134
   //HELD SLAVESELECT HIGH
135
   mcp2515_slave_select(id, 0);
136
   
137
}
138
139
140
/*******************************************************************************
141
*
142
* Name:  mcp2515_read
143
*
144
* Zweck: Liest Daten (n Bytes) aus einem MCP2515-Register.
145
*
146
* Prototyp: void mcp2515_read(unsigned char id, unsigned char cAdress,
147
*                             unsigned char *cData, unsigned char n)
148
*
149
* Parameter:
150
*           unsigned char id (E): MCP2515 wählen
151
*
152
*           unsigned char cAdress (E): MCP2515 Registeradresse
153
*
154
*           unsigned char *cData (A): Datenspeicher
155
*
156
*           unsigned char n (E) : Anzahl der zu lesenden Bytes
157
*
158
* Funktionswert: -
159
*
160
* Hinweis: Registeradresse wird bei jedem Lesevorgang inkrementiert.
161
*
162
*******************************************************************************/
163
void mcp2515_read(unsigned char id, unsigned char cAdress, unsigned char *cData, unsigned char n)
164
{
165
   //HELD SLAVESELECT LOW
166
   mcp2515_slave_select(id, 1);
167
168
   spi_write(id, SPI_READ);
169
   spi_write(id, cAdress);
170
   for (unsigned char i = 0; i < n; i++)
171
   {
172
      spi_read(id , &cData[i]);
173
   }
174
175
   //HELD SLAVESELECT HIGH
176
   mcp2515_slave_select(id, 0);
177
}
178
179
180
/*******************************************************************************
181
*
182
* Name:  mcp2515_read_rx
183
*
184
* Zweck: Liest Daten aus dem MCP2515-ReveiveBuffer-Register
185
*
186
* Prototyp: void mcp2515_read_rx(unsigned char id, unsigned char cAdress,
187
*                                unsigned char *cData)
188
*
189
* Parameter:
190
*           unsigned char id (E): MCP2515 wählen
191
*
192
*           unsigned char cAdress (E): MCP2515 Registeradresse Offset
193
*
194
*           unsigned char *cData (A): Datenspeicher
195
*
196
*
197
* Funktionswert: -
198
*
199
* Hinweis: Nach dem Slave-Deselect wird das Receive-Interrupt-Flag gelöscht
200
*
201
*******************************************************************************/
202
void mcp2515_read_rx(unsigned char id, unsigned char cAdress, unsigned char *cData)
203
{
204
   //HELD SLAVESELECT LOW
205
   mcp2515_slave_select(id, 1);
206
207
   spi_write(id, SPI_READ_RX + cAdress); //cAdress = {0,2,4,6}
208
   spi_read(id , cData);
209
210
   //HELD SLAVESELECT HIGH
211
   mcp2515_slave_select(id, 0); //Interruptsflag will be cleared
212
}
213
214
/*******************************************************************************
215
*
216
* Name:  mcp2515_bitmod
217
*
218
* Zweck: Verändert bstimmte nach einer Maske auswählbare Bits in einem Register.
219
*
220
* Prototyp: void mcp2515_bitmod(unsigned char id, unsigned char cAdress,
221
*                               unsigned char cMask, unsigned char cData)
222
*
223
* Parameter:
224
*           unsigned char id (E): MCP2515 wählen
225
*
226
*           unsigned char cAdress (E): MCP2515 Registeradresse
227
*
228
*           unsigned char cMask (E): Veränderungsmaske
229
*
230
*           unsigned char *cData (E): Bit(s) 1/0
231
*
232
*
233
* Funktionswert: -
234
*
235
* Hinweis: Nötig um bei Veränderung bestimmter Register kein Interrupt
236
*          auszulösen (siehe Dateblatt)
237
*
238
*******************************************************************************/
239
void mcp2515_bitmod(unsigned char id, unsigned char cAdress, unsigned char cMask, unsigned char cData)
240
{
241
   //HELD SLAVESELECT LOW
242
   mcp2515_slave_select(id, 1);
243
244
   spi_write(id, SPI_BIT_MODIFY);
245
   spi_write(id, cAdress);
246
   spi_write(id, cMask);
247
   spi_write(id, cData);
248
249
   //HELD SLAVESELECT HIGH
250
   mcp2515_slave_select(id, 0);
251
}
252
253
/*******************************************************************************
254
*
255
* Name:  mcp2515_status
256
*
257
* Zweck: Auslesen des Statusregisters
258
*
259
* Prototyp: void mcp2515_status(unsigned char id, unsigned char *cStatus)
260
*
261
* Parameter:
262
*           unsigned char id (E): MCP2515 wählen
263
*
264
*           unsigned char *cStatus (A): Statusbyte
265
*
266
*
267
* Funktionswert: -
268
*
269
* Hinweis: -
270
*
271
*******************************************************************************/
272
void mcp2515_status(unsigned char id, unsigned char *cStatus)
273
{
274
   //HELD SLAVESELECT LOW
275
   mcp2515_slave_select(id, 1);
276
277
   spi_write(id, SPI_READ_STATUS);
278
   spi_read(id, cStatus);
279
280
   //HELD SLAVESELECT HIGH
281
   mcp2515_slave_select(id, 0);
282
}
283
284
/*******************************************************************************
285
*
286
* Name:  mcp2515_rx_status
287
*
288
* Zweck: Auslesen des Status der Buffer-Register
289
*
290
* Prototyp: void mcp2515_rx_status(unsigned char id, unsigned char *cStatus)
291
*
292
* Parameter:
293
*           unsigned char id (E): MCP2515 wählen
294
*
295
*           unsigned char *cStatus (A): Statusbyte
296
*
297
*
298
* Funktionswert: -
299
*
300
* Hinweis: -
301
*
302
*******************************************************************************/
303
void mcp2515_rx_status(unsigned char id, unsigned char *cStatus)
304
{
305
   //HELD SLAVESELECT LOW
306
   mcp2515_slave_select(id, 1);
307
308
   spi_write(id, SPI_RX_STATUS);
309
   spi_read(id, cStatus);
310
311
   //HELD SLAVESELECT HIGH
312
   mcp2515_slave_select(id, 0);
313
}
314
315
/*******************************************************************************
316
*
317
* Name:  mcp2515_reset
318
*
319
* Zweck: Softreset des MCP2515
320
*
321
* Prototyp: void mcp2515_reset(unsigned char id)
322
*
323
* Parameter:
324
*           unsigned char id (E): MCP2515 wählen
325
*
326
*
327
* Funktionswert: -
328
*
329
* Hinweis: -
330
*
331
*******************************************************************************/
332
void mcp2515_reset(unsigned char id)
333
{
334
   //HELD SLAVESELECT LOW
335
   mcp2515_slave_select(id, 1);
336
337
   spi_write(id, SPI_RESET);
338
339
   //HELD SLAVESELECT HIGH
340
   mcp2515_slave_select(id, 0);
341
}
342
343
/*******************************************************************************
344
*
345
* Name:  mcp2515_rts
346
*
347
* Zweck: Den MCP2515 auffordern einen bestimmen Transmit-Buffer zu senden
348
*
349
* Prototyp: void mcp2515_rts(unsigned char id, unsigned char buffer)
350
*
351
* Parameter:
352
*           unsigned char id (E): MCP2515 wählen
353
*
354
*           unsigned char buffer (E): MCP2515 Buffer-Nr.
355
*
356
*
357
* Funktionswert: -
358
*
359
* Hinweis: -
360
*
361
*******************************************************************************/
362
void mcp2515_rts(unsigned char id, unsigned char buffer)
363
{
364
   //HELD SLAVESELECT LOW
365
   mcp2515_slave_select(id, 1);
366
367
   spi_write(id, SPI_RTS | buffer);
368
369
   //HELD SLAVESELECT HIGH
370
   mcp2515_slave_select(id, 0);
371
}
372
373
/*******************************************************************************
374
*
375
* Name:  mcp2515_slave_select
376
*
377
* Zweck: MCP2515 auswählen.
378
*
379
* Prototyp: void mcp2515_slave_select(unsigned char spi_id,
380
*                                     unsigned char slave_select)
381
*
382
* Parameter:
383
*           unsigned char spi_id (E): MCP2515 wählen
384
*
385
*           unsigned char slave_select (E): Select(1)/Deselect(0) Slave
386
*
387
*
388
* Funktionswert: -
389
*
390
* Hinweis: Von Port-Implementierung des ATMega48 abhängig
391
*
392
*******************************************************************************/
393
void mcp2515_slave_select(unsigned char spi_id, unsigned char slave_select)
394
{
395
   _delay_us(1);
396
   if (spi_id == 0)
397
   {
398
      if (slave_select)
399
      {
400
         PORTB &= ~(1<<PB2);
401
         _delay_us(1);
402
      }
403
      else
404
      {
405
         PORTB |= (1<<PB2);
406
      }
407
   }
408
   else if (spi_id == 1)
409
   {
410
      if (slave_select)
411
      {
412
         PORTD &= ~(1<<PD7);
413
      }
414
      else
415
      {
416
         PORTD |= (1<<PD7);
417
         _delay_us(1);
418
      }
419
   }
420
}
421
422
/*******************************************************************************
423
*
424
* Name:  can_tx
425
*
426
* Zweck: CAN-Nachrichten mit MCP2515 auf den Bus senden
427
*
428
* Prototyp: void can_tx(unsigned char id, can_msg_t *msg)
429
*
430
* Parameter:
431
*           unsigned char id (E): MCP2515 wählen
432
*
433
*           can_msg_t *msg (E): CAN-Nachricht
434
*
435
*
436
* Funktionswert: -
437
*
438
* Hinweis: -
439
*
440
*******************************************************************************/
441
void can_tx(unsigned char id, can_msg_t *msg)
442
{
443
   //Funktion benutz ausschließlich Puffer0 zum versenden einer Nachricht
444
445
   //Warten bis Puffer frei
446
   unsigned char status = 0;
447
   do
448
   {
449
      mcp2515_status(id, &status);
450
   }
451
   while ((status & TXB0CNTRL_TXREQ) == TXB0CNTRL_TXREQ);
452
453
   //Lade Daten in den Puffer
454
   //Lade ID (Byte 10-3) in Regster TXB0IDH
455
   mcp2515_write(id, TXB0SIDH, (msg->id >> 3));
456
   //Lade ID (Byte 2-0) in Regster TXB0IDL
457
   mcp2515_write(id, TXB0SIDL, (msg->id << 4));
458
   //Lade DLC
459
   mcp2515_write(id, TXB0DLC, msg->dlc);
460
   //Lade Daten
461
   switch(msg->dlc)
462
   {
463
      case 8:
464
         mcp2515_write(id, TXB0D7, msg->data[7]);
465
      case 7:
466
         mcp2515_write(id, TXB0D6, msg->data[6]);
467
      case 6:
468
         mcp2515_write(id, TXB0D5, msg->data[5]);
469
      case 5:
470
         mcp2515_write(id, TXB0D4, msg->data[4]);
471
      case 4:   
472
473
         mcp2515_write(id, TXB0D3, msg->data[3]);
474
      case 3:   
475
         mcp2515_write(id, TXB0D2, msg->data[2]);
476
      case 2:   
477
         mcp2515_write(id, TXB0D1, msg->data[1]);
478
      case 1:
479
         mcp2515_write(id, TXB0D0, msg->data[0]);
480
      default:
481
         break;
482
   }
483
   //Sende Daten (ohne warten auf Interrupt)
484
   mcp2515_rts(id, T0);
485
}
486
487
/*******************************************************************************
488
*
489
* Name:  can_rx
490
*
491
* Zweck: Empfangene CAN-Nachrichten lesen
492
*
493
* Prototyp: void can_rx(unsigned char id, unsigned char buffer , can_msg_t *msg)
494
*
495
* Parameter:
496
*           unsigned char id (E): MCP2515 wählen
497
*
498
*           unsigned char buffer (E): Receive-Buffer-Nr.
499
*
500
*           can_msg_t *msg (A): CAN-Nachricht
501
*
502
*
503
* Funktionswert: -
504
*
505
* Hinweis: -
506
*
507
*******************************************************************************/
508
void can_rx(unsigned char id, unsigned char buffer, can_msg_t *msg)
509
{
510
   unsigned char cBuffer[8] = {0,0,0,0,0,0,0,0};
511
512
   //Vorher ist bekannt welcher Puffer gelesen werden soll
513
   //Pufferadressen
514
   mcp2515_rxb_t *rxb = 0;
515
   switch(buffer)
516
   {
517
      case 0:
518
         rxb = &rxb0;
519
         break;
520
      case 1:
521
         rxb = &rxb1;
522
         break;
523
      default:
524
         break;
525
   }
526
527
   mcp2515_read(id, rxb->idh, &cBuffer[0], 1);
528
   mcp2515_read(id, RXB0SIDL, &cBuffer[1], 1);
529
   msg->id = cBuffer[0];
530
   msg->id = msg->id << 3 | cBuffer[1] >> 5; //ID zusammenfügen
531
   mcp2515_read(id, rxb->dlc, &msg->dlc, 1); //DLC lesen
532
   mcp2515_read(id, rxb->d0, &msg->data[0], msg->dlc); //Daten lesen
533
}