59-CAN_LoLevel-Library (STM32F4)

mit dieser Library kann die CAN-Schnittstelle vom STM32F4 benutzt werden

die CAN-Pins die benutzt werden sollen, müssen im C-File eingetragen werden
(im H-File kann die CAN-Baudrate eingestellt werden)

es gibt zwei identische Librarys, getrennt für CAN-1 und CAN-2

die Filter-Funktionen vom STM32F4 sind sehr Umfangreich. Ich habe versucht alles so einfach wie möglich zu halten, aber es wurden trotzdem 4 Funktionen.
(Beschreibung siehe unten)

es können CAN-Frames in den 4 Modes :
[standard_Data, standard_Remote, extended_Data, extended_Remote]
gesendet und empfangen werden

es muss ein externer CAN-Transeiver-IC angeschlossen werden (z.B. SN65HVD230D) und der Terminations-Widerstand (120 Ohm) für den BUS darf nicht vergessen werden.

Filterbeschreibung :

Die Filter dienen dazu um CAN-Frames die für die CPU nicht wichtig sind wegzufiltern. Es können Filter für “standard” und “extended” CAN-Frames gesetzt werden.
Direkt nach der Init Funktion sind keine Filter aktiv und alle Frames werden empfangen.

Für CAN1 können bis zu 14 Filter eingerichtet werden (Nr. 0…13)
Für CAN2 könen bis zu 14 Filter eingerichtet werden (Nr. 14 bis 27)

Filter-Liste : alle empfangenen CAN-Frames werden mit den Einträgen in der Liste verglichen, wenn die ID+Mode übereinstimmt landet der Frame im Empfangspuffer.

dieser Filter kann man dann einsetzen, wenn man einzelne CAN-IDs freigeben will.
(z.B. 4 einzelne IDs : 0×123, 0×463, 0×228, 0×447)

Filter-Maske : alle empfangenen CAN-Frames werden mit einer Maske versehen und dann mit der ID+Mode verglichen, bei Übereinstimmung landet der Frame im Empfangspuffer.

Alle Bits die in der Maske auf ’1′ stehen, müssen mit der ID übereinstimmen.
Alle Bits die in der Maske auf ’0′ stehen, können einen beliebigen wert haben.

diesen Filter kann man dann einsetzen, wenn man ganze ID-Blöcke freigeben will.
(z.B. 16 IDs : 0×120 bis 0x12F)

Bilder :

im Beispiel wurde CAN-1 mit dieser Pin-Belegung benutzt :

1
2
CAN_TX an PB9
CAN_RX an PB8

Voraussetzungen :

1
2
Benutzte Module der CooCox-IDE : GPIO, CAN, MISC
Benutzte Librarys : keine

Enumerationen (für CAN1) :

1
2
3
4
5
6
typedef enum {
  CAN1_STD_DATA =0, // standard Daten-Frame
  CAN1_STD_REMOTE,  // standard Remote-Frame
  CAN1_EXT_DATA,    // extended Daten-Frame
  CAN1_EXT_REMOTE   // extended Remote-Frame
}CAN1_FRAME_MODE_t;

:

1
2
3
4
typedef enum {
  CAN1_RX_EMPTY =0,  // noch kein CAN-Frame empfangen
  CAN1_RX_READY      // CAN-Frame wurde empfangen
}CAN1_STATUS_t;

TX-Struktur :

1
2
3
4
5
typedef struct {
  uint32_t can_id;    // STD=11bit  EXT=29bit
  uint8_t anz_bytes;  // anzahl der daten [0...8]
  uint8_t data[8];    // datenbytes
}CAN1_TX_FRAME_t;

RX-Struktur :

1
2
3
4
5
6
typedef struct {
  CAN1_FRAME_MODE_t frame_mode;    // Frame-Mode
  uint32_t can_id;    // STD=11bit  EXT=29bit
  uint8_t anz_bytes;  // anzahl der daten [0...8]
  uint8_t data[8];    // datenbytes
}CAN1_RX_FRAME_t;

Funktionen (für CAN1) :

1
2
3
4
5
6
void UB_CAN1_Init(void);                                       // zum init der CAN-Schnittstelle
ErrorStatus UB_CAN1_send_std_data(CAN1_TX_FRAME_t tx_frame);   // zum senden von standard data frames
ErrorStatus UB_CAN1_send_std_remote(CAN1_TX_FRAME_t tx_frame); // zum senden von standard remote frames
ErrorStatus UB_CAN1_send_ext_data(CAN1_TX_FRAME_t tx_frame);   // zum senden von extended data frames
ErrorStatus UB_CAN1_send_ext_remote(CAN1_TX_FRAME_t tx_frame); // zum senden von extended remote Frames
CAN1_STATUS_t UB_CAN1_receive(CAN1_RX_FRAME_t *rx_frame);      // zum empfangen von Frames

Filter-Funktionen (für CAN1) :

1
2
3
4
void UB_CAN1_std_FilterList(CAN1_STD_FL_t filter, uint8_t nr); // 1...4 Filter für std-ID
void UB_CAN1_std_FilterMask(CAN1_STD_FM_t filter, uint8_t nr); // 1..2 Filter+Maske für std-ID
void UB_CAN1_ext_FilterList(CAN1_EXT_FL_t filter, uint8_t nr); // 1..2 Filter für ext-ID
void UB_CAN1_ext_FilterMask(CAN1_EXT_FM_t filter, uint8_t nr); // 1 Filter+Maske für ext-ID

Beispiel :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
//--------------------------------------------------------------
// File     : main.c
// Datum    : 14.09.2013
// Version  : 1.0
// Autor    : UB
// EMail    : mc-4u(@)t-online.de
// Web      : www.mikrocontroller-4u.de
// CPU      : STM32F4
// IDE      : CooCox CoIDE 1.7.4
// GCC      : 4.7 2012q4
// Module   : CMSIS_BOOT, M4_CMSIS_CORE
// Funktion : Demo der CAN-LoLevel-Library
// Hinweis  : Diese zwei Files muessen auf 8MHz stehen
//              "cmsis_boot/stm32f4xx.h"
//              "cmsis_boot/system_stm32f4xx.c"
//--------------------------------------------------------------
 
#include "main.h"
#include "stm32_ub_led.h"
#include "stm32_ub_can1.h"
 
int main(void)
{
  uint32_t delay=0;
  uint8_t wert=0;
  CAN1_TX_FRAME_t myTXFrame; // Puffer für TX-Daten
  CAN1_RX_FRAME_t myRXFrame; // Puffer für RX-Daten
 
  SystemInit(); // Quarz Einstellungen aktivieren
 
  // Init der LEDs
  UB_Led_Init();
 
  // Init vom CAN-1 (an PB8+PB9)
  UB_CAN1_Init();
 
  while(1)
  {
    //---------------------------
    // senden
    //---------------------------
    delay++;
    if(delay>5000000) {
      // zyklisch ein CAN-Telegramm senden
      delay=0;
      UB_Led_Toggle(LED_GREEN);
      // telegramm erstellen
      myTXFrame.can_id=0x123; // ID ist egal
      myTXFrame.anz_bytes=1;  // ein Datenbyte wird gesendet
      myTXFrame.data[0]=wert; // Datenwert
      // Frame senden
      UB_CAN1_send_std_data(myTXFrame);
      // Datenwert wird nach jedem senden incrementiert
      wert++;
    }
 
    //---------------------------
    // empfangen
    //---------------------------
    if(UB_CAN1_receive(&myRXFrame)==CAN1_RX_READY) {
      // es wurde etwas empfangen
      UB_Led_Toggle(LED_BLUE);
      // Datenbyte auswerten (nur als Demo)
      if((myRXFrame.data[0]&0x02)!=0) {
        // beim empfangenen Datenwert ist das Bit1 gesetzt
        UB_Led_Toggle(LED_RED);
      }
    }
  }
}

Hier die Library zum Download :

ub_stm32f4_can_v102

Hier der komplette CooCox-Projektordner zum Download :

Demo_59_CAN_LoLevel


13 Antworten auf 59-CAN_LoLevel-Library (STM32F4)

  1. Gorka sagt:

    Super Arbeit. Danke sehr.
    Ich habe hier viel gelernt…
    Seit ein Paar Tage versuche ich CAN und USB gleichzeitig zu nutzen, aber es sieht, das beide libs nicht kompatibel sind… CAN schnittstelle functioniert einwandfrei bis man einen USB Stick anschließt. Und beide, CAN und USB libs funktionieren bei mir ohne Probleme, aber nur getrennt…
    Hast du es irgendwann zufälligerweise probiert?

    • admin_ub sagt:

      Beim STM32F1 geht die Kombination nicht…beim F4 müsste es eigentlich laufen, habe es aber selbst nicht ausprobiert.

      • Gorka sagt:

        Hallo nochmals,
        ich kapiere leider noch nicht warum beide Beispiele, CAN und USB_HOST, beim F4DISCOVERY nicht kompatible sind… Beide funktionieren ohne Probleme aber sobald ich beide CooCox Projekte fusioniere, läuft CAN nur bis ich den USB Stick einschließe und danach nicht mehr. Test-Datei „USB_File.txt” wird generiert, aber auch nur das erste Mal, dass den USB Stick eingeschlossen wird… Hat jemand Ahnung, warum es sein kann?
        Danke sehr!

        • Gorka sagt:

          SOLVED: Ich habe den STM Board einfach per USB eingeschaltet, aber mein Laptop gibt nicht genug Strom um USB und CAN gleichzeitig nutzen zu können, und deswegen funktionierten beide nicht gleichzeitig… verrückt! ;-)

  2. Tine sagt:

    Deine Website ist super. Daumen hoch.
    Meine Frage ist, ob es möglich ist mit dem F4 per CAN im DMA-Mode zu senden und empfangen. Mit der UART ist das problemlos möglich. Aber auch mit CAN?

    • admin_ub sagt:

      so wie ich das im RefManual gesehen habe nicht.

  3. Niko sagt:

    Ich möchte mal ein Dankeschön für diese Arbeit aussprechen, die du hier geleistet hast. Deine ganzen Beispiele haben es mir ermöglicht, innerhalb kurzer Zeit das STM32F4 Discovery Board zu verstehen und damit einen CAN Bus aufzubauen.
    Das war und ist definitiv eine große Unterstützung gewesen :)

    MfG
    Niko

  4. R. sagt:

    Hallo,
    zunächst möchte ich mich für diese super Seite bei dir bedanken! Hat mir schon viel weitergeholfen.

    Im Moment versuche ich gerade an meinem STM32F4 Disco Board den CAN in Betrieb zu nehmen, allerdings habe ich folgendes Problem:

    Ich habe zum Testen deine CAN_LO_Level Demo heruntergeladen und kompiliert. Alles prima soweit. Wenn ich nun aber ein Oszi an die beiden CAN Pins hänge (PB8 + PB9) kommen da einfach nur dauerhaft ~3 V raus.

    Dann hab ich gesehen, dass du schreibst ein externer Transciever sollte dran sein, also hab ich den ISO1050 den ich im Projekt verwenden möchte dran gehängt, inkl. 120 Ohm Abschlusswiderstand und dann gemessen. Nun komen aus den beiden Pins dauerhaft ~ 1,6 V raus, aber ein Signal kann ich leider nicht erkennen.

    Kannst du mir da weiterhelfen?

    Viele Grüße
    Ralph

    • admin_ub sagt:

      CAN braucht eine Gegenstelle sonst bricht das senden einfach ab. Du musst das Oszi auf “Single-Trigger” stellen um da was zu sehen. Oder mach den ISO1050 nochmal weg und verbinde PB9 und PB8 vom Prozessor, dann werden zwar ständig Telegramme gesendet aber zumindest siehst du was am TX-Pin PB9.

  5. Reamon sagt:

    Hallo,
    erstmal möchte ich die tolle Arbeit loben. Das hat mich beim Verständnis sehr geholfen.
    Ich wollte zusätzlich den CAN2 nutzen und habe dein Code erweitert.
    Aber das Problem ist, dass ich über CAN2 nur senden kann, aber nicht empfangen.
    CAN1 kann ich ganz normal senden und empfangen.
    Ich habe festgestellt, dass CAN2_RX0_IRQHandler() gar nicht aufgerufen wird wenn eine neue Botschaft über CAN2 kommt.
    Gibt es da ein Trick?
    Ich wäre sehr dankbar wenn jemand mir helfen könnte.

    • admin_ub sagt:

      ich habe damals CAN1 und CAN2 getestet (allerdings nicht CAN1+CAN2). Lass mal in der Software die CAN1-Files komplett weg (event. stören die sich) und setze keine Filter ob es dann funktioniert.
      Hast du verifiziert das die Pegel am RX-Pin der CPU stimmen ?

  6. Reamon sagt:

    Es lag an der falschen Filterbank. Filterbank 0 bus 13 sind für CAN1 und Filterbank 14 bis 27 sind für CAN2. Deshalb konnte über CAN2 nichts empfangen werden, weil eben der Filter nichts durchgelassen hat.
    Danke!

    • admin_ub sagt:

      ok, diese Info steht oben im Text, im Sourcecode und im RefManual :-)
      und in meinem Quellcode wird eine falsche Filternummer gar nicht zugelassen.


Wie hat Dir dieser Artikel gefallen?

1 Stern2 Sterne3 Sterne4 Sterne5 Sterne (Noch keine Bewertungen)
Loading...

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert