Forum: Mikrocontroller und Digitale Elektronik AVR-CAN-Lib hängt nach check_message


von Jens R. (tecdroid)


Lesenswert?

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
1
#include <avr/io.h>
2
3
#include <can.h>
4
5
char table[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b',
6
    'c', 'd', 'e', 'f' };
7
const uint8_t can_filter[] PROGMEM =
8
    {
9
        // Group 0
10
        MCP2515_FILTER(0),        // Filter 0
11
        MCP2515_FILTER(0),        // Filter 1
12
13
        MCP2515_FILTER(0),        // Filter 0
14
        MCP2515_FILTER(0),        // Filter 1
15
16
        MCP2515_FILTER(0),        // Mask 0 (for group 0)
17
        MCP2515_FILTER(0),        // Mask 0 (for group 0)
18
19
        MCP2515_FILTER(0),        // Mask 0 (for group 0)
20
        MCP2515_FILTER(0),        // Mask 0 (for group 0)
21
    };
22
// 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?

von Harry L. (mysth)


Lesenswert?

Im Normalfall brauchst du kein can_check_message().
Es reicht vollkommen, wen du das so machst:
1
    // Try to read the message
2
    if (can_get_message((can_t *)&msg))
3
    {
4
      modules_can_receiver((can_t*)&msg);
5
    }

von Jens R. (tecdroid)


Lesenswert?

Auch das scheint er wohl nicht zu mögen.
Hab jetzt mal das mitgelieferte Example angepasst
1
/*
2
 * main2.c
3
 *
4
 *  Created on: 02.05.2018
5
 *      Author: tecdroid
6
 */
7
// coding: utf-8
8
9
#include <avr/io.h>
10
#include <avr/pgmspace.h>
11
12
#include <can.h>
13
14
void serial_init() {
15
  UBRR0 = 103;
16
  UCSR0B |= (1 << RXEN0) | (1 << TXEN0);
17
  UCSR0C |= (1 << UCSZ00) | (1 << UCSZ01);
18
}
19
20
void serial_send_char(char c) {
21
  /* Wait for empty transmit buffer */
22
  while (!(UCSR0A & (1 << UDRE0)))
23
    ;
24
  /* Put data into buffer, sends the data */
25
  UDR0 = c;
26
}
27
28
29
// -----------------------------------------------------------------------------
30
/** Set filters and masks.
31
 *
32
 * The filters are divided in two groups:
33
 *
34
 * Group 0: Filter 0 and 1 with corresponding mask 0.
35
 * Group 1: Filter 2, 3, 4 and 5 with corresponding mask 1.
36
 *
37
 * If a group mask is set to 0, the group will receive all messages.
38
 *
39
 * If you want to receive ONLY 11 bit identifiers, set your filters
40
 * and masks as follows:
41
 *
42
 *  uint8_t can_filter[] PROGMEM = {
43
 *    // Group 0
44
 *    MCP2515_FILTER(0),        // Filter 0
45
 *    MCP2515_FILTER(0),        // Filter 1
46
 *
47
 *    // Group 1
48
 *    MCP2515_FILTER(0),        // Filter 2
49
 *    MCP2515_FILTER(0),        // Filter 3
50
 *    MCP2515_FILTER(0),        // Filter 4
51
 *    MCP2515_FILTER(0),        // Filter 5
52
 *
53
 *    MCP2515_FILTER(0),        // Mask 0 (for group 0)
54
 *    MCP2515_FILTER(0),        // Mask 1 (for group 1)
55
 *  };
56
 *
57
 *
58
 * If you want to receive ONLY 29 bit identifiers, set your filters
59
 * and masks as follows:
60
 *
61
 * \code
62
 *  uint8_t can_filter[] PROGMEM = {
63
 *    // Group 0
64
 *    MCP2515_FILTER_EXTENDED(0),    // Filter 0
65
 *    MCP2515_FILTER_EXTENDED(0),    // Filter 1
66
 *
67
 *    // Group 1
68
 *    MCP2515_FILTER_EXTENDED(0),    // Filter 2
69
 *    MCP2515_FILTER_EXTENDED(0),    // Filter 3
70
 *    MCP2515_FILTER_EXTENDED(0),    // Filter 4
71
 *    MCP2515_FILTER_EXTENDED(0),    // Filter 5
72
 *
73
 *    MCP2515_FILTER_EXTENDED(0),    // Mask 0 (for group 0)
74
 *    MCP2515_FILTER_EXTENDED(0),    // Mask 1 (for group 1)
75
 *  };
76
 * \endcode
77
 *
78
 * If you want to receive both 11 and 29 bit identifiers, set your filters
79
 * and masks as follows:
80
 */
81
const uint8_t can_filter[] PROGMEM =
82
{
83
  // Group 0
84
  MCP2515_FILTER(0),        // Filter 0
85
  MCP2515_FILTER(0),        // Filter 1
86
87
  // Group 1
88
  MCP2515_FILTER(0),    // Filter 2
89
  MCP2515_FILTER(0),    // Filter 3
90
  MCP2515_FILTER(0),    // Filter 4
91
  MCP2515_FILTER(0),    // Filter 5
92
93
  MCP2515_FILTER(0),        // Mask 0 (for group 0)
94
  MCP2515_FILTER(0),    // Mask 1 (for group 1)
95
};
96
// You can receive 11 bit identifiers with either group 0 or 1.
97
98
99
// -----------------------------------------------------------------------------
100
// Main loop for receiving and sending messages.
101
102
int main(void)
103
{
104
  serial_init();
105
  // Initialize MCP2515
106
  can_init(BITRATE_250_KBPS);
107
108
  // Load filters and masks
109
  can_static_filter(can_filter);
110
111
  // Create a test messsage
112
  can_t msg;
113
114
  msg.id = 0x123;
115
  msg.flags.rtr = 0;
116
//  msg.flags.extended = 1;
117
118
  msg.length = 4;
119
  msg.data[0] = 0xde;
120
  msg.data[1] = 0xad;
121
  msg.data[2] = 0xbe;
122
  msg.data[3] = 0xef;
123
124
  // Send the message
125
  can_send_message(&msg);
126
127
  serial_send_char('1');
128
//  can_t msg;
129
  while (1)
130
  {
131
    // Check if a new messag was received
132
//    if (can_check_message())
133
//    {
134
//      serial_send_char('2');
135
136
      // Try to read the message
137
      if (can_get_message(&msg))
138
      {
139
        serial_send_char('3');
140
141
        // If we received a message resend it with a different id
142
        msg.id += 10;
143
144
        // Send the new message
145
        can_send_message(&msg);
146
      }
147
//    }
148
  }
149
150
  return 0;
151
}


Vielleicht hab ich die lib falsch konfiguriert?
1
#ifndef  CONFIG_H
2
#define  CONFIG_H
3
4
#define CAN_CONFIG_LOADED
5
6
// -----------------------------------------------------------------------------
7
/* Global settings for building the can-lib and application program.
8
 *
9
 * The following two #defines must be set identically for the can-lib and
10
 * your application program. They control the underlying CAN struct. If the
11
 * settings disagree, the underlying CAN struct will be broken, with
12
 * unpredictable results.
13
 * If can.h detects that any of the #defines is not defined, it will set them
14
 * to the default values shown here, so it is in your own interest to have a
15
 * consistent setting. Ommiting the #defines in both can-lib and application
16
 * program will apply the defaults in a consistent way too.
17
 *
18
 * Select if you want to use 29 bit identifiers.
19
 */
20
#define  SUPPORT_EXTENDED_CANID  0
21
22
/* Select if you want to use timestamps.
23
 * Timestamps are sourced from a register internal to the AT90CAN.
24
 * Selecting them on any other controller will have no effect, they will
25
 * be 0 all the time.
26
 */
27
#define  SUPPORT_TIMESTAMPS    0
28
29
30
// -----------------------------------------------------------------------------
31
/* Global settings for building the can-lib.
32
 *
33
 * Select ONE CAN controller for which you are building the can-lib. 
34
 */
35
#define  SUPPORT_MCP2515      1
36
#define  SUPPORT_AT90CAN      0
37
#define  SUPPORT_SJA1000      0
38
39
40
// -----------------------------------------------------------------------------
41
/* Setting for MCP2515
42
 *
43
 * Declare which pins you are using for communication.
44
 * Remember NOT to use them in your application!
45
 * It is a good idea to use bits from the port that carries MOSI, MISO, SCK.
46
 */
47
#define  MCP2515_CS        B,1
48
#define  MCP2515_INT        B,2
49
50
// -----------------------------------------------------------------------------
51
// Setting for SJA1000
52
53
#define  SJA1000_INT        E,0
54
#define  SJA1000_MEMORY_MAPPED  1
55
56
// memory-mapped interface
57
#define  SJA1000_BASE_ADDR    0x8000    // for ATMega162
58
59
/*
60
// port-interface
61
#define  SJA1000_WR        D,6
62
#define  SJA1000_RD        D,7
63
64
#define  SJA1000_ALE        E,1
65
#define  SJA1000_CS        C,0
66
#define  SJA1000_DATA      A
67
*/
68
69
// -----------------------------------------------------------------------------
70
// Setting for AT90CAN
71
72
// Number of CAN messages which are buffered in RAM additinally to the MObs
73
#define CAN_RX_BUFFER_SIZE    16
74
#define CAN_TX_BUFFER_SIZE    8
75
76
// only available if CAN_TX_BUFFER_SIZE > 0
77
#define CAN_FORCE_TX_ORDER    1
78
79
#endif  // CONFIG_H

von WR (Gast)


Lesenswert?

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

von Harry L. (mysth)


Lesenswert?

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:
1
// -----------------------------------------------------------------------------
2
/* Setting for MCP2515
3
 *
4
 * Declare which pins you are using for communication.
5
 * Remember NOT to use them in your application!
6
 * It is a good idea to use bits from the port that carries MOSI, MISO, SCK.
7
 */
8
#define  MCP2515_CS        B,2
9
#define  MCP2515_INT        D,2

von Jens R. (tecdroid)


Lesenswert?

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

von Harry L. (mysth)


Lesenswert?

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.

: Bearbeitet durch User
von Jens R. (tecdroid)


Lesenswert?

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?

von Harry L. (mysth)


Lesenswert?

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

: Bearbeitet durch User
von Harry L. (mysth)


Lesenswert?

Wenn du weitere Fragen hast, dann schau am besten mal auf unserem 
Mumble-Server (Voice-Chat) vorbei:
https://www.canonversteher.de/content/t%C3%A4glicher-tech-talk-auf-unserem-mumble-server

von Jens R. (tecdroid)


Lesenswert?

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.

Beitrag #5416121 wurde vom Autor gelöscht.
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.