Hallo,
ich bastle gerade an einer Kommunikation zwischen eine Raspberry Pi und
einem ATmega328 (selbst gebasteltes MCP2515) via can und habe hierfür
die CAN-Lib vom kreativen Chaos zurate gezogen.
Nun kann ich damit sogar senden, aber nichts empfangen. Zuerst dachte
ich, es wäre die Hardware aber jetzt hab ich mal einen Arduino Uno mit
einem CAN-Breakout Board verdrahtet und bekomme genau den gleichen
Effekt: Senden funktioniert, empfangen nicht.
Hier mal mein Testcode
// You can receive 11 bit identifiers with either group 0 or 1.
23
24
void serial_init() {
25
UBRR0 = 103;
26
UCSR0B |= (1 << RXEN0) | (1 << TXEN0);
27
UCSR0C |= (1 << UCSZ00) | (1 << UCSZ01);
28
}
29
30
void serial_send_char(char c) {
31
/* Wait for empty transmit buffer */
32
while (!(UCSR0A & (1 << UDRE0)))
33
;
34
/* Put data into buffer, sends the data */
35
UDR0 = c;
36
}
37
38
void serial_send_byte(char b) {
39
serial_send_char(table[b >> 4]);
40
serial_send_char(table[b & 0x0f]);
41
}
42
43
void serial_print(can_t * msg) {
44
char val = msg->id >> 8;
45
serial_send_byte(val);
46
val = msg->id & 0xff;
47
serial_send_byte(val);
48
49
serial_send_byte('#');
50
for (char i = 0; i < msg->length; i++) {
51
serial_send_byte(msg->data[i]);
52
}
53
serial_send_byte('\r');
54
serial_send_byte('\n');
55
}
56
57
int main(int argc, char **argv) {
58
serial_init();
59
60
// if(! can_init(BITRATE_125_KBPS)) {
61
if(! can_init(BITRATE_250_KBPS)) { /* doppelte Baudrate weil der MCP im Breakout nur halbe Taktrate hat */
62
serial_send_char('e');
63
serial_send_char('r');
64
serial_send_char('r');
65
serial_send_char('o');
66
serial_send_char('r');
67
serial_send_char('\r');
68
serial_send_char('\n');
69
}
70
can_static_filter(can_filter);
71
72
73
can_t msg;
74
75
msg.id = 0x064;
76
msg.flags.rtr = 0;
77
78
msg.length = 8;
79
msg.data[0] = 0X00;
80
msg.data[1] = 0x33;
81
msg.data[2] = 0x44;
82
msg.data[3] = 0x88;
83
msg.data[4] = 0xaa;
84
msg.data[5] = 0xbb;
85
msg.data[6] = 0xcc;
86
msg.data[7] = 0xf0;
87
88
can_send_message(&msg);
89
90
serial_send_char('d');
91
serial_send_char('o');
92
serial_send_char('n');
93
serial_send_char('e');
94
serial_send_char('.');
95
serial_send_char('\r');
96
serial_send_char('\n');
97
98
char x = '.';
99
while (1) {
100
101
if (can_check_message()) {
102
can_t rcv;
103
104
serial_send_char('-');
105
can_send_message(&msg);
106
serial_send_char('-');
107
108
if (can_get_message(&rcv))
109
{
110
// serial_print(&rcv);
111
112
if (x == '.') {
113
x = '-';
114
} else {
115
x = '.';
116
}
117
}
118
serial_send_char(x);
119
}
120
121
}
122
}
Aalso ein candump auf meinem linuxsystem empfängt das erste sendmessage
ohne Probleme.
Dann ist der AVR im mainloop und ich sende per cansend einen Datensatz.
Nachdem can_check_message true liefert wird '-' ausgegeben. Auf meiner
Konsole erscheint dies auch.
Aber egal ob ich jetzt ein get_message mache oder ein send_message, der
AVR bleibt stehen. Es scheint, als würde er sich in der Kommunikation
mit dem MCP fest fressen..
Die Filter sind dabei offensichtlich unerheblich. Ich kann sie auch raus
nehmen, der Effekt ist der Gleiche.
Was mache ich falsch?
Hallo Jens,
ich betreibe erfolgreich einen ATMEGA 328 mit einem MCP2515 als
CAN-Busteilnehmer.
Als Schnittstelle zum MCP2515 benutze ich die SPI-Schnittstelle
(4-Draht)
des ATMEGA328 und nicht die serielle Schnittstelle. Deiner Beschreibung
nach liegt das Problem vermutlich in der Kommunikation ATMEGA- MCP.
Um den Fehler zu finden empfehle ich Dir den MCP2515 im LOOPBACK-Modus
zu
betreiben: Du empfängst was Du sendest.
Ich kann Dir auch meine SPI-Funktionsbibliothek zur Kommunikation
mit dem MCP2515 zur Verfügung stellen. Falls Du Interesse hast melde
Dich
per PM.
Gruss Werner
Mit welchem Pin (des ATMega) hast du die INT-Leitung des MCP verbunden,
und hast du das auch in der CANconfig.h des Librarys korrekt angegeben?
Bei mir sieht das so aus:
Hallo Werner,
die serielle Schnittstelle ist für mich nur der Debug Port. Ich nutze
natürlich den normalen SPI des ATmega.
Wenn du mir deine Library zur Verfügung stellen würdest, wär das für
mich super :) Ansonsten hätt ich jetzt angefangen, mir eine eigene zu
basteln..
Jens R. schrieb:> Wenn du mir deine Library zur Verfügung stellen würdest, wär das für> mich super :) Ansonsten hätt ich jetzt angefangen, mir eine eigene zu> basteln..
Lass es!
Die Funktionen der CAN-Lib funktionieren ganz hervorragen!
Ich hab noch keine Bessere gesehen.
Harry L. schrieb:> Mit welchem Pin (des ATMega) hast du die INT-Leitung des MCP verbunden,> und hast du das auch in der CANconfig.h des Librarys korrekt angegeben?
Ich habe CS auf B1 und INT auf B2, das ist auch korrekt belegt.
Wenn die Lib denn täte was sie soll, wär ich ja auch zufrieden ;)
Ja, die config.h ist entsprechend gesetzt. Anderenfalls würde das Ding
sich ja auch gar nicht initialisieren lassen. das can_check_message()
tut ja prinzipiell auch noch was es soll sowie eine Nachricht gesendet
wurde.
Hast du das Ganze auf einem ATmega328? Eventuell kannst du mir ja
einfach deine libcan.a zur Verfügung stellen?
Ich hab das nicht als separates Library gebaut, sondern die Files
komplett ins Projekt integriert.
Eine (nicht aktuelle - aber lauffähige) Version meiner Software findest
du hier:
https://cloud.it-livetalk.de/index.php/s/S9AUPlSYGDydGaf
[edit]
Ja!
Läuft einem ATMega328
zur Info. Hab das Problem nach langem Suchen gefunden und es ist ein
klarer Fall von RTFM.
Mein Board ist so verdrahtet, dass es den PB2 als INT nutzt. Dies ist
auch der Slave Select des AVR.
Wenn der MCP jetzt irgendetwas empfängt, geht diese Leitung auf Low und
der AVR schaltet automatisch in den SPI-Slave Modus.
Ich habe jetzt einen Workaround gebastelt.
diff --git a/src/mcp2515_buffer.c b/src/mcp2515_buffer.c
index 1b68838..0468486 100644
--- a/src/mcp2515_buffer.c
+++ b/src/mcp2515_buffer.c
@@ -37,7 +37,19 @@
bool mcp2515_check_message(void)
{
#if defined(MCP2515_INT)
+ // set and restore PB2
+ #if defined(SPI_INT_SS)
+ #warning "Slave Select used as INT. creating workaround"
+ uint8_t ddrb = DDRB;
+ DDRB &= ~(1<<PB2);
+ #endif
return ((!IS_SET(MCP2515_INT)) ? true : false);
+
+ #if defined(SPI_INT_SS)
+ SPCR |= (1<<MSTR);
+ DDRB = ddrb;
+ #endif
+
#else
#ifdef RXnBF_FUNKTION
if (!IS_SET(MCP2515_RX0BF) ||
!IS_SET(MCP2515_RX1BF))
in der config.h muss jetzt noch folgender Eintrag gemacht werden:
#define SPI_INT_SS 1
Im Programm wird PB2 grundsätzlich als Ausgang geführt:
DDRB |= (1<<PB2);
Der Workaround speichert vor dem Abfragen den Status von DDRB und setzt
den Pin dann auf low. Anschließend wird der Pin abgefragt und zuletzt
DDRB restored, bzw. der SPI wieder in den Master Mode versetzt.