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