mikrocontroller.net

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


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
Autor: Jens R. (tecdroid)
Datum:

Bewertung
0 lesenswert
nicht 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
#include <avr/io.h>

#include <can.h>

char table[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b',
    'c', 'd', 'e', 'f' };
const uint8_t can_filter[] PROGMEM =
    {
        // Group 0
        MCP2515_FILTER(0),        // Filter 0
        MCP2515_FILTER(0),        // Filter 1

        MCP2515_FILTER(0),        // Filter 0
        MCP2515_FILTER(0),        // Filter 1

        MCP2515_FILTER(0),        // Mask 0 (for group 0)
        MCP2515_FILTER(0),        // Mask 0 (for group 0)

        MCP2515_FILTER(0),        // Mask 0 (for group 0)
        MCP2515_FILTER(0),        // Mask 0 (for group 0)
    };
// You can receive 11 bit identifiers with either group 0 or 1.

void serial_init() {
  UBRR0 = 103;
  UCSR0B |= (1 << RXEN0) | (1 << TXEN0);
  UCSR0C |= (1 << UCSZ00) | (1 << UCSZ01);
}

void serial_send_char(char c) {
  /* Wait for empty transmit buffer */
  while (!(UCSR0A & (1 << UDRE0)))
    ;
  /* Put data into buffer, sends the data */
  UDR0 = c;
}

void serial_send_byte(char b) {
  serial_send_char(table[b >> 4]);
  serial_send_char(table[b & 0x0f]);
}

void serial_print(can_t * msg) {
  char val = msg->id >> 8;
  serial_send_byte(val);
  val = msg->id & 0xff;
  serial_send_byte(val);

  serial_send_byte('#');
  for (char i = 0; i < msg->length; i++) {
    serial_send_byte(msg->data[i]);
  }
  serial_send_byte('\r');
  serial_send_byte('\n');
}

int main(int argc, char **argv) {
  serial_init();

//  if(! can_init(BITRATE_125_KBPS)) {
  if(! can_init(BITRATE_250_KBPS)) { /* doppelte Baudrate weil der MCP im Breakout nur halbe Taktrate hat */
    serial_send_char('e');
    serial_send_char('r');
    serial_send_char('r');
    serial_send_char('o');
    serial_send_char('r');
    serial_send_char('\r');
    serial_send_char('\n');
  }
  can_static_filter(can_filter);


  can_t msg;

  msg.id = 0x064;
  msg.flags.rtr = 0;

  msg.length = 8;
  msg.data[0] = 0X00;
  msg.data[1] = 0x33;
  msg.data[2] = 0x44;
  msg.data[3] = 0x88;
  msg.data[4] = 0xaa;
  msg.data[5] = 0xbb;
  msg.data[6] = 0xcc;
  msg.data[7] = 0xf0;

  can_send_message(&msg);

  serial_send_char('d');
  serial_send_char('o');
  serial_send_char('n');
  serial_send_char('e');
  serial_send_char('.');
  serial_send_char('\r');
  serial_send_char('\n');

  char x = '.';
  while (1) {

    if (can_check_message()) {
      can_t rcv;

      serial_send_char('-');
      can_send_message(&msg);
      serial_send_char('-');

      if (can_get_message(&rcv))
      {
//        serial_print(&rcv);

        if (x == '.') {
          x = '-';
        } else {
          x = '.';
        }
      }
      serial_send_char(x);
    }

  }
}

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?

Autor: Harry L. (mysth)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Im Normalfall brauchst du kein can_check_message().
Es reicht vollkommen, wen du das so machst:
    // Try to read the message
    if (can_get_message((can_t *)&msg))
    {
      modules_can_receiver((can_t*)&msg);
    }

Autor: Jens R. (tecdroid)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Auch das scheint er wohl nicht zu mögen.
Hab jetzt mal das mitgelieferte Example angepasst
/*
 * main2.c
 *
 *  Created on: 02.05.2018
 *      Author: tecdroid
 */
// coding: utf-8

#include <avr/io.h>
#include <avr/pgmspace.h>

#include <can.h>

void serial_init() {
  UBRR0 = 103;
  UCSR0B |= (1 << RXEN0) | (1 << TXEN0);
  UCSR0C |= (1 << UCSZ00) | (1 << UCSZ01);
}

void serial_send_char(char c) {
  /* Wait for empty transmit buffer */
  while (!(UCSR0A & (1 << UDRE0)))
    ;
  /* Put data into buffer, sends the data */
  UDR0 = c;
}


// -----------------------------------------------------------------------------
/** Set filters and masks.
 *
 * The filters are divided in two groups:
 *
 * Group 0: Filter 0 and 1 with corresponding mask 0.
 * Group 1: Filter 2, 3, 4 and 5 with corresponding mask 1.
 *
 * If a group mask is set to 0, the group will receive all messages.
 *
 * If you want to receive ONLY 11 bit identifiers, set your filters
 * and masks as follows:
 *
 *  uint8_t can_filter[] PROGMEM = {
 *    // Group 0
 *    MCP2515_FILTER(0),        // Filter 0
 *    MCP2515_FILTER(0),        // Filter 1
 *
 *    // Group 1
 *    MCP2515_FILTER(0),        // Filter 2
 *    MCP2515_FILTER(0),        // Filter 3
 *    MCP2515_FILTER(0),        // Filter 4
 *    MCP2515_FILTER(0),        // Filter 5
 *
 *    MCP2515_FILTER(0),        // Mask 0 (for group 0)
 *    MCP2515_FILTER(0),        // Mask 1 (for group 1)
 *  };
 *
 *
 * If you want to receive ONLY 29 bit identifiers, set your filters
 * and masks as follows:
 *
 * \code
 *  uint8_t can_filter[] PROGMEM = {
 *    // Group 0
 *    MCP2515_FILTER_EXTENDED(0),    // Filter 0
 *    MCP2515_FILTER_EXTENDED(0),    // Filter 1
 *
 *    // Group 1
 *    MCP2515_FILTER_EXTENDED(0),    // Filter 2
 *    MCP2515_FILTER_EXTENDED(0),    // Filter 3
 *    MCP2515_FILTER_EXTENDED(0),    // Filter 4
 *    MCP2515_FILTER_EXTENDED(0),    // Filter 5
 *
 *    MCP2515_FILTER_EXTENDED(0),    // Mask 0 (for group 0)
 *    MCP2515_FILTER_EXTENDED(0),    // Mask 1 (for group 1)
 *  };
 * \endcode
 *
 * If you want to receive both 11 and 29 bit identifiers, set your filters
 * and masks as follows:
 */
const uint8_t can_filter[] PROGMEM =
{
  // Group 0
  MCP2515_FILTER(0),        // Filter 0
  MCP2515_FILTER(0),        // Filter 1

  // Group 1
  MCP2515_FILTER(0),    // Filter 2
  MCP2515_FILTER(0),    // Filter 3
  MCP2515_FILTER(0),    // Filter 4
  MCP2515_FILTER(0),    // Filter 5

  MCP2515_FILTER(0),        // Mask 0 (for group 0)
  MCP2515_FILTER(0),    // Mask 1 (for group 1)
};
// You can receive 11 bit identifiers with either group 0 or 1.


// -----------------------------------------------------------------------------
// Main loop for receiving and sending messages.

int main(void)
{
  serial_init();
  // Initialize MCP2515
  can_init(BITRATE_250_KBPS);

  // Load filters and masks
  can_static_filter(can_filter);

  // Create a test messsage
  can_t msg;

  msg.id = 0x123;
  msg.flags.rtr = 0;
//  msg.flags.extended = 1;

  msg.length = 4;
  msg.data[0] = 0xde;
  msg.data[1] = 0xad;
  msg.data[2] = 0xbe;
  msg.data[3] = 0xef;

  // Send the message
  can_send_message(&msg);

  serial_send_char('1');
//  can_t msg;
  while (1)
  {
    // Check if a new messag was received
//    if (can_check_message())
//    {
//      serial_send_char('2');

      // Try to read the message
      if (can_get_message(&msg))
      {
        serial_send_char('3');

        // If we received a message resend it with a different id
        msg.id += 10;

        // Send the new message
        can_send_message(&msg);
      }
//    }
  }

  return 0;
}


Vielleicht hab ich die lib falsch konfiguriert?
#ifndef  CONFIG_H
#define  CONFIG_H

#define CAN_CONFIG_LOADED

// -----------------------------------------------------------------------------
/* Global settings for building the can-lib and application program.
 *
 * The following two #defines must be set identically for the can-lib and
 * your application program. They control the underlying CAN struct. If the
 * settings disagree, the underlying CAN struct will be broken, with
 * unpredictable results.
 * If can.h detects that any of the #defines is not defined, it will set them
 * to the default values shown here, so it is in your own interest to have a
 * consistent setting. Ommiting the #defines in both can-lib and application
 * program will apply the defaults in a consistent way too.
 *
 * Select if you want to use 29 bit identifiers.
 */
#define  SUPPORT_EXTENDED_CANID  0

/* Select if you want to use timestamps.
 * Timestamps are sourced from a register internal to the AT90CAN.
 * Selecting them on any other controller will have no effect, they will
 * be 0 all the time.
 */
#define  SUPPORT_TIMESTAMPS    0


// -----------------------------------------------------------------------------
/* Global settings for building the can-lib.
 *
 * Select ONE CAN controller for which you are building the can-lib. 
 */
#define  SUPPORT_MCP2515      1
#define  SUPPORT_AT90CAN      0
#define  SUPPORT_SJA1000      0


// -----------------------------------------------------------------------------
/* Setting for MCP2515
 *
 * Declare which pins you are using for communication.
 * Remember NOT to use them in your application!
 * It is a good idea to use bits from the port that carries MOSI, MISO, SCK.
 */
#define  MCP2515_CS        B,1
#define  MCP2515_INT        B,2

// -----------------------------------------------------------------------------
// Setting for SJA1000

#define  SJA1000_INT        E,0
#define  SJA1000_MEMORY_MAPPED  1

// memory-mapped interface
#define  SJA1000_BASE_ADDR    0x8000    // for ATMega162

/*
// port-interface
#define  SJA1000_WR        D,6
#define  SJA1000_RD        D,7

#define  SJA1000_ALE        E,1
#define  SJA1000_CS        C,0
#define  SJA1000_DATA      A
*/

// -----------------------------------------------------------------------------
// Setting for AT90CAN

// Number of CAN messages which are buffered in RAM additinally to the MObs
#define CAN_RX_BUFFER_SIZE    16
#define CAN_TX_BUFFER_SIZE    8

// only available if CAN_TX_BUFFER_SIZE > 0
#define CAN_FORCE_TX_ORDER    1

#endif  // CONFIG_H

Autor: WR (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Harry L. (mysth)
Datum:

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


Autor: Jens R. (tecdroid)
Datum:

Bewertung
0 lesenswert
nicht 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..

Autor: Harry L. (mysth)
Datum:

Bewertung
0 lesenswert
nicht 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
Autor: Jens R. (tecdroid)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Harry L. (mysth)
Datum:

Bewertung
0 lesenswert
nicht 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
Autor: Harry L. (mysth)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Jens R. (tecdroid)
Datum:

Bewertung
0 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.