Forum: Mikrocontroller und Digitale Elektronik CAN / mcp2515: rtr bit immer gesetzt


von Philipp H. (atmega-bastler)


Lesenswert?

Hallo zusammen,

ich beschäftige mich zurzeit ein wenig mit CAN Bus und dem mcp2515. 
Allerdings stehe ich derzeit vor einem kleinen Problem, dessen Lösung 
ich leider alleine nicht finde.

Wenn ich eine Nachricht versende, egal ob normal oder loopBack Modus, 
ist immer das rtr bit gesetzt, obwohl ich dieses beim Senden nicht 
setze.
Das einzige was im empfangenen Paket stimmt ist die ID, ansonsten ist 
nichts so wie es sein soll.

Kann mir jemand erklären woher das kommt und wie ich das Problem lösen 
kann?

Hier meine Sendefunktion:

uint8_t can_send_message(CANMessage *p_message)
{
    uint8_t status, address;

    // Status des MCP2515 auslesen
    PORT_CS &= ~(1<<P_CS);
    spi_putc(SPI_READ_STATUS);
    status = spi_putc(0xff);
    spi_putc(0xff);
    PORT_CS |= (1<<P_CS);

    if (!(status & (1<<2))) {
        address = 0x00;
    }
    else if (!(status & (1<<4))) {
        address = 0x02;
    }
    else if (!(status & (1<<6))) {
        address = 0x04;
    }
    else {
        return 0;
    }

    PORT_CS &= ~(1<<P_CS);    // CS Low
    spi_putc(SPI_WRITE_TX | address);

    // Standard ID einstellen
    spi_putc((uint8_t) (p_message->id>>3));
    spi_putc((uint8_t) (p_message->id<<5));

    // Extended ID
    //spi_putc(0x00);
    //spi_putc(0x00);

    uint8_t length = p_message->length;

    if (length > 8) {
        length = 8;
    }

    // Ist die Nachricht ein "Remote Transmit Request" ?
    if (p_message->rtr)
    {

        // Nachrichten Laenge + RTR einstellen
        spi_putc((1<<RTR) | length);
    }
    else
    {
        // Nachrichten Laenge einstellen
        spi_putc(length);

        // Daten
        for (uint8_t i=0;i<length;i++) {
            spi_putc(p_message->data[i]);
        }
    }
    PORT_CS |= (1<<P_CS);      // CS auf High

    asm volatile ("nop");

    PORT_CS &= ~(1<<P_CS);    // CS wieder Low
    if (address == 0x00) {
        spi_putc(SPI_RTS | 0x01);
    } else {
        spi_putc(SPI_RTS | address);
    }
    PORT_CS |= (1<<P_CS);      // CS auf High

    return 1;
}

(stammt von http://www.kreatives-chaos.com, nur leicht modifiziert)

das CANMessage struct sieht folgendermaßen aus:

typedef struct
{
  uint16_t  id;
  uint8_t    rtr;
  uint8_t    length;
  uint8_t    data[8];
} CANMessage;

und wird so ausgefüllt:

msg.id = 0x0123;
msg.length = 1;
msg.rtr = 0;
msg.data[0] = 0xab;


Danke schonmal im vorraus!
mfg
Philipp

von Bastian W. (jackfrost)


Lesenswert?

Hi,

Ich sende über CAN Statusmeldungen und Sensordaten. Mit dem MCP2515 
läuft das ohne Probleme. Du kannst dir die Dateien unter 
https://github.com/JackFrost80/Wasserzaehler-CAN-Modul/blob/master/CAN.cpp 
ja mal anschauen.

Das Projekt ist für einen Atxmega und in C++ geschrieben.

Gruß JackFrost

von H.Joachim S. (crazyhorse)


Lesenswert?

Gerade mal den alten (funktionierenden) Kram herausgeholt, 2 
Unterschiede sind mir aufgefallen:

 // Standard ID einstellen
     spi_putc((unsigned char) (p_message->id>>3));
     spi_putc((unsigned char) (p_message->id<<5));

 // Extended ID
     spi_putc(0x00);
     spi_putc(0x00);

und:

     PORTB |= (1<<SPI_CS1);      // CS high
     #asm  ("nop");
     #asm  ("nop");

Ob es daran liegt, kann ich dir nicht sagen, schau ich jetzt nicht nach 
und probier ich auch nicht aus :-), der MCP2515 ist in der Mottenkiste.

von Bastian W. (jackfrost)


Lesenswert?

Poste mal einen Frame vom Sende MCP und den gleichen dann vom Empfänger

Die EID musst du setzen auch wenn du nur die ID verwendest , sonst ist 
alles um zwei Bytes verschoben wenn du den Adresspointer nicht neu 
setzt.

Gruß JackFrost

von H.Joachim S. (crazyhorse)


Lesenswert?

Bastian W. schrieb:
> Die EID musst du setzen auch wenn du nur die ID verwendest , sonst ist
> alles um zwei Bytes verschoben

Dann passt das ja mit den og. 2 Nullbytes, dem gesetzten RTR usw.

von Philipp H. (atmega-bastler)


Lesenswert?

H.Joachim S. schrieb:
> // Extended ID
>      spi_putc(0x00);
>      spi_putc(0x00);

Bastian W. schrieb:
> Die EID musst du setzen auch wenn du nur die ID verwendest

vielen Dank für die Antworten. Daran hats gelegen, funktioniert jezt :))

mfg
Philipp

EDIT:
Zumindest im Loopback betrieb.
auf dem Bus sind die Nachrichten zu sehen, auch am rx pin des mcp2515 
kommen die daten an. Aber ich bekomme leider keinen Interrupt am 
empfänger :(

Der code zum initialisieren sieht folgendermaßen aus:
    // SPI Interface initialisieren
    spi_init();

    // MCP2515 per Software Reset zuruecksetzten,
    // danach ist der MCP2515 im Configuration Mode
    PORT_CS &= ~(1<<P_CS);
    spi_putc( SPI_RESET );
    _delay_ms(1);
    PORT_CS |= (1<<P_CS);

    // etwas warten bis sich der MCP2515 zurueckgesetzt hat
    _delay_ms(10);

    // BRP = 7
    mcp2515_write_register( CNF1, (1<<BRP0)|(1<<BRP1)|(1<<BRP2) );

    // Prop Seg und Phase Seg1 einstellen
    mcp2515_write_register( CNF2, (1<<BTLMODE)|(1<<PHSEG11) );

    // Wake-up Filter deaktivieren, Phase Seg2 einstellen
    mcp2515_write_register( CNF3, (1<<PHSEG21) );

    // Aktivieren der Rx Buffer Interrupts
    mcp2515_write_register( CANINTE, (1<<RX1IE)|(1<<RX0IE) );

    /*
     *  Einstellen der Filter
     */

    // Buffer 0 : Empfangen aller Nachrichten
    mcp2515_write_register( RXB0CTRL, (1<<RXM1)|(1<<RXM0) );

    // Buffer 1 : Empfangen aller Nachrichten
    mcp2515_write_register( RXB1CTRL, (1<<RXM1)|(1<<RXM0) );

    // Alle Bits der Empfangsmaske loeschen,
    // damit werden alle Nachrichten empfangen
    mcp2515_write_register( RXM0SIDH, 0 );
    mcp2515_write_register( RXM0SIDL, 0 );
    mcp2515_write_register( RXM0EID8, 0 );
    mcp2515_write_register( RXM0EID0, 0 );

    mcp2515_write_register( RXM1SIDH, 0 );
    mcp2515_write_register( RXM1SIDL, 0 );
    mcp2515_write_register( RXM1EID8, 0 );
    mcp2515_write_register( RXM1EID0, 0 );

    /*
     *  Einstellen der Pin Funktionen
     */

    // Deaktivieren der Pins RXnBF Pins (High Impedance State)
    mcp2515_write_register( BFPCTRL, 0 );

    // TXnRTS Bits als Inputs schalten
    mcp2515_write_register( TXRTSCTRL, 0 );

    // Device zurueck in den normalen Modus versetzten
    mcp2515_bit_modify( CANCTRL, 0xE0, 0);


mfg
Philipp

: Bearbeitet durch User
von H.Joachim S. (crazyhorse)


Lesenswert?

Hast du denn eigentlich schon irgendetwas selbst gemacht zur 
Fehlersuche?
Du setzt hier den 1:1  kopierten Code (?, sieht zumindest so aus) rein 
und die einzige Info: Keinen RX-Int. Finde ich persönlich ein bisschen 
dünne...
Die Routinen von kreatives Chaos funktionieren jedenfalls allesamt. D.h. 
der Fehler wird entweder an der Platine/Verdrahtung liegen oder am 
Interruptprogramm/Initialisierung des MC.

von Philipp H. (atmega-bastler)


Lesenswert?

H.Joachim S. schrieb:
> Hast du denn eigentlich schon irgendetwas selbst gemacht zur
> Fehlersuche?
> Du setzt hier den 1:1  kopierten Code (?, sieht zumindest so aus) rein
> und die einzige Info: Keinen RX-Int. Finde ich persönlich ein bisschen
> dünne...
> Die Routinen von kreatives Chaos funktionieren jedenfalls allesamt. D.h.
> der Fehler wird entweder an der Platine/Verdrahtung liegen oder am
> Interruptprogramm/Initialisierung des MC.

Sorry Hierfür, war ziemlich verzweifelt nachdem ich zwei tage fehler 
gesucht habe.

ABER: Es funktioniert, hatte einen Wackelkontakt auf meinem Steckbrett 
;)

Vielen Dank nochmal!
mfg
Philipp

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.